• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* $OpenBSD: authfile.c,v 1.122 2016/11/25 23:24: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 "rsa.h"
46 #include "misc.h"
47 #include "atomicio.h"
48 #include "sshkey.h"
49 #include "sshbuf.h"
50 #include "ssherr.h"
51 #include "krl.h"
52 
53 #define MAX_KEY_FILE_SIZE	(1024 * 1024)
54 
55 /* Save a key blob to a file */
56 static int
sshkey_save_private_blob(struct sshbuf * keybuf,const char * filename)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
sshkey_save_private(struct sshkey * key,const char * filename,const char * passphrase,const char * comment,int force_new_format,const char * new_format_cipher,int new_format_rounds)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
sshkey_load_file(int fd,struct sshbuf * blob)98 sshkey_load_file(int fd, struct sshbuf *blob)
99 {
100 	u_char buf[1024];
101 	size_t len;
102 	struct stat st;
103 	int r, dontmax = 0;
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 	/*
111 	 * Pre-allocate the buffer used for the key contents and clamp its
112 	 * maximum size. This ensures that key contents are never leaked via
113 	 * implicit realloc() in the sshbuf code.
114 	 */
115 	if ((st.st_mode & S_IFREG) == 0 || st.st_size <= 0) {
116 		st.st_size = 64*1024; /* 64k should be enough for anyone :) */
117 		dontmax = 1;
118 	}
119 	if ((r = sshbuf_allocate(blob, st.st_size)) != 0 ||
120 	    (dontmax && (r = sshbuf_set_max_size(blob, st.st_size)) != 0))
121 		return r;
122 	for (;;) {
123 		if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) {
124 			if (errno == EPIPE)
125 				break;
126 			r = SSH_ERR_SYSTEM_ERROR;
127 			goto out;
128 		}
129 		if ((r = sshbuf_put(blob, buf, len)) != 0)
130 			goto out;
131 		if (sshbuf_len(blob) > MAX_KEY_FILE_SIZE) {
132 			r = SSH_ERR_INVALID_FORMAT;
133 			goto out;
134 		}
135 	}
136 	if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
137 	    st.st_size != (off_t)sshbuf_len(blob)) {
138 		r = SSH_ERR_FILE_CHANGED;
139 		goto out;
140 	}
141 	r = 0;
142 
143  out:
144 	explicit_bzero(buf, sizeof(buf));
145 	if (r != 0)
146 		sshbuf_reset(blob);
147 	return r;
148 }
149 
150 #ifdef WITH_SSH1
151 /*
152  * Loads the public part of the ssh v1 key file.  Returns NULL if an error was
153  * encountered (the file does not exist or is not readable), and the key
154  * otherwise.
155  */
156 static int
sshkey_load_public_rsa1(int fd,struct sshkey ** keyp,char ** commentp)157 sshkey_load_public_rsa1(int fd, struct sshkey **keyp, char **commentp)
158 {
159 	struct sshbuf *b = NULL;
160 	int r;
161 
162 	if (keyp != NULL)
163 		*keyp = NULL;
164 	if (commentp != NULL)
165 		*commentp = NULL;
166 
167 	if ((b = sshbuf_new()) == NULL)
168 		return SSH_ERR_ALLOC_FAIL;
169 	if ((r = sshkey_load_file(fd, b)) != 0)
170 		goto out;
171 	if ((r = sshkey_parse_public_rsa1_fileblob(b, keyp, commentp)) != 0)
172 		goto out;
173 	r = 0;
174  out:
175 	sshbuf_free(b);
176 	return r;
177 }
178 #endif /* WITH_SSH1 */
179 
180 /* XXX remove error() calls from here? */
181 int
sshkey_perm_ok(int fd,const char * filename)182 sshkey_perm_ok(int fd, const char *filename)
183 {
184 	struct stat st;
185 
186 	if (fstat(fd, &st) < 0)
187 		return SSH_ERR_SYSTEM_ERROR;
188 	/*
189 	 * if a key owned by the user is accessed, then we check the
190 	 * permissions of the file. if the key owned by a different user,
191 	 * then we don't care.
192 	 */
193 #ifdef HAVE_CYGWIN
194 	if (check_ntsec(filename))
195 #endif
196 	if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
197 		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
198 		error("@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @");
199 		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
200 		error("Permissions 0%3.3o for '%s' are too open.",
201 		    (u_int)st.st_mode & 0777, filename);
202 		error("It is required that your private key files are NOT accessible by others.");
203 		error("This private key will be ignored.");
204 		return SSH_ERR_KEY_BAD_PERMISSIONS;
205 	}
206 	return 0;
207 }
208 
209 /* XXX kill perm_ok now that we have SSH_ERR_KEY_BAD_PERMISSIONS? */
210 int
sshkey_load_private_type(int type,const char * filename,const char * passphrase,struct sshkey ** keyp,char ** commentp,int * perm_ok)211 sshkey_load_private_type(int type, const char *filename, const char *passphrase,
212     struct sshkey **keyp, char **commentp, int *perm_ok)
213 {
214 	int fd, r;
215 
216 	if (keyp != NULL)
217 		*keyp = NULL;
218 	if (commentp != NULL)
219 		*commentp = NULL;
220 
221 	if ((fd = open(filename, O_RDONLY)) < 0) {
222 		if (perm_ok != NULL)
223 			*perm_ok = 0;
224 		return SSH_ERR_SYSTEM_ERROR;
225 	}
226 	if (sshkey_perm_ok(fd, filename) != 0) {
227 		if (perm_ok != NULL)
228 			*perm_ok = 0;
229 		r = SSH_ERR_KEY_BAD_PERMISSIONS;
230 		goto out;
231 	}
232 	if (perm_ok != NULL)
233 		*perm_ok = 1;
234 
235 	r = sshkey_load_private_type_fd(fd, type, passphrase, keyp, commentp);
236  out:
237 	close(fd);
238 	return r;
239 }
240 
241 int
sshkey_load_private_type_fd(int fd,int type,const char * passphrase,struct sshkey ** keyp,char ** commentp)242 sshkey_load_private_type_fd(int fd, int type, const char *passphrase,
243     struct sshkey **keyp, char **commentp)
244 {
245 	struct sshbuf *buffer = NULL;
246 	int r;
247 
248 	if (keyp != NULL)
249 		*keyp = NULL;
250 	if ((buffer = sshbuf_new()) == NULL) {
251 		r = SSH_ERR_ALLOC_FAIL;
252 		goto out;
253 	}
254 	if ((r = sshkey_load_file(fd, buffer)) != 0 ||
255 	    (r = sshkey_parse_private_fileblob_type(buffer, type,
256 	    passphrase, keyp, commentp)) != 0)
257 		goto out;
258 
259 	/* success */
260 	r = 0;
261  out:
262 	sshbuf_free(buffer);
263 	return r;
264 }
265 
266 /* XXX this is almost identical to sshkey_load_private_type() */
267 int
sshkey_load_private(const char * filename,const char * passphrase,struct sshkey ** keyp,char ** commentp)268 sshkey_load_private(const char *filename, const char *passphrase,
269     struct sshkey **keyp, char **commentp)
270 {
271 	struct sshbuf *buffer = NULL;
272 	int r, fd;
273 
274 	if (keyp != NULL)
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, buffer)) != 0 ||
291 	    (r = sshkey_parse_private_fileblob(buffer, passphrase, keyp,
292 	    commentp)) != 0)
293 		goto out;
294 	r = 0;
295  out:
296 	close(fd);
297 	sshbuf_free(buffer);
298 	return r;
299 }
300 
301 static int
sshkey_try_load_public(struct sshkey * k,const char * filename,char ** commentp)302 sshkey_try_load_public(struct sshkey *k, const char *filename, char **commentp)
303 {
304 	FILE *f;
305 	char line[SSH_MAX_PUBKEY_BYTES];
306 	char *cp;
307 	u_long linenum = 0;
308 	int r;
309 
310 	if (commentp != NULL)
311 		*commentp = NULL;
312 	if ((f = fopen(filename, "r")) == NULL)
313 		return SSH_ERR_SYSTEM_ERROR;
314 	while (read_keyfile_line(f, filename, line, sizeof(line),
315 		    &linenum) != -1) {
316 		cp = line;
317 		switch (*cp) {
318 		case '#':
319 		case '\n':
320 		case '\0':
321 			continue;
322 		}
323 		/* Abort loading if this looks like a private key */
324 		if (strncmp(cp, "-----BEGIN", 10) == 0 ||
325 		    strcmp(cp, "SSH PRIVATE KEY FILE") == 0)
326 			break;
327 		/* Skip leading whitespace. */
328 		for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
329 			;
330 		if (*cp) {
331 			if ((r = sshkey_read(k, &cp)) == 0) {
332 				cp[strcspn(cp, "\r\n")] = '\0';
333 				if (commentp) {
334 					*commentp = strdup(*cp ?
335 					    cp : filename);
336 					if (*commentp == NULL)
337 						r = SSH_ERR_ALLOC_FAIL;
338 				}
339 				fclose(f);
340 				return r;
341 			}
342 		}
343 	}
344 	fclose(f);
345 	return SSH_ERR_INVALID_FORMAT;
346 }
347 
348 /* load public key from ssh v1 private or any pubkey file */
349 int
sshkey_load_public(const char * filename,struct sshkey ** keyp,char ** commentp)350 sshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp)
351 {
352 	struct sshkey *pub = NULL;
353 	char file[PATH_MAX];
354 	int r, fd;
355 
356 	if (keyp != NULL)
357 		*keyp = NULL;
358 	if (commentp != NULL)
359 		*commentp = NULL;
360 
361 	/* XXX should load file once and attempt to parse each format */
362 
363 	if ((fd = open(filename, O_RDONLY)) < 0)
364 		goto skip;
365 #ifdef WITH_SSH1
366 	/* try rsa1 private key */
367 	r = sshkey_load_public_rsa1(fd, keyp, commentp);
368 	close(fd);
369 	switch (r) {
370 	case SSH_ERR_INTERNAL_ERROR:
371 	case SSH_ERR_ALLOC_FAIL:
372 	case SSH_ERR_INVALID_ARGUMENT:
373 	case SSH_ERR_SYSTEM_ERROR:
374 	case 0:
375 		return r;
376 	}
377 #else /* WITH_SSH1 */
378 	close(fd);
379 #endif /* WITH_SSH1 */
380 
381 	/* try ssh2 public key */
382 	if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
383 		return SSH_ERR_ALLOC_FAIL;
384 	if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
385 		if (keyp != NULL)
386 			*keyp = pub;
387 		return 0;
388 	}
389 	sshkey_free(pub);
390 
391 #ifdef WITH_SSH1
392 	/* try rsa1 public key */
393 	if ((pub = sshkey_new(KEY_RSA1)) == NULL)
394 		return SSH_ERR_ALLOC_FAIL;
395 	if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
396 		if (keyp != NULL)
397 			*keyp = pub;
398 		return 0;
399 	}
400 	sshkey_free(pub);
401 #endif /* WITH_SSH1 */
402 
403  skip:
404 	/* try .pub suffix */
405 	if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
406 		return SSH_ERR_ALLOC_FAIL;
407 	r = SSH_ERR_ALLOC_FAIL;	/* in case strlcpy or strlcat fail */
408 	if ((strlcpy(file, filename, sizeof file) < sizeof(file)) &&
409 	    (strlcat(file, ".pub", sizeof file) < sizeof(file)) &&
410 	    (r = sshkey_try_load_public(pub, file, commentp)) == 0) {
411 		if (keyp != NULL)
412 			*keyp = pub;
413 		return 0;
414 	}
415 	sshkey_free(pub);
416 
417 	return r;
418 }
419 
420 /* Load the certificate associated with the named private key */
421 int
sshkey_load_cert(const char * filename,struct sshkey ** keyp)422 sshkey_load_cert(const char *filename, struct sshkey **keyp)
423 {
424 	struct sshkey *pub = NULL;
425 	char *file = NULL;
426 	int r = SSH_ERR_INTERNAL_ERROR;
427 
428 	if (keyp != NULL)
429 		*keyp = NULL;
430 
431 	if (asprintf(&file, "%s-cert.pub", filename) == -1)
432 		return SSH_ERR_ALLOC_FAIL;
433 
434 	if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
435 		goto out;
436 	}
437 	if ((r = sshkey_try_load_public(pub, file, NULL)) != 0)
438 		goto out;
439 	/* success */
440 	if (keyp != NULL) {
441 		*keyp = pub;
442 		pub = NULL;
443 	}
444 	r = 0;
445  out:
446 	free(file);
447 	sshkey_free(pub);
448 	return r;
449 }
450 
451 /* Load private key and certificate */
452 int
sshkey_load_private_cert(int type,const char * filename,const char * passphrase,struct sshkey ** keyp,int * perm_ok)453 sshkey_load_private_cert(int type, const char *filename, const char *passphrase,
454     struct sshkey **keyp, int *perm_ok)
455 {
456 	struct sshkey *key = NULL, *cert = NULL;
457 	int r;
458 
459 	if (keyp != NULL)
460 		*keyp = NULL;
461 
462 	switch (type) {
463 #ifdef WITH_OPENSSL
464 	case KEY_RSA:
465 	case KEY_DSA:
466 	case KEY_ECDSA:
467 #endif /* WITH_OPENSSL */
468 	case KEY_ED25519:
469 	case KEY_UNSPEC:
470 		break;
471 	default:
472 		return SSH_ERR_KEY_TYPE_UNKNOWN;
473 	}
474 
475 	if ((r = sshkey_load_private_type(type, filename,
476 	    passphrase, &key, NULL, perm_ok)) != 0 ||
477 	    (r = sshkey_load_cert(filename, &cert)) != 0)
478 		goto out;
479 
480 	/* Make sure the private key matches the certificate */
481 	if (sshkey_equal_public(key, cert) == 0) {
482 		r = SSH_ERR_KEY_CERT_MISMATCH;
483 		goto out;
484 	}
485 
486 	if ((r = sshkey_to_certified(key)) != 0 ||
487 	    (r = sshkey_cert_copy(cert, key)) != 0)
488 		goto out;
489 	r = 0;
490 	if (keyp != NULL) {
491 		*keyp = key;
492 		key = NULL;
493 	}
494  out:
495 	sshkey_free(key);
496 	sshkey_free(cert);
497 	return r;
498 }
499 
500 /*
501  * Returns success if the specified "key" is listed in the file "filename",
502  * SSH_ERR_KEY_NOT_FOUND: if the key is not listed or another error.
503  * If "strict_type" is set then the key type must match exactly,
504  * otherwise a comparison that ignores certficiate data is performed.
505  * If "check_ca" is set and "key" is a certificate, then its CA key is
506  * also checked and sshkey_in_file() will return success if either is found.
507  */
508 int
sshkey_in_file(struct sshkey * key,const char * filename,int strict_type,int check_ca)509 sshkey_in_file(struct sshkey *key, const char *filename, int strict_type,
510     int check_ca)
511 {
512 	FILE *f;
513 	char line[SSH_MAX_PUBKEY_BYTES];
514 	char *cp;
515 	u_long linenum = 0;
516 	int r = 0;
517 	struct sshkey *pub = NULL;
518 	int (*sshkey_compare)(const struct sshkey *, const struct sshkey *) =
519 	    strict_type ?  sshkey_equal : sshkey_equal_public;
520 
521 	if ((f = fopen(filename, "r")) == NULL)
522 		return SSH_ERR_SYSTEM_ERROR;
523 
524 	while (read_keyfile_line(f, filename, line, sizeof(line),
525 	    &linenum) != -1) {
526 		cp = line;
527 
528 		/* Skip leading whitespace. */
529 		for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
530 			;
531 
532 		/* Skip comments and empty lines */
533 		switch (*cp) {
534 		case '#':
535 		case '\n':
536 		case '\0':
537 			continue;
538 		}
539 
540 		if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
541 			r = SSH_ERR_ALLOC_FAIL;
542 			goto out;
543 		}
544 		if ((r = sshkey_read(pub, &cp)) != 0)
545 			goto out;
546 		if (sshkey_compare(key, pub) ||
547 		    (check_ca && sshkey_is_cert(key) &&
548 		    sshkey_compare(key->cert->signature_key, pub))) {
549 			r = 0;
550 			goto out;
551 		}
552 		sshkey_free(pub);
553 		pub = NULL;
554 	}
555 	r = SSH_ERR_KEY_NOT_FOUND;
556  out:
557 	sshkey_free(pub);
558 	fclose(f);
559 	return r;
560 }
561 
562 /*
563  * Checks whether the specified key is revoked, returning 0 if not,
564  * SSH_ERR_KEY_REVOKED if it is or another error code if something
565  * unexpected happened.
566  * This will check both the key and, if it is a certificate, its CA key too.
567  * "revoked_keys_file" may be a KRL or a one-per-line list of public keys.
568  */
569 int
sshkey_check_revoked(struct sshkey * key,const char * revoked_keys_file)570 sshkey_check_revoked(struct sshkey *key, const char *revoked_keys_file)
571 {
572 	int r;
573 
574 	r = ssh_krl_file_contains_key(revoked_keys_file, key);
575 	/* If this was not a KRL to begin with then continue below */
576 	if (r != SSH_ERR_KRL_BAD_MAGIC)
577 		return r;
578 
579 	/*
580 	 * If the file is not a KRL or we can't handle KRLs then attempt to
581 	 * parse the file as a flat list of keys.
582 	 */
583 	switch ((r = sshkey_in_file(key, revoked_keys_file, 0, 1))) {
584 	case 0:
585 		/* Key found => revoked */
586 		return SSH_ERR_KEY_REVOKED;
587 	case SSH_ERR_KEY_NOT_FOUND:
588 		/* Key not found => not revoked */
589 		return 0;
590 	default:
591 		/* Some other error occurred */
592 		return r;
593 	}
594 }
595 
596