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