Merge branch 'vendor/DHCPCD'
[dragonfly.git] / crypto / openssh / authfile.c
1 /* $OpenBSD: authfile.c,v 1.127 2017/07/01 13:50:45 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/uio.h>
31
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <stdio.h>
35 #include <stdarg.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unistd.h>
39 #include <limits.h>
40
41 #include "cipher.h"
42 #include "ssh.h"
43 #include "log.h"
44 #include "authfile.h"
45 #include "misc.h"
46 #include "atomicio.h"
47 #include "sshkey.h"
48 #include "sshbuf.h"
49 #include "ssherr.h"
50 #include "krl.h"
51
52 #define MAX_KEY_FILE_SIZE       (1024 * 1024)
53
54 /* Save a key blob to a file */
55 static int
56 sshkey_save_private_blob(struct sshbuf *keybuf, const char *filename)
57 {
58         int fd, oerrno;
59
60         if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)
61                 return SSH_ERR_SYSTEM_ERROR;
62         if (atomicio(vwrite, fd, (u_char *)sshbuf_ptr(keybuf),
63             sshbuf_len(keybuf)) != sshbuf_len(keybuf)) {
64                 oerrno = errno;
65                 close(fd);
66                 unlink(filename);
67                 errno = oerrno;
68                 return SSH_ERR_SYSTEM_ERROR;
69         }
70         close(fd);
71         return 0;
72 }
73
74 int
75 sshkey_save_private(struct sshkey *key, const char *filename,
76     const char *passphrase, const char *comment,
77     int force_new_format, const char *new_format_cipher, int new_format_rounds)
78 {
79         struct sshbuf *keyblob = NULL;
80         int r;
81
82         if ((keyblob = sshbuf_new()) == NULL)
83                 return SSH_ERR_ALLOC_FAIL;
84         if ((r = sshkey_private_to_fileblob(key, keyblob, passphrase, comment,
85             force_new_format, new_format_cipher, new_format_rounds)) != 0)
86                 goto out;
87         if ((r = sshkey_save_private_blob(keyblob, filename)) != 0)
88                 goto out;
89         r = 0;
90  out:
91         sshbuf_free(keyblob);
92         return r;
93 }
94
95 /* Load a key from a fd into a buffer */
96 int
97 sshkey_load_file(int fd, struct sshbuf *blob)
98 {
99         u_char buf[1024];
100         size_t len;
101         struct stat st;
102         int r;
103
104         if (fstat(fd, &st) < 0)
105                 return SSH_ERR_SYSTEM_ERROR;
106         if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
107             st.st_size > MAX_KEY_FILE_SIZE)
108                 return SSH_ERR_INVALID_FORMAT;
109         for (;;) {
110                 if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) {
111                         if (errno == EPIPE)
112                                 break;
113                         r = SSH_ERR_SYSTEM_ERROR;
114                         goto out;
115                 }
116                 if ((r = sshbuf_put(blob, buf, len)) != 0)
117                         goto out;
118                 if (sshbuf_len(blob) > MAX_KEY_FILE_SIZE) {
119                         r = SSH_ERR_INVALID_FORMAT;
120                         goto out;
121                 }
122         }
123         if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
124             st.st_size != (off_t)sshbuf_len(blob)) {
125                 r = SSH_ERR_FILE_CHANGED;
126                 goto out;
127         }
128         r = 0;
129
130  out:
131         explicit_bzero(buf, sizeof(buf));
132         if (r != 0)
133                 sshbuf_reset(blob);
134         return r;
135 }
136
137
138 /* XXX remove error() calls from here? */
139 int
140 sshkey_perm_ok(int fd, const char *filename)
141 {
142         struct stat st;
143
144         if (fstat(fd, &st) < 0)
145                 return SSH_ERR_SYSTEM_ERROR;
146         /*
147          * if a key owned by the user is accessed, then we check the
148          * permissions of the file. if the key owned by a different user,
149          * then we don't care.
150          */
151 #ifdef HAVE_CYGWIN
152         if (check_ntsec(filename))
153 #endif
154         if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
155                 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
156                 error("@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @");
157                 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
158                 error("Permissions 0%3.3o for '%s' are too open.",
159                     (u_int)st.st_mode & 0777, filename);
160                 error("It is required that your private key files are NOT accessible by others.");
161                 error("This private key will be ignored.");
162                 return SSH_ERR_KEY_BAD_PERMISSIONS;
163         }
164         return 0;
165 }
166
167 /* XXX kill perm_ok now that we have SSH_ERR_KEY_BAD_PERMISSIONS? */
168 int
169 sshkey_load_private_type(int type, const char *filename, const char *passphrase,
170     struct sshkey **keyp, char **commentp, int *perm_ok)
171 {
172         int fd, r;
173
174         if (keyp != NULL)
175                 *keyp = NULL;
176         if (commentp != NULL)
177                 *commentp = NULL;
178
179         if ((fd = open(filename, O_RDONLY)) < 0) {
180                 if (perm_ok != NULL)
181                         *perm_ok = 0;
182                 return SSH_ERR_SYSTEM_ERROR;
183         }
184         if (sshkey_perm_ok(fd, filename) != 0) {
185                 if (perm_ok != NULL)
186                         *perm_ok = 0;
187                 r = SSH_ERR_KEY_BAD_PERMISSIONS;
188                 goto out;
189         }
190         if (perm_ok != NULL)
191                 *perm_ok = 1;
192
193         r = sshkey_load_private_type_fd(fd, type, passphrase, keyp, commentp);
194  out:
195         close(fd);
196         return r;
197 }
198
199 int
200 sshkey_load_private_type_fd(int fd, int type, const char *passphrase,
201     struct sshkey **keyp, char **commentp)
202 {
203         struct sshbuf *buffer = NULL;
204         int r;
205
206         if (keyp != NULL)
207                 *keyp = NULL;
208         if ((buffer = sshbuf_new()) == NULL) {
209                 r = SSH_ERR_ALLOC_FAIL;
210                 goto out;
211         }
212         if ((r = sshkey_load_file(fd, buffer)) != 0 ||
213             (r = sshkey_parse_private_fileblob_type(buffer, type,
214             passphrase, keyp, commentp)) != 0)
215                 goto out;
216
217         /* success */
218         r = 0;
219  out:
220         sshbuf_free(buffer);
221         return r;
222 }
223
224 /* XXX this is almost identical to sshkey_load_private_type() */
225 int
226 sshkey_load_private(const char *filename, const char *passphrase,
227     struct sshkey **keyp, char **commentp)
228 {
229         struct sshbuf *buffer = NULL;
230         int r, fd;
231
232         if (keyp != NULL)
233                 *keyp = NULL;
234         if (commentp != NULL)
235                 *commentp = NULL;
236
237         if ((fd = open(filename, O_RDONLY)) < 0)
238                 return SSH_ERR_SYSTEM_ERROR;
239         if (sshkey_perm_ok(fd, filename) != 0) {
240                 r = SSH_ERR_KEY_BAD_PERMISSIONS;
241                 goto out;
242         }
243
244         if ((buffer = sshbuf_new()) == NULL) {
245                 r = SSH_ERR_ALLOC_FAIL;
246                 goto out;
247         }
248         if ((r = sshkey_load_file(fd, buffer)) != 0 ||
249             (r = sshkey_parse_private_fileblob(buffer, passphrase, keyp,
250             commentp)) != 0)
251                 goto out;
252         r = 0;
253  out:
254         close(fd);
255         sshbuf_free(buffer);
256         return r;
257 }
258
259 static int
260 sshkey_try_load_public(struct sshkey *k, const char *filename, char **commentp)
261 {
262         FILE *f;
263         char line[SSH_MAX_PUBKEY_BYTES];
264         char *cp;
265         u_long linenum = 0;
266         int r;
267
268         if (commentp != NULL)
269                 *commentp = NULL;
270         if ((f = fopen(filename, "r")) == NULL)
271                 return SSH_ERR_SYSTEM_ERROR;
272         while (read_keyfile_line(f, filename, line, sizeof(line),
273                     &linenum) != -1) {
274                 cp = line;
275                 switch (*cp) {
276                 case '#':
277                 case '\n':
278                 case '\0':
279                         continue;
280                 }
281                 /* Abort loading if this looks like a private key */
282                 if (strncmp(cp, "-----BEGIN", 10) == 0 ||
283                     strcmp(cp, "SSH PRIVATE KEY FILE") == 0)
284                         break;
285                 /* Skip leading whitespace. */
286                 for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
287                         ;
288                 if (*cp) {
289                         if ((r = sshkey_read(k, &cp)) == 0) {
290                                 cp[strcspn(cp, "\r\n")] = '\0';
291                                 if (commentp) {
292                                         *commentp = strdup(*cp ?
293                                             cp : filename);
294                                         if (*commentp == NULL)
295                                                 r = SSH_ERR_ALLOC_FAIL;
296                                 }
297                                 fclose(f);
298                                 return r;
299                         }
300                 }
301         }
302         fclose(f);
303         return SSH_ERR_INVALID_FORMAT;
304 }
305
306 /* load public key from any pubkey file */
307 int
308 sshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp)
309 {
310         struct sshkey *pub = NULL;
311         char *file = NULL;
312         int r;
313
314         if (keyp != NULL)
315                 *keyp = NULL;
316         if (commentp != NULL)
317                 *commentp = NULL;
318
319         if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
320                 return SSH_ERR_ALLOC_FAIL;
321         if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
322                 if (keyp != NULL) {
323                         *keyp = pub;
324                         pub = NULL;
325                 }
326                 r = 0;
327                 goto out;
328         }
329         sshkey_free(pub);
330
331         /* try .pub suffix */
332         if (asprintf(&file, "%s.pub", filename) == -1)
333                 return SSH_ERR_ALLOC_FAIL;
334         if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
335                 r = SSH_ERR_ALLOC_FAIL;
336                 goto out;
337         }
338         if ((r = sshkey_try_load_public(pub, file, commentp)) == 0) {
339                 if (keyp != NULL) {
340                         *keyp = pub;
341                         pub = NULL;
342                 }
343                 r = 0;
344         }
345  out:
346         free(file);
347         sshkey_free(pub);
348         return r;
349 }
350
351 /* Load the certificate associated with the named private key */
352 int
353 sshkey_load_cert(const char *filename, struct sshkey **keyp)
354 {
355         struct sshkey *pub = NULL;
356         char *file = NULL;
357         int r = SSH_ERR_INTERNAL_ERROR;
358
359         if (keyp != NULL)
360                 *keyp = NULL;
361
362         if (asprintf(&file, "%s-cert.pub", filename) == -1)
363                 return SSH_ERR_ALLOC_FAIL;
364
365         if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
366                 goto out;
367         }
368         if ((r = sshkey_try_load_public(pub, file, NULL)) != 0)
369                 goto out;
370         /* success */
371         if (keyp != NULL) {
372                 *keyp = pub;
373                 pub = NULL;
374         }
375         r = 0;
376  out:
377         free(file);
378         sshkey_free(pub);
379         return r;
380 }
381
382 /* Load private key and certificate */
383 int
384 sshkey_load_private_cert(int type, const char *filename, const char *passphrase,
385     struct sshkey **keyp, int *perm_ok)
386 {
387         struct sshkey *key = NULL, *cert = NULL;
388         int r;
389
390         if (keyp != NULL)
391                 *keyp = NULL;
392
393         switch (type) {
394 #ifdef WITH_OPENSSL
395         case KEY_RSA:
396         case KEY_DSA:
397         case KEY_ECDSA:
398 #endif /* WITH_OPENSSL */
399         case KEY_ED25519:
400         case KEY_UNSPEC:
401                 break;
402         default:
403                 return SSH_ERR_KEY_TYPE_UNKNOWN;
404         }
405
406         if ((r = sshkey_load_private_type(type, filename,
407             passphrase, &key, NULL, perm_ok)) != 0 ||
408             (r = sshkey_load_cert(filename, &cert)) != 0)
409                 goto out;
410
411         /* Make sure the private key matches the certificate */
412         if (sshkey_equal_public(key, cert) == 0) {
413                 r = SSH_ERR_KEY_CERT_MISMATCH;
414                 goto out;
415         }
416
417         if ((r = sshkey_to_certified(key)) != 0 ||
418             (r = sshkey_cert_copy(cert, key)) != 0)
419                 goto out;
420         r = 0;
421         if (keyp != NULL) {
422                 *keyp = key;
423                 key = NULL;
424         }
425  out:
426         sshkey_free(key);
427         sshkey_free(cert);
428         return r;
429 }
430
431 /*
432  * Returns success if the specified "key" is listed in the file "filename",
433  * SSH_ERR_KEY_NOT_FOUND: if the key is not listed or another error.
434  * If "strict_type" is set then the key type must match exactly,
435  * otherwise a comparison that ignores certficiate data is performed.
436  * If "check_ca" is set and "key" is a certificate, then its CA key is
437  * also checked and sshkey_in_file() will return success if either is found.
438  */
439 int
440 sshkey_in_file(struct sshkey *key, const char *filename, int strict_type,
441     int check_ca)
442 {
443         FILE *f;
444         char line[SSH_MAX_PUBKEY_BYTES];
445         char *cp;
446         u_long linenum = 0;
447         int r = 0;
448         struct sshkey *pub = NULL;
449         int (*sshkey_compare)(const struct sshkey *, const struct sshkey *) =
450             strict_type ?  sshkey_equal : sshkey_equal_public;
451
452         if ((f = fopen(filename, "r")) == NULL)
453                 return SSH_ERR_SYSTEM_ERROR;
454
455         while (read_keyfile_line(f, filename, line, sizeof(line),
456             &linenum) != -1) {
457                 cp = line;
458
459                 /* Skip leading whitespace. */
460                 for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
461                         ;
462
463                 /* Skip comments and empty lines */
464                 switch (*cp) {
465                 case '#':
466                 case '\n':
467                 case '\0':
468                         continue;
469                 }
470
471                 if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
472                         r = SSH_ERR_ALLOC_FAIL;
473                         goto out;
474                 }
475                 if ((r = sshkey_read(pub, &cp)) != 0)
476                         goto out;
477                 if (sshkey_compare(key, pub) ||
478                     (check_ca && sshkey_is_cert(key) &&
479                     sshkey_compare(key->cert->signature_key, pub))) {
480                         r = 0;
481                         goto out;
482                 }
483                 sshkey_free(pub);
484                 pub = NULL;
485         }
486         r = SSH_ERR_KEY_NOT_FOUND;
487  out:
488         sshkey_free(pub);
489         fclose(f);
490         return r;
491 }
492
493 /*
494  * Checks whether the specified key is revoked, returning 0 if not,
495  * SSH_ERR_KEY_REVOKED if it is or another error code if something
496  * unexpected happened.
497  * This will check both the key and, if it is a certificate, its CA key too.
498  * "revoked_keys_file" may be a KRL or a one-per-line list of public keys.
499  */
500 int
501 sshkey_check_revoked(struct sshkey *key, const char *revoked_keys_file)
502 {
503         int r;
504
505         r = ssh_krl_file_contains_key(revoked_keys_file, key);
506         /* If this was not a KRL to begin with then continue below */
507         if (r != SSH_ERR_KRL_BAD_MAGIC)
508                 return r;
509
510         /*
511          * If the file is not a KRL or we can't handle KRLs then attempt to
512          * parse the file as a flat list of keys.
513          */
514         switch ((r = sshkey_in_file(key, revoked_keys_file, 0, 1))) {
515         case 0:
516                 /* Key found => revoked */
517                 return SSH_ERR_KEY_REVOKED;
518         case SSH_ERR_KEY_NOT_FOUND:
519                 /* Key not found => not revoked */
520                 return 0;
521         default:
522                 /* Some other error occurred */
523                 return r;
524         }
525 }
526