xref: /freebsd/crypto/openssh/authfile.c (revision f7167e0ea0bf5aaabff9490453b3b71b3f1b4d51)
1*f7167e0eSDag-Erling Smørgrav /* $OpenBSD: authfile.c,v 1.101 2013/12/29 04:35:50 djm Exp $ */
2511b41d2SMark Murray /*
3511b41d2SMark Murray  * Author: Tatu Ylonen <ylo@cs.hut.fi>
4511b41d2SMark Murray  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5511b41d2SMark Murray  *                    All rights reserved
6511b41d2SMark Murray  * This file contains functions for reading and writing identity files, and
7511b41d2SMark Murray  * for reading the passphrase from the user.
8511b41d2SMark Murray  *
9c2d3a559SKris Kennaway  * As far as I am concerned, the code I have written for this software
10c2d3a559SKris Kennaway  * can be used freely for any purpose.  Any derived versions of this
11c2d3a559SKris Kennaway  * software must be clearly marked as such, and if the derived work is
12c2d3a559SKris Kennaway  * incompatible with the protocol description in the RFC file, it must be
13c2d3a559SKris Kennaway  * called by a name other than "ssh" or "Secure Shell".
14c2d3a559SKris Kennaway  *
15c2d3a559SKris Kennaway  *
16*f7167e0eSDag-Erling Smørgrav  * Copyright (c) 2000, 2013 Markus Friedl.  All rights reserved.
17c2d3a559SKris Kennaway  *
18c2d3a559SKris Kennaway  * Redistribution and use in source and binary forms, with or without
19c2d3a559SKris Kennaway  * modification, are permitted provided that the following conditions
20c2d3a559SKris Kennaway  * are met:
21c2d3a559SKris Kennaway  * 1. Redistributions of source code must retain the above copyright
22c2d3a559SKris Kennaway  *    notice, this list of conditions and the following disclaimer.
23c2d3a559SKris Kennaway  * 2. Redistributions in binary form must reproduce the above copyright
24c2d3a559SKris Kennaway  *    notice, this list of conditions and the following disclaimer in the
25c2d3a559SKris Kennaway  *    documentation and/or other materials provided with the distribution.
26c2d3a559SKris Kennaway  *
27c2d3a559SKris Kennaway  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
28c2d3a559SKris Kennaway  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29c2d3a559SKris Kennaway  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30c2d3a559SKris Kennaway  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
31c2d3a559SKris Kennaway  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
32c2d3a559SKris Kennaway  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33c2d3a559SKris Kennaway  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34c2d3a559SKris Kennaway  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35c2d3a559SKris Kennaway  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
36c2d3a559SKris Kennaway  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37511b41d2SMark Murray  */
38511b41d2SMark Murray 
39511b41d2SMark Murray #include "includes.h"
40333ee039SDag-Erling Smørgrav 
41333ee039SDag-Erling Smørgrav #include <sys/types.h>
42333ee039SDag-Erling Smørgrav #include <sys/stat.h>
43333ee039SDag-Erling Smørgrav #include <sys/param.h>
44333ee039SDag-Erling Smørgrav #include <sys/uio.h>
45511b41d2SMark Murray 
46ca3176e7SBrian Feldman #include <openssl/err.h>
47e8aafc91SKris Kennaway #include <openssl/evp.h>
48ca3176e7SBrian Feldman #include <openssl/pem.h>
49e8aafc91SKris Kennaway 
50b15c8340SDag-Erling Smørgrav /* compatibility with old or broken OpenSSL versions */
51b15c8340SDag-Erling Smørgrav #include "openbsd-compat/openssl-compat.h"
52b15c8340SDag-Erling Smørgrav 
53*f7167e0eSDag-Erling Smørgrav #include "crypto_api.h"
54*f7167e0eSDag-Erling Smørgrav 
55333ee039SDag-Erling Smørgrav #include <errno.h>
56333ee039SDag-Erling Smørgrav #include <fcntl.h>
57333ee039SDag-Erling Smørgrav #include <stdarg.h>
58333ee039SDag-Erling Smørgrav #include <stdio.h>
59333ee039SDag-Erling Smørgrav #include <stdlib.h>
60333ee039SDag-Erling Smørgrav #include <string.h>
61333ee039SDag-Erling Smørgrav #include <unistd.h>
62333ee039SDag-Erling Smørgrav 
63*f7167e0eSDag-Erling Smørgrav #ifdef HAVE_UTIL_H
64*f7167e0eSDag-Erling Smørgrav #include <util.h>
65*f7167e0eSDag-Erling Smørgrav #endif
66*f7167e0eSDag-Erling Smørgrav 
67511b41d2SMark Murray #include "xmalloc.h"
68333ee039SDag-Erling Smørgrav #include "cipher.h"
69511b41d2SMark Murray #include "buffer.h"
70e8aafc91SKris Kennaway #include "key.h"
71ca3176e7SBrian Feldman #include "ssh.h"
72ca3176e7SBrian Feldman #include "log.h"
73ca3176e7SBrian Feldman #include "authfile.h"
74af12a3e7SDag-Erling Smørgrav #include "rsa.h"
75aa49c926SDag-Erling Smørgrav #include "misc.h"
76d4ecd108SDag-Erling Smørgrav #include "atomicio.h"
77*f7167e0eSDag-Erling Smørgrav #include "uuencode.h"
78*f7167e0eSDag-Erling Smørgrav 
79*f7167e0eSDag-Erling Smørgrav /* openssh private key file format */
80*f7167e0eSDag-Erling Smørgrav #define MARK_BEGIN		"-----BEGIN OPENSSH PRIVATE KEY-----\n"
81*f7167e0eSDag-Erling Smørgrav #define MARK_END		"-----END OPENSSH PRIVATE KEY-----\n"
82*f7167e0eSDag-Erling Smørgrav #define KDFNAME			"bcrypt"
83*f7167e0eSDag-Erling Smørgrav #define AUTH_MAGIC		"openssh-key-v1"
84*f7167e0eSDag-Erling Smørgrav #define SALT_LEN		16
85*f7167e0eSDag-Erling Smørgrav #define DEFAULT_CIPHERNAME	"aes256-cbc"
86*f7167e0eSDag-Erling Smørgrav #define	DEFAULT_ROUNDS		16
87511b41d2SMark Murray 
88e146993eSDag-Erling Smørgrav #define MAX_KEY_FILE_SIZE	(1024 * 1024)
89e146993eSDag-Erling Smørgrav 
90ca3176e7SBrian Feldman /* Version identification string for SSH v1 identity files. */
91ca3176e7SBrian Feldman static const char authfile_id_string[] =
92ca3176e7SBrian Feldman     "SSH PRIVATE KEY FILE FORMAT 1.1\n";
93511b41d2SMark Murray 
94*f7167e0eSDag-Erling Smørgrav static int
95*f7167e0eSDag-Erling Smørgrav key_private_to_blob2(Key *prv, Buffer *blob, const char *passphrase,
96*f7167e0eSDag-Erling Smørgrav     const char *comment, const char *ciphername, int rounds)
97*f7167e0eSDag-Erling Smørgrav {
98*f7167e0eSDag-Erling Smørgrav 	u_char *key, *cp, salt[SALT_LEN];
99*f7167e0eSDag-Erling Smørgrav 	size_t keylen, ivlen, blocksize, authlen;
100*f7167e0eSDag-Erling Smørgrav 	u_int len, check;
101*f7167e0eSDag-Erling Smørgrav 	int i, n;
102*f7167e0eSDag-Erling Smørgrav 	const Cipher *c;
103*f7167e0eSDag-Erling Smørgrav 	Buffer encoded, b, kdf;
104*f7167e0eSDag-Erling Smørgrav 	CipherContext ctx;
105*f7167e0eSDag-Erling Smørgrav 	const char *kdfname = KDFNAME;
106*f7167e0eSDag-Erling Smørgrav 
107*f7167e0eSDag-Erling Smørgrav 	if (rounds <= 0)
108*f7167e0eSDag-Erling Smørgrav 		rounds = DEFAULT_ROUNDS;
109*f7167e0eSDag-Erling Smørgrav 	if (passphrase == NULL || !strlen(passphrase)) {
110*f7167e0eSDag-Erling Smørgrav 		ciphername = "none";
111*f7167e0eSDag-Erling Smørgrav 		kdfname = "none";
112*f7167e0eSDag-Erling Smørgrav 	} else if (ciphername == NULL)
113*f7167e0eSDag-Erling Smørgrav 		ciphername = DEFAULT_CIPHERNAME;
114*f7167e0eSDag-Erling Smørgrav 	else if (cipher_number(ciphername) != SSH_CIPHER_SSH2)
115*f7167e0eSDag-Erling Smørgrav 		fatal("invalid cipher");
116*f7167e0eSDag-Erling Smørgrav 
117*f7167e0eSDag-Erling Smørgrav 	if ((c = cipher_by_name(ciphername)) == NULL)
118*f7167e0eSDag-Erling Smørgrav 		fatal("unknown cipher name");
119*f7167e0eSDag-Erling Smørgrav 	buffer_init(&kdf);
120*f7167e0eSDag-Erling Smørgrav 	blocksize = cipher_blocksize(c);
121*f7167e0eSDag-Erling Smørgrav 	keylen = cipher_keylen(c);
122*f7167e0eSDag-Erling Smørgrav 	ivlen = cipher_ivlen(c);
123*f7167e0eSDag-Erling Smørgrav 	authlen = cipher_authlen(c);
124*f7167e0eSDag-Erling Smørgrav 	key = xcalloc(1, keylen + ivlen);
125*f7167e0eSDag-Erling Smørgrav 	if (strcmp(kdfname, "none") != 0) {
126*f7167e0eSDag-Erling Smørgrav 		arc4random_buf(salt, SALT_LEN);
127*f7167e0eSDag-Erling Smørgrav 		if (bcrypt_pbkdf(passphrase, strlen(passphrase),
128*f7167e0eSDag-Erling Smørgrav 		    salt, SALT_LEN, key, keylen + ivlen, rounds) < 0)
129*f7167e0eSDag-Erling Smørgrav 			fatal("bcrypt_pbkdf failed");
130*f7167e0eSDag-Erling Smørgrav 		buffer_put_string(&kdf, salt, SALT_LEN);
131*f7167e0eSDag-Erling Smørgrav 		buffer_put_int(&kdf, rounds);
132*f7167e0eSDag-Erling Smørgrav 	}
133*f7167e0eSDag-Erling Smørgrav 	cipher_init(&ctx, c, key, keylen, key + keylen , ivlen, 1);
134*f7167e0eSDag-Erling Smørgrav 	memset(key, 0, keylen + ivlen);
135*f7167e0eSDag-Erling Smørgrav 	free(key);
136*f7167e0eSDag-Erling Smørgrav 
137*f7167e0eSDag-Erling Smørgrav 	buffer_init(&encoded);
138*f7167e0eSDag-Erling Smørgrav 	buffer_append(&encoded, AUTH_MAGIC, sizeof(AUTH_MAGIC));
139*f7167e0eSDag-Erling Smørgrav 	buffer_put_cstring(&encoded, ciphername);
140*f7167e0eSDag-Erling Smørgrav 	buffer_put_cstring(&encoded, kdfname);
141*f7167e0eSDag-Erling Smørgrav 	buffer_put_string(&encoded, buffer_ptr(&kdf), buffer_len(&kdf));
142*f7167e0eSDag-Erling Smørgrav 	buffer_put_int(&encoded, 1);			/* number of keys */
143*f7167e0eSDag-Erling Smørgrav 	key_to_blob(prv, &cp, &len);			/* public key */
144*f7167e0eSDag-Erling Smørgrav 	buffer_put_string(&encoded, cp, len);
145*f7167e0eSDag-Erling Smørgrav 
146*f7167e0eSDag-Erling Smørgrav 	memset(cp, 0, len);
147*f7167e0eSDag-Erling Smørgrav 	free(cp);
148*f7167e0eSDag-Erling Smørgrav 
149*f7167e0eSDag-Erling Smørgrav 	buffer_free(&kdf);
150*f7167e0eSDag-Erling Smørgrav 
151*f7167e0eSDag-Erling Smørgrav 	/* set up the buffer that will be encrypted */
152*f7167e0eSDag-Erling Smørgrav 	buffer_init(&b);
153*f7167e0eSDag-Erling Smørgrav 
154*f7167e0eSDag-Erling Smørgrav 	/* Random check bytes */
155*f7167e0eSDag-Erling Smørgrav 	check = arc4random();
156*f7167e0eSDag-Erling Smørgrav 	buffer_put_int(&b, check);
157*f7167e0eSDag-Erling Smørgrav 	buffer_put_int(&b, check);
158*f7167e0eSDag-Erling Smørgrav 
159*f7167e0eSDag-Erling Smørgrav 	/* append private key and comment*/
160*f7167e0eSDag-Erling Smørgrav 	key_private_serialize(prv, &b);
161*f7167e0eSDag-Erling Smørgrav 	buffer_put_cstring(&b, comment);
162*f7167e0eSDag-Erling Smørgrav 
163*f7167e0eSDag-Erling Smørgrav 	/* padding */
164*f7167e0eSDag-Erling Smørgrav 	i = 0;
165*f7167e0eSDag-Erling Smørgrav 	while (buffer_len(&b) % blocksize)
166*f7167e0eSDag-Erling Smørgrav 		buffer_put_char(&b, ++i & 0xff);
167*f7167e0eSDag-Erling Smørgrav 
168*f7167e0eSDag-Erling Smørgrav 	/* length */
169*f7167e0eSDag-Erling Smørgrav 	buffer_put_int(&encoded, buffer_len(&b));
170*f7167e0eSDag-Erling Smørgrav 
171*f7167e0eSDag-Erling Smørgrav 	/* encrypt */
172*f7167e0eSDag-Erling Smørgrav 	cp = buffer_append_space(&encoded, buffer_len(&b) + authlen);
173*f7167e0eSDag-Erling Smørgrav 	if (cipher_crypt(&ctx, 0, cp, buffer_ptr(&b), buffer_len(&b), 0,
174*f7167e0eSDag-Erling Smørgrav 	    authlen) != 0)
175*f7167e0eSDag-Erling Smørgrav 		fatal("%s: cipher_crypt failed", __func__);
176*f7167e0eSDag-Erling Smørgrav 	buffer_free(&b);
177*f7167e0eSDag-Erling Smørgrav 	cipher_cleanup(&ctx);
178*f7167e0eSDag-Erling Smørgrav 
179*f7167e0eSDag-Erling Smørgrav 	/* uuencode */
180*f7167e0eSDag-Erling Smørgrav 	len = 2 * buffer_len(&encoded);
181*f7167e0eSDag-Erling Smørgrav 	cp = xmalloc(len);
182*f7167e0eSDag-Erling Smørgrav 	n = uuencode(buffer_ptr(&encoded), buffer_len(&encoded),
183*f7167e0eSDag-Erling Smørgrav 	    (char *)cp, len);
184*f7167e0eSDag-Erling Smørgrav 	if (n < 0)
185*f7167e0eSDag-Erling Smørgrav 		fatal("%s: uuencode", __func__);
186*f7167e0eSDag-Erling Smørgrav 
187*f7167e0eSDag-Erling Smørgrav 	buffer_clear(blob);
188*f7167e0eSDag-Erling Smørgrav 	buffer_append(blob, MARK_BEGIN, sizeof(MARK_BEGIN) - 1);
189*f7167e0eSDag-Erling Smørgrav 	for (i = 0; i < n; i++) {
190*f7167e0eSDag-Erling Smørgrav 		buffer_put_char(blob, cp[i]);
191*f7167e0eSDag-Erling Smørgrav 		if (i % 70 == 69)
192*f7167e0eSDag-Erling Smørgrav 			buffer_put_char(blob, '\n');
193*f7167e0eSDag-Erling Smørgrav 	}
194*f7167e0eSDag-Erling Smørgrav 	if (i % 70 != 69)
195*f7167e0eSDag-Erling Smørgrav 		buffer_put_char(blob, '\n');
196*f7167e0eSDag-Erling Smørgrav 	buffer_append(blob, MARK_END, sizeof(MARK_END) - 1);
197*f7167e0eSDag-Erling Smørgrav 	free(cp);
198*f7167e0eSDag-Erling Smørgrav 
199*f7167e0eSDag-Erling Smørgrav 	return buffer_len(blob);
200*f7167e0eSDag-Erling Smørgrav }
201*f7167e0eSDag-Erling Smørgrav 
202*f7167e0eSDag-Erling Smørgrav static Key *
203*f7167e0eSDag-Erling Smørgrav key_parse_private2(Buffer *blob, int type, const char *passphrase,
204*f7167e0eSDag-Erling Smørgrav     char **commentp)
205*f7167e0eSDag-Erling Smørgrav {
206*f7167e0eSDag-Erling Smørgrav 	u_char *key = NULL, *cp, *salt = NULL, pad, last;
207*f7167e0eSDag-Erling Smørgrav 	char *comment = NULL, *ciphername = NULL, *kdfname = NULL, *kdfp;
208*f7167e0eSDag-Erling Smørgrav 	u_int keylen = 0, ivlen, blocksize, slen, klen, len, rounds, nkeys;
209*f7167e0eSDag-Erling Smørgrav 	u_int check1, check2, m1len, m2len;
210*f7167e0eSDag-Erling Smørgrav 	size_t authlen;
211*f7167e0eSDag-Erling Smørgrav 	const Cipher *c;
212*f7167e0eSDag-Erling Smørgrav 	Buffer b, encoded, copy, kdf;
213*f7167e0eSDag-Erling Smørgrav 	CipherContext ctx;
214*f7167e0eSDag-Erling Smørgrav 	Key *k = NULL;
215*f7167e0eSDag-Erling Smørgrav 	int dlen, ret, i;
216*f7167e0eSDag-Erling Smørgrav 
217*f7167e0eSDag-Erling Smørgrav 	buffer_init(&b);
218*f7167e0eSDag-Erling Smørgrav 	buffer_init(&kdf);
219*f7167e0eSDag-Erling Smørgrav 	buffer_init(&encoded);
220*f7167e0eSDag-Erling Smørgrav 	buffer_init(&copy);
221*f7167e0eSDag-Erling Smørgrav 
222*f7167e0eSDag-Erling Smørgrav 	/* uudecode */
223*f7167e0eSDag-Erling Smørgrav 	m1len = sizeof(MARK_BEGIN) - 1;
224*f7167e0eSDag-Erling Smørgrav 	m2len = sizeof(MARK_END) - 1;
225*f7167e0eSDag-Erling Smørgrav 	cp = buffer_ptr(blob);
226*f7167e0eSDag-Erling Smørgrav 	len = buffer_len(blob);
227*f7167e0eSDag-Erling Smørgrav 	if (len < m1len || memcmp(cp, MARK_BEGIN, m1len)) {
228*f7167e0eSDag-Erling Smørgrav 		debug("%s: missing begin marker", __func__);
229*f7167e0eSDag-Erling Smørgrav 		goto out;
230*f7167e0eSDag-Erling Smørgrav 	}
231*f7167e0eSDag-Erling Smørgrav 	cp += m1len;
232*f7167e0eSDag-Erling Smørgrav 	len -= m1len;
233*f7167e0eSDag-Erling Smørgrav 	while (len) {
234*f7167e0eSDag-Erling Smørgrav 		if (*cp != '\n' && *cp != '\r')
235*f7167e0eSDag-Erling Smørgrav 			buffer_put_char(&encoded, *cp);
236*f7167e0eSDag-Erling Smørgrav 		last = *cp;
237*f7167e0eSDag-Erling Smørgrav 		len--;
238*f7167e0eSDag-Erling Smørgrav 		cp++;
239*f7167e0eSDag-Erling Smørgrav 		if (last == '\n') {
240*f7167e0eSDag-Erling Smørgrav 			if (len >= m2len && !memcmp(cp, MARK_END, m2len)) {
241*f7167e0eSDag-Erling Smørgrav 				buffer_put_char(&encoded, '\0');
242*f7167e0eSDag-Erling Smørgrav 				break;
243*f7167e0eSDag-Erling Smørgrav 			}
244*f7167e0eSDag-Erling Smørgrav 		}
245*f7167e0eSDag-Erling Smørgrav 	}
246*f7167e0eSDag-Erling Smørgrav 	if (!len) {
247*f7167e0eSDag-Erling Smørgrav 		debug("%s: no end marker", __func__);
248*f7167e0eSDag-Erling Smørgrav 		goto out;
249*f7167e0eSDag-Erling Smørgrav 	}
250*f7167e0eSDag-Erling Smørgrav 	len = buffer_len(&encoded);
251*f7167e0eSDag-Erling Smørgrav 	if ((cp = buffer_append_space(&copy, len)) == NULL) {
252*f7167e0eSDag-Erling Smørgrav 		error("%s: buffer_append_space", __func__);
253*f7167e0eSDag-Erling Smørgrav 		goto out;
254*f7167e0eSDag-Erling Smørgrav 	}
255*f7167e0eSDag-Erling Smørgrav 	if ((dlen = uudecode(buffer_ptr(&encoded), cp, len)) < 0) {
256*f7167e0eSDag-Erling Smørgrav 		error("%s: uudecode failed", __func__);
257*f7167e0eSDag-Erling Smørgrav 		goto out;
258*f7167e0eSDag-Erling Smørgrav 	}
259*f7167e0eSDag-Erling Smørgrav 	if ((u_int)dlen > len) {
260*f7167e0eSDag-Erling Smørgrav 		error("%s: crazy uudecode length %d > %u", __func__, dlen, len);
261*f7167e0eSDag-Erling Smørgrav 		goto out;
262*f7167e0eSDag-Erling Smørgrav 	}
263*f7167e0eSDag-Erling Smørgrav 	buffer_consume_end(&copy, len - dlen);
264*f7167e0eSDag-Erling Smørgrav 	if (buffer_len(&copy) < sizeof(AUTH_MAGIC) ||
265*f7167e0eSDag-Erling Smørgrav 	    memcmp(buffer_ptr(&copy), AUTH_MAGIC, sizeof(AUTH_MAGIC))) {
266*f7167e0eSDag-Erling Smørgrav 		error("%s: bad magic", __func__);
267*f7167e0eSDag-Erling Smørgrav 		goto out;
268*f7167e0eSDag-Erling Smørgrav 	}
269*f7167e0eSDag-Erling Smørgrav 	buffer_consume(&copy, sizeof(AUTH_MAGIC));
270*f7167e0eSDag-Erling Smørgrav 
271*f7167e0eSDag-Erling Smørgrav 	ciphername = buffer_get_cstring_ret(&copy, NULL);
272*f7167e0eSDag-Erling Smørgrav 	if (ciphername == NULL ||
273*f7167e0eSDag-Erling Smørgrav 	    (c = cipher_by_name(ciphername)) == NULL) {
274*f7167e0eSDag-Erling Smørgrav 		error("%s: unknown cipher name", __func__);
275*f7167e0eSDag-Erling Smørgrav 		goto out;
276*f7167e0eSDag-Erling Smørgrav 	}
277*f7167e0eSDag-Erling Smørgrav 	if ((passphrase == NULL || !strlen(passphrase)) &&
278*f7167e0eSDag-Erling Smørgrav 	    strcmp(ciphername, "none") != 0) {
279*f7167e0eSDag-Erling Smørgrav 		/* passphrase required */
280*f7167e0eSDag-Erling Smørgrav 		goto out;
281*f7167e0eSDag-Erling Smørgrav 	}
282*f7167e0eSDag-Erling Smørgrav 	kdfname = buffer_get_cstring_ret(&copy, NULL);
283*f7167e0eSDag-Erling Smørgrav 	if (kdfname == NULL ||
284*f7167e0eSDag-Erling Smørgrav 	    (!strcmp(kdfname, "none") && !strcmp(kdfname, "bcrypt"))) {
285*f7167e0eSDag-Erling Smørgrav 		error("%s: unknown kdf name", __func__);
286*f7167e0eSDag-Erling Smørgrav 		goto out;
287*f7167e0eSDag-Erling Smørgrav 	}
288*f7167e0eSDag-Erling Smørgrav 	if (!strcmp(kdfname, "none") && strcmp(ciphername, "none") != 0) {
289*f7167e0eSDag-Erling Smørgrav 		error("%s: cipher %s requires kdf", __func__, ciphername);
290*f7167e0eSDag-Erling Smørgrav 		goto out;
291*f7167e0eSDag-Erling Smørgrav 	}
292*f7167e0eSDag-Erling Smørgrav 	/* kdf options */
293*f7167e0eSDag-Erling Smørgrav 	kdfp = buffer_get_string_ptr_ret(&copy, &klen);
294*f7167e0eSDag-Erling Smørgrav 	if (kdfp == NULL) {
295*f7167e0eSDag-Erling Smørgrav 		error("%s: kdf options not set", __func__);
296*f7167e0eSDag-Erling Smørgrav 		goto out;
297*f7167e0eSDag-Erling Smørgrav 	}
298*f7167e0eSDag-Erling Smørgrav 	if (klen > 0) {
299*f7167e0eSDag-Erling Smørgrav 		if ((cp = buffer_append_space(&kdf, klen)) == NULL) {
300*f7167e0eSDag-Erling Smørgrav 			error("%s: kdf alloc failed", __func__);
301*f7167e0eSDag-Erling Smørgrav 			goto out;
302*f7167e0eSDag-Erling Smørgrav 		}
303*f7167e0eSDag-Erling Smørgrav 		memcpy(cp, kdfp, klen);
304*f7167e0eSDag-Erling Smørgrav 	}
305*f7167e0eSDag-Erling Smørgrav 	/* number of keys */
306*f7167e0eSDag-Erling Smørgrav 	if (buffer_get_int_ret(&nkeys, &copy) < 0) {
307*f7167e0eSDag-Erling Smørgrav 		error("%s: key counter missing", __func__);
308*f7167e0eSDag-Erling Smørgrav 		goto out;
309*f7167e0eSDag-Erling Smørgrav 	}
310*f7167e0eSDag-Erling Smørgrav 	if (nkeys != 1) {
311*f7167e0eSDag-Erling Smørgrav 		error("%s: only one key supported", __func__);
312*f7167e0eSDag-Erling Smørgrav 		goto out;
313*f7167e0eSDag-Erling Smørgrav 	}
314*f7167e0eSDag-Erling Smørgrav 	/* pubkey */
315*f7167e0eSDag-Erling Smørgrav 	if ((cp = buffer_get_string_ret(&copy, &len)) == NULL) {
316*f7167e0eSDag-Erling Smørgrav 		error("%s: pubkey not found", __func__);
317*f7167e0eSDag-Erling Smørgrav 		goto out;
318*f7167e0eSDag-Erling Smørgrav 	}
319*f7167e0eSDag-Erling Smørgrav 	free(cp); /* XXX check pubkey against decrypted private key */
320*f7167e0eSDag-Erling Smørgrav 
321*f7167e0eSDag-Erling Smørgrav 	/* size of encrypted key blob */
322*f7167e0eSDag-Erling Smørgrav 	len = buffer_get_int(&copy);
323*f7167e0eSDag-Erling Smørgrav 	blocksize = cipher_blocksize(c);
324*f7167e0eSDag-Erling Smørgrav 	authlen = cipher_authlen(c);
325*f7167e0eSDag-Erling Smørgrav 	if (len < blocksize) {
326*f7167e0eSDag-Erling Smørgrav 		error("%s: encrypted data too small", __func__);
327*f7167e0eSDag-Erling Smørgrav 		goto out;
328*f7167e0eSDag-Erling Smørgrav 	}
329*f7167e0eSDag-Erling Smørgrav 	if (len % blocksize) {
330*f7167e0eSDag-Erling Smørgrav 		error("%s: length not multiple of blocksize", __func__);
331*f7167e0eSDag-Erling Smørgrav 		goto out;
332*f7167e0eSDag-Erling Smørgrav 	}
333*f7167e0eSDag-Erling Smørgrav 
334*f7167e0eSDag-Erling Smørgrav 	/* setup key */
335*f7167e0eSDag-Erling Smørgrav 	keylen = cipher_keylen(c);
336*f7167e0eSDag-Erling Smørgrav 	ivlen = cipher_ivlen(c);
337*f7167e0eSDag-Erling Smørgrav 	key = xcalloc(1, keylen + ivlen);
338*f7167e0eSDag-Erling Smørgrav 	if (!strcmp(kdfname, "bcrypt")) {
339*f7167e0eSDag-Erling Smørgrav 		if ((salt = buffer_get_string_ret(&kdf, &slen)) == NULL) {
340*f7167e0eSDag-Erling Smørgrav 			error("%s: salt not set", __func__);
341*f7167e0eSDag-Erling Smørgrav 			goto out;
342*f7167e0eSDag-Erling Smørgrav 		}
343*f7167e0eSDag-Erling Smørgrav 		if (buffer_get_int_ret(&rounds, &kdf) < 0) {
344*f7167e0eSDag-Erling Smørgrav 			error("%s: rounds not set", __func__);
345*f7167e0eSDag-Erling Smørgrav 			goto out;
346*f7167e0eSDag-Erling Smørgrav 		}
347*f7167e0eSDag-Erling Smørgrav 		if (bcrypt_pbkdf(passphrase, strlen(passphrase), salt, slen,
348*f7167e0eSDag-Erling Smørgrav 		    key, keylen + ivlen, rounds) < 0) {
349*f7167e0eSDag-Erling Smørgrav 			error("%s: bcrypt_pbkdf failed", __func__);
350*f7167e0eSDag-Erling Smørgrav 			goto out;
351*f7167e0eSDag-Erling Smørgrav 		}
352*f7167e0eSDag-Erling Smørgrav 	}
353*f7167e0eSDag-Erling Smørgrav 
354*f7167e0eSDag-Erling Smørgrav 	cp = buffer_append_space(&b, len);
355*f7167e0eSDag-Erling Smørgrav 	cipher_init(&ctx, c, key, keylen, key + keylen, ivlen, 0);
356*f7167e0eSDag-Erling Smørgrav 	ret = cipher_crypt(&ctx, 0, cp, buffer_ptr(&copy), len, 0, authlen);
357*f7167e0eSDag-Erling Smørgrav 	cipher_cleanup(&ctx);
358*f7167e0eSDag-Erling Smørgrav 	buffer_consume(&copy, len);
359*f7167e0eSDag-Erling Smørgrav 
360*f7167e0eSDag-Erling Smørgrav 	/* fail silently on decryption errors */
361*f7167e0eSDag-Erling Smørgrav 	if (ret != 0) {
362*f7167e0eSDag-Erling Smørgrav 		debug("%s: decrypt failed", __func__);
363*f7167e0eSDag-Erling Smørgrav 		goto out;
364*f7167e0eSDag-Erling Smørgrav 	}
365*f7167e0eSDag-Erling Smørgrav 
366*f7167e0eSDag-Erling Smørgrav 	if (buffer_len(&copy) != 0) {
367*f7167e0eSDag-Erling Smørgrav 		error("%s: key blob has trailing data (len = %u)", __func__,
368*f7167e0eSDag-Erling Smørgrav 		    buffer_len(&copy));
369*f7167e0eSDag-Erling Smørgrav 		goto out;
370*f7167e0eSDag-Erling Smørgrav 	}
371*f7167e0eSDag-Erling Smørgrav 
372*f7167e0eSDag-Erling Smørgrav 	/* check bytes */
373*f7167e0eSDag-Erling Smørgrav 	if (buffer_get_int_ret(&check1, &b) < 0 ||
374*f7167e0eSDag-Erling Smørgrav 	    buffer_get_int_ret(&check2, &b) < 0) {
375*f7167e0eSDag-Erling Smørgrav 		error("check bytes missing");
376*f7167e0eSDag-Erling Smørgrav 		goto out;
377*f7167e0eSDag-Erling Smørgrav 	}
378*f7167e0eSDag-Erling Smørgrav 	if (check1 != check2) {
379*f7167e0eSDag-Erling Smørgrav 		debug("%s: decrypt failed: 0x%08x != 0x%08x", __func__,
380*f7167e0eSDag-Erling Smørgrav 		    check1, check2);
381*f7167e0eSDag-Erling Smørgrav 		goto out;
382*f7167e0eSDag-Erling Smørgrav 	}
383*f7167e0eSDag-Erling Smørgrav 
384*f7167e0eSDag-Erling Smørgrav 	k = key_private_deserialize(&b);
385*f7167e0eSDag-Erling Smørgrav 
386*f7167e0eSDag-Erling Smørgrav 	/* comment */
387*f7167e0eSDag-Erling Smørgrav 	comment = buffer_get_cstring_ret(&b, NULL);
388*f7167e0eSDag-Erling Smørgrav 
389*f7167e0eSDag-Erling Smørgrav 	i = 0;
390*f7167e0eSDag-Erling Smørgrav 	while (buffer_len(&b)) {
391*f7167e0eSDag-Erling Smørgrav 		if (buffer_get_char_ret(&pad, &b) == -1 ||
392*f7167e0eSDag-Erling Smørgrav 		    pad != (++i & 0xff)) {
393*f7167e0eSDag-Erling Smørgrav 			error("%s: bad padding", __func__);
394*f7167e0eSDag-Erling Smørgrav 			key_free(k);
395*f7167e0eSDag-Erling Smørgrav 			k = NULL;
396*f7167e0eSDag-Erling Smørgrav 			goto out;
397*f7167e0eSDag-Erling Smørgrav 		}
398*f7167e0eSDag-Erling Smørgrav 	}
399*f7167e0eSDag-Erling Smørgrav 
400*f7167e0eSDag-Erling Smørgrav 	if (k && commentp) {
401*f7167e0eSDag-Erling Smørgrav 		*commentp = comment;
402*f7167e0eSDag-Erling Smørgrav 		comment = NULL;
403*f7167e0eSDag-Erling Smørgrav 	}
404*f7167e0eSDag-Erling Smørgrav 
405*f7167e0eSDag-Erling Smørgrav 	/* XXX decode pubkey and check against private */
406*f7167e0eSDag-Erling Smørgrav  out:
407*f7167e0eSDag-Erling Smørgrav 	free(ciphername);
408*f7167e0eSDag-Erling Smørgrav 	free(kdfname);
409*f7167e0eSDag-Erling Smørgrav 	free(salt);
410*f7167e0eSDag-Erling Smørgrav 	free(comment);
411*f7167e0eSDag-Erling Smørgrav 	if (key)
412*f7167e0eSDag-Erling Smørgrav 		memset(key, 0, keylen + ivlen);
413*f7167e0eSDag-Erling Smørgrav 	free(key);
414*f7167e0eSDag-Erling Smørgrav 	buffer_free(&encoded);
415*f7167e0eSDag-Erling Smørgrav 	buffer_free(&copy);
416*f7167e0eSDag-Erling Smørgrav 	buffer_free(&kdf);
417*f7167e0eSDag-Erling Smørgrav 	buffer_free(&b);
418*f7167e0eSDag-Erling Smørgrav 	return k;
419*f7167e0eSDag-Erling Smørgrav }
420*f7167e0eSDag-Erling Smørgrav 
421511b41d2SMark Murray /*
4224a421b63SDag-Erling Smørgrav  * Serialises the authentication (private) key to a blob, encrypting it with
4234a421b63SDag-Erling Smørgrav  * passphrase.  The identification of the blob (lowest 64 bits of n) will
424511b41d2SMark Murray  * precede the key to provide identification of the key without needing a
425511b41d2SMark Murray  * passphrase.
426511b41d2SMark Murray  */
427af12a3e7SDag-Erling Smørgrav static int
4284a421b63SDag-Erling Smørgrav key_private_rsa1_to_blob(Key *key, Buffer *blob, const char *passphrase,
429ca3176e7SBrian Feldman     const char *comment)
430511b41d2SMark Murray {
431511b41d2SMark Murray 	Buffer buffer, encrypted;
432af12a3e7SDag-Erling Smørgrav 	u_char buf[100], *cp;
4334a421b63SDag-Erling Smørgrav 	int i, cipher_num;
43409958426SBrian Feldman 	CipherContext ciphercontext;
435e4a9863fSDag-Erling Smørgrav 	const Cipher *cipher;
43621e764dfSDag-Erling Smørgrav 	u_int32_t rnd;
437511b41d2SMark Murray 
438511b41d2SMark Murray 	/*
439511b41d2SMark Murray 	 * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting
440511b41d2SMark Murray 	 * to another cipher; otherwise use SSH_AUTHFILE_CIPHER.
441511b41d2SMark Murray 	 */
442af12a3e7SDag-Erling Smørgrav 	cipher_num = (strcmp(passphrase, "") == 0) ?
443af12a3e7SDag-Erling Smørgrav 	    SSH_CIPHER_NONE : SSH_AUTHFILE_CIPHER;
444af12a3e7SDag-Erling Smørgrav 	if ((cipher = cipher_by_number(cipher_num)) == NULL)
44509958426SBrian Feldman 		fatal("save_private_key_rsa: bad cipher");
446511b41d2SMark Murray 
447511b41d2SMark Murray 	/* This buffer is used to built the secret part of the private key. */
448511b41d2SMark Murray 	buffer_init(&buffer);
449511b41d2SMark Murray 
450511b41d2SMark Murray 	/* Put checkbytes for checking passphrase validity. */
45121e764dfSDag-Erling Smørgrav 	rnd = arc4random();
45221e764dfSDag-Erling Smørgrav 	buf[0] = rnd & 0xff;
45321e764dfSDag-Erling Smørgrav 	buf[1] = (rnd >> 8) & 0xff;
454511b41d2SMark Murray 	buf[2] = buf[0];
455511b41d2SMark Murray 	buf[3] = buf[1];
456511b41d2SMark Murray 	buffer_append(&buffer, buf, 4);
457511b41d2SMark Murray 
458511b41d2SMark Murray 	/*
459511b41d2SMark Murray 	 * Store the private key (n and e will not be stored because they
460511b41d2SMark Murray 	 * will be stored in plain text, and storing them also in encrypted
461511b41d2SMark Murray 	 * format would just give known plaintext).
462511b41d2SMark Murray 	 */
463ca3176e7SBrian Feldman 	buffer_put_bignum(&buffer, key->rsa->d);
464ca3176e7SBrian Feldman 	buffer_put_bignum(&buffer, key->rsa->iqmp);
465ca3176e7SBrian Feldman 	buffer_put_bignum(&buffer, key->rsa->q);	/* reverse from SSL p */
466ca3176e7SBrian Feldman 	buffer_put_bignum(&buffer, key->rsa->p);	/* reverse from SSL q */
467511b41d2SMark Murray 
468511b41d2SMark Murray 	/* Pad the part to be encrypted until its size is a multiple of 8. */
469511b41d2SMark Murray 	while (buffer_len(&buffer) % 8 != 0)
470511b41d2SMark Murray 		buffer_put_char(&buffer, 0);
471511b41d2SMark Murray 
472511b41d2SMark Murray 	/* This buffer will be used to contain the data in the file. */
473511b41d2SMark Murray 	buffer_init(&encrypted);
474511b41d2SMark Murray 
475511b41d2SMark Murray 	/* First store keyfile id string. */
476ca3176e7SBrian Feldman 	for (i = 0; authfile_id_string[i]; i++)
477ca3176e7SBrian Feldman 		buffer_put_char(&encrypted, authfile_id_string[i]);
478511b41d2SMark Murray 	buffer_put_char(&encrypted, 0);
479511b41d2SMark Murray 
480511b41d2SMark Murray 	/* Store cipher type. */
481af12a3e7SDag-Erling Smørgrav 	buffer_put_char(&encrypted, cipher_num);
482511b41d2SMark Murray 	buffer_put_int(&encrypted, 0);	/* For future extension */
483511b41d2SMark Murray 
484511b41d2SMark Murray 	/* Store public key.  This will be in plain text. */
485ca3176e7SBrian Feldman 	buffer_put_int(&encrypted, BN_num_bits(key->rsa->n));
486ca3176e7SBrian Feldman 	buffer_put_bignum(&encrypted, key->rsa->n);
487ca3176e7SBrian Feldman 	buffer_put_bignum(&encrypted, key->rsa->e);
488af12a3e7SDag-Erling Smørgrav 	buffer_put_cstring(&encrypted, comment);
489511b41d2SMark Murray 
490511b41d2SMark Murray 	/* Allocate space for the private part of the key in the buffer. */
491af12a3e7SDag-Erling Smørgrav 	cp = buffer_append_space(&encrypted, buffer_len(&buffer));
492511b41d2SMark Murray 
493af12a3e7SDag-Erling Smørgrav 	cipher_set_key_string(&ciphercontext, cipher, passphrase,
494af12a3e7SDag-Erling Smørgrav 	    CIPHER_ENCRYPT);
495*f7167e0eSDag-Erling Smørgrav 	if (cipher_crypt(&ciphercontext, 0, cp,
496*f7167e0eSDag-Erling Smørgrav 	    buffer_ptr(&buffer), buffer_len(&buffer), 0, 0) != 0)
497*f7167e0eSDag-Erling Smørgrav 		fatal("%s: cipher_crypt failed", __func__);
498af12a3e7SDag-Erling Smørgrav 	cipher_cleanup(&ciphercontext);
49909958426SBrian Feldman 	memset(&ciphercontext, 0, sizeof(ciphercontext));
500511b41d2SMark Murray 
501511b41d2SMark Murray 	/* Destroy temporary data. */
502511b41d2SMark Murray 	memset(buf, 0, sizeof(buf));
503511b41d2SMark Murray 	buffer_free(&buffer);
504511b41d2SMark Murray 
5054a421b63SDag-Erling Smørgrav 	buffer_append(blob, buffer_ptr(&encrypted), buffer_len(&encrypted));
5061ec0d754SDag-Erling Smørgrav 	buffer_free(&encrypted);
5074a421b63SDag-Erling Smørgrav 
508511b41d2SMark Murray 	return 1;
509511b41d2SMark Murray }
510511b41d2SMark Murray 
5114a421b63SDag-Erling Smørgrav /* convert SSH v2 key in OpenSSL PEM format */
512af12a3e7SDag-Erling Smørgrav static int
5134a421b63SDag-Erling Smørgrav key_private_pem_to_blob(Key *key, Buffer *blob, const char *_passphrase,
514ca3176e7SBrian Feldman     const char *comment)
515e8aafc91SKris Kennaway {
516ca3176e7SBrian Feldman 	int success = 0;
5174a421b63SDag-Erling Smørgrav 	int blen, len = strlen(_passphrase);
518af12a3e7SDag-Erling Smørgrav 	u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL;
519b15c8340SDag-Erling Smørgrav #if (OPENSSL_VERSION_NUMBER < 0x00907000L)
520af12a3e7SDag-Erling Smørgrav 	const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL;
521b15c8340SDag-Erling Smørgrav #else
522b15c8340SDag-Erling Smørgrav 	const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL;
523b15c8340SDag-Erling Smørgrav #endif
5244a421b63SDag-Erling Smørgrav 	const u_char *bptr;
5254a421b63SDag-Erling Smørgrav 	BIO *bio;
526e8aafc91SKris Kennaway 
527e8aafc91SKris Kennaway 	if (len > 0 && len <= 4) {
528ca3176e7SBrian Feldman 		error("passphrase too short: have %d bytes, need > 4", len);
529e8aafc91SKris Kennaway 		return 0;
530e8aafc91SKris Kennaway 	}
5314a421b63SDag-Erling Smørgrav 	if ((bio = BIO_new(BIO_s_mem())) == NULL) {
5324a421b63SDag-Erling Smørgrav 		error("%s: BIO_new failed", __func__);
533e8aafc91SKris Kennaway 		return 0;
534e8aafc91SKris Kennaway 	}
535ca3176e7SBrian Feldman 	switch (key->type) {
536ca3176e7SBrian Feldman 	case KEY_DSA:
5374a421b63SDag-Erling Smørgrav 		success = PEM_write_bio_DSAPrivateKey(bio, key->dsa,
538ca3176e7SBrian Feldman 		    cipher, passphrase, len, NULL, NULL);
539ca3176e7SBrian Feldman 		break;
5404a421b63SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC
5414a421b63SDag-Erling Smørgrav 	case KEY_ECDSA:
5424a421b63SDag-Erling Smørgrav 		success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa,
5434a421b63SDag-Erling Smørgrav 		    cipher, passphrase, len, NULL, NULL);
5444a421b63SDag-Erling Smørgrav 		break;
5454a421b63SDag-Erling Smørgrav #endif
546ca3176e7SBrian Feldman 	case KEY_RSA:
5474a421b63SDag-Erling Smørgrav 		success = PEM_write_bio_RSAPrivateKey(bio, key->rsa,
548ca3176e7SBrian Feldman 		    cipher, passphrase, len, NULL, NULL);
549ca3176e7SBrian Feldman 		break;
550e8aafc91SKris Kennaway 	}
5514a421b63SDag-Erling Smørgrav 	if (success) {
5524a421b63SDag-Erling Smørgrav 		if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0)
5534a421b63SDag-Erling Smørgrav 			success = 0;
5544a421b63SDag-Erling Smørgrav 		else
5554a421b63SDag-Erling Smørgrav 			buffer_append(blob, bptr, blen);
5564a421b63SDag-Erling Smørgrav 	}
5574a421b63SDag-Erling Smørgrav 	BIO_free(bio);
558e8aafc91SKris Kennaway 	return success;
559e8aafc91SKris Kennaway }
560e8aafc91SKris Kennaway 
5614a421b63SDag-Erling Smørgrav /* Save a key blob to a file */
5624a421b63SDag-Erling Smørgrav static int
5634a421b63SDag-Erling Smørgrav key_save_private_blob(Buffer *keybuf, const char *filename)
5644a421b63SDag-Erling Smørgrav {
5654a421b63SDag-Erling Smørgrav 	int fd;
5664a421b63SDag-Erling Smørgrav 
5674a421b63SDag-Erling Smørgrav 	if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
5684a421b63SDag-Erling Smørgrav 		error("open %s failed: %s.", filename, strerror(errno));
5694a421b63SDag-Erling Smørgrav 		return 0;
5704a421b63SDag-Erling Smørgrav 	}
5714a421b63SDag-Erling Smørgrav 	if (atomicio(vwrite, fd, buffer_ptr(keybuf),
5724a421b63SDag-Erling Smørgrav 	    buffer_len(keybuf)) != buffer_len(keybuf)) {
5734a421b63SDag-Erling Smørgrav 		error("write to key file %s failed: %s", filename,
5744a421b63SDag-Erling Smørgrav 		    strerror(errno));
5754a421b63SDag-Erling Smørgrav 		close(fd);
5764a421b63SDag-Erling Smørgrav 		unlink(filename);
5774a421b63SDag-Erling Smørgrav 		return 0;
5784a421b63SDag-Erling Smørgrav 	}
5794a421b63SDag-Erling Smørgrav 	close(fd);
5804a421b63SDag-Erling Smørgrav 	return 1;
5814a421b63SDag-Erling Smørgrav }
5824a421b63SDag-Erling Smørgrav 
5834a421b63SDag-Erling Smørgrav /* Serialise "key" to buffer "blob" */
5844a421b63SDag-Erling Smørgrav static int
5854a421b63SDag-Erling Smørgrav key_private_to_blob(Key *key, Buffer *blob, const char *passphrase,
586*f7167e0eSDag-Erling Smørgrav     const char *comment, int force_new_format, const char *new_format_cipher,
587*f7167e0eSDag-Erling Smørgrav     int new_format_rounds)
5884a421b63SDag-Erling Smørgrav {
5894a421b63SDag-Erling Smørgrav 	switch (key->type) {
5904a421b63SDag-Erling Smørgrav 	case KEY_RSA1:
5914a421b63SDag-Erling Smørgrav 		return key_private_rsa1_to_blob(key, blob, passphrase, comment);
5924a421b63SDag-Erling Smørgrav 	case KEY_DSA:
5934a421b63SDag-Erling Smørgrav 	case KEY_ECDSA:
5944a421b63SDag-Erling Smørgrav 	case KEY_RSA:
595*f7167e0eSDag-Erling Smørgrav 		if (force_new_format) {
596*f7167e0eSDag-Erling Smørgrav 			return key_private_to_blob2(key, blob, passphrase,
597*f7167e0eSDag-Erling Smørgrav 			    comment, new_format_cipher, new_format_rounds);
598*f7167e0eSDag-Erling Smørgrav 		}
5994a421b63SDag-Erling Smørgrav 		return key_private_pem_to_blob(key, blob, passphrase, comment);
600*f7167e0eSDag-Erling Smørgrav 	case KEY_ED25519:
601*f7167e0eSDag-Erling Smørgrav 		return key_private_to_blob2(key, blob, passphrase,
602*f7167e0eSDag-Erling Smørgrav 		    comment, new_format_cipher, new_format_rounds);
6034a421b63SDag-Erling Smørgrav 	default:
6044a421b63SDag-Erling Smørgrav 		error("%s: cannot save key type %d", __func__, key->type);
6054a421b63SDag-Erling Smørgrav 		return 0;
6064a421b63SDag-Erling Smørgrav 	}
6074a421b63SDag-Erling Smørgrav }
6084a421b63SDag-Erling Smørgrav 
609e8aafc91SKris Kennaway int
610ca3176e7SBrian Feldman key_save_private(Key *key, const char *filename, const char *passphrase,
611*f7167e0eSDag-Erling Smørgrav     const char *comment, int force_new_format, const char *new_format_cipher,
612*f7167e0eSDag-Erling Smørgrav     int new_format_rounds)
613e8aafc91SKris Kennaway {
6144a421b63SDag-Erling Smørgrav 	Buffer keyblob;
6154a421b63SDag-Erling Smørgrav 	int success = 0;
6164a421b63SDag-Erling Smørgrav 
6174a421b63SDag-Erling Smørgrav 	buffer_init(&keyblob);
618*f7167e0eSDag-Erling Smørgrav 	if (!key_private_to_blob(key, &keyblob, passphrase, comment,
619*f7167e0eSDag-Erling Smørgrav 	    force_new_format, new_format_cipher, new_format_rounds))
6204a421b63SDag-Erling Smørgrav 		goto out;
6214a421b63SDag-Erling Smørgrav 	if (!key_save_private_blob(&keyblob, filename))
6224a421b63SDag-Erling Smørgrav 		goto out;
6234a421b63SDag-Erling Smørgrav 	success = 1;
6244a421b63SDag-Erling Smørgrav  out:
6254a421b63SDag-Erling Smørgrav 	buffer_free(&keyblob);
6264a421b63SDag-Erling Smørgrav 	return success;
627e8aafc91SKris Kennaway }
6284a421b63SDag-Erling Smørgrav 
6294a421b63SDag-Erling Smørgrav /*
6304a421b63SDag-Erling Smørgrav  * Parse the public, unencrypted portion of a RSA1 key.
6314a421b63SDag-Erling Smørgrav  */
6324a421b63SDag-Erling Smørgrav static Key *
6334a421b63SDag-Erling Smørgrav key_parse_public_rsa1(Buffer *blob, char **commentp)
6344a421b63SDag-Erling Smørgrav {
6354a421b63SDag-Erling Smørgrav 	Key *pub;
636e146993eSDag-Erling Smørgrav 	Buffer copy;
6374a421b63SDag-Erling Smørgrav 
6384a421b63SDag-Erling Smørgrav 	/* Check that it is at least big enough to contain the ID string. */
6394a421b63SDag-Erling Smørgrav 	if (buffer_len(blob) < sizeof(authfile_id_string)) {
6404a421b63SDag-Erling Smørgrav 		debug3("Truncated RSA1 identifier");
6414a421b63SDag-Erling Smørgrav 		return NULL;
6424a421b63SDag-Erling Smørgrav 	}
6434a421b63SDag-Erling Smørgrav 
6444a421b63SDag-Erling Smørgrav 	/*
6454a421b63SDag-Erling Smørgrav 	 * Make sure it begins with the id string.  Consume the id string
6464a421b63SDag-Erling Smørgrav 	 * from the buffer.
6474a421b63SDag-Erling Smørgrav 	 */
6484a421b63SDag-Erling Smørgrav 	if (memcmp(buffer_ptr(blob), authfile_id_string,
6494a421b63SDag-Erling Smørgrav 	    sizeof(authfile_id_string)) != 0) {
6504a421b63SDag-Erling Smørgrav 		debug3("Incorrect RSA1 identifier");
6514a421b63SDag-Erling Smørgrav 		return NULL;
6524a421b63SDag-Erling Smørgrav 	}
653e146993eSDag-Erling Smørgrav 	buffer_init(&copy);
654e146993eSDag-Erling Smørgrav 	buffer_append(&copy, buffer_ptr(blob), buffer_len(blob));
655e146993eSDag-Erling Smørgrav 	buffer_consume(&copy, sizeof(authfile_id_string));
6564a421b63SDag-Erling Smørgrav 
6574a421b63SDag-Erling Smørgrav 	/* Skip cipher type and reserved data. */
658e146993eSDag-Erling Smørgrav 	(void) buffer_get_char(&copy);		/* cipher type */
659e146993eSDag-Erling Smørgrav 	(void) buffer_get_int(&copy);		/* reserved */
6604a421b63SDag-Erling Smørgrav 
6614a421b63SDag-Erling Smørgrav 	/* Read the public key from the buffer. */
662e146993eSDag-Erling Smørgrav 	(void) buffer_get_int(&copy);
6634a421b63SDag-Erling Smørgrav 	pub = key_new(KEY_RSA1);
664e146993eSDag-Erling Smørgrav 	buffer_get_bignum(&copy, pub->rsa->n);
665e146993eSDag-Erling Smørgrav 	buffer_get_bignum(&copy, pub->rsa->e);
6664a421b63SDag-Erling Smørgrav 	if (commentp)
667e146993eSDag-Erling Smørgrav 		*commentp = buffer_get_string(&copy, NULL);
6684a421b63SDag-Erling Smørgrav 	/* The encrypted private part is not parsed by this function. */
669e146993eSDag-Erling Smørgrav 	buffer_free(&copy);
6704a421b63SDag-Erling Smørgrav 
6714a421b63SDag-Erling Smørgrav 	return pub;
6724a421b63SDag-Erling Smørgrav }
6734a421b63SDag-Erling Smørgrav 
674e146993eSDag-Erling Smørgrav /* Load a key from a fd into a buffer */
675e146993eSDag-Erling Smørgrav int
6764a421b63SDag-Erling Smørgrav key_load_file(int fd, const char *filename, Buffer *blob)
6774a421b63SDag-Erling Smørgrav {
678e146993eSDag-Erling Smørgrav 	u_char buf[1024];
6794a421b63SDag-Erling Smørgrav 	size_t len;
6804a421b63SDag-Erling Smørgrav 	struct stat st;
6814a421b63SDag-Erling Smørgrav 
6824a421b63SDag-Erling Smørgrav 	if (fstat(fd, &st) < 0) {
6834a421b63SDag-Erling Smørgrav 		error("%s: fstat of key file %.200s%sfailed: %.100s", __func__,
6844a421b63SDag-Erling Smørgrav 		    filename == NULL ? "" : filename,
6854a421b63SDag-Erling Smørgrav 		    filename == NULL ? "" : " ",
6864a421b63SDag-Erling Smørgrav 		    strerror(errno));
687e8aafc91SKris Kennaway 		return 0;
688e8aafc91SKris Kennaway 	}
689e146993eSDag-Erling Smørgrav 	if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
690e146993eSDag-Erling Smørgrav 	    st.st_size > MAX_KEY_FILE_SIZE) {
691e146993eSDag-Erling Smørgrav  toobig:
6924a421b63SDag-Erling Smørgrav 		error("%s: key file %.200s%stoo large", __func__,
6934a421b63SDag-Erling Smørgrav 		    filename == NULL ? "" : filename,
6944a421b63SDag-Erling Smørgrav 		    filename == NULL ? "" : " ");
6954a421b63SDag-Erling Smørgrav 		return 0;
6964a421b63SDag-Erling Smørgrav 	}
697462c32cbSDag-Erling Smørgrav 	buffer_clear(blob);
698e146993eSDag-Erling Smørgrav 	for (;;) {
699e146993eSDag-Erling Smørgrav 		if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) {
700e146993eSDag-Erling Smørgrav 			if (errno == EPIPE)
701e146993eSDag-Erling Smørgrav 				break;
702e146993eSDag-Erling Smørgrav 			debug("%s: read from key file %.200s%sfailed: %.100s",
703e146993eSDag-Erling Smørgrav 			    __func__, filename == NULL ? "" : filename,
704e146993eSDag-Erling Smørgrav 			    filename == NULL ? "" : " ", strerror(errno));
7054a421b63SDag-Erling Smørgrav 			buffer_clear(blob);
706e146993eSDag-Erling Smørgrav 			bzero(buf, sizeof(buf));
7074a421b63SDag-Erling Smørgrav 			return 0;
7084a421b63SDag-Erling Smørgrav 		}
709e146993eSDag-Erling Smørgrav 		buffer_append(blob, buf, len);
710e146993eSDag-Erling Smørgrav 		if (buffer_len(blob) > MAX_KEY_FILE_SIZE) {
711e146993eSDag-Erling Smørgrav 			buffer_clear(blob);
712e146993eSDag-Erling Smørgrav 			bzero(buf, sizeof(buf));
713e146993eSDag-Erling Smørgrav 			goto toobig;
714e146993eSDag-Erling Smørgrav 		}
715e146993eSDag-Erling Smørgrav 	}
716e146993eSDag-Erling Smørgrav 	bzero(buf, sizeof(buf));
717e146993eSDag-Erling Smørgrav 	if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
718e146993eSDag-Erling Smørgrav 	    st.st_size != buffer_len(blob)) {
719e146993eSDag-Erling Smørgrav 		debug("%s: key file %.200s%schanged size while reading",
720e146993eSDag-Erling Smørgrav 		    __func__, filename == NULL ? "" : filename,
721e146993eSDag-Erling Smørgrav 		    filename == NULL ? "" : " ");
722e146993eSDag-Erling Smørgrav 		buffer_clear(blob);
723e146993eSDag-Erling Smørgrav 		return 0;
724e146993eSDag-Erling Smørgrav 	}
725e146993eSDag-Erling Smørgrav 
7264a421b63SDag-Erling Smørgrav 	return 1;
7274a421b63SDag-Erling Smørgrav }
728e8aafc91SKris Kennaway 
729511b41d2SMark Murray /*
730ca3176e7SBrian Feldman  * Loads the public part of the ssh v1 key file.  Returns NULL if an error was
731ca3176e7SBrian Feldman  * encountered (the file does not exist or is not readable), and the key
732511b41d2SMark Murray  * otherwise.
733511b41d2SMark Murray  */
734af12a3e7SDag-Erling Smørgrav static Key *
735ca3176e7SBrian Feldman key_load_public_rsa1(int fd, const char *filename, char **commentp)
736511b41d2SMark Murray {
737511b41d2SMark Murray 	Buffer buffer;
738ca3176e7SBrian Feldman 	Key *pub;
739511b41d2SMark Murray 
740511b41d2SMark Murray 	buffer_init(&buffer);
7414a421b63SDag-Erling Smørgrav 	if (!key_load_file(fd, filename, &buffer)) {
742511b41d2SMark Murray 		buffer_free(&buffer);
743ca3176e7SBrian Feldman 		return NULL;
744511b41d2SMark Murray 	}
745511b41d2SMark Murray 
7464a421b63SDag-Erling Smørgrav 	pub = key_parse_public_rsa1(&buffer, commentp);
7474a421b63SDag-Erling Smørgrav 	if (pub == NULL)
7484a421b63SDag-Erling Smørgrav 		debug3("Could not load \"%s\" as a RSA1 public key", filename);
749511b41d2SMark Murray 	buffer_free(&buffer);
750ca3176e7SBrian Feldman 	return pub;
751511b41d2SMark Murray }
752511b41d2SMark Murray 
753ca3176e7SBrian Feldman /* load public key from private-key file, works only for SSH v1 */
754ca3176e7SBrian Feldman Key *
755ca3176e7SBrian Feldman key_load_public_type(int type, const char *filename, char **commentp)
756e8aafc91SKris Kennaway {
757ca3176e7SBrian Feldman 	Key *pub;
758ca3176e7SBrian Feldman 	int fd;
759ca3176e7SBrian Feldman 
760ca3176e7SBrian Feldman 	if (type == KEY_RSA1) {
761ca3176e7SBrian Feldman 		fd = open(filename, O_RDONLY);
762ca3176e7SBrian Feldman 		if (fd < 0)
763ca3176e7SBrian Feldman 			return NULL;
764ca3176e7SBrian Feldman 		pub = key_load_public_rsa1(fd, filename, commentp);
765ca3176e7SBrian Feldman 		close(fd);
766ca3176e7SBrian Feldman 		return pub;
767e8aafc91SKris Kennaway 	}
768ca3176e7SBrian Feldman 	return NULL;
769e8aafc91SKris Kennaway }
770e8aafc91SKris Kennaway 
771af12a3e7SDag-Erling Smørgrav static Key *
7724a421b63SDag-Erling Smørgrav key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp)
773511b41d2SMark Murray {
774d4ecd108SDag-Erling Smørgrav 	int check1, check2, cipher_type;
7754a421b63SDag-Erling Smørgrav 	Buffer decrypted;
776af12a3e7SDag-Erling Smørgrav 	u_char *cp;
77709958426SBrian Feldman 	CipherContext ciphercontext;
778e4a9863fSDag-Erling Smørgrav 	const Cipher *cipher;
779ca3176e7SBrian Feldman 	Key *prv = NULL;
780e146993eSDag-Erling Smørgrav 	Buffer copy;
781511b41d2SMark Murray 
782ca3176e7SBrian Feldman 	/* Check that it is at least big enough to contain the ID string. */
7834a421b63SDag-Erling Smørgrav 	if (buffer_len(blob) < sizeof(authfile_id_string)) {
7844a421b63SDag-Erling Smørgrav 		debug3("Truncated RSA1 identifier");
785ca3176e7SBrian Feldman 		return NULL;
786511b41d2SMark Murray 	}
7874a421b63SDag-Erling Smørgrav 
788511b41d2SMark Murray 	/*
789511b41d2SMark Murray 	 * Make sure it begins with the id string.  Consume the id string
790511b41d2SMark Murray 	 * from the buffer.
791511b41d2SMark Murray 	 */
7924a421b63SDag-Erling Smørgrav 	if (memcmp(buffer_ptr(blob), authfile_id_string,
7934a421b63SDag-Erling Smørgrav 	    sizeof(authfile_id_string)) != 0) {
7944a421b63SDag-Erling Smørgrav 		debug3("Incorrect RSA1 identifier");
795ca3176e7SBrian Feldman 		return NULL;
796511b41d2SMark Murray 	}
797e146993eSDag-Erling Smørgrav 	buffer_init(&copy);
798e146993eSDag-Erling Smørgrav 	buffer_append(&copy, buffer_ptr(blob), buffer_len(blob));
799e146993eSDag-Erling Smørgrav 	buffer_consume(&copy, sizeof(authfile_id_string));
800ca3176e7SBrian Feldman 
801511b41d2SMark Murray 	/* Read cipher type. */
802e146993eSDag-Erling Smørgrav 	cipher_type = buffer_get_char(&copy);
803e146993eSDag-Erling Smørgrav 	(void) buffer_get_int(&copy);	/* Reserved data. */
804511b41d2SMark Murray 
805511b41d2SMark Murray 	/* Read the public key from the buffer. */
806e146993eSDag-Erling Smørgrav 	(void) buffer_get_int(&copy);
807ca3176e7SBrian Feldman 	prv = key_new_private(KEY_RSA1);
808ca3176e7SBrian Feldman 
809e146993eSDag-Erling Smørgrav 	buffer_get_bignum(&copy, prv->rsa->n);
810e146993eSDag-Erling Smørgrav 	buffer_get_bignum(&copy, prv->rsa->e);
811ca3176e7SBrian Feldman 	if (commentp)
812e146993eSDag-Erling Smørgrav 		*commentp = buffer_get_string(&copy, NULL);
813511b41d2SMark Murray 	else
814e146993eSDag-Erling Smørgrav 		(void)buffer_get_string_ptr(&copy, NULL);
815511b41d2SMark Murray 
816511b41d2SMark Murray 	/* Check that it is a supported cipher. */
81709958426SBrian Feldman 	cipher = cipher_by_number(cipher_type);
81809958426SBrian Feldman 	if (cipher == NULL) {
8194a421b63SDag-Erling Smørgrav 		debug("Unsupported RSA1 cipher %d", cipher_type);
820e146993eSDag-Erling Smørgrav 		buffer_free(&copy);
821511b41d2SMark Murray 		goto fail;
822511b41d2SMark Murray 	}
823511b41d2SMark Murray 	/* Initialize space for decrypted data. */
824511b41d2SMark Murray 	buffer_init(&decrypted);
825e146993eSDag-Erling Smørgrav 	cp = buffer_append_space(&decrypted, buffer_len(&copy));
826511b41d2SMark Murray 
827511b41d2SMark Murray 	/* Rest of the buffer is encrypted.  Decrypt it using the passphrase. */
828af12a3e7SDag-Erling Smørgrav 	cipher_set_key_string(&ciphercontext, cipher, passphrase,
829af12a3e7SDag-Erling Smørgrav 	    CIPHER_DECRYPT);
830*f7167e0eSDag-Erling Smørgrav 	if (cipher_crypt(&ciphercontext, 0, cp,
831*f7167e0eSDag-Erling Smørgrav 	    buffer_ptr(&copy), buffer_len(&copy), 0, 0) != 0)
832*f7167e0eSDag-Erling Smørgrav 		fatal("%s: cipher_crypt failed", __func__);
833af12a3e7SDag-Erling Smørgrav 	cipher_cleanup(&ciphercontext);
83409958426SBrian Feldman 	memset(&ciphercontext, 0, sizeof(ciphercontext));
835e146993eSDag-Erling Smørgrav 	buffer_free(&copy);
836511b41d2SMark Murray 
837511b41d2SMark Murray 	check1 = buffer_get_char(&decrypted);
838511b41d2SMark Murray 	check2 = buffer_get_char(&decrypted);
839511b41d2SMark Murray 	if (check1 != buffer_get_char(&decrypted) ||
840511b41d2SMark Murray 	    check2 != buffer_get_char(&decrypted)) {
841511b41d2SMark Murray 		if (strcmp(passphrase, "") != 0)
8424a421b63SDag-Erling Smørgrav 			debug("Bad passphrase supplied for RSA1 key");
843511b41d2SMark Murray 		/* Bad passphrase. */
844511b41d2SMark Murray 		buffer_free(&decrypted);
845ca3176e7SBrian Feldman 		goto fail;
846511b41d2SMark Murray 	}
847511b41d2SMark Murray 	/* Read the rest of the private key. */
848ca3176e7SBrian Feldman 	buffer_get_bignum(&decrypted, prv->rsa->d);
849ca3176e7SBrian Feldman 	buffer_get_bignum(&decrypted, prv->rsa->iqmp);		/* u */
850ca3176e7SBrian Feldman 	/* in SSL and SSH v1 p and q are exchanged */
851ca3176e7SBrian Feldman 	buffer_get_bignum(&decrypted, prv->rsa->q);		/* p */
852ca3176e7SBrian Feldman 	buffer_get_bignum(&decrypted, prv->rsa->p);		/* q */
853511b41d2SMark Murray 
854ca3176e7SBrian Feldman 	/* calculate p-1 and q-1 */
855af12a3e7SDag-Erling Smørgrav 	rsa_generate_additional_parameters(prv->rsa);
856511b41d2SMark Murray 
857511b41d2SMark Murray 	buffer_free(&decrypted);
858e73e9afaSDag-Erling Smørgrav 
859e73e9afaSDag-Erling Smørgrav 	/* enable blinding */
860e73e9afaSDag-Erling Smørgrav 	if (RSA_blinding_on(prv->rsa, NULL) != 1) {
8614a421b63SDag-Erling Smørgrav 		error("%s: RSA_blinding_on failed", __func__);
862e73e9afaSDag-Erling Smørgrav 		goto fail;
863e73e9afaSDag-Erling Smørgrav 	}
864ca3176e7SBrian Feldman 	return prv;
865511b41d2SMark Murray 
866ca3176e7SBrian Feldman fail:
867e4a9863fSDag-Erling Smørgrav 	if (commentp != NULL)
868e4a9863fSDag-Erling Smørgrav 		free(*commentp);
869ca3176e7SBrian Feldman 	key_free(prv);
870ca3176e7SBrian Feldman 	return NULL;
871511b41d2SMark Murray }
872e8aafc91SKris Kennaway 
8734a421b63SDag-Erling Smørgrav static Key *
8744a421b63SDag-Erling Smørgrav key_parse_private_pem(Buffer *blob, int type, const char *passphrase,
875ca3176e7SBrian Feldman     char **commentp)
876e8aafc91SKris Kennaway {
877ca3176e7SBrian Feldman 	EVP_PKEY *pk = NULL;
878ca3176e7SBrian Feldman 	Key *prv = NULL;
879ca3176e7SBrian Feldman 	char *name = "<no key>";
8804a421b63SDag-Erling Smørgrav 	BIO *bio;
881e8aafc91SKris Kennaway 
8824a421b63SDag-Erling Smørgrav 	if ((bio = BIO_new_mem_buf(buffer_ptr(blob),
8834a421b63SDag-Erling Smørgrav 	    buffer_len(blob))) == NULL) {
8844a421b63SDag-Erling Smørgrav 		error("%s: BIO_new_mem_buf failed", __func__);
885ca3176e7SBrian Feldman 		return NULL;
886e8aafc91SKris Kennaway 	}
8874a421b63SDag-Erling Smørgrav 
8884a421b63SDag-Erling Smørgrav 	pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, (char *)passphrase);
8894a421b63SDag-Erling Smørgrav 	BIO_free(bio);
890ca3176e7SBrian Feldman 	if (pk == NULL) {
8914a421b63SDag-Erling Smørgrav 		debug("%s: PEM_read_PrivateKey failed", __func__);
892ca3176e7SBrian Feldman 		(void)ERR_get_error();
893ca3176e7SBrian Feldman 	} else if (pk->type == EVP_PKEY_RSA &&
894ca3176e7SBrian Feldman 	    (type == KEY_UNSPEC||type==KEY_RSA)) {
895ca3176e7SBrian Feldman 		prv = key_new(KEY_UNSPEC);
896ca3176e7SBrian Feldman 		prv->rsa = EVP_PKEY_get1_RSA(pk);
897ca3176e7SBrian Feldman 		prv->type = KEY_RSA;
898ca3176e7SBrian Feldman 		name = "rsa w/o comment";
899ca3176e7SBrian Feldman #ifdef DEBUG_PK
900ca3176e7SBrian Feldman 		RSA_print_fp(stderr, prv->rsa, 8);
901e8aafc91SKris Kennaway #endif
902e73e9afaSDag-Erling Smørgrav 		if (RSA_blinding_on(prv->rsa, NULL) != 1) {
9034a421b63SDag-Erling Smørgrav 			error("%s: RSA_blinding_on failed", __func__);
904e73e9afaSDag-Erling Smørgrav 			key_free(prv);
905e73e9afaSDag-Erling Smørgrav 			prv = NULL;
906e73e9afaSDag-Erling Smørgrav 		}
907ca3176e7SBrian Feldman 	} else if (pk->type == EVP_PKEY_DSA &&
908ca3176e7SBrian Feldman 	    (type == KEY_UNSPEC||type==KEY_DSA)) {
909ca3176e7SBrian Feldman 		prv = key_new(KEY_UNSPEC);
910ca3176e7SBrian Feldman 		prv->dsa = EVP_PKEY_get1_DSA(pk);
911ca3176e7SBrian Feldman 		prv->type = KEY_DSA;
912ca3176e7SBrian Feldman 		name = "dsa w/o comment";
913ca3176e7SBrian Feldman #ifdef DEBUG_PK
914ca3176e7SBrian Feldman 		DSA_print_fp(stderr, prv->dsa, 8);
915ca3176e7SBrian Feldman #endif
9164a421b63SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC
9174a421b63SDag-Erling Smørgrav 	} else if (pk->type == EVP_PKEY_EC &&
9184a421b63SDag-Erling Smørgrav 	    (type == KEY_UNSPEC||type==KEY_ECDSA)) {
9194a421b63SDag-Erling Smørgrav 		prv = key_new(KEY_UNSPEC);
9204a421b63SDag-Erling Smørgrav 		prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk);
9214a421b63SDag-Erling Smørgrav 		prv->type = KEY_ECDSA;
9224a421b63SDag-Erling Smørgrav 		if ((prv->ecdsa_nid = key_ecdsa_key_to_nid(prv->ecdsa)) == -1 ||
9234a421b63SDag-Erling Smørgrav 		    key_curve_nid_to_name(prv->ecdsa_nid) == NULL ||
9244a421b63SDag-Erling Smørgrav 		    key_ec_validate_public(EC_KEY_get0_group(prv->ecdsa),
9254a421b63SDag-Erling Smørgrav 		    EC_KEY_get0_public_key(prv->ecdsa)) != 0 ||
9264a421b63SDag-Erling Smørgrav 		    key_ec_validate_private(prv->ecdsa) != 0) {
9274a421b63SDag-Erling Smørgrav 			error("%s: bad ECDSA key", __func__);
9284a421b63SDag-Erling Smørgrav 			key_free(prv);
9294a421b63SDag-Erling Smørgrav 			prv = NULL;
930ca3176e7SBrian Feldman 		}
9314a421b63SDag-Erling Smørgrav 		name = "ecdsa w/o comment";
9324a421b63SDag-Erling Smørgrav #ifdef DEBUG_PK
9334a421b63SDag-Erling Smørgrav 		if (prv != NULL && prv->ecdsa != NULL)
9344a421b63SDag-Erling Smørgrav 			key_dump_ec_key(prv->ecdsa);
9354a421b63SDag-Erling Smørgrav #endif
9364a421b63SDag-Erling Smørgrav #endif /* OPENSSL_HAS_ECC */
9374a421b63SDag-Erling Smørgrav 	} else {
9384a421b63SDag-Erling Smørgrav 		error("%s: PEM_read_PrivateKey: mismatch or "
9394a421b63SDag-Erling Smørgrav 		    "unknown EVP_PKEY save_type %d", __func__, pk->save_type);
9404a421b63SDag-Erling Smørgrav 	}
941ca3176e7SBrian Feldman 	if (pk != NULL)
942ca3176e7SBrian Feldman 		EVP_PKEY_free(pk);
943ca3176e7SBrian Feldman 	if (prv != NULL && commentp)
944ca3176e7SBrian Feldman 		*commentp = xstrdup(name);
945ca3176e7SBrian Feldman 	debug("read PEM private key done: type %s",
946ca3176e7SBrian Feldman 	    prv ? key_type(prv) : "<unknown>");
947ca3176e7SBrian Feldman 	return prv;
948e8aafc91SKris Kennaway }
949e8aafc91SKris Kennaway 
9504a421b63SDag-Erling Smørgrav Key *
9514a421b63SDag-Erling Smørgrav key_load_private_pem(int fd, int type, const char *passphrase,
9524a421b63SDag-Erling Smørgrav     char **commentp)
9534a421b63SDag-Erling Smørgrav {
9544a421b63SDag-Erling Smørgrav 	Buffer buffer;
9554a421b63SDag-Erling Smørgrav 	Key *prv;
9564a421b63SDag-Erling Smørgrav 
9574a421b63SDag-Erling Smørgrav 	buffer_init(&buffer);
9584a421b63SDag-Erling Smørgrav 	if (!key_load_file(fd, NULL, &buffer)) {
9594a421b63SDag-Erling Smørgrav 		buffer_free(&buffer);
9604a421b63SDag-Erling Smørgrav 		return NULL;
9614a421b63SDag-Erling Smørgrav 	}
9624a421b63SDag-Erling Smørgrav 	prv = key_parse_private_pem(&buffer, type, passphrase, commentp);
9634a421b63SDag-Erling Smørgrav 	buffer_free(&buffer);
9644a421b63SDag-Erling Smørgrav 	return prv;
9654a421b63SDag-Erling Smørgrav }
9664a421b63SDag-Erling Smørgrav 
967333ee039SDag-Erling Smørgrav int
968ca3176e7SBrian Feldman key_perm_ok(int fd, const char *filename)
969e8aafc91SKris Kennaway {
970e8aafc91SKris Kennaway 	struct stat st;
971e8aafc91SKris Kennaway 
972af12a3e7SDag-Erling Smørgrav 	if (fstat(fd, &st) < 0)
973af12a3e7SDag-Erling Smørgrav 		return 0;
974af12a3e7SDag-Erling Smørgrav 	/*
975af12a3e7SDag-Erling Smørgrav 	 * if a key owned by the user is accessed, then we check the
976af12a3e7SDag-Erling Smørgrav 	 * permissions of the file. if the key owned by a different user,
977af12a3e7SDag-Erling Smørgrav 	 * then we don't care.
978af12a3e7SDag-Erling Smørgrav 	 */
979989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN
980989dd127SDag-Erling Smørgrav 	if (check_ntsec(filename))
981989dd127SDag-Erling Smørgrav #endif
982af12a3e7SDag-Erling Smørgrav 	if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
983e8aafc91SKris Kennaway 		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
984e8aafc91SKris Kennaway 		error("@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @");
985e8aafc91SKris Kennaway 		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
986af12a3e7SDag-Erling Smørgrav 		error("Permissions 0%3.3o for '%s' are too open.",
987cf2b5f3bSDag-Erling Smørgrav 		    (u_int)st.st_mode & 0777, filename);
988e146993eSDag-Erling Smørgrav 		error("It is required that your private key files are NOT accessible by others.");
989ca3176e7SBrian Feldman 		error("This private key will be ignored.");
990e8aafc91SKris Kennaway 		return 0;
991e8aafc91SKris Kennaway 	}
992ca3176e7SBrian Feldman 	return 1;
993e8aafc91SKris Kennaway }
994ca3176e7SBrian Feldman 
9954a421b63SDag-Erling Smørgrav static Key *
9964a421b63SDag-Erling Smørgrav key_parse_private_type(Buffer *blob, int type, const char *passphrase,
9974a421b63SDag-Erling Smørgrav     char **commentp)
9984a421b63SDag-Erling Smørgrav {
999*f7167e0eSDag-Erling Smørgrav 	Key *k;
1000*f7167e0eSDag-Erling Smørgrav 
10014a421b63SDag-Erling Smørgrav 	switch (type) {
10024a421b63SDag-Erling Smørgrav 	case KEY_RSA1:
10034a421b63SDag-Erling Smørgrav 		return key_parse_private_rsa1(blob, passphrase, commentp);
10044a421b63SDag-Erling Smørgrav 	case KEY_DSA:
10054a421b63SDag-Erling Smørgrav 	case KEY_ECDSA:
10064a421b63SDag-Erling Smørgrav 	case KEY_RSA:
1007*f7167e0eSDag-Erling Smørgrav 		return key_parse_private_pem(blob, type, passphrase, commentp);
1008*f7167e0eSDag-Erling Smørgrav 	case KEY_ED25519:
1009*f7167e0eSDag-Erling Smørgrav 		return key_parse_private2(blob, type, passphrase, commentp);
10104a421b63SDag-Erling Smørgrav 	case KEY_UNSPEC:
1011*f7167e0eSDag-Erling Smørgrav 		if ((k = key_parse_private2(blob, type, passphrase, commentp)))
1012*f7167e0eSDag-Erling Smørgrav 			return k;
10134a421b63SDag-Erling Smørgrav 		return key_parse_private_pem(blob, type, passphrase, commentp);
10144a421b63SDag-Erling Smørgrav 	default:
1015e146993eSDag-Erling Smørgrav 		error("%s: cannot parse key type %d", __func__, type);
10164a421b63SDag-Erling Smørgrav 		break;
10174a421b63SDag-Erling Smørgrav 	}
10184a421b63SDag-Erling Smørgrav 	return NULL;
10194a421b63SDag-Erling Smørgrav }
10204a421b63SDag-Erling Smørgrav 
1021ca3176e7SBrian Feldman Key *
1022ca3176e7SBrian Feldman key_load_private_type(int type, const char *filename, const char *passphrase,
1023333ee039SDag-Erling Smørgrav     char **commentp, int *perm_ok)
1024ca3176e7SBrian Feldman {
1025ca3176e7SBrian Feldman 	int fd;
10264a421b63SDag-Erling Smørgrav 	Key *ret;
10274a421b63SDag-Erling Smørgrav 	Buffer buffer;
1028ca3176e7SBrian Feldman 
1029ca3176e7SBrian Feldman 	fd = open(filename, O_RDONLY);
1030b15c8340SDag-Erling Smørgrav 	if (fd < 0) {
1031b15c8340SDag-Erling Smørgrav 		debug("could not open key file '%s': %s", filename,
1032b15c8340SDag-Erling Smørgrav 		    strerror(errno));
1033b15c8340SDag-Erling Smørgrav 		if (perm_ok != NULL)
1034b15c8340SDag-Erling Smørgrav 			*perm_ok = 0;
1035ca3176e7SBrian Feldman 		return NULL;
1036b15c8340SDag-Erling Smørgrav 	}
1037ca3176e7SBrian Feldman 	if (!key_perm_ok(fd, filename)) {
1038333ee039SDag-Erling Smørgrav 		if (perm_ok != NULL)
1039333ee039SDag-Erling Smørgrav 			*perm_ok = 0;
1040ca3176e7SBrian Feldman 		error("bad permissions: ignore key: %s", filename);
1041ca3176e7SBrian Feldman 		close(fd);
1042ca3176e7SBrian Feldman 		return NULL;
1043e8aafc91SKris Kennaway 	}
1044333ee039SDag-Erling Smørgrav 	if (perm_ok != NULL)
1045333ee039SDag-Erling Smørgrav 		*perm_ok = 1;
10464a421b63SDag-Erling Smørgrav 
10474a421b63SDag-Erling Smørgrav 	buffer_init(&buffer);
10484a421b63SDag-Erling Smørgrav 	if (!key_load_file(fd, filename, &buffer)) {
10494a421b63SDag-Erling Smørgrav 		buffer_free(&buffer);
1050ca3176e7SBrian Feldman 		close(fd);
1051ca3176e7SBrian Feldman 		return NULL;
1052ca3176e7SBrian Feldman 	}
10534a421b63SDag-Erling Smørgrav 	close(fd);
10544a421b63SDag-Erling Smørgrav 	ret = key_parse_private_type(&buffer, type, passphrase, commentp);
10554a421b63SDag-Erling Smørgrav 	buffer_free(&buffer);
10564a421b63SDag-Erling Smørgrav 	return ret;
10574a421b63SDag-Erling Smørgrav }
1058ca3176e7SBrian Feldman 
1059ca3176e7SBrian Feldman Key *
1060e146993eSDag-Erling Smørgrav key_parse_private(Buffer *buffer, const char *filename,
1061e146993eSDag-Erling Smørgrav     const char *passphrase, char **commentp)
1062e146993eSDag-Erling Smørgrav {
1063e146993eSDag-Erling Smørgrav 	Key *pub, *prv;
1064e146993eSDag-Erling Smørgrav 
1065e146993eSDag-Erling Smørgrav 	/* it's a SSH v1 key if the public key part is readable */
1066e146993eSDag-Erling Smørgrav 	pub = key_parse_public_rsa1(buffer, commentp);
1067e146993eSDag-Erling Smørgrav 	if (pub == NULL) {
1068e146993eSDag-Erling Smørgrav 		prv = key_parse_private_type(buffer, KEY_UNSPEC,
1069e146993eSDag-Erling Smørgrav 		    passphrase, NULL);
1070e146993eSDag-Erling Smørgrav 		/* use the filename as a comment for PEM */
1071e146993eSDag-Erling Smørgrav 		if (commentp && prv)
1072e146993eSDag-Erling Smørgrav 			*commentp = xstrdup(filename);
1073e146993eSDag-Erling Smørgrav 	} else {
1074e146993eSDag-Erling Smørgrav 		key_free(pub);
1075e146993eSDag-Erling Smørgrav 		/* key_parse_public_rsa1() has already loaded the comment */
1076e146993eSDag-Erling Smørgrav 		prv = key_parse_private_type(buffer, KEY_RSA1, passphrase,
1077e146993eSDag-Erling Smørgrav 		    NULL);
1078e146993eSDag-Erling Smørgrav 	}
1079e146993eSDag-Erling Smørgrav 	return prv;
1080e146993eSDag-Erling Smørgrav }
1081e146993eSDag-Erling Smørgrav 
1082e146993eSDag-Erling Smørgrav Key *
1083ca3176e7SBrian Feldman key_load_private(const char *filename, const char *passphrase,
1084ca3176e7SBrian Feldman     char **commentp)
1085ca3176e7SBrian Feldman {
1086e146993eSDag-Erling Smørgrav 	Key *prv;
1087e146993eSDag-Erling Smørgrav 	Buffer buffer;
1088ca3176e7SBrian Feldman 	int fd;
1089ca3176e7SBrian Feldman 
1090ca3176e7SBrian Feldman 	fd = open(filename, O_RDONLY);
1091b15c8340SDag-Erling Smørgrav 	if (fd < 0) {
1092b15c8340SDag-Erling Smørgrav 		debug("could not open key file '%s': %s", filename,
1093b15c8340SDag-Erling Smørgrav 		    strerror(errno));
1094ca3176e7SBrian Feldman 		return NULL;
1095b15c8340SDag-Erling Smørgrav 	}
1096ca3176e7SBrian Feldman 	if (!key_perm_ok(fd, filename)) {
1097ca3176e7SBrian Feldman 		error("bad permissions: ignore key: %s", filename);
1098e8aafc91SKris Kennaway 		close(fd);
1099ca3176e7SBrian Feldman 		return NULL;
1100ca3176e7SBrian Feldman 	}
11014a421b63SDag-Erling Smørgrav 
11024a421b63SDag-Erling Smørgrav 	buffer_init(&buffer);
11034a421b63SDag-Erling Smørgrav 	if (!key_load_file(fd, filename, &buffer)) {
11044a421b63SDag-Erling Smørgrav 		buffer_free(&buffer);
11054a421b63SDag-Erling Smørgrav 		close(fd);
11064a421b63SDag-Erling Smørgrav 		return NULL;
11074a421b63SDag-Erling Smørgrav 	}
11084a421b63SDag-Erling Smørgrav 	close(fd);
11094a421b63SDag-Erling Smørgrav 
1110e146993eSDag-Erling Smørgrav 	prv = key_parse_private(&buffer, filename, passphrase, commentp);
11114a421b63SDag-Erling Smørgrav 	buffer_free(&buffer);
1112af12a3e7SDag-Erling Smørgrav 	return prv;
1113e8aafc91SKris Kennaway }
1114c2d3a559SKris Kennaway 
1115af12a3e7SDag-Erling Smørgrav static int
1116ca3176e7SBrian Feldman key_try_load_public(Key *k, const char *filename, char **commentp)
1117c2d3a559SKris Kennaway {
1118c2d3a559SKris Kennaway 	FILE *f;
1119aa49c926SDag-Erling Smørgrav 	char line[SSH_MAX_PUBKEY_BYTES];
1120c2d3a559SKris Kennaway 	char *cp;
1121aa49c926SDag-Erling Smørgrav 	u_long linenum = 0;
1122c2d3a559SKris Kennaway 
1123c2d3a559SKris Kennaway 	f = fopen(filename, "r");
1124c2d3a559SKris Kennaway 	if (f != NULL) {
1125aa49c926SDag-Erling Smørgrav 		while (read_keyfile_line(f, filename, line, sizeof(line),
1126aa49c926SDag-Erling Smørgrav 			    &linenum) != -1) {
1127c2d3a559SKris Kennaway 			cp = line;
1128c2d3a559SKris Kennaway 			switch (*cp) {
1129c2d3a559SKris Kennaway 			case '#':
1130c2d3a559SKris Kennaway 			case '\n':
1131c2d3a559SKris Kennaway 			case '\0':
1132c2d3a559SKris Kennaway 				continue;
1133c2d3a559SKris Kennaway 			}
1134e146993eSDag-Erling Smørgrav 			/* Abort loading if this looks like a private key */
1135e146993eSDag-Erling Smørgrav 			if (strncmp(cp, "-----BEGIN", 10) == 0)
1136e146993eSDag-Erling Smørgrav 				break;
1137c2d3a559SKris Kennaway 			/* Skip leading whitespace. */
1138c2d3a559SKris Kennaway 			for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
1139c2d3a559SKris Kennaway 				;
1140c2d3a559SKris Kennaway 			if (*cp) {
1141ca3176e7SBrian Feldman 				if (key_read(k, &cp) == 1) {
1142e146993eSDag-Erling Smørgrav 					cp[strcspn(cp, "\r\n")] = '\0';
1143e146993eSDag-Erling Smørgrav 					if (commentp) {
1144e146993eSDag-Erling Smørgrav 						*commentp = xstrdup(*cp ?
1145e146993eSDag-Erling Smørgrav 						    cp : filename);
1146e146993eSDag-Erling Smørgrav 					}
1147c2d3a559SKris Kennaway 					fclose(f);
1148c2d3a559SKris Kennaway 					return 1;
1149c2d3a559SKris Kennaway 				}
1150c2d3a559SKris Kennaway 			}
1151c2d3a559SKris Kennaway 		}
1152c2d3a559SKris Kennaway 		fclose(f);
1153c2d3a559SKris Kennaway 	}
1154c2d3a559SKris Kennaway 	return 0;
1155c2d3a559SKris Kennaway }
1156c2d3a559SKris Kennaway 
1157ca3176e7SBrian Feldman /* load public key from ssh v1 private or any pubkey file */
1158ca3176e7SBrian Feldman Key *
1159ca3176e7SBrian Feldman key_load_public(const char *filename, char **commentp)
1160c2d3a559SKris Kennaway {
1161ca3176e7SBrian Feldman 	Key *pub;
1162ca3176e7SBrian Feldman 	char file[MAXPATHLEN];
1163c2d3a559SKris Kennaway 
1164cf2b5f3bSDag-Erling Smørgrav 	/* try rsa1 private key */
1165ca3176e7SBrian Feldman 	pub = key_load_public_type(KEY_RSA1, filename, commentp);
1166ca3176e7SBrian Feldman 	if (pub != NULL)
1167ca3176e7SBrian Feldman 		return pub;
1168cf2b5f3bSDag-Erling Smørgrav 
1169cf2b5f3bSDag-Erling Smørgrav 	/* try rsa1 public key */
1170cf2b5f3bSDag-Erling Smørgrav 	pub = key_new(KEY_RSA1);
1171cf2b5f3bSDag-Erling Smørgrav 	if (key_try_load_public(pub, filename, commentp) == 1)
1172cf2b5f3bSDag-Erling Smørgrav 		return pub;
1173cf2b5f3bSDag-Erling Smørgrav 	key_free(pub);
1174cf2b5f3bSDag-Erling Smørgrav 
1175cf2b5f3bSDag-Erling Smørgrav 	/* try ssh2 public key */
1176ca3176e7SBrian Feldman 	pub = key_new(KEY_UNSPEC);
1177ca3176e7SBrian Feldman 	if (key_try_load_public(pub, filename, commentp) == 1)
1178ca3176e7SBrian Feldman 		return pub;
1179ca3176e7SBrian Feldman 	if ((strlcpy(file, filename, sizeof file) < sizeof(file)) &&
1180ca3176e7SBrian Feldman 	    (strlcat(file, ".pub", sizeof file) < sizeof(file)) &&
1181ca3176e7SBrian Feldman 	    (key_try_load_public(pub, file, commentp) == 1))
1182ca3176e7SBrian Feldman 		return pub;
1183ca3176e7SBrian Feldman 	key_free(pub);
1184ca3176e7SBrian Feldman 	return NULL;
1185c2d3a559SKris Kennaway }
1186b15c8340SDag-Erling Smørgrav 
1187e2f6069cSDag-Erling Smørgrav /* Load the certificate associated with the named private key */
1188e2f6069cSDag-Erling Smørgrav Key *
1189e2f6069cSDag-Erling Smørgrav key_load_cert(const char *filename)
1190e2f6069cSDag-Erling Smørgrav {
1191e2f6069cSDag-Erling Smørgrav 	Key *pub;
1192e2f6069cSDag-Erling Smørgrav 	char *file;
1193e2f6069cSDag-Erling Smørgrav 
1194e2f6069cSDag-Erling Smørgrav 	pub = key_new(KEY_UNSPEC);
1195e2f6069cSDag-Erling Smørgrav 	xasprintf(&file, "%s-cert.pub", filename);
1196e2f6069cSDag-Erling Smørgrav 	if (key_try_load_public(pub, file, NULL) == 1) {
1197e4a9863fSDag-Erling Smørgrav 		free(file);
1198e2f6069cSDag-Erling Smørgrav 		return pub;
1199e2f6069cSDag-Erling Smørgrav 	}
1200e4a9863fSDag-Erling Smørgrav 	free(file);
1201e2f6069cSDag-Erling Smørgrav 	key_free(pub);
1202e2f6069cSDag-Erling Smørgrav 	return NULL;
1203e2f6069cSDag-Erling Smørgrav }
1204e2f6069cSDag-Erling Smørgrav 
1205e2f6069cSDag-Erling Smørgrav /* Load private key and certificate */
1206e2f6069cSDag-Erling Smørgrav Key *
1207e2f6069cSDag-Erling Smørgrav key_load_private_cert(int type, const char *filename, const char *passphrase,
1208e2f6069cSDag-Erling Smørgrav     int *perm_ok)
1209e2f6069cSDag-Erling Smørgrav {
1210e2f6069cSDag-Erling Smørgrav 	Key *key, *pub;
1211e2f6069cSDag-Erling Smørgrav 
1212e2f6069cSDag-Erling Smørgrav 	switch (type) {
1213e2f6069cSDag-Erling Smørgrav 	case KEY_RSA:
1214e2f6069cSDag-Erling Smørgrav 	case KEY_DSA:
12154a421b63SDag-Erling Smørgrav 	case KEY_ECDSA:
1216*f7167e0eSDag-Erling Smørgrav 	case KEY_ED25519:
1217e2f6069cSDag-Erling Smørgrav 		break;
1218e2f6069cSDag-Erling Smørgrav 	default:
1219e2f6069cSDag-Erling Smørgrav 		error("%s: unsupported key type", __func__);
1220e2f6069cSDag-Erling Smørgrav 		return NULL;
1221e2f6069cSDag-Erling Smørgrav 	}
1222e2f6069cSDag-Erling Smørgrav 
1223e2f6069cSDag-Erling Smørgrav 	if ((key = key_load_private_type(type, filename,
1224e2f6069cSDag-Erling Smørgrav 	    passphrase, NULL, perm_ok)) == NULL)
1225e2f6069cSDag-Erling Smørgrav 		return NULL;
1226e2f6069cSDag-Erling Smørgrav 
1227e2f6069cSDag-Erling Smørgrav 	if ((pub = key_load_cert(filename)) == NULL) {
1228e2f6069cSDag-Erling Smørgrav 		key_free(key);
1229e2f6069cSDag-Erling Smørgrav 		return NULL;
1230e2f6069cSDag-Erling Smørgrav 	}
1231e2f6069cSDag-Erling Smørgrav 
1232e2f6069cSDag-Erling Smørgrav 	/* Make sure the private key matches the certificate */
1233e2f6069cSDag-Erling Smørgrav 	if (key_equal_public(key, pub) == 0) {
1234e2f6069cSDag-Erling Smørgrav 		error("%s: certificate does not match private key %s",
1235e2f6069cSDag-Erling Smørgrav 		    __func__, filename);
1236e2f6069cSDag-Erling Smørgrav 	} else if (key_to_certified(key, key_cert_is_legacy(pub)) != 0) {
1237e2f6069cSDag-Erling Smørgrav 		error("%s: key_to_certified failed", __func__);
1238e2f6069cSDag-Erling Smørgrav 	} else {
1239e2f6069cSDag-Erling Smørgrav 		key_cert_copy(pub, key);
1240e2f6069cSDag-Erling Smørgrav 		key_free(pub);
1241e2f6069cSDag-Erling Smørgrav 		return key;
1242e2f6069cSDag-Erling Smørgrav 	}
1243e2f6069cSDag-Erling Smørgrav 
1244e2f6069cSDag-Erling Smørgrav 	key_free(key);
1245e2f6069cSDag-Erling Smørgrav 	key_free(pub);
1246e2f6069cSDag-Erling Smørgrav 	return NULL;
1247e2f6069cSDag-Erling Smørgrav }
1248e2f6069cSDag-Erling Smørgrav 
1249b15c8340SDag-Erling Smørgrav /*
1250b15c8340SDag-Erling Smørgrav  * Returns 1 if the specified "key" is listed in the file "filename",
1251b15c8340SDag-Erling Smørgrav  * 0 if the key is not listed or -1 on error.
1252b15c8340SDag-Erling Smørgrav  * If strict_type is set then the key type must match exactly,
1253b15c8340SDag-Erling Smørgrav  * otherwise a comparison that ignores certficiate data is performed.
1254b15c8340SDag-Erling Smørgrav  */
1255b15c8340SDag-Erling Smørgrav int
1256b15c8340SDag-Erling Smørgrav key_in_file(Key *key, const char *filename, int strict_type)
1257b15c8340SDag-Erling Smørgrav {
1258b15c8340SDag-Erling Smørgrav 	FILE *f;
1259b15c8340SDag-Erling Smørgrav 	char line[SSH_MAX_PUBKEY_BYTES];
1260b15c8340SDag-Erling Smørgrav 	char *cp;
1261b15c8340SDag-Erling Smørgrav 	u_long linenum = 0;
1262b15c8340SDag-Erling Smørgrav 	int ret = 0;
1263b15c8340SDag-Erling Smørgrav 	Key *pub;
1264b15c8340SDag-Erling Smørgrav 	int (*key_compare)(const Key *, const Key *) = strict_type ?
1265b15c8340SDag-Erling Smørgrav 	    key_equal : key_equal_public;
1266b15c8340SDag-Erling Smørgrav 
1267b15c8340SDag-Erling Smørgrav 	if ((f = fopen(filename, "r")) == NULL) {
1268b15c8340SDag-Erling Smørgrav 		if (errno == ENOENT) {
1269b15c8340SDag-Erling Smørgrav 			debug("%s: keyfile \"%s\" missing", __func__, filename);
1270b15c8340SDag-Erling Smørgrav 			return 0;
1271b15c8340SDag-Erling Smørgrav 		} else {
1272b15c8340SDag-Erling Smørgrav 			error("%s: could not open keyfile \"%s\": %s", __func__,
1273b15c8340SDag-Erling Smørgrav 			    filename, strerror(errno));
1274b15c8340SDag-Erling Smørgrav 			return -1;
1275b15c8340SDag-Erling Smørgrav 		}
1276b15c8340SDag-Erling Smørgrav 	}
1277b15c8340SDag-Erling Smørgrav 
1278b15c8340SDag-Erling Smørgrav 	while (read_keyfile_line(f, filename, line, sizeof(line),
1279b15c8340SDag-Erling Smørgrav 		    &linenum) != -1) {
1280b15c8340SDag-Erling Smørgrav 		cp = line;
1281b15c8340SDag-Erling Smørgrav 
1282b15c8340SDag-Erling Smørgrav 		/* Skip leading whitespace. */
1283b15c8340SDag-Erling Smørgrav 		for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
1284b15c8340SDag-Erling Smørgrav 			;
1285b15c8340SDag-Erling Smørgrav 
1286b15c8340SDag-Erling Smørgrav 		/* Skip comments and empty lines */
1287b15c8340SDag-Erling Smørgrav 		switch (*cp) {
1288b15c8340SDag-Erling Smørgrav 		case '#':
1289b15c8340SDag-Erling Smørgrav 		case '\n':
1290b15c8340SDag-Erling Smørgrav 		case '\0':
1291b15c8340SDag-Erling Smørgrav 			continue;
1292b15c8340SDag-Erling Smørgrav 		}
1293b15c8340SDag-Erling Smørgrav 
1294b15c8340SDag-Erling Smørgrav 		pub = key_new(KEY_UNSPEC);
1295b15c8340SDag-Erling Smørgrav 		if (key_read(pub, &cp) != 1) {
1296b15c8340SDag-Erling Smørgrav 			key_free(pub);
1297b15c8340SDag-Erling Smørgrav 			continue;
1298b15c8340SDag-Erling Smørgrav 		}
1299b15c8340SDag-Erling Smørgrav 		if (key_compare(key, pub)) {
1300b15c8340SDag-Erling Smørgrav 			ret = 1;
1301b15c8340SDag-Erling Smørgrav 			key_free(pub);
1302b15c8340SDag-Erling Smørgrav 			break;
1303b15c8340SDag-Erling Smørgrav 		}
1304b15c8340SDag-Erling Smørgrav 		key_free(pub);
1305b15c8340SDag-Erling Smørgrav 	}
1306b15c8340SDag-Erling Smørgrav 	fclose(f);
1307b15c8340SDag-Erling Smørgrav 	return ret;
1308b15c8340SDag-Erling Smørgrav }
1309