xref: /openbsd-src/usr.bin/ssh/authfile.c (revision aa997e528a848ca5596493c2a801bdd6fb26ae61)
1 /* $OpenBSD: authfile.c,v 1.128 2018/02/23 15:58:37 markus 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)) < 0)
59 		return SSH_ERR_SYSTEM_ERROR;
60 	if (atomicio(vwrite, fd, (u_char *)sshbuf_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 force_new_format, const char *new_format_cipher, int new_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 	    force_new_format, new_format_cipher, new_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) < 0)
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) < 0)
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 /* XXX kill perm_ok now that we have SSH_ERR_KEY_BAD_PERMISSIONS? */
163 int
164 sshkey_load_private_type(int type, const char *filename, const char *passphrase,
165     struct sshkey **keyp, char **commentp, int *perm_ok)
166 {
167 	int fd, r;
168 
169 	if (keyp != NULL)
170 		*keyp = NULL;
171 	if (commentp != NULL)
172 		*commentp = NULL;
173 
174 	if ((fd = open(filename, O_RDONLY)) < 0) {
175 		if (perm_ok != NULL)
176 			*perm_ok = 0;
177 		return SSH_ERR_SYSTEM_ERROR;
178 	}
179 	if (sshkey_perm_ok(fd, filename) != 0) {
180 		if (perm_ok != NULL)
181 			*perm_ok = 0;
182 		r = SSH_ERR_KEY_BAD_PERMISSIONS;
183 		goto out;
184 	}
185 	if (perm_ok != NULL)
186 		*perm_ok = 1;
187 
188 	r = sshkey_load_private_type_fd(fd, type, passphrase, keyp, commentp);
189 	if (r == 0 && keyp && *keyp)
190 		r = sshkey_set_filename(*keyp, filename);
191  out:
192 	close(fd);
193 	return r;
194 }
195 
196 int
197 sshkey_load_private_type_fd(int fd, int type, const char *passphrase,
198     struct sshkey **keyp, char **commentp)
199 {
200 	struct sshbuf *buffer = NULL;
201 	int r;
202 
203 	if (keyp != NULL)
204 		*keyp = NULL;
205 	if ((buffer = sshbuf_new()) == NULL) {
206 		r = SSH_ERR_ALLOC_FAIL;
207 		goto out;
208 	}
209 	if ((r = sshkey_load_file(fd, buffer)) != 0 ||
210 	    (r = sshkey_parse_private_fileblob_type(buffer, type,
211 	    passphrase, keyp, commentp)) != 0)
212 		goto out;
213 
214 	/* success */
215 	r = 0;
216  out:
217 	sshbuf_free(buffer);
218 	return r;
219 }
220 
221 /* XXX this is almost identical to sshkey_load_private_type() */
222 int
223 sshkey_load_private(const char *filename, const char *passphrase,
224     struct sshkey **keyp, char **commentp)
225 {
226 	struct sshbuf *buffer = NULL;
227 	int r, fd;
228 
229 	if (keyp != NULL)
230 		*keyp = NULL;
231 	if (commentp != NULL)
232 		*commentp = NULL;
233 
234 	if ((fd = open(filename, O_RDONLY)) < 0)
235 		return SSH_ERR_SYSTEM_ERROR;
236 	if (sshkey_perm_ok(fd, filename) != 0) {
237 		r = SSH_ERR_KEY_BAD_PERMISSIONS;
238 		goto out;
239 	}
240 
241 	if ((buffer = sshbuf_new()) == NULL) {
242 		r = SSH_ERR_ALLOC_FAIL;
243 		goto out;
244 	}
245 	if ((r = sshkey_load_file(fd, buffer)) != 0 ||
246 	    (r = sshkey_parse_private_fileblob(buffer, passphrase, keyp,
247 	    commentp)) != 0)
248 		goto out;
249 	if (keyp && *keyp &&
250 	    (r = sshkey_set_filename(*keyp, filename)) != 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_XMSS:
401 	case KEY_UNSPEC:
402 		break;
403 	default:
404 		return SSH_ERR_KEY_TYPE_UNKNOWN;
405 	}
406 
407 	if ((r = sshkey_load_private_type(type, filename,
408 	    passphrase, &key, NULL, perm_ok)) != 0 ||
409 	    (r = sshkey_load_cert(filename, &cert)) != 0)
410 		goto out;
411 
412 	/* Make sure the private key matches the certificate */
413 	if (sshkey_equal_public(key, cert) == 0) {
414 		r = SSH_ERR_KEY_CERT_MISMATCH;
415 		goto out;
416 	}
417 
418 	if ((r = sshkey_to_certified(key)) != 0 ||
419 	    (r = sshkey_cert_copy(cert, key)) != 0)
420 		goto out;
421 	r = 0;
422 	if (keyp != NULL) {
423 		*keyp = key;
424 		key = NULL;
425 	}
426  out:
427 	sshkey_free(key);
428 	sshkey_free(cert);
429 	return r;
430 }
431 
432 /*
433  * Returns success if the specified "key" is listed in the file "filename",
434  * SSH_ERR_KEY_NOT_FOUND: if the key is not listed or another error.
435  * If "strict_type" is set then the key type must match exactly,
436  * otherwise a comparison that ignores certficiate data is performed.
437  * If "check_ca" is set and "key" is a certificate, then its CA key is
438  * also checked and sshkey_in_file() will return success if either is found.
439  */
440 int
441 sshkey_in_file(struct sshkey *key, const char *filename, int strict_type,
442     int check_ca)
443 {
444 	FILE *f;
445 	char line[SSH_MAX_PUBKEY_BYTES];
446 	char *cp;
447 	u_long linenum = 0;
448 	int r = 0;
449 	struct sshkey *pub = NULL;
450 	int (*sshkey_compare)(const struct sshkey *, const struct sshkey *) =
451 	    strict_type ?  sshkey_equal : sshkey_equal_public;
452 
453 	if ((f = fopen(filename, "r")) == NULL)
454 		return SSH_ERR_SYSTEM_ERROR;
455 
456 	while (read_keyfile_line(f, filename, line, sizeof(line),
457 	    &linenum) != -1) {
458 		cp = line;
459 
460 		/* Skip leading whitespace. */
461 		for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
462 			;
463 
464 		/* Skip comments and empty lines */
465 		switch (*cp) {
466 		case '#':
467 		case '\n':
468 		case '\0':
469 			continue;
470 		}
471 
472 		if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
473 			r = SSH_ERR_ALLOC_FAIL;
474 			goto out;
475 		}
476 		if ((r = sshkey_read(pub, &cp)) != 0)
477 			goto out;
478 		if (sshkey_compare(key, pub) ||
479 		    (check_ca && sshkey_is_cert(key) &&
480 		    sshkey_compare(key->cert->signature_key, pub))) {
481 			r = 0;
482 			goto out;
483 		}
484 		sshkey_free(pub);
485 		pub = NULL;
486 	}
487 	r = SSH_ERR_KEY_NOT_FOUND;
488  out:
489 	sshkey_free(pub);
490 	fclose(f);
491 	return r;
492 }
493 
494 /*
495  * Checks whether the specified key is revoked, returning 0 if not,
496  * SSH_ERR_KEY_REVOKED if it is or another error code if something
497  * unexpected happened.
498  * This will check both the key and, if it is a certificate, its CA key too.
499  * "revoked_keys_file" may be a KRL or a one-per-line list of public keys.
500  */
501 int
502 sshkey_check_revoked(struct sshkey *key, const char *revoked_keys_file)
503 {
504 	int r;
505 
506 	r = ssh_krl_file_contains_key(revoked_keys_file, key);
507 	/* If this was not a KRL to begin with then continue below */
508 	if (r != SSH_ERR_KRL_BAD_MAGIC)
509 		return r;
510 
511 	/*
512 	 * If the file is not a KRL or we can't handle KRLs then attempt to
513 	 * parse the file as a flat list of keys.
514 	 */
515 	switch ((r = sshkey_in_file(key, revoked_keys_file, 0, 1))) {
516 	case 0:
517 		/* Key found => revoked */
518 		return SSH_ERR_KEY_REVOKED;
519 	case SSH_ERR_KEY_NOT_FOUND:
520 		/* Key not found => not revoked */
521 		return 0;
522 	default:
523 		/* Some other error occurred */
524 		return r;
525 	}
526 }
527 
528