xref: /dragonfly/crypto/openssh/authfile.c (revision 279dd846)
1 /* $OpenBSD: authfile.c,v 1.107 2014/06/24 01:13:21 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/param.h>
31 #include <sys/uio.h>
32 
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <stdio.h>
36 #include <stdarg.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 
41 #include "cipher.h"
42 #include "key.h"
43 #include "ssh.h"
44 #include "log.h"
45 #include "authfile.h"
46 #include "rsa.h"
47 #include "misc.h"
48 #include "atomicio.h"
49 #include "sshbuf.h"
50 #include "ssherr.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, const char *filename, 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 #ifdef WITH_SSH1
138 /*
139  * Loads the public part of the ssh v1 key file.  Returns NULL if an error was
140  * encountered (the file does not exist or is not readable), and the key
141  * otherwise.
142  */
143 static int
144 sshkey_load_public_rsa1(int fd, const char *filename,
145     struct sshkey **keyp, char **commentp)
146 {
147 	struct sshbuf *b = NULL;
148 	int r;
149 
150 	*keyp = NULL;
151 	if (commentp != NULL)
152 		*commentp = NULL;
153 
154 	if ((b = sshbuf_new()) == NULL)
155 		return SSH_ERR_ALLOC_FAIL;
156 	if ((r = sshkey_load_file(fd, filename, b)) != 0)
157 		goto out;
158 	if ((r = sshkey_parse_public_rsa1_fileblob(b, keyp, commentp)) != 0)
159 		goto out;
160 	r = 0;
161  out:
162 	sshbuf_free(b);
163 	return r;
164 }
165 #endif /* WITH_SSH1 */
166 
167 #ifdef WITH_OPENSSL
168 /* XXX Deprecate? */
169 int
170 sshkey_load_private_pem(int fd, int type, const char *passphrase,
171     struct sshkey **keyp, char **commentp)
172 {
173 	struct sshbuf *buffer = NULL;
174 	int r;
175 
176 	*keyp = NULL;
177 	if (commentp != NULL)
178 		*commentp = NULL;
179 
180 	if ((buffer = sshbuf_new()) == NULL)
181 		return SSH_ERR_ALLOC_FAIL;
182 	if ((r = sshkey_load_file(fd, NULL, buffer)) != 0)
183 		goto out;
184 	if ((r = sshkey_parse_private_pem_fileblob(buffer, type, passphrase,
185 	    keyp, commentp)) != 0)
186 		goto out;
187 	r = 0;
188  out:
189 	sshbuf_free(buffer);
190 	return r;
191 }
192 #endif /* WITH_OPENSSL */
193 
194 /* XXX remove error() calls from here? */
195 int
196 sshkey_perm_ok(int fd, const char *filename)
197 {
198 	struct stat st;
199 
200 	if (fstat(fd, &st) < 0)
201 		return SSH_ERR_SYSTEM_ERROR;
202 	/*
203 	 * if a key owned by the user is accessed, then we check the
204 	 * permissions of the file. if the key owned by a different user,
205 	 * then we don't care.
206 	 */
207 #ifdef HAVE_CYGWIN
208 	if (check_ntsec(filename))
209 #endif
210 	if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
211 		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
212 		error("@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @");
213 		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
214 		error("Permissions 0%3.3o for '%s' are too open.",
215 		    (u_int)st.st_mode & 0777, filename);
216 		error("It is recommended that your private key files are NOT accessible by others.");
217 		error("This private key will be ignored.");
218 		return SSH_ERR_KEY_BAD_PERMISSIONS;
219 	}
220 	return 0;
221 }
222 
223 /* XXX kill perm_ok now that we have SSH_ERR_KEY_BAD_PERMISSIONS? */
224 int
225 sshkey_load_private_type(int type, const char *filename, const char *passphrase,
226     struct sshkey **keyp, char **commentp, int *perm_ok)
227 {
228 	int fd, r;
229 	struct sshbuf *buffer = NULL;
230 
231 	*keyp = NULL;
232 	if (commentp != NULL)
233 		*commentp = NULL;
234 
235 	if ((fd = open(filename, O_RDONLY)) < 0) {
236 		if (perm_ok != NULL)
237 			*perm_ok = 0;
238 		return SSH_ERR_SYSTEM_ERROR;
239 	}
240 	if (sshkey_perm_ok(fd, filename) != 0) {
241 		if (perm_ok != NULL)
242 			*perm_ok = 0;
243 		r = SSH_ERR_KEY_BAD_PERMISSIONS;
244 		goto out;
245 	}
246 	if (perm_ok != NULL)
247 		*perm_ok = 1;
248 
249 	if ((buffer = sshbuf_new()) == NULL) {
250 		r = SSH_ERR_ALLOC_FAIL;
251 		goto out;
252 	}
253 	if ((r = sshkey_load_file(fd, filename, buffer)) != 0)
254 		goto out;
255 	if ((r = sshkey_parse_private_fileblob_type(buffer, type, passphrase,
256 	    keyp, commentp)) != 0)
257 		goto out;
258 	r = 0;
259  out:
260 	close(fd);
261 	if (buffer != NULL)
262 		sshbuf_free(buffer);
263 	return r;
264 }
265 
266 /* XXX this is almost identical to sshkey_load_private_type() */
267 int
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 	*keyp = NULL;
275 	if (commentp != NULL)
276 		*commentp = NULL;
277 
278 	if ((fd = open(filename, O_RDONLY)) < 0)
279 		return SSH_ERR_SYSTEM_ERROR;
280 	if (sshkey_perm_ok(fd, filename) != 0) {
281 		r = SSH_ERR_KEY_BAD_PERMISSIONS;
282 		goto out;
283 	}
284 
285 	if ((buffer = sshbuf_new()) == NULL) {
286 		r = SSH_ERR_ALLOC_FAIL;
287 		goto out;
288 	}
289 	if ((r = sshkey_load_file(fd, filename, buffer)) != 0 ||
290 	    (r = sshkey_parse_private_fileblob(buffer, passphrase, filename,
291 	    keyp, commentp)) != 0)
292 		goto out;
293 	r = 0;
294  out:
295 	close(fd);
296 	if (buffer != NULL)
297 		sshbuf_free(buffer);
298 	return r;
299 }
300 
301 static int
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
350 sshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp)
351 {
352 	struct sshkey *pub = NULL;
353 	char file[MAXPATHLEN];
354 	int r, fd;
355 
356 	if (keyp != NULL)
357 		*keyp = NULL;
358 	if (commentp != NULL)
359 		*commentp = NULL;
360 
361 	if ((fd = open(filename, O_RDONLY)) < 0)
362 		goto skip;
363 #ifdef WITH_SSH1
364 	/* try rsa1 private key */
365 	r = sshkey_load_public_rsa1(fd, filename, keyp, commentp);
366 	close(fd);
367 	switch (r) {
368 	case SSH_ERR_INTERNAL_ERROR:
369 	case SSH_ERR_ALLOC_FAIL:
370 	case SSH_ERR_INVALID_ARGUMENT:
371 	case SSH_ERR_SYSTEM_ERROR:
372 	case 0:
373 		return r;
374 	}
375 #endif /* WITH_SSH1 */
376 
377 	/* try ssh2 public key */
378 	if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
379 		return SSH_ERR_ALLOC_FAIL;
380 	if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
381 		if (keyp != NULL)
382 			*keyp = pub;
383 		return 0;
384 	}
385 	sshkey_free(pub);
386 
387 #ifdef WITH_SSH1
388 	/* try rsa1 public key */
389 	if ((pub = sshkey_new(KEY_RSA1)) == NULL)
390 		return SSH_ERR_ALLOC_FAIL;
391 	if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
392 		if (keyp != NULL)
393 			*keyp = pub;
394 		return 0;
395 	}
396 	sshkey_free(pub);
397 #endif /* WITH_SSH1 */
398 
399  skip:
400 	/* try .pub suffix */
401 	if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
402 		return SSH_ERR_ALLOC_FAIL;
403 	r = SSH_ERR_ALLOC_FAIL;	/* in case strlcpy or strlcat fail */
404 	if ((strlcpy(file, filename, sizeof file) < sizeof(file)) &&
405 	    (strlcat(file, ".pub", sizeof file) < sizeof(file)) &&
406 	    (r = sshkey_try_load_public(pub, file, commentp)) == 0) {
407 		if (keyp != NULL)
408 			*keyp = pub;
409 		return 0;
410 	}
411 	sshkey_free(pub);
412 	return r;
413 }
414 
415 /* Load the certificate associated with the named private key */
416 int
417 sshkey_load_cert(const char *filename, struct sshkey **keyp)
418 {
419 	struct sshkey *pub = NULL;
420 	char *file = NULL;
421 	int r = SSH_ERR_INTERNAL_ERROR;
422 
423 	*keyp = NULL;
424 
425 	if (asprintf(&file, "%s-cert.pub", filename) == -1)
426 		return SSH_ERR_ALLOC_FAIL;
427 
428 	if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
429 		goto out;
430 	}
431 	if ((r = sshkey_try_load_public(pub, file, NULL)) != 0)
432 		goto out;
433 
434 	*keyp = pub;
435 	pub = NULL;
436 	r = 0;
437 
438  out:
439 	if (file != NULL)
440 		free(file);
441 	if (pub != NULL)
442 		sshkey_free(pub);
443 	return r;
444 }
445 
446 /* Load private key and certificate */
447 int
448 sshkey_load_private_cert(int type, const char *filename, const char *passphrase,
449     struct sshkey **keyp, int *perm_ok)
450 {
451 	struct sshkey *key = NULL, *cert = NULL;
452 	int r;
453 
454 	*keyp = NULL;
455 
456 	switch (type) {
457 #ifdef WITH_OPENSSL
458 	case KEY_RSA:
459 	case KEY_DSA:
460 	case KEY_ECDSA:
461 	case KEY_ED25519:
462 #endif /* WITH_OPENSSL */
463 	case KEY_UNSPEC:
464 		break;
465 	default:
466 		return SSH_ERR_KEY_TYPE_UNKNOWN;
467 	}
468 
469 	if ((r = sshkey_load_private_type(type, filename,
470 	    passphrase, &key, NULL, perm_ok)) != 0 ||
471 	    (r = sshkey_load_cert(filename, &cert)) != 0)
472 		goto out;
473 
474 	/* Make sure the private key matches the certificate */
475 	if (sshkey_equal_public(key, cert) == 0) {
476 		r = SSH_ERR_KEY_CERT_MISMATCH;
477 		goto out;
478 	}
479 
480 	if ((r = sshkey_to_certified(key, sshkey_cert_is_legacy(cert))) != 0 ||
481 	    (r = sshkey_cert_copy(cert, key)) != 0)
482 		goto out;
483 	r = 0;
484 	*keyp = key;
485 	key = NULL;
486  out:
487 	if (key != NULL)
488 		sshkey_free(key);
489 	if (cert != NULL)
490 		sshkey_free(cert);
491 	return r;
492 }
493 
494 /*
495  * Returns success if the specified "key" is listed in the file "filename",
496  * SSH_ERR_KEY_NOT_FOUND: if the key is not listed or another error.
497  * If strict_type is set then the key type must match exactly,
498  * otherwise a comparison that ignores certficiate data is performed.
499  */
500 int
501 sshkey_in_file(struct sshkey *key, const char *filename, int strict_type)
502 {
503 	FILE *f;
504 	char line[SSH_MAX_PUBKEY_BYTES];
505 	char *cp;
506 	u_long linenum = 0;
507 	int r = 0;
508 	struct sshkey *pub = NULL;
509 	int (*sshkey_compare)(const struct sshkey *, const struct sshkey *) =
510 	    strict_type ?  sshkey_equal : sshkey_equal_public;
511 
512 	if ((f = fopen(filename, "r")) == NULL) {
513 		if (errno == ENOENT)
514 			return SSH_ERR_KEY_NOT_FOUND;
515 		else
516 			return SSH_ERR_SYSTEM_ERROR;
517 	}
518 
519 	while (read_keyfile_line(f, filename, line, sizeof(line),
520 	    &linenum) != -1) {
521 		cp = line;
522 
523 		/* Skip leading whitespace. */
524 		for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
525 			;
526 
527 		/* Skip comments and empty lines */
528 		switch (*cp) {
529 		case '#':
530 		case '\n':
531 		case '\0':
532 			continue;
533 		}
534 
535 		if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
536 			r = SSH_ERR_ALLOC_FAIL;
537 			goto out;
538 		}
539 		if ((r = sshkey_read(pub, &cp)) != 0)
540 			goto out;
541 		if (sshkey_compare(key, pub)) {
542 			r = 0;
543 			goto out;
544 		}
545 		sshkey_free(pub);
546 		pub = NULL;
547 	}
548 	r = SSH_ERR_KEY_NOT_FOUND;
549  out:
550 	if (pub != NULL)
551 		sshkey_free(pub);
552 	fclose(f);
553 	return r;
554 }
555 
556