xref: /openssh-portable/authfile.c (revision c514f3c0)
1*c514f3c0Sdjm@openbsd.org /* $OpenBSD: authfile.c,v 1.141 2020/06/18 23:33:38 djm Exp $ */
2d4a8b7e3SDamien Miller /*
3bcd00abdSDamien Miller  * Copyright (c) 2000, 2013 Markus Friedl.  All rights reserved.
4e4340be5SDamien Miller  *
5e4340be5SDamien Miller  * Redistribution and use in source and binary forms, with or without
6e4340be5SDamien Miller  * modification, are permitted provided that the following conditions
7e4340be5SDamien Miller  * are met:
8e4340be5SDamien Miller  * 1. Redistributions of source code must retain the above copyright
9e4340be5SDamien Miller  *    notice, this list of conditions and the following disclaimer.
10e4340be5SDamien Miller  * 2. Redistributions in binary form must reproduce the above copyright
11e4340be5SDamien Miller  *    notice, this list of conditions and the following disclaimer in the
12e4340be5SDamien Miller  *    documentation and/or other materials provided with the distribution.
13e4340be5SDamien Miller  *
14e4340be5SDamien Miller  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15e4340be5SDamien Miller  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16e4340be5SDamien Miller  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17e4340be5SDamien Miller  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18e4340be5SDamien Miller  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19e4340be5SDamien Miller  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20e4340be5SDamien Miller  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21e4340be5SDamien Miller  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22e4340be5SDamien Miller  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23e4340be5SDamien Miller  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24d4a8b7e3SDamien Miller  */
25d4a8b7e3SDamien Miller 
26d4a8b7e3SDamien Miller #include "includes.h"
27f17883e6SDamien Miller 
28f17883e6SDamien Miller #include <sys/types.h>
29f17883e6SDamien Miller #include <sys/stat.h>
30d7834353SDamien Miller #include <sys/uio.h>
31d4a8b7e3SDamien Miller 
32ba724050SDarren Tucker #include <errno.h>
3357cf6385SDamien Miller #include <fcntl.h>
34a7a73ee3SDamien Miller #include <stdio.h>
358668706dSDamien Miller #include <stdarg.h>
36e7a1e5cfSDamien Miller #include <stdlib.h>
37e3476ed0SDamien Miller #include <string.h>
38e6b3b610SDamien Miller #include <unistd.h>
39087266ecSderaadt@openbsd.org #include <limits.h>
4057cf6385SDamien Miller 
41d7834353SDamien Miller #include "cipher.h"
42226cfa03SBen Lindstrom #include "ssh.h"
43226cfa03SBen Lindstrom #include "log.h"
4431ca54aaSBen Lindstrom #include "authfile.h"
45f0f90989SDarren Tucker #include "misc.h"
46eccb9de7SDamien Miller #include "atomicio.h"
4716db0a7eSmarkus@openbsd.org #include "sshkey.h"
488668706dSDamien Miller #include "sshbuf.h"
498668706dSDamien Miller #include "ssherr.h"
505e39a499Sdjm@openbsd.org #include "krl.h"
51d4a8b7e3SDamien Miller 
522ce12ef1SDamien Miller #define MAX_KEY_FILE_SIZE	(1024 * 1024)
532ce12ef1SDamien Miller 
54a2327927SDamien Miller /* Save a key blob to a file */
55a2327927SDamien Miller static int
sshkey_save_private_blob(struct sshbuf * keybuf,const char * filename)568668706dSDamien Miller sshkey_save_private_blob(struct sshbuf *keybuf, const char *filename)
57a2327927SDamien Miller {
5899aa8035Sdjm@openbsd.org 	int r;
5999aa8035Sdjm@openbsd.org 	mode_t omask;
60a2327927SDamien Miller 
6199aa8035Sdjm@openbsd.org 	omask = umask(077);
6299aa8035Sdjm@openbsd.org 	r = sshbuf_write_file(filename, keybuf);
6399aa8035Sdjm@openbsd.org 	umask(omask);
6499aa8035Sdjm@openbsd.org 	return r;
65a2327927SDamien Miller }
66a2327927SDamien Miller 
67eba71babSDamien Miller int
sshkey_save_private(struct sshkey * key,const char * filename,const char * passphrase,const char * comment,int format,const char * openssh_format_cipher,int openssh_format_rounds)688668706dSDamien Miller sshkey_save_private(struct sshkey *key, const char *filename,
698668706dSDamien Miller     const char *passphrase, const char *comment,
70eb0d8e70Sdjm@openbsd.org     int format, const char *openssh_format_cipher, int openssh_format_rounds)
71eba71babSDamien Miller {
728668706dSDamien Miller 	struct sshbuf *keyblob = NULL;
738668706dSDamien Miller 	int r;
74a2327927SDamien Miller 
758668706dSDamien Miller 	if ((keyblob = sshbuf_new()) == NULL)
768668706dSDamien Miller 		return SSH_ERR_ALLOC_FAIL;
778668706dSDamien Miller 	if ((r = sshkey_private_to_fileblob(key, keyblob, passphrase, comment,
78eb0d8e70Sdjm@openbsd.org 	    format, openssh_format_cipher, openssh_format_rounds)) != 0)
79a2327927SDamien Miller 		goto out;
808668706dSDamien Miller 	if ((r = sshkey_save_private_blob(keyblob, filename)) != 0)
81a2327927SDamien Miller 		goto out;
828668706dSDamien Miller 	r = 0;
83a2327927SDamien Miller  out:
848668706dSDamien Miller 	sshbuf_free(keyblob);
858668706dSDamien Miller 	return r;
86eba71babSDamien Miller }
87a2327927SDamien Miller 
888668706dSDamien Miller /* XXX remove error() calls from here? */
898668706dSDamien Miller int
sshkey_perm_ok(int fd,const char * filename)908668706dSDamien Miller sshkey_perm_ok(int fd, const char *filename)
91eba71babSDamien Miller {
92eba71babSDamien Miller 	struct stat st;
93eba71babSDamien Miller 
944d28fa78Sderaadt@openbsd.org 	if (fstat(fd, &st) == -1)
958668706dSDamien Miller 		return SSH_ERR_SYSTEM_ERROR;
967aff2613SBen Lindstrom 	/*
977aff2613SBen Lindstrom 	 * if a key owned by the user is accessed, then we check the
987aff2613SBen Lindstrom 	 * permissions of the file. if the key owned by a different user,
997aff2613SBen Lindstrom 	 * then we don't care.
1007aff2613SBen Lindstrom 	 */
101b70b61f5SDamien Miller #ifdef HAVE_CYGWIN
102b70b61f5SDamien Miller 	if (check_ntsec(filename))
103b70b61f5SDamien Miller #endif
1047aff2613SBen Lindstrom 	if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
105eba71babSDamien Miller 		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
106eba71babSDamien Miller 		error("@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @");
107eba71babSDamien Miller 		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1087aff2613SBen Lindstrom 		error("Permissions 0%3.3o for '%s' are too open.",
10904bd8b0bSDamien Miller 		    (u_int)st.st_mode & 0777, filename);
1106b0d576bSdjm@openbsd.org 		error("It is required that your private key files are NOT accessible by others.");
111d0fca423SBen Lindstrom 		error("This private key will be ignored.");
1128668706dSDamien Miller 		return SSH_ERR_KEY_BAD_PERMISSIONS;
1138668706dSDamien Miller 	}
114eba71babSDamien Miller 	return 0;
115eba71babSDamien Miller }
116b257cca7SBen Lindstrom 
1178668706dSDamien Miller int
sshkey_load_private_type(int type,const char * filename,const char * passphrase,struct sshkey ** keyp,char ** commentp)1188668706dSDamien Miller sshkey_load_private_type(int type, const char *filename, const char *passphrase,
1196b39a7b4Sdtucker@openbsd.org     struct sshkey **keyp, char **commentp)
120a2327927SDamien Miller {
1218668706dSDamien Miller 	int fd, r;
122bcd00abdSDamien Miller 
123dce19bf6Sdjm@openbsd.org 	if (keyp != NULL)
1248668706dSDamien Miller 		*keyp = NULL;
1258668706dSDamien Miller 	if (commentp != NULL)
1268668706dSDamien Miller 		*commentp = NULL;
127a2327927SDamien Miller 
1286b39a7b4Sdtucker@openbsd.org 	if ((fd = open(filename, O_RDONLY)) == -1)
1298668706dSDamien Miller 		return SSH_ERR_SYSTEM_ERROR;
1306b39a7b4Sdtucker@openbsd.org 
1316b39a7b4Sdtucker@openbsd.org 	r = sshkey_perm_ok(fd, filename);
1326b39a7b4Sdtucker@openbsd.org 	if (r != 0)
1338668706dSDamien Miller 		goto out;
134a2327927SDamien Miller 
1351195f4cbSdjm@openbsd.org 	r = sshkey_load_private_type_fd(fd, type, passphrase, keyp, commentp);
1361b11ea7cSmarkus@openbsd.org 	if (r == 0 && keyp && *keyp)
1371b11ea7cSmarkus@openbsd.org 		r = sshkey_set_filename(*keyp, filename);
1381195f4cbSdjm@openbsd.org  out:
1391195f4cbSdjm@openbsd.org 	close(fd);
1401195f4cbSdjm@openbsd.org 	return r;
1411195f4cbSdjm@openbsd.org }
1421195f4cbSdjm@openbsd.org 
1431195f4cbSdjm@openbsd.org int
sshkey_load_private(const char * filename,const char * passphrase,struct sshkey ** keyp,char ** commentp)144094dd513Sdjm@openbsd.org sshkey_load_private(const char *filename, const char *passphrase,
145094dd513Sdjm@openbsd.org     struct sshkey **keyp, char **commentp)
146094dd513Sdjm@openbsd.org {
147094dd513Sdjm@openbsd.org 	return sshkey_load_private_type(KEY_UNSPEC, filename, passphrase,
148094dd513Sdjm@openbsd.org 	    keyp, commentp);
149094dd513Sdjm@openbsd.org }
150094dd513Sdjm@openbsd.org 
151094dd513Sdjm@openbsd.org int
sshkey_load_private_type_fd(int fd,int type,const char * passphrase,struct sshkey ** keyp,char ** commentp)1521195f4cbSdjm@openbsd.org sshkey_load_private_type_fd(int fd, int type, const char *passphrase,
1531195f4cbSdjm@openbsd.org     struct sshkey **keyp, char **commentp)
1541195f4cbSdjm@openbsd.org {
1551195f4cbSdjm@openbsd.org 	struct sshbuf *buffer = NULL;
1561195f4cbSdjm@openbsd.org 	int r;
1571195f4cbSdjm@openbsd.org 
158dce19bf6Sdjm@openbsd.org 	if (keyp != NULL)
159dce19bf6Sdjm@openbsd.org 		*keyp = NULL;
16099aa8035Sdjm@openbsd.org 	if ((r = sshbuf_load_fd(fd, &buffer)) != 0 ||
1611195f4cbSdjm@openbsd.org 	    (r = sshkey_parse_private_fileblob_type(buffer, type,
1621195f4cbSdjm@openbsd.org 	    passphrase, keyp, commentp)) != 0)
1638668706dSDamien Miller 		goto out;
1641195f4cbSdjm@openbsd.org 
1651195f4cbSdjm@openbsd.org 	/* success */
1668668706dSDamien Miller 	r = 0;
1678668706dSDamien Miller  out:
1688668706dSDamien Miller 	sshbuf_free(buffer);
1698668706dSDamien Miller 	return r;
170a2327927SDamien Miller }
171d0fca423SBen Lindstrom 
1722b13d393Sdjm@openbsd.org /* Load a pubkey from the unencrypted envelope of a new-format private key */
1732b13d393Sdjm@openbsd.org static int
sshkey_load_pubkey_from_private(const char * filename,struct sshkey ** pubkeyp)1742b13d393Sdjm@openbsd.org sshkey_load_pubkey_from_private(const char *filename, struct sshkey **pubkeyp)
1752b13d393Sdjm@openbsd.org {
1762b13d393Sdjm@openbsd.org 	struct sshbuf *buffer = NULL;
1772b13d393Sdjm@openbsd.org 	struct sshkey *pubkey = NULL;
1782b13d393Sdjm@openbsd.org 	int r, fd;
1792b13d393Sdjm@openbsd.org 
1802b13d393Sdjm@openbsd.org 	if (pubkeyp != NULL)
1812b13d393Sdjm@openbsd.org 		*pubkeyp = NULL;
1822b13d393Sdjm@openbsd.org 
1832b13d393Sdjm@openbsd.org 	if ((fd = open(filename, O_RDONLY)) == -1)
1842b13d393Sdjm@openbsd.org 		return SSH_ERR_SYSTEM_ERROR;
1852b13d393Sdjm@openbsd.org 	if ((r = sshbuf_load_fd(fd, &buffer)) != 0 ||
1862b13d393Sdjm@openbsd.org 	    (r = sshkey_parse_pubkey_from_private_fileblob_type(buffer,
1872b13d393Sdjm@openbsd.org 	    KEY_UNSPEC, &pubkey)) != 0)
1882b13d393Sdjm@openbsd.org 		goto out;
1892b13d393Sdjm@openbsd.org 	if ((r = sshkey_set_filename(pubkey, filename)) != 0)
1902b13d393Sdjm@openbsd.org 		goto out;
1912b13d393Sdjm@openbsd.org 	/* success */
1922b13d393Sdjm@openbsd.org 	if (pubkeyp != NULL) {
1932b13d393Sdjm@openbsd.org 		*pubkeyp = pubkey;
1942b13d393Sdjm@openbsd.org 		pubkey = NULL;
1952b13d393Sdjm@openbsd.org 	}
1962b13d393Sdjm@openbsd.org 	r = 0;
1972b13d393Sdjm@openbsd.org  out:
1982b13d393Sdjm@openbsd.org 	close(fd);
1992b13d393Sdjm@openbsd.org 	sshbuf_free(buffer);
2002b13d393Sdjm@openbsd.org 	sshkey_free(pubkey);
2012b13d393Sdjm@openbsd.org 	return r;
2022b13d393Sdjm@openbsd.org }
2032b13d393Sdjm@openbsd.org 
204bba81213SBen Lindstrom static int
sshkey_try_load_public(struct sshkey ** kp,const char * filename,char ** commentp)205d01f3930Sdjm@openbsd.org sshkey_try_load_public(struct sshkey **kp, const char *filename,
206d01f3930Sdjm@openbsd.org     char **commentp)
207e4340be5SDamien Miller {
208e4340be5SDamien Miller 	FILE *f;
2097f906352Smarkus@openbsd.org 	char *line = NULL, *cp;
2107f906352Smarkus@openbsd.org 	size_t linesize = 0;
2118668706dSDamien Miller 	int r;
212d01f3930Sdjm@openbsd.org 	struct sshkey *k = NULL;
213e4340be5SDamien Miller 
214d01f3930Sdjm@openbsd.org 	*kp = NULL;
2158668706dSDamien Miller 	if (commentp != NULL)
2168668706dSDamien Miller 		*commentp = NULL;
2178668706dSDamien Miller 	if ((f = fopen(filename, "r")) == NULL)
2188668706dSDamien Miller 		return SSH_ERR_SYSTEM_ERROR;
219d01f3930Sdjm@openbsd.org 	if ((k = sshkey_new(KEY_UNSPEC)) == NULL) {
220d01f3930Sdjm@openbsd.org 		fclose(f);
221d01f3930Sdjm@openbsd.org 		return SSH_ERR_ALLOC_FAIL;
222d01f3930Sdjm@openbsd.org 	}
2237f906352Smarkus@openbsd.org 	while (getline(&line, &linesize, f) != -1) {
224e4340be5SDamien Miller 		cp = line;
225e4340be5SDamien Miller 		switch (*cp) {
226e4340be5SDamien Miller 		case '#':
227e4340be5SDamien Miller 		case '\n':
228e4340be5SDamien Miller 		case '\0':
229e4340be5SDamien Miller 			continue;
230e4340be5SDamien Miller 		}
2313219824fSDamien Miller 		/* Abort loading if this looks like a private key */
2328668706dSDamien Miller 		if (strncmp(cp, "-----BEGIN", 10) == 0 ||
2338668706dSDamien Miller 		    strcmp(cp, "SSH PRIVATE KEY FILE") == 0)
2343219824fSDamien Miller 			break;
235e4340be5SDamien Miller 		/* Skip leading whitespace. */
236e4340be5SDamien Miller 		for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
237e4340be5SDamien Miller 			;
238e4340be5SDamien Miller 		if (*cp) {
2398668706dSDamien Miller 			if ((r = sshkey_read(k, &cp)) == 0) {
24004bb56efSDamien Miller 				cp[strcspn(cp, "\r\n")] = '\0';
24104bb56efSDamien Miller 				if (commentp) {
2428668706dSDamien Miller 					*commentp = strdup(*cp ?
24304bb56efSDamien Miller 					    cp : filename);
2448668706dSDamien Miller 					if (*commentp == NULL)
2458668706dSDamien Miller 						r = SSH_ERR_ALLOC_FAIL;
24604bb56efSDamien Miller 				}
247d01f3930Sdjm@openbsd.org 				/* success */
248d01f3930Sdjm@openbsd.org 				*kp = k;
2497f906352Smarkus@openbsd.org 				free(line);
250e4340be5SDamien Miller 				fclose(f);
2518668706dSDamien Miller 				return r;
252e4340be5SDamien Miller 			}
253e4340be5SDamien Miller 		}
254e4340be5SDamien Miller 	}
255d01f3930Sdjm@openbsd.org 	free(k);
2567f906352Smarkus@openbsd.org 	free(line);
257e4340be5SDamien Miller 	fclose(f);
2588668706dSDamien Miller 	return SSH_ERR_INVALID_FORMAT;
259e4340be5SDamien Miller }
260e4340be5SDamien Miller 
261afbfa68fSmarkus@openbsd.org /* load public key from any pubkey file */
2628668706dSDamien Miller int
sshkey_load_public(const char * filename,struct sshkey ** keyp,char ** commentp)2638668706dSDamien Miller sshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp)
264e4340be5SDamien Miller {
265d01f3930Sdjm@openbsd.org 	char *pubfile = NULL;
266*c514f3c0Sdjm@openbsd.org 	int r, oerrno;
267e4340be5SDamien Miller 
2688668706dSDamien Miller 	if (keyp != NULL)
2698668706dSDamien Miller 		*keyp = NULL;
2708668706dSDamien Miller 	if (commentp != NULL)
2718668706dSDamien Miller 		*commentp = NULL;
2728668706dSDamien Miller 
273d01f3930Sdjm@openbsd.org 	if ((r = sshkey_try_load_public(keyp, filename, commentp)) == 0)
274afbfa68fSmarkus@openbsd.org 		goto out;
2758668706dSDamien Miller 
2768668706dSDamien Miller 	/* try .pub suffix */
277d01f3930Sdjm@openbsd.org 	if (asprintf(&pubfile, "%s.pub", filename) == -1)
2788668706dSDamien Miller 		return SSH_ERR_ALLOC_FAIL;
279d01f3930Sdjm@openbsd.org 	if ((r = sshkey_try_load_public(keyp, pubfile, commentp)) == 0)
280afbfa68fSmarkus@openbsd.org 		goto out;
281d01f3930Sdjm@openbsd.org 
2822b13d393Sdjm@openbsd.org 	/* finally, try to extract public key from private key file */
2832b13d393Sdjm@openbsd.org 	if ((r = sshkey_load_pubkey_from_private(filename, keyp)) == 0)
2842b13d393Sdjm@openbsd.org 		goto out;
2852b13d393Sdjm@openbsd.org 
286*c514f3c0Sdjm@openbsd.org 	/* Pretend we couldn't find the key */
287*c514f3c0Sdjm@openbsd.org 	r = SSH_ERR_SYSTEM_ERROR;
288*c514f3c0Sdjm@openbsd.org 	errno = ENOENT;
289*c514f3c0Sdjm@openbsd.org 
290afbfa68fSmarkus@openbsd.org  out:
291*c514f3c0Sdjm@openbsd.org 	oerrno = errno;
292d01f3930Sdjm@openbsd.org 	free(pubfile);
293*c514f3c0Sdjm@openbsd.org 	errno = oerrno;
2948668706dSDamien Miller 	return r;
295e4340be5SDamien Miller }
2961aed65ebSDamien Miller 
297c158331fSDamien Miller /* Load the certificate associated with the named private key */
2988668706dSDamien Miller int
sshkey_load_cert(const char * filename,struct sshkey ** keyp)2998668706dSDamien Miller sshkey_load_cert(const char *filename, struct sshkey **keyp)
300c158331fSDamien Miller {
3018668706dSDamien Miller 	struct sshkey *pub = NULL;
3028668706dSDamien Miller 	char *file = NULL;
3038668706dSDamien Miller 	int r = SSH_ERR_INTERNAL_ERROR;
304c158331fSDamien Miller 
305dce19bf6Sdjm@openbsd.org 	if (keyp != NULL)
3068668706dSDamien Miller 		*keyp = NULL;
3078668706dSDamien Miller 
3088668706dSDamien Miller 	if (asprintf(&file, "%s-cert.pub", filename) == -1)
3098668706dSDamien Miller 		return SSH_ERR_ALLOC_FAIL;
3108668706dSDamien Miller 
311d01f3930Sdjm@openbsd.org 	r = sshkey_try_load_public(keyp, file, NULL);
312a627d42eSDarren Tucker 	free(file);
3138668706dSDamien Miller 	sshkey_free(pub);
3148668706dSDamien Miller 	return r;
315c158331fSDamien Miller }
316c158331fSDamien Miller 
317c158331fSDamien Miller /* Load private key and certificate */
3188668706dSDamien Miller int
sshkey_load_private_cert(int type,const char * filename,const char * passphrase,struct sshkey ** keyp)3198668706dSDamien Miller sshkey_load_private_cert(int type, const char *filename, const char *passphrase,
3206b39a7b4Sdtucker@openbsd.org     struct sshkey **keyp)
321c158331fSDamien Miller {
3228668706dSDamien Miller 	struct sshkey *key = NULL, *cert = NULL;
3238668706dSDamien Miller 	int r;
3248668706dSDamien Miller 
325dce19bf6Sdjm@openbsd.org 	if (keyp != NULL)
3268668706dSDamien Miller 		*keyp = NULL;
327c158331fSDamien Miller 
328c158331fSDamien Miller 	switch (type) {
3291f0311c7SDamien Miller #ifdef WITH_OPENSSL
330c158331fSDamien Miller 	case KEY_RSA:
331c158331fSDamien Miller 	case KEY_DSA:
332eb8b60e3SDamien Miller 	case KEY_ECDSA:
3338668706dSDamien Miller #endif /* WITH_OPENSSL */
33416db0a7eSmarkus@openbsd.org 	case KEY_ED25519:
3351b11ea7cSmarkus@openbsd.org 	case KEY_XMSS:
3368668706dSDamien Miller 	case KEY_UNSPEC:
337c158331fSDamien Miller 		break;
338c158331fSDamien Miller 	default:
3398668706dSDamien Miller 		return SSH_ERR_KEY_TYPE_UNKNOWN;
340c158331fSDamien Miller 	}
341c158331fSDamien Miller 
3428668706dSDamien Miller 	if ((r = sshkey_load_private_type(type, filename,
3436b39a7b4Sdtucker@openbsd.org 	    passphrase, &key, NULL)) != 0 ||
3448668706dSDamien Miller 	    (r = sshkey_load_cert(filename, &cert)) != 0)
3458668706dSDamien Miller 		goto out;
346c158331fSDamien Miller 
347c158331fSDamien Miller 	/* Make sure the private key matches the certificate */
3488668706dSDamien Miller 	if (sshkey_equal_public(key, cert) == 0) {
3498668706dSDamien Miller 		r = SSH_ERR_KEY_CERT_MISMATCH;
3508668706dSDamien Miller 		goto out;
351c158331fSDamien Miller 	}
352c158331fSDamien Miller 
353c28fc62dSdjm@openbsd.org 	if ((r = sshkey_to_certified(key)) != 0 ||
3548668706dSDamien Miller 	    (r = sshkey_cert_copy(cert, key)) != 0)
3558668706dSDamien Miller 		goto out;
3568668706dSDamien Miller 	r = 0;
357dce19bf6Sdjm@openbsd.org 	if (keyp != NULL) {
3588668706dSDamien Miller 		*keyp = key;
3598668706dSDamien Miller 		key = NULL;
360dce19bf6Sdjm@openbsd.org 	}
3618668706dSDamien Miller  out:
3628668706dSDamien Miller 	sshkey_free(key);
3638668706dSDamien Miller 	sshkey_free(cert);
3648668706dSDamien Miller 	return r;
365c158331fSDamien Miller }
366c158331fSDamien Miller 
3671aed65ebSDamien Miller /*
3688668706dSDamien Miller  * Returns success if the specified "key" is listed in the file "filename",
3698668706dSDamien Miller  * SSH_ERR_KEY_NOT_FOUND: if the key is not listed or another error.
3705e39a499Sdjm@openbsd.org  * If "strict_type" is set then the key type must match exactly,
3711aed65ebSDamien Miller  * otherwise a comparison that ignores certficiate data is performed.
3725e39a499Sdjm@openbsd.org  * If "check_ca" is set and "key" is a certificate, then its CA key is
3735e39a499Sdjm@openbsd.org  * also checked and sshkey_in_file() will return success if either is found.
3741aed65ebSDamien Miller  */
3751aed65ebSDamien Miller int
sshkey_in_file(struct sshkey * key,const char * filename,int strict_type,int check_ca)3765e39a499Sdjm@openbsd.org sshkey_in_file(struct sshkey *key, const char *filename, int strict_type,
3775e39a499Sdjm@openbsd.org     int check_ca)
3781aed65ebSDamien Miller {
3791aed65ebSDamien Miller 	FILE *f;
3807f906352Smarkus@openbsd.org 	char *line = NULL, *cp;
3817f906352Smarkus@openbsd.org 	size_t linesize = 0;
3828668706dSDamien Miller 	int r = 0;
3838668706dSDamien Miller 	struct sshkey *pub = NULL;
3847f906352Smarkus@openbsd.org 
3858668706dSDamien Miller 	int (*sshkey_compare)(const struct sshkey *, const struct sshkey *) =
3868668706dSDamien Miller 	    strict_type ?  sshkey_equal : sshkey_equal_public;
3871aed65ebSDamien Miller 
3885e39a499Sdjm@openbsd.org 	if ((f = fopen(filename, "r")) == NULL)
3898668706dSDamien Miller 		return SSH_ERR_SYSTEM_ERROR;
3901aed65ebSDamien Miller 
3917f906352Smarkus@openbsd.org 	while (getline(&line, &linesize, f) != -1) {
392bbc8af72Sdjm@openbsd.org 		sshkey_free(pub);
393bbc8af72Sdjm@openbsd.org 		pub = NULL;
3941aed65ebSDamien Miller 		cp = line;
3951aed65ebSDamien Miller 
3961aed65ebSDamien Miller 		/* Skip leading whitespace. */
3971aed65ebSDamien Miller 		for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
3981aed65ebSDamien Miller 			;
3991aed65ebSDamien Miller 
4001aed65ebSDamien Miller 		/* Skip comments and empty lines */
4011aed65ebSDamien Miller 		switch (*cp) {
4021aed65ebSDamien Miller 		case '#':
4031aed65ebSDamien Miller 		case '\n':
4041aed65ebSDamien Miller 		case '\0':
4051aed65ebSDamien Miller 			continue;
4061aed65ebSDamien Miller 		}
4071aed65ebSDamien Miller 
4088668706dSDamien Miller 		if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
4098668706dSDamien Miller 			r = SSH_ERR_ALLOC_FAIL;
4108668706dSDamien Miller 			goto out;
4111aed65ebSDamien Miller 		}
412bbc8af72Sdjm@openbsd.org 		switch (r = sshkey_read(pub, &cp)) {
413bbc8af72Sdjm@openbsd.org 		case 0:
414bbc8af72Sdjm@openbsd.org 			break;
415bbc8af72Sdjm@openbsd.org 		case SSH_ERR_KEY_LENGTH:
416bbc8af72Sdjm@openbsd.org 			continue;
417bbc8af72Sdjm@openbsd.org 		default:
4188668706dSDamien Miller 			goto out;
419bbc8af72Sdjm@openbsd.org 		}
4205e39a499Sdjm@openbsd.org 		if (sshkey_compare(key, pub) ||
4215e39a499Sdjm@openbsd.org 		    (check_ca && sshkey_is_cert(key) &&
4225e39a499Sdjm@openbsd.org 		    sshkey_compare(key->cert->signature_key, pub))) {
4238668706dSDamien Miller 			r = 0;
4248668706dSDamien Miller 			goto out;
4251aed65ebSDamien Miller 		}
4261aed65ebSDamien Miller 	}
4278668706dSDamien Miller 	r = SSH_ERR_KEY_NOT_FOUND;
4288668706dSDamien Miller  out:
4297f906352Smarkus@openbsd.org 	free(line);
4308668706dSDamien Miller 	sshkey_free(pub);
4311aed65ebSDamien Miller 	fclose(f);
4328668706dSDamien Miller 	return r;
4331aed65ebSDamien Miller }
4348668706dSDamien Miller 
4355e39a499Sdjm@openbsd.org /*
4365e39a499Sdjm@openbsd.org  * Checks whether the specified key is revoked, returning 0 if not,
4375e39a499Sdjm@openbsd.org  * SSH_ERR_KEY_REVOKED if it is or another error code if something
4385e39a499Sdjm@openbsd.org  * unexpected happened.
4395e39a499Sdjm@openbsd.org  * This will check both the key and, if it is a certificate, its CA key too.
4405e39a499Sdjm@openbsd.org  * "revoked_keys_file" may be a KRL or a one-per-line list of public keys.
4415e39a499Sdjm@openbsd.org  */
4425e39a499Sdjm@openbsd.org int
sshkey_check_revoked(struct sshkey * key,const char * revoked_keys_file)4435e39a499Sdjm@openbsd.org sshkey_check_revoked(struct sshkey *key, const char *revoked_keys_file)
4445e39a499Sdjm@openbsd.org {
4455e39a499Sdjm@openbsd.org 	int r;
4465e39a499Sdjm@openbsd.org 
4475e39a499Sdjm@openbsd.org 	r = ssh_krl_file_contains_key(revoked_keys_file, key);
4485e39a499Sdjm@openbsd.org 	/* If this was not a KRL to begin with then continue below */
4495e39a499Sdjm@openbsd.org 	if (r != SSH_ERR_KRL_BAD_MAGIC)
4505e39a499Sdjm@openbsd.org 		return r;
4515e39a499Sdjm@openbsd.org 
4525e39a499Sdjm@openbsd.org 	/*
4535e39a499Sdjm@openbsd.org 	 * If the file is not a KRL or we can't handle KRLs then attempt to
4545e39a499Sdjm@openbsd.org 	 * parse the file as a flat list of keys.
4555e39a499Sdjm@openbsd.org 	 */
4565e39a499Sdjm@openbsd.org 	switch ((r = sshkey_in_file(key, revoked_keys_file, 0, 1))) {
4575e39a499Sdjm@openbsd.org 	case 0:
4585e39a499Sdjm@openbsd.org 		/* Key found => revoked */
4595e39a499Sdjm@openbsd.org 		return SSH_ERR_KEY_REVOKED;
4605e39a499Sdjm@openbsd.org 	case SSH_ERR_KEY_NOT_FOUND:
4615e39a499Sdjm@openbsd.org 		/* Key not found => not revoked */
4625e39a499Sdjm@openbsd.org 		return 0;
4635e39a499Sdjm@openbsd.org 	default:
4645e39a499Sdjm@openbsd.org 		/* Some other error occurred */
4655e39a499Sdjm@openbsd.org 		return r;
4665e39a499Sdjm@openbsd.org 	}
4675e39a499Sdjm@openbsd.org }
4685e39a499Sdjm@openbsd.org 
469dd8002fbSdjm@openbsd.org /*
470dd8002fbSdjm@openbsd.org  * Advanced *cpp past the end of key options, defined as the first unquoted
471dd8002fbSdjm@openbsd.org  * whitespace character. Returns 0 on success or -1 on failure (e.g.
472dd8002fbSdjm@openbsd.org  * unterminated quotes).
473dd8002fbSdjm@openbsd.org  */
474dd8002fbSdjm@openbsd.org int
sshkey_advance_past_options(char ** cpp)475dd8002fbSdjm@openbsd.org