xref: /openbsd-src/usr.bin/ssh/authfile.c (revision ae3cb403620ab940fbaabb3055fac045a63d56b7)
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 
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  out:
190 	close(fd);
191 	return r;
192 }
193 
194 int
195 sshkey_load_private_type_fd(int fd, int type, const char *passphrase,
196     struct sshkey **keyp, char **commentp)
197 {
198 	struct sshbuf *buffer = NULL;
199 	int r;
200 
201 	if (keyp != NULL)
202 		*keyp = NULL;
203 	if ((buffer = sshbuf_new()) == NULL) {
204 		r = SSH_ERR_ALLOC_FAIL;
205 		goto out;
206 	}
207 	if ((r = sshkey_load_file(fd, buffer)) != 0 ||
208 	    (r = sshkey_parse_private_fileblob_type(buffer, type,
209 	    passphrase, keyp, commentp)) != 0)
210 		goto out;
211 
212 	/* success */
213 	r = 0;
214  out:
215 	sshbuf_free(buffer);
216 	return r;
217 }
218 
219 /* XXX this is almost identical to sshkey_load_private_type() */
220 int
221 sshkey_load_private(const char *filename, const char *passphrase,
222     struct sshkey **keyp, char **commentp)
223 {
224 	struct sshbuf *buffer = NULL;
225 	int r, fd;
226 
227 	if (keyp != NULL)
228 		*keyp = NULL;
229 	if (commentp != NULL)
230 		*commentp = NULL;
231 
232 	if ((fd = open(filename, O_RDONLY)) < 0)
233 		return SSH_ERR_SYSTEM_ERROR;
234 	if (sshkey_perm_ok(fd, filename) != 0) {
235 		r = SSH_ERR_KEY_BAD_PERMISSIONS;
236 		goto out;
237 	}
238 
239 	if ((buffer = sshbuf_new()) == NULL) {
240 		r = SSH_ERR_ALLOC_FAIL;
241 		goto out;
242 	}
243 	if ((r = sshkey_load_file(fd, buffer)) != 0 ||
244 	    (r = sshkey_parse_private_fileblob(buffer, passphrase, keyp,
245 	    commentp)) != 0)
246 		goto out;
247 	r = 0;
248  out:
249 	close(fd);
250 	sshbuf_free(buffer);
251 	return r;
252 }
253 
254 static int
255 sshkey_try_load_public(struct sshkey *k, const char *filename, char **commentp)
256 {
257 	FILE *f;
258 	char line[SSH_MAX_PUBKEY_BYTES];
259 	char *cp;
260 	u_long linenum = 0;
261 	int r;
262 
263 	if (commentp != NULL)
264 		*commentp = NULL;
265 	if ((f = fopen(filename, "r")) == NULL)
266 		return SSH_ERR_SYSTEM_ERROR;
267 	while (read_keyfile_line(f, filename, line, sizeof(line),
268 		    &linenum) != -1) {
269 		cp = line;
270 		switch (*cp) {
271 		case '#':
272 		case '\n':
273 		case '\0':
274 			continue;
275 		}
276 		/* Abort loading if this looks like a private key */
277 		if (strncmp(cp, "-----BEGIN", 10) == 0 ||
278 		    strcmp(cp, "SSH PRIVATE KEY FILE") == 0)
279 			break;
280 		/* Skip leading whitespace. */
281 		for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
282 			;
283 		if (*cp) {
284 			if ((r = sshkey_read(k, &cp)) == 0) {
285 				cp[strcspn(cp, "\r\n")] = '\0';
286 				if (commentp) {
287 					*commentp = strdup(*cp ?
288 					    cp : filename);
289 					if (*commentp == NULL)
290 						r = SSH_ERR_ALLOC_FAIL;
291 				}
292 				fclose(f);
293 				return r;
294 			}
295 		}
296 	}
297 	fclose(f);
298 	return SSH_ERR_INVALID_FORMAT;
299 }
300 
301 /* load public key from any pubkey file */
302 int
303 sshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp)
304 {
305 	struct sshkey *pub = NULL;
306 	char *file = NULL;
307 	int r;
308 
309 	if (keyp != NULL)
310 		*keyp = NULL;
311 	if (commentp != NULL)
312 		*commentp = NULL;
313 
314 	if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
315 		return SSH_ERR_ALLOC_FAIL;
316 	if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
317 		if (keyp != NULL) {
318 			*keyp = pub;
319 			pub = NULL;
320 		}
321 		r = 0;
322 		goto out;
323 	}
324 	sshkey_free(pub);
325 
326 	/* try .pub suffix */
327 	if (asprintf(&file, "%s.pub", filename) == -1)
328 		return SSH_ERR_ALLOC_FAIL;
329 	if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
330 		r = SSH_ERR_ALLOC_FAIL;
331 		goto out;
332 	}
333 	if ((r = sshkey_try_load_public(pub, file, commentp)) == 0) {
334 		if (keyp != NULL) {
335 			*keyp = pub;
336 			pub = NULL;
337 		}
338 		r = 0;
339 	}
340  out:
341 	free(file);
342 	sshkey_free(pub);
343 	return r;
344 }
345 
346 /* Load the certificate associated with the named private key */
347 int
348 sshkey_load_cert(const char *filename, struct sshkey **keyp)
349 {
350 	struct sshkey *pub = NULL;
351 	char *file = NULL;
352 	int r = SSH_ERR_INTERNAL_ERROR;
353 
354 	if (keyp != NULL)
355 		*keyp = NULL;
356 
357 	if (asprintf(&file, "%s-cert.pub", filename) == -1)
358 		return SSH_ERR_ALLOC_FAIL;
359 
360 	if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
361 		goto out;
362 	}
363 	if ((r = sshkey_try_load_public(pub, file, NULL)) != 0)
364 		goto out;
365 	/* success */
366 	if (keyp != NULL) {
367 		*keyp = pub;
368 		pub = NULL;
369 	}
370 	r = 0;
371  out:
372 	free(file);
373 	sshkey_free(pub);
374 	return r;
375 }
376 
377 /* Load private key and certificate */
378 int
379 sshkey_load_private_cert(int type, const char *filename, const char *passphrase,
380     struct sshkey **keyp, int *perm_ok)
381 {
382 	struct sshkey *key = NULL, *cert = NULL;
383 	int r;
384 
385 	if (keyp != NULL)
386 		*keyp = NULL;
387 
388 	switch (type) {
389 #ifdef WITH_OPENSSL
390 	case KEY_RSA:
391 	case KEY_DSA:
392 	case KEY_ECDSA:
393 #endif /* WITH_OPENSSL */
394 	case KEY_ED25519:
395 	case KEY_UNSPEC:
396 		break;
397 	default:
398 		return SSH_ERR_KEY_TYPE_UNKNOWN;
399 	}
400 
401 	if ((r = sshkey_load_private_type(type, filename,
402 	    passphrase, &key, NULL, perm_ok)) != 0 ||
403 	    (r = sshkey_load_cert(filename, &cert)) != 0)
404 		goto out;
405 
406 	/* Make sure the private key matches the certificate */
407 	if (sshkey_equal_public(key, cert) == 0) {
408 		r = SSH_ERR_KEY_CERT_MISMATCH;
409 		goto out;
410 	}
411 
412 	if ((r = sshkey_to_certified(key)) != 0 ||
413 	    (r = sshkey_cert_copy(cert, key)) != 0)
414 		goto out;
415 	r = 0;
416 	if (keyp != NULL) {
417 		*keyp = key;
418 		key = NULL;
419 	}
420  out:
421 	sshkey_free(key);
422 	sshkey_free(cert);
423 	return r;
424 }
425 
426 /*
427  * Returns success if the specified "key" is listed in the file "filename",
428  * SSH_ERR_KEY_NOT_FOUND: if the key is not listed or another error.
429  * If "strict_type" is set then the key type must match exactly,
430  * otherwise a comparison that ignores certficiate data is performed.
431  * If "check_ca" is set and "key" is a certificate, then its CA key is
432  * also checked and sshkey_in_file() will return success if either is found.
433  */
434 int
435 sshkey_in_file(struct sshkey *key, const char *filename, int strict_type,
436     int check_ca)
437 {
438 	FILE *f;
439 	char line[SSH_MAX_PUBKEY_BYTES];
440 	char *cp;
441 	u_long linenum = 0;
442 	int r = 0;
443 	struct sshkey *pub = NULL;
444 	int (*sshkey_compare)(const struct sshkey *, const struct sshkey *) =
445 	    strict_type ?  sshkey_equal : sshkey_equal_public;
446 
447 	if ((f = fopen(filename, "r")) == NULL)
448 		return SSH_ERR_SYSTEM_ERROR;
449 
450 	while (read_keyfile_line(f, filename, line, sizeof(line),
451 	    &linenum) != -1) {
452 		cp = line;
453 
454 		/* Skip leading whitespace. */
455 		for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
456 			;
457 
458 		/* Skip comments and empty lines */
459 		switch (*cp) {
460 		case '#':
461 		case '\n':
462 		case '\0':
463 			continue;
464 		}
465 
466 		if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
467 			r = SSH_ERR_ALLOC_FAIL;
468 			goto out;
469 		}
470 		if ((r = sshkey_read(pub, &cp)) != 0)
471 			goto out;
472 		if (sshkey_compare(key, pub) ||
473 		    (check_ca && sshkey_is_cert(key) &&
474 		    sshkey_compare(key->cert->signature_key, pub))) {
475 			r = 0;
476 			goto out;
477 		}
478 		sshkey_free(pub);
479 		pub = NULL;
480 	}
481 	r = SSH_ERR_KEY_NOT_FOUND;
482  out:
483 	sshkey_free(pub);
484 	fclose(f);
485 	return r;
486 }
487 
488 /*
489  * Checks whether the specified key is revoked, returning 0 if not,
490  * SSH_ERR_KEY_REVOKED if it is or another error code if something
491  * unexpected happened.
492  * This will check both the key and, if it is a certificate, its CA key too.
493  * "revoked_keys_file" may be a KRL or a one-per-line list of public keys.
494  */
495 int
496 sshkey_check_revoked(struct sshkey *key, const char *revoked_keys_file)
497 {
498 	int r;
499 
500 	r = ssh_krl_file_contains_key(revoked_keys_file, key);
501 	/* If this was not a KRL to begin with then continue below */
502 	if (r != SSH_ERR_KRL_BAD_MAGIC)
503 		return r;
504 
505 	/*
506 	 * If the file is not a KRL or we can't handle KRLs then attempt to
507 	 * parse the file as a flat list of keys.
508 	 */
509 	switch ((r = sshkey_in_file(key, revoked_keys_file, 0, 1))) {
510 	case 0:
511 		/* Key found => revoked */
512 		return SSH_ERR_KEY_REVOKED;
513 	case SSH_ERR_KEY_NOT_FOUND:
514 		/* Key not found => not revoked */
515 		return 0;
516 	default:
517 		/* Some other error occurred */
518 		return r;
519 	}
520 }
521 
522