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