fe70a368cf07508176c874882e5e59be063eedd5
[dragonfly.git] / crypto / openssh / authfile.c
1 /* $OpenBSD: authfile.c,v 1.107 2014/06/24 01:13:21 djm Exp $ */
2 /*
3  * Copyright (c) 2000, 2013 Markus Friedl.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "includes.h"
27
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/param.h>
31 #include <sys/uio.h>
32
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <stdio.h>
36 #include <stdarg.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40
41 #include "cipher.h"
42 #include "key.h"
43 #include "ssh.h"
44 #include "log.h"
45 #include "authfile.h"
46 #include "rsa.h"
47 #include "misc.h"
48 #include "atomicio.h"
49 #include "sshbuf.h"
50 #include "ssherr.h"
51 #include "pathnames.h"
52
53 #define MAX_KEY_FILE_SIZE       (1024 * 1024)
54
55 /* Save a key blob to a file */
56 static int
57 sshkey_save_private_blob(struct sshbuf *keybuf, const char *filename)
58 {
59         int fd, oerrno;
60
61         if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)
62                 return SSH_ERR_SYSTEM_ERROR;
63         if (atomicio(vwrite, fd, (u_char *)sshbuf_ptr(keybuf),
64             sshbuf_len(keybuf)) != sshbuf_len(keybuf)) {
65                 oerrno = errno;
66                 close(fd);
67                 unlink(filename);
68                 errno = oerrno;
69                 return SSH_ERR_SYSTEM_ERROR;
70         }
71         close(fd);
72         return 0;
73 }
74
75 int
76 sshkey_save_private(struct sshkey *key, const char *filename,
77     const char *passphrase, const char *comment,
78     int force_new_format, const char *new_format_cipher, int new_format_rounds)
79 {
80         struct sshbuf *keyblob = NULL;
81         int r;
82
83         if ((keyblob = sshbuf_new()) == NULL)
84                 return SSH_ERR_ALLOC_FAIL;
85         if ((r = sshkey_private_to_fileblob(key, keyblob, passphrase, comment,
86             force_new_format, new_format_cipher, new_format_rounds)) != 0)
87                 goto out;
88         if ((r = sshkey_save_private_blob(keyblob, filename)) != 0)
89                 goto out;
90         r = 0;
91  out:
92         sshbuf_free(keyblob);
93         return r;
94 }
95
96 /* Load a key from a fd into a buffer */
97 int
98 sshkey_load_file(int fd, const char *filename, struct sshbuf *blob)
99 {
100         u_char buf[1024];
101         size_t len;
102         struct stat st;
103         int r;
104
105         if (fstat(fd, &st) < 0)
106                 return SSH_ERR_SYSTEM_ERROR;
107         if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
108             st.st_size > MAX_KEY_FILE_SIZE)
109                 return SSH_ERR_INVALID_FORMAT;
110         for (;;) {
111                 if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) {
112                         if (errno == EPIPE)
113                                 break;
114                         r = SSH_ERR_SYSTEM_ERROR;
115                         goto out;
116                 }
117                 if ((r = sshbuf_put(blob, buf, len)) != 0)
118                         goto out;
119                 if (sshbuf_len(blob) > MAX_KEY_FILE_SIZE) {
120                         r = SSH_ERR_INVALID_FORMAT;
121                         goto out;
122                 }
123         }
124         if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
125             st.st_size != (off_t)sshbuf_len(blob)) {
126                 r = SSH_ERR_FILE_CHANGED;
127                 goto out;
128         }
129         r = 0;
130
131  out:
132         explicit_bzero(buf, sizeof(buf));
133         if (r != 0)
134                 sshbuf_reset(blob);
135         return r;
136 }
137
138 #ifdef WITH_SSH1
139 /*
140  * Loads the public part of the ssh v1 key file.  Returns NULL if an error was
141  * encountered (the file does not exist or is not readable), and the key
142  * otherwise.
143  */
144 static int
145 sshkey_load_public_rsa1(int fd, const char *filename,
146     struct sshkey **keyp, char **commentp)
147 {
148         struct sshbuf *b = NULL;
149         int r;
150
151         *keyp = NULL;
152         if (commentp != NULL)
153                 *commentp = NULL;
154
155         if ((b = sshbuf_new()) == NULL)
156                 return SSH_ERR_ALLOC_FAIL;
157         if ((r = sshkey_load_file(fd, filename, b)) != 0)
158                 goto out;
159         if ((r = sshkey_parse_public_rsa1_fileblob(b, keyp, commentp)) != 0)
160                 goto out;
161         r = 0;
162  out:
163         sshbuf_free(b);
164         return r;
165 }
166 #endif /* WITH_SSH1 */
167
168 #ifdef WITH_OPENSSL
169 /* XXX Deprecate? */
170 int
171 sshkey_load_private_pem(int fd, int type, const char *passphrase,
172     struct sshkey **keyp, char **commentp)
173 {
174         struct sshbuf *buffer = NULL;
175         int r;
176
177         *keyp = NULL;
178         if (commentp != NULL)
179                 *commentp = NULL;
180
181         if ((buffer = sshbuf_new()) == NULL)
182                 return SSH_ERR_ALLOC_FAIL;
183         if ((r = sshkey_load_file(fd, NULL, buffer)) != 0)
184                 goto out;
185         if ((r = sshkey_parse_private_pem_fileblob(buffer, type, passphrase,
186             keyp, commentp)) != 0)
187                 goto out;
188         r = 0;
189  out:
190         sshbuf_free(buffer);
191         return r;
192 }
193 #endif /* WITH_OPENSSL */
194
195 /* XXX remove error() calls from here? */
196 int
197 sshkey_perm_ok(int fd, const char *filename)
198 {
199         struct stat st;
200
201         if (fstat(fd, &st) < 0)
202                 return SSH_ERR_SYSTEM_ERROR;
203         /*
204          * if a key owned by the user is accessed, then we check the
205          * permissions of the file. if the key owned by a different user,
206          * then we don't care.
207          */
208 #ifdef HAVE_CYGWIN
209         if (check_ntsec(filename))
210 #endif
211         if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
212                 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
213                 error("@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @");
214                 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
215                 error("Permissions 0%3.3o for '%s' are too open.",
216                     (u_int)st.st_mode & 0777, filename);
217                 error("It is recommended that your private key files are NOT accessible by others.");
218                 error("This private key will be ignored.");
219                 return SSH_ERR_KEY_BAD_PERMISSIONS;
220         }
221         return 0;
222 }
223
224 /* XXX kill perm_ok now that we have SSH_ERR_KEY_BAD_PERMISSIONS? */
225 int
226 sshkey_load_private_type(int type, const char *filename, const char *passphrase,
227     struct sshkey **keyp, char **commentp, int *perm_ok)
228 {
229         int fd, r;
230         struct sshbuf *buffer = NULL;
231
232         *keyp = NULL;
233         if (commentp != NULL)
234                 *commentp = NULL;
235
236         if ((fd = open(filename, O_RDONLY)) < 0) {
237                 if (perm_ok != NULL)
238                         *perm_ok = 0;
239                 return SSH_ERR_SYSTEM_ERROR;
240         }
241         if (sshkey_perm_ok(fd, filename) != 0) {
242                 if (perm_ok != NULL)
243                         *perm_ok = 0;
244                 r = SSH_ERR_KEY_BAD_PERMISSIONS;
245                 goto out;
246         }
247         if (perm_ok != NULL)
248                 *perm_ok = 1;
249
250         if ((buffer = sshbuf_new()) == NULL) {
251                 r = SSH_ERR_ALLOC_FAIL;
252                 goto out;
253         }
254         if ((r = sshkey_load_file(fd, filename, buffer)) != 0)
255                 goto out;
256         if ((r = sshkey_parse_private_fileblob_type(buffer, type, passphrase,
257             keyp, commentp)) != 0)
258                 goto out;
259         r = 0;
260  out:
261         close(fd);
262         if (buffer != NULL)
263                 sshbuf_free(buffer);
264         return r;
265 }
266
267 /* XXX this is almost identical to sshkey_load_private_type() */
268 int
269 sshkey_load_private(const char *filename, const char *passphrase,
270     struct sshkey **keyp, char **commentp)
271 {
272         struct sshbuf *buffer = NULL;
273         int r, fd;
274
275         *keyp = NULL;
276         if (commentp != NULL)
277                 *commentp = NULL;
278
279         if ((fd = open(filename, O_RDONLY)) < 0)
280                 return SSH_ERR_SYSTEM_ERROR;
281         if (sshkey_perm_ok(fd, filename) != 0) {
282                 r = SSH_ERR_KEY_BAD_PERMISSIONS;
283                 goto out;
284         }
285
286         if ((buffer = sshbuf_new()) == NULL) {
287                 r = SSH_ERR_ALLOC_FAIL;
288                 goto out;
289         }
290         if ((r = sshkey_load_file(fd, filename, buffer)) != 0 ||
291             (r = sshkey_parse_private_fileblob(buffer, passphrase, filename,
292             keyp, commentp)) != 0)
293                 goto out;
294         r = 0;
295  out:
296         close(fd);
297         if (buffer != NULL)
298                 sshbuf_free(buffer);
299         return r;
300 }
301
302 static int
303 sshkey_try_load_public(struct sshkey *k, const char *filename, char **commentp)
304 {
305         FILE *f;
306         char line[SSH_MAX_PUBKEY_BYTES];
307         char *cp;
308         u_long linenum = 0;
309         int r;
310
311         if (commentp != NULL)
312                 *commentp = NULL;
313         if ((f = fopen(filename, "r")) == NULL)
314                 return SSH_ERR_SYSTEM_ERROR;
315         while (read_keyfile_line(f, filename, line, sizeof(line),
316                     &linenum) != -1) {
317                 cp = line;
318                 switch (*cp) {
319                 case '#':
320                 case '\n':
321                 case '\0':
322                         continue;
323                 }
324                 /* Abort loading if this looks like a private key */
325                 if (strncmp(cp, "-----BEGIN", 10) == 0 ||
326                     strcmp(cp, "SSH PRIVATE KEY FILE") == 0)
327                         break;
328                 /* Skip leading whitespace. */
329                 for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
330                         ;
331                 if (*cp) {
332                         if ((r = sshkey_read(k, &cp)) == 0) {
333                                 cp[strcspn(cp, "\r\n")] = '\0';
334                                 if (commentp) {
335                                         *commentp = strdup(*cp ?
336                                             cp : filename);
337                                         if (*commentp == NULL)
338                                                 r = SSH_ERR_ALLOC_FAIL;
339                                 }
340                                 fclose(f);
341                                 return r;
342                         }
343                 }
344         }
345         fclose(f);
346         return SSH_ERR_INVALID_FORMAT;
347 }
348
349 /* load public key from ssh v1 private or any pubkey file */
350 int
351 sshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp)
352 {
353         struct sshkey *pub = NULL;
354         char file[MAXPATHLEN];
355         int r, fd;
356
357         if (keyp != NULL)
358                 *keyp = NULL;
359         if (commentp != NULL)
360                 *commentp = NULL;
361
362         if ((fd = open(filename, O_RDONLY)) < 0)
363                 goto skip;
364 #ifdef WITH_SSH1
365         /* try rsa1 private key */
366         r = sshkey_load_public_rsa1(fd, filename, keyp, commentp);
367         close(fd);
368         switch (r) {
369         case SSH_ERR_INTERNAL_ERROR:
370         case SSH_ERR_ALLOC_FAIL:
371         case SSH_ERR_INVALID_ARGUMENT:
372         case SSH_ERR_SYSTEM_ERROR:
373         case 0:
374                 return r;
375         }
376 #endif /* WITH_SSH1 */
377
378         /* try ssh2 public key */
379         if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
380                 return SSH_ERR_ALLOC_FAIL;
381         if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
382                 if (keyp != NULL)
383                         *keyp = pub;
384                 return 0;
385         }
386         sshkey_free(pub);
387
388 #ifdef WITH_SSH1
389         /* try rsa1 public key */
390         if ((pub = sshkey_new(KEY_RSA1)) == NULL)
391                 return SSH_ERR_ALLOC_FAIL;
392         if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
393                 if (keyp != NULL)
394                         *keyp = pub;
395                 return 0;
396         }
397         sshkey_free(pub);
398 #endif /* WITH_SSH1 */
399
400  skip:
401         /* try .pub suffix */
402         if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
403                 return SSH_ERR_ALLOC_FAIL;
404         r = SSH_ERR_ALLOC_FAIL; /* in case strlcpy or strlcat fail */
405         if ((strlcpy(file, filename, sizeof file) < sizeof(file)) &&
406             (strlcat(file, ".pub", sizeof file) < sizeof(file)) &&
407             (r = sshkey_try_load_public(pub, file, commentp)) == 0) {
408                 if (keyp != NULL)
409                         *keyp = pub;
410                 return 0;
411         }
412         sshkey_free(pub);
413         return r;
414 }
415
416 char *
417 blacklist_filename(const Key *key)
418 {
419         char *name;
420
421         xasprintf(&name, "%s.%s-%u",
422             _PATH_BLACKLIST, key_type(key), key_size(key));
423         return name;
424 }
425
426 /* Scan a blacklist of known-vulnerable keys. */
427 int
428 blacklisted_key(Key *key)
429 {
430         char *blacklist_file;
431         int fd = -1;
432         char *dgst_hex = NULL;
433         char *dgst_packed = NULL, *p;
434         int i;
435         size_t line_len;
436         struct stat st;
437         char buf[256];
438         off_t start, lower, upper;
439         int ret = 0;
440
441         blacklist_file = blacklist_filename(key);
442         debug("Checking blacklist file %s", blacklist_file);
443         fd = open(blacklist_file, O_RDONLY);
444         if (fd < 0)
445                 goto out;
446
447         dgst_hex = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
448         /* Remove all colons */
449         dgst_packed = xcalloc(1, strlen(dgst_hex) + 1);
450         for (i = 0, p = dgst_packed; dgst_hex[i]; i++)
451                 if (dgst_hex[i] != ':')
452                         *p++ = dgst_hex[i];
453         /* Only compare least-significant 80 bits (to keep the blacklist
454          * size down)
455          */
456         line_len = strlen(dgst_packed + 12);
457         if (line_len > 32)
458                 goto out;
459
460         /* Skip leading comments */
461         start = 0;
462         for (;;) {
463                 ssize_t r;
464                 char *newline;
465
466                 r = atomicio(read, fd, buf, 256);
467                 if (r <= 0)
468                         goto out;
469                 if (buf[0] != '#')
470                         break;
471
472                 newline = memchr(buf, '\n', 256);
473                 if (!newline)
474                         goto out;
475                 start += newline + 1 - buf;
476                 if (lseek(fd, start, SEEK_SET) < 0)
477                         goto out;
478         }
479
480         /* Initialise binary search record numbers */
481         if (fstat(fd, &st) < 0)
482                 goto out;
483         lower = 0;
484         upper = (st.st_size - start) / (line_len + 1);
485
486         while (lower != upper) {
487                 off_t cur;
488                 char buf[32];
489                 int cmp;
490
491                 cur = lower + (upper - lower) / 2;
492
493                 /* Read this line and compare to digest; this is
494                  * overflow-safe since cur < max(off_t) / (line_len + 1) */
495                 if (lseek(fd, start + cur * (line_len + 1), SEEK_SET) < 0)
496                         break;
497                 if (atomicio(read, fd, buf, line_len) != line_len)
498                         break;
499                 cmp = memcmp(buf, dgst_packed + 12, line_len);
500                 if (cmp < 0) {
501                         if (cur == lower)
502                                 break;
503                         lower = cur;
504                 } else if (cmp > 0) {
505                         if (cur == upper)
506                                 break;
507                         upper = cur;
508                 } else {
509                         debug("Found %s in blacklist", dgst_hex);
510                         ret = 1;
511                         break;
512                 }
513         }
514
515 out:
516         if (dgst_packed)
517                 xfree(dgst_packed);
518         if (dgst_hex)
519                 xfree(dgst_hex);
520         if (fd >= 0)
521                 close(fd);
522         xfree(blacklist_file);
523         return ret;
524 }
525
526 /* Load the certificate associated with the named private key */
527 int
528 sshkey_load_cert(const char *filename, struct sshkey **keyp)
529 {
530         struct sshkey *pub = NULL;
531         char *file = NULL;
532         int r = SSH_ERR_INTERNAL_ERROR;
533
534         *keyp = NULL;
535
536         if (asprintf(&file, "%s-cert.pub", filename) == -1)
537                 return SSH_ERR_ALLOC_FAIL;
538
539         if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
540                 goto out;
541         }
542         if ((r = sshkey_try_load_public(pub, file, NULL)) != 0)
543                 goto out;
544
545         *keyp = pub;
546         pub = NULL;
547         r = 0;
548
549  out:
550         if (file != NULL)
551                 free(file);
552         if (pub != NULL)
553                 sshkey_free(pub);
554         return r;
555 }
556
557 /* Load private key and certificate */
558 int
559 sshkey_load_private_cert(int type, const char *filename, const char *passphrase,
560     struct sshkey **keyp, int *perm_ok)
561 {
562         struct sshkey *key = NULL, *cert = NULL;
563         int r;
564
565         *keyp = NULL;
566
567         switch (type) {
568 #ifdef WITH_OPENSSL
569         case KEY_RSA:
570         case KEY_DSA:
571         case KEY_ECDSA:
572         case KEY_ED25519:
573 #endif /* WITH_OPENSSL */
574         case KEY_UNSPEC:
575                 break;
576         default:
577                 return SSH_ERR_KEY_TYPE_UNKNOWN;
578         }
579
580         if ((r = sshkey_load_private_type(type, filename,
581             passphrase, &key, NULL, perm_ok)) != 0 ||
582             (r = sshkey_load_cert(filename, &cert)) != 0)
583                 goto out;
584
585         /* Make sure the private key matches the certificate */
586         if (sshkey_equal_public(key, cert) == 0) {
587                 r = SSH_ERR_KEY_CERT_MISMATCH;
588                 goto out;
589         }
590
591         if ((r = sshkey_to_certified(key, sshkey_cert_is_legacy(cert))) != 0 ||
592             (r = sshkey_cert_copy(cert, key)) != 0)
593                 goto out;
594         r = 0;
595         *keyp = key;
596         key = NULL;
597  out:
598         if (key != NULL)
599                 sshkey_free(key);
600         if (cert != NULL)
601                 sshkey_free(cert);
602         return r;
603 }
604
605 /*
606  * Returns success if the specified "key" is listed in the file "filename",
607  * SSH_ERR_KEY_NOT_FOUND: if the key is not listed or another error.
608  * If strict_type is set then the key type must match exactly,
609  * otherwise a comparison that ignores certficiate data is performed.
610  */
611 int
612 sshkey_in_file(struct sshkey *key, const char *filename, int strict_type)
613 {
614         FILE *f;
615         char line[SSH_MAX_PUBKEY_BYTES];
616         char *cp;
617         u_long linenum = 0;
618         int r = 0;
619         struct sshkey *pub = NULL;
620         int (*sshkey_compare)(const struct sshkey *, const struct sshkey *) =
621             strict_type ?  sshkey_equal : sshkey_equal_public;
622
623         if ((f = fopen(filename, "r")) == NULL) {
624                 if (errno == ENOENT)
625                         return SSH_ERR_KEY_NOT_FOUND;
626                 else
627                         return SSH_ERR_SYSTEM_ERROR;
628         }
629
630         while (read_keyfile_line(f, filename, line, sizeof(line),
631             &linenum) != -1) {
632                 cp = line;
633
634                 /* Skip leading whitespace. */
635                 for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
636                         ;
637
638                 /* Skip comments and empty lines */
639                 switch (*cp) {
640                 case '#':
641                 case '\n':
642                 case '\0':
643                         continue;
644                 }
645
646                 if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
647                         r = SSH_ERR_ALLOC_FAIL;
648                         goto out;
649                 }
650                 if ((r = sshkey_read(pub, &cp)) != 0)
651                         goto out;
652                 if (sshkey_compare(key, pub)) {
653                         r = 0;
654                         goto out;
655                 }
656                 sshkey_free(pub);
657                 pub = NULL;
658         }
659         r = SSH_ERR_KEY_NOT_FOUND;
660  out:
661         if (pub != NULL)
662                 sshkey_free(pub);
663         fclose(f);
664         return r;
665 }
666