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