xref: /dragonfly/crypto/openssh/authfile.c (revision ff0a8843)
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 
527