1255767Sdes/* $OpenBSD: authfile.c,v 1.97 2013/05/17 00:13:13 djm Exp $ */
257429Smarkm/*
357429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi>
457429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
557429Smarkm *                    All rights reserved
657429Smarkm * This file contains functions for reading and writing identity files, and
757429Smarkm * for reading the passphrase from the user.
860576Skris *
965674Skris * As far as I am concerned, the code I have written for this software
1065674Skris * can be used freely for any purpose.  Any derived versions of this
1165674Skris * software must be clearly marked as such, and if the derived work is
1265674Skris * incompatible with the protocol description in the RFC file, it must be
1365674Skris * called by a name other than "ssh" or "Secure Shell".
1465674Skris *
1565674Skris *
1665674Skris * Copyright (c) 2000 Markus Friedl.  All rights reserved.
1765674Skris *
1865674Skris * Redistribution and use in source and binary forms, with or without
1965674Skris * modification, are permitted provided that the following conditions
2065674Skris * are met:
2165674Skris * 1. Redistributions of source code must retain the above copyright
2265674Skris *    notice, this list of conditions and the following disclaimer.
2365674Skris * 2. Redistributions in binary form must reproduce the above copyright
2465674Skris *    notice, this list of conditions and the following disclaimer in the
2565674Skris *    documentation and/or other materials provided with the distribution.
2665674Skris *
2765674Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2865674Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2965674Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
3065674Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
3165674Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
3265674Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3365674Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3465674Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3565674Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3665674Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3757429Smarkm */
3857429Smarkm
3957429Smarkm#include "includes.h"
4057429Smarkm
41162856Sdes#include <sys/types.h>
42162856Sdes#include <sys/stat.h>
43162856Sdes#include <sys/param.h>
44162856Sdes#include <sys/uio.h>
45162856Sdes
4676262Sgreen#include <openssl/err.h>
4776262Sgreen#include <openssl/evp.h>
4860576Skris#include <openssl/pem.h>
4960576Skris
50204917Sdes/* compatibility with old or broken OpenSSL versions */
51204917Sdes#include "openbsd-compat/openssl-compat.h"
52204917Sdes
53162856Sdes#include <errno.h>
54162856Sdes#include <fcntl.h>
55162856Sdes#include <stdarg.h>
56162856Sdes#include <stdio.h>
57162856Sdes#include <stdlib.h>
58162856Sdes#include <string.h>
59162856Sdes#include <unistd.h>
60162856Sdes
61162856Sdes#include "xmalloc.h"
6276262Sgreen#include "cipher.h"
6357429Smarkm#include "buffer.h"
6476262Sgreen#include "key.h"
6557429Smarkm#include "ssh.h"
6676262Sgreen#include "log.h"
6776262Sgreen#include "authfile.h"
6892559Sdes#include "rsa.h"
69147005Sdes#include "misc.h"
70149753Sdes#include "atomicio.h"
7157429Smarkm
72226046Sdes#define MAX_KEY_FILE_SIZE	(1024 * 1024)
73226046Sdes
7476262Sgreen/* Version identification string for SSH v1 identity files. */
7576262Sgreenstatic const char authfile_id_string[] =
7676262Sgreen    "SSH PRIVATE KEY FILE FORMAT 1.1\n";
7757429Smarkm
7857429Smarkm/*
79221420Sdes * Serialises the authentication (private) key to a blob, encrypting it with
80221420Sdes * passphrase.  The identification of the blob (lowest 64 bits of n) will
8157429Smarkm * precede the key to provide identification of the key without needing a
8257429Smarkm * passphrase.
8357429Smarkm */
8492559Sdesstatic int
85221420Sdeskey_private_rsa1_to_blob(Key *key, Buffer *blob, const char *passphrase,
8676262Sgreen    const char *comment)
8757429Smarkm{
8857429Smarkm	Buffer buffer, encrypted;
8992559Sdes	u_char buf[100], *cp;
90221420Sdes	int i, cipher_num;
9169591Sgreen	CipherContext ciphercontext;
92255767Sdes	const Cipher *cipher;
93137019Sdes	u_int32_t rnd;
9457429Smarkm
9557429Smarkm	/*
9657429Smarkm	 * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting
9757429Smarkm	 * to another cipher; otherwise use SSH_AUTHFILE_CIPHER.
9857429Smarkm	 */
9992559Sdes	cipher_num = (strcmp(passphrase, "") == 0) ?
10092559Sdes	    SSH_CIPHER_NONE : SSH_AUTHFILE_CIPHER;
10192559Sdes	if ((cipher = cipher_by_number(cipher_num)) == NULL)
10269591Sgreen		fatal("save_private_key_rsa: bad cipher");
10357429Smarkm
10457429Smarkm	/* This buffer is used to built the secret part of the private key. */
10557429Smarkm	buffer_init(&buffer);
10657429Smarkm
10757429Smarkm	/* Put checkbytes for checking passphrase validity. */
108137019Sdes	rnd = arc4random();
109137019Sdes	buf[0] = rnd & 0xff;
110137019Sdes	buf[1] = (rnd >> 8) & 0xff;
11157429Smarkm	buf[2] = buf[0];
11257429Smarkm	buf[3] = buf[1];
11357429Smarkm	buffer_append(&buffer, buf, 4);
11457429Smarkm
11557429Smarkm	/*
11657429Smarkm	 * Store the private key (n and e will not be stored because they
11757429Smarkm	 * will be stored in plain text, and storing them also in encrypted
11857429Smarkm	 * format would just give known plaintext).
11957429Smarkm	 */
12076262Sgreen	buffer_put_bignum(&buffer, key->rsa->d);
12176262Sgreen	buffer_put_bignum(&buffer, key->rsa->iqmp);
12276262Sgreen	buffer_put_bignum(&buffer, key->rsa->q);	/* reverse from SSL p */
12376262Sgreen	buffer_put_bignum(&buffer, key->rsa->p);	/* reverse from SSL q */
12457429Smarkm
12557429Smarkm	/* Pad the part to be encrypted until its size is a multiple of 8. */
12657429Smarkm	while (buffer_len(&buffer) % 8 != 0)
12757429Smarkm		buffer_put_char(&buffer, 0);
12857429Smarkm
12957429Smarkm	/* This buffer will be used to contain the data in the file. */
13057429Smarkm	buffer_init(&encrypted);
13157429Smarkm
13257429Smarkm	/* First store keyfile id string. */
13376262Sgreen	for (i = 0; authfile_id_string[i]; i++)
13476262Sgreen		buffer_put_char(&encrypted, authfile_id_string[i]);
13557429Smarkm	buffer_put_char(&encrypted, 0);
13657429Smarkm
13757429Smarkm	/* Store cipher type. */
13892559Sdes	buffer_put_char(&encrypted, cipher_num);
13957429Smarkm	buffer_put_int(&encrypted, 0);	/* For future extension */
14057429Smarkm
14157429Smarkm	/* Store public key.  This will be in plain text. */
14276262Sgreen	buffer_put_int(&encrypted, BN_num_bits(key->rsa->n));
14376262Sgreen	buffer_put_bignum(&encrypted, key->rsa->n);
14476262Sgreen	buffer_put_bignum(&encrypted, key->rsa->e);
14592559Sdes	buffer_put_cstring(&encrypted, comment);
14657429Smarkm
14757429Smarkm	/* Allocate space for the private part of the key in the buffer. */
14892559Sdes	cp = buffer_append_space(&encrypted, buffer_len(&buffer));
14957429Smarkm
15092559Sdes	cipher_set_key_string(&ciphercontext, cipher, passphrase,
15192559Sdes	    CIPHER_ENCRYPT);
15292559Sdes	cipher_crypt(&ciphercontext, cp,
153248619Sdes	    buffer_ptr(&buffer), buffer_len(&buffer), 0, 0);
15492559Sdes	cipher_cleanup(&ciphercontext);
15569591Sgreen	memset(&ciphercontext, 0, sizeof(ciphercontext));
15657429Smarkm
15757429Smarkm	/* Destroy temporary data. */
15857429Smarkm	memset(buf, 0, sizeof(buf));
15957429Smarkm	buffer_free(&buffer);
16057429Smarkm
161221420Sdes	buffer_append(blob, buffer_ptr(&encrypted), buffer_len(&encrypted));
16257429Smarkm	buffer_free(&encrypted);
163221420Sdes
16457429Smarkm	return 1;
16557429Smarkm}
16657429Smarkm
167221420Sdes/* convert SSH v2 key in OpenSSL PEM format */
16892559Sdesstatic int
169221420Sdeskey_private_pem_to_blob(Key *key, Buffer *blob, const char *_passphrase,
17076262Sgreen    const char *comment)
17160576Skris{
17276262Sgreen	int success = 0;
173221420Sdes	int blen, len = strlen(_passphrase);
17492559Sdes	u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL;
175204917Sdes#if (OPENSSL_VERSION_NUMBER < 0x00907000L)
17692559Sdes	const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL;
177204917Sdes#else
178204917Sdes	const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL;
179204917Sdes#endif
180221420Sdes	const u_char *bptr;
181221420Sdes	BIO *bio;
18260576Skris
18360576Skris	if (len > 0 && len <= 4) {
18476262Sgreen		error("passphrase too short: have %d bytes, need > 4", len);
18560576Skris		return 0;
18660576Skris	}
187221420Sdes	if ((bio = BIO_new(BIO_s_mem())) == NULL) {
188221420Sdes		error("%s: BIO_new failed", __func__);
18960576Skris		return 0;
19060576Skris	}
19176262Sgreen	switch (key->type) {
19276262Sgreen	case KEY_DSA:
193221420Sdes		success = PEM_write_bio_DSAPrivateKey(bio, key->dsa,
19476262Sgreen		    cipher, passphrase, len, NULL, NULL);
19576262Sgreen		break;
196221420Sdes#ifdef OPENSSL_HAS_ECC
197221420Sdes	case KEY_ECDSA:
198221420Sdes		success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa,
199221420Sdes		    cipher, passphrase, len, NULL, NULL);
200221420Sdes		break;
201221420Sdes#endif
20276262Sgreen	case KEY_RSA:
203221420Sdes		success = PEM_write_bio_RSAPrivateKey(bio, key->rsa,
20476262Sgreen		    cipher, passphrase, len, NULL, NULL);
20576262Sgreen		break;
20660576Skris	}
207221420Sdes	if (success) {
208221420Sdes		if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0)
209221420Sdes			success = 0;
210221420Sdes		else
211221420Sdes			buffer_append(blob, bptr, blen);
212221420Sdes	}
213221420Sdes	BIO_free(bio);
21460576Skris	return success;
21560576Skris}
21660576Skris
217221420Sdes/* Save a key blob to a file */
218221420Sdesstatic int
219221420Sdeskey_save_private_blob(Buffer *keybuf, const char *filename)
220221420Sdes{
221221420Sdes	int fd;
222221420Sdes
223221420Sdes	if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
224221420Sdes		error("open %s failed: %s.", filename, strerror(errno));
225221420Sdes		return 0;
226221420Sdes	}
227221420Sdes	if (atomicio(vwrite, fd, buffer_ptr(keybuf),
228221420Sdes	    buffer_len(keybuf)) != buffer_len(keybuf)) {
229221420Sdes		error("write to key file %s failed: %s", filename,
230221420Sdes		    strerror(errno));
231221420Sdes		close(fd);
232221420Sdes		unlink(filename);
233221420Sdes		return 0;
234221420Sdes	}
235221420Sdes	close(fd);
236221420Sdes	return 1;
237221420Sdes}
238221420Sdes
239221420Sdes/* Serialise "key" to buffer "blob" */
240221420Sdesstatic int
241221420Sdeskey_private_to_blob(Key *key, Buffer *blob, const char *passphrase,
24260576Skris    const char *comment)
24360576Skris{
24460576Skris	switch (key->type) {
24576262Sgreen	case KEY_RSA1:
246221420Sdes		return key_private_rsa1_to_blob(key, blob, passphrase, comment);
24760576Skris	case KEY_DSA:
248221420Sdes	case KEY_ECDSA:
24976262Sgreen	case KEY_RSA:
250221420Sdes		return key_private_pem_to_blob(key, blob, passphrase, comment);
25160576Skris	default:
252221420Sdes		error("%s: cannot save key type %d", __func__, key->type);
253221420Sdes		return 0;
25460576Skris	}
25560576Skris}
25660576Skris
257221420Sdesint
258221420Sdeskey_save_private(Key *key, const char *filename, const char *passphrase,
259221420Sdes    const char *comment)
260221420Sdes{
261221420Sdes	Buffer keyblob;
262221420Sdes	int success = 0;
263221420Sdes
264221420Sdes	buffer_init(&keyblob);
265221420Sdes	if (!key_private_to_blob(key, &keyblob, passphrase, comment))
266221420Sdes		goto out;
267221420Sdes	if (!key_save_private_blob(&keyblob, filename))
268221420Sdes		goto out;
269221420Sdes	success = 1;
270221420Sdes out:
271221420Sdes	buffer_free(&keyblob);
272221420Sdes	return success;
273221420Sdes}
274221420Sdes
27557429Smarkm/*
276221420Sdes * Parse the public, unencrypted portion of a RSA1 key.
27757429Smarkm */
27892559Sdesstatic Key *
279221420Sdeskey_parse_public_rsa1(Buffer *blob, char **commentp)
28057429Smarkm{
28176262Sgreen	Key *pub;
282226046Sdes	Buffer copy;
283221420Sdes
284221420Sdes	/* Check that it is at least big enough to contain the ID string. */
285221420Sdes	if (buffer_len(blob) < sizeof(authfile_id_string)) {
286221420Sdes		debug3("Truncated RSA1 identifier");
287221420Sdes		return NULL;
288221420Sdes	}
289221420Sdes
290221420Sdes	/*
291221420Sdes	 * Make sure it begins with the id string.  Consume the id string
292221420Sdes	 * from the buffer.
293221420Sdes	 */
294221420Sdes	if (memcmp(buffer_ptr(blob), authfile_id_string,
295221420Sdes	    sizeof(authfile_id_string)) != 0) {
296221420Sdes		debug3("Incorrect RSA1 identifier");
297221420Sdes		return NULL;
298221420Sdes	}
299226046Sdes	buffer_init(&copy);
300226046Sdes	buffer_append(&copy, buffer_ptr(blob), buffer_len(blob));
301226046Sdes	buffer_consume(&copy, sizeof(authfile_id_string));
302221420Sdes
303221420Sdes	/* Skip cipher type and reserved data. */
304226046Sdes	(void) buffer_get_char(&copy);		/* cipher type */
305226046Sdes	(void) buffer_get_int(&copy);		/* reserved */
306221420Sdes
307221420Sdes	/* Read the public key from the buffer. */
308226046Sdes	(void) buffer_get_int(&copy);
309221420Sdes	pub = key_new(KEY_RSA1);
310226046Sdes	buffer_get_bignum(&copy, pub->rsa->n);
311226046Sdes	buffer_get_bignum(&copy, pub->rsa->e);
312221420Sdes	if (commentp)
313226046Sdes		*commentp = buffer_get_string(&copy, NULL);
314221420Sdes	/* The encrypted private part is not parsed by this function. */
315226046Sdes	buffer_free(&copy);
316221420Sdes
317221420Sdes	return pub;
318221420Sdes}
319221420Sdes
320226046Sdes/* Load a key from a fd into a buffer */
321226046Sdesint
322221420Sdeskey_load_file(int fd, const char *filename, Buffer *blob)
323221420Sdes{
324226046Sdes	u_char buf[1024];
325221420Sdes	size_t len;
326113911Sdes	struct stat st;
32757429Smarkm
328113911Sdes	if (fstat(fd, &st) < 0) {
329221420Sdes		error("%s: fstat of key file %.200s%sfailed: %.100s", __func__,
330221420Sdes		    filename == NULL ? "" : filename,
331221420Sdes		    filename == NULL ? "" : " ",
332221420Sdes		    strerror(errno));
333221420Sdes		return 0;
334113911Sdes	}
335226046Sdes	if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
336226046Sdes	    st.st_size > MAX_KEY_FILE_SIZE) {
337226046Sdes toobig:
338221420Sdes		error("%s: key file %.200s%stoo large", __func__,
339221420Sdes		    filename == NULL ? "" : filename,
340221420Sdes		    filename == NULL ? "" : " ");
341221420Sdes		return 0;
342147005Sdes	}
343240075Sdes	buffer_clear(blob);
344226046Sdes	for (;;) {
345226046Sdes		if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) {
346226046Sdes			if (errno == EPIPE)
347226046Sdes				break;
348226046Sdes			debug("%s: read from key file %.200s%sfailed: %.100s",
349226046Sdes			    __func__, filename == NULL ? "" : filename,
350226046Sdes			    filename == NULL ? "" : " ", strerror(errno));
351226046Sdes			buffer_clear(blob);
352226046Sdes			bzero(buf, sizeof(buf));
353226046Sdes			return 0;
354226046Sdes		}
355226046Sdes		buffer_append(blob, buf, len);
356226046Sdes		if (buffer_len(blob) > MAX_KEY_FILE_SIZE) {
357226046Sdes			buffer_clear(blob);
358226046Sdes			bzero(buf, sizeof(buf));
359226046Sdes			goto toobig;
360226046Sdes		}
361226046Sdes	}
362226046Sdes	bzero(buf, sizeof(buf));
363226046Sdes	if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
364226046Sdes	    st.st_size != buffer_len(blob)) {
365226046Sdes		debug("%s: key file %.200s%schanged size while reading",
366226046Sdes		    __func__, filename == NULL ? "" : filename,
367226046Sdes		    filename == NULL ? "" : " ");
368221420Sdes		buffer_clear(blob);
369221420Sdes		return 0;
37057429Smarkm	}
371226046Sdes
372221420Sdes	return 1;
373221420Sdes}
37457429Smarkm
375221420Sdes/*
376221420Sdes * Loads the public part of the ssh v1 key file.  Returns NULL if an error was
377221420Sdes * encountered (the file does not exist or is not readable), and the key
378221420Sdes * otherwise.
379221420Sdes */
380221420Sdesstatic Key *
381221420Sdeskey_load_public_rsa1(int fd, const char *filename, char **commentp)
382221420Sdes{
383221420Sdes	Buffer buffer;
384221420Sdes	Key *pub;
385221420Sdes
386221420Sdes	buffer_init(&buffer);
387221420Sdes	if (!key_load_file(fd, filename, &buffer)) {
38857429Smarkm		buffer_free(&buffer);
38976262Sgreen		return NULL;
39057429Smarkm	}
39157429Smarkm
392221420Sdes	pub = key_parse_public_rsa1(&buffer, commentp);
393221420Sdes	if (pub == NULL)
394221420Sdes		debug3("Could not load \"%s\" as a RSA1 public key", filename);
39557429Smarkm	buffer_free(&buffer);
39676262Sgreen	return pub;
39757429Smarkm}
39857429Smarkm
39976262Sgreen/* load public key from private-key file, works only for SSH v1 */
40076262SgreenKey *
40176262Sgreenkey_load_public_type(int type, const char *filename, char **commentp)
40260576Skris{
40376262Sgreen	Key *pub;
40476262Sgreen	int fd;
40576262Sgreen
40676262Sgreen	if (type == KEY_RSA1) {
40776262Sgreen		fd = open(filename, O_RDONLY);
40876262Sgreen		if (fd < 0)
40976262Sgreen			return NULL;
41076262Sgreen		pub = key_load_public_rsa1(fd, filename, commentp);
41176262Sgreen		close(fd);
41276262Sgreen		return pub;
41360576Skris	}
41476262Sgreen	return NULL;
41560576Skris}
41660576Skris
41792559Sdesstatic Key *
418221420Sdeskey_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp)
41957429Smarkm{
420149753Sdes	int check1, check2, cipher_type;
421221420Sdes	Buffer decrypted;
42292559Sdes	u_char *cp;
42369591Sgreen	CipherContext ciphercontext;
424255767Sdes	const Cipher *cipher;
42576262Sgreen	Key *prv = NULL;
426226046Sdes	Buffer copy;
42757429Smarkm
428221420Sdes	/* Check that it is at least big enough to contain the ID string. */
429221420Sdes	if (buffer_len(blob) < sizeof(authfile_id_string)) {
430221420Sdes		debug3("Truncated RSA1 identifier");
431113911Sdes		return NULL;
432113911Sdes	}
43357429Smarkm
43457429Smarkm	/*
43557429Smarkm	 * Make sure it begins with the id string.  Consume the id string
43657429Smarkm	 * from the buffer.
43757429Smarkm	 */
438221420Sdes	if (memcmp(buffer_ptr(blob), authfile_id_string,
439221420Sdes	    sizeof(authfile_id_string)) != 0) {
440221420Sdes		debug3("Incorrect RSA1 identifier");
441221420Sdes		return NULL;
442221420Sdes	}
443226046Sdes	buffer_init(&copy);
444226046Sdes	buffer_append(&copy, buffer_ptr(blob), buffer_len(blob));
445226046Sdes	buffer_consume(&copy, sizeof(authfile_id_string));
44676262Sgreen
44757429Smarkm	/* Read cipher type. */
448226046Sdes	cipher_type = buffer_get_char(&copy);
449226046Sdes	(void) buffer_get_int(&copy);	/* Reserved data. */
45057429Smarkm
45157429Smarkm	/* Read the public key from the buffer. */
452226046Sdes	(void) buffer_get_int(&copy);
45376262Sgreen	prv = key_new_private(KEY_RSA1);
45476262Sgreen
455226046Sdes	buffer_get_bignum(&copy, prv->rsa->n);
456226046Sdes	buffer_get_bignum(&copy, prv->rsa->e);
45776262Sgreen	if (commentp)
458226046Sdes		*commentp = buffer_get_string(&copy, NULL);
45957429Smarkm	else
460226046Sdes		(void)buffer_get_string_ptr(&copy, NULL);
46157429Smarkm
46257429Smarkm	/* Check that it is a supported cipher. */
46369591Sgreen	cipher = cipher_by_number(cipher_type);
46469591Sgreen	if (cipher == NULL) {
465221420Sdes		debug("Unsupported RSA1 cipher %d", cipher_type);
466226046Sdes		buffer_free(&copy);
46757429Smarkm		goto fail;
46857429Smarkm	}
46957429Smarkm	/* Initialize space for decrypted data. */
47057429Smarkm	buffer_init(&decrypted);
471226046Sdes	cp = buffer_append_space(&decrypted, buffer_len(&copy));
47257429Smarkm
47357429Smarkm	/* Rest of the buffer is encrypted.  Decrypt it using the passphrase. */
47492559Sdes	cipher_set_key_string(&ciphercontext, cipher, passphrase,
47592559Sdes	    CIPHER_DECRYPT);
47692559Sdes	cipher_crypt(&ciphercontext, cp,
477248619Sdes	    buffer_ptr(&copy), buffer_len(&copy), 0, 0);
47892559Sdes	cipher_cleanup(&ciphercontext);
47969591Sgreen	memset(&ciphercontext, 0, sizeof(ciphercontext));
480226046Sdes	buffer_free(&copy);
48157429Smarkm
48257429Smarkm	check1 = buffer_get_char(&decrypted);
48357429Smarkm	check2 = buffer_get_char(&decrypted);
48457429Smarkm	if (check1 != buffer_get_char(&decrypted) ||
48557429Smarkm	    check2 != buffer_get_char(&decrypted)) {
48657429Smarkm		if (strcmp(passphrase, "") != 0)
487221420Sdes			debug("Bad passphrase supplied for RSA1 key");
48857429Smarkm		/* Bad passphrase. */
48957429Smarkm		buffer_free(&decrypted);
49076262Sgreen		goto fail;
49157429Smarkm	}
49257429Smarkm	/* Read the rest of the private key. */
49376262Sgreen	buffer_get_bignum(&decrypted, prv->rsa->d);
49476262Sgreen	buffer_get_bignum(&decrypted, prv->rsa->iqmp);		/* u */
49576262Sgreen	/* in SSL and SSH v1 p and q are exchanged */
49676262Sgreen	buffer_get_bignum(&decrypted, prv->rsa->q);		/* p */
49776262Sgreen	buffer_get_bignum(&decrypted, prv->rsa->p);		/* q */
49857429Smarkm
49976262Sgreen	/* calculate p-1 and q-1 */
50092559Sdes	rsa_generate_additional_parameters(prv->rsa);
50157429Smarkm
50257429Smarkm	buffer_free(&decrypted);
503113911Sdes
504113911Sdes	/* enable blinding */
505113911Sdes	if (RSA_blinding_on(prv->rsa, NULL) != 1) {
506221420Sdes		error("%s: RSA_blinding_on failed", __func__);
507113911Sdes		goto fail;
508113911Sdes	}
50976262Sgreen	return prv;
51057429Smarkm
51176262Sgreenfail:
512255767Sdes	if (commentp != NULL)
513255767Sdes		free(*commentp);
51476262Sgreen	key_free(prv);
51576262Sgreen	return NULL;
51657429Smarkm}
51760576Skris
518221420Sdesstatic Key *
519221420Sdeskey_parse_private_pem(Buffer *blob, int type, const char *passphrase,
52076262Sgreen    char **commentp)
52160576Skris{
52276262Sgreen	EVP_PKEY *pk = NULL;
52376262Sgreen	Key *prv = NULL;
52476262Sgreen	char *name = "<no key>";
525221420Sdes	BIO *bio;
52660576Skris
527221420Sdes	if ((bio = BIO_new_mem_buf(buffer_ptr(blob),
528221420Sdes	    buffer_len(blob))) == NULL) {
529221420Sdes		error("%s: BIO_new_mem_buf failed", __func__);
53076262Sgreen		return NULL;
53160576Skris	}
532221420Sdes
533221420Sdes	pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, (char *)passphrase);
534221420Sdes	BIO_free(bio);
53576262Sgreen	if (pk == NULL) {
536221420Sdes		debug("%s: PEM_read_PrivateKey failed", __func__);
53776262Sgreen		(void)ERR_get_error();
53876262Sgreen	} else if (pk->type == EVP_PKEY_RSA &&
53992559Sdes	    (type == KEY_UNSPEC||type==KEY_RSA)) {
54076262Sgreen		prv = key_new(KEY_UNSPEC);
54176262Sgreen		prv->rsa = EVP_PKEY_get1_RSA(pk);
54276262Sgreen		prv->type = KEY_RSA;
54376262Sgreen		name = "rsa w/o comment";
54476262Sgreen#ifdef DEBUG_PK
54576262Sgreen		RSA_print_fp(stderr, prv->rsa, 8);
54676262Sgreen#endif
547113911Sdes		if (RSA_blinding_on(prv->rsa, NULL) != 1) {
548221420Sdes			error("%s: RSA_blinding_on failed", __func__);
549113911Sdes			key_free(prv);
550113911Sdes			prv = NULL;
551113911Sdes		}
55276262Sgreen	} else if (pk->type == EVP_PKEY_DSA &&
55392559Sdes	    (type == KEY_UNSPEC||type==KEY_DSA)) {
55476262Sgreen		prv = key_new(KEY_UNSPEC);
55576262Sgreen		prv->dsa = EVP_PKEY_get1_DSA(pk);
55676262Sgreen		prv->type = KEY_DSA;
55776262Sgreen		name = "dsa w/o comment";
55876262Sgreen#ifdef DEBUG_PK
55976262Sgreen		DSA_print_fp(stderr, prv->dsa, 8);
56076262Sgreen#endif
561221420Sdes#ifdef OPENSSL_HAS_ECC
562221420Sdes	} else if (pk->type == EVP_PKEY_EC &&
563221420Sdes	    (type == KEY_UNSPEC||type==KEY_ECDSA)) {
564221420Sdes		prv = key_new(KEY_UNSPEC);
565221420Sdes		prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk);
566221420Sdes		prv->type = KEY_ECDSA;
567221420Sdes		if ((prv->ecdsa_nid = key_ecdsa_key_to_nid(prv->ecdsa)) == -1 ||
568221420Sdes		    key_curve_nid_to_name(prv->ecdsa_nid) == NULL ||
569221420Sdes		    key_ec_validate_public(EC_KEY_get0_group(prv->ecdsa),
570221420Sdes		    EC_KEY_get0_public_key(prv->ecdsa)) != 0 ||
571221420Sdes		    key_ec_validate_private(prv->ecdsa) != 0) {
572221420Sdes			error("%s: bad ECDSA key", __func__);
573221420Sdes			key_free(prv);
574221420Sdes			prv = NULL;
575221420Sdes		}
576221420Sdes		name = "ecdsa w/o comment";
577221420Sdes#ifdef DEBUG_PK
578221420Sdes		if (prv != NULL && prv->ecdsa != NULL)
579221420Sdes			key_dump_ec_key(prv->ecdsa);
580221420Sdes#endif
581221420Sdes#endif /* OPENSSL_HAS_ECC */
58260576Skris	} else {
583221420Sdes		error("%s: PEM_read_PrivateKey: mismatch or "
584221420Sdes		    "unknown EVP_PKEY save_type %d", __func__, pk->save_type);
58560576Skris	}
58676262Sgreen	if (pk != NULL)
58776262Sgreen		EVP_PKEY_free(pk);
58876262Sgreen	if (prv != NULL && commentp)
58976262Sgreen		*commentp = xstrdup(name);
59076262Sgreen	debug("read PEM private key done: type %s",
59176262Sgreen	    prv ? key_type(prv) : "<unknown>");
59276262Sgreen	return prv;
59360576Skris}
59460576Skris
595221420SdesKey *
596221420Sdeskey_load_private_pem(int fd, int type, const char *passphrase,
597221420Sdes    char **commentp)
598221420Sdes{
599221420Sdes	Buffer buffer;
600221420Sdes	Key *prv;
601221420Sdes
602221420Sdes	buffer_init(&buffer);
603221420Sdes	if (!key_load_file(fd, NULL, &buffer)) {
604221420Sdes		buffer_free(&buffer);
605221420Sdes		return NULL;
606221420Sdes	}
607221420Sdes	prv = key_parse_private_pem(&buffer, type, passphrase, commentp);
608221420Sdes	buffer_free(&buffer);
609221420Sdes	return prv;
610221420Sdes}
611221420Sdes
612162856Sdesint
61376262Sgreenkey_perm_ok(int fd, const char *filename)
61460576Skris{
61560576Skris	struct stat st;
61660576Skris
61792559Sdes	if (fstat(fd, &st) < 0)
61892559Sdes		return 0;
61992559Sdes	/*
62092559Sdes	 * if a key owned by the user is accessed, then we check the
62192559Sdes	 * permissions of the file. if the key owned by a different user,
62292559Sdes	 * then we don't care.
62392559Sdes	 */
62498941Sdes#ifdef HAVE_CYGWIN
62598941Sdes	if (check_ntsec(filename))
62698941Sdes#endif
62792559Sdes	if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
62860576Skris		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
62960576Skris		error("@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @");
63060576Skris		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
63192559Sdes		error("Permissions 0%3.3o for '%s' are too open.",
632124211Sdes		    (u_int)st.st_mode & 0777, filename);
633226046Sdes		error("It is required that your private key files are NOT accessible by others.");
63476262Sgreen		error("This private key will be ignored.");
63560576Skris		return 0;
63660576Skris	}
63776262Sgreen	return 1;
63876262Sgreen}
63976262Sgreen
640221420Sdesstatic Key *
641221420Sdeskey_parse_private_type(Buffer *blob, int type, const char *passphrase,
642221420Sdes    char **commentp)
643221420Sdes{
644221420Sdes	switch (type) {
645221420Sdes	case KEY_RSA1:
646221420Sdes		return key_parse_private_rsa1(blob, passphrase, commentp);
647221420Sdes	case KEY_DSA:
648221420Sdes	case KEY_ECDSA:
649221420Sdes	case KEY_RSA:
650221420Sdes	case KEY_UNSPEC:
651221420Sdes		return key_parse_private_pem(blob, type, passphrase, commentp);
652221420Sdes	default:
653226046Sdes		error("%s: cannot parse key type %d", __func__, type);
654221420Sdes		break;
655221420Sdes	}
656221420Sdes	return NULL;
657221420Sdes}
658221420Sdes
65976262SgreenKey *
66076262Sgreenkey_load_private_type(int type, const char *filename, const char *passphrase,
661162856Sdes    char **commentp, int *perm_ok)
66276262Sgreen{
66376262Sgreen	int fd;
664221420Sdes	Key *ret;
665221420Sdes	Buffer buffer;
66676262Sgreen
66776262Sgreen	fd = open(filename, O_RDONLY);
668204917Sdes	if (fd < 0) {
669204917Sdes		debug("could not open key file '%s': %s", filename,
670204917Sdes		    strerror(errno));
671204917Sdes		if (perm_ok != NULL)
672204917Sdes			*perm_ok = 0;
67376262Sgreen		return NULL;
674204917Sdes	}
67576262Sgreen	if (!key_perm_ok(fd, filename)) {
676162856Sdes		if (perm_ok != NULL)
677162856Sdes			*perm_ok = 0;
67876262Sgreen		error("bad permissions: ignore key: %s", filename);
67976262Sgreen		close(fd);
68076262Sgreen		return NULL;
68176262Sgreen	}
682162856Sdes	if (perm_ok != NULL)
683162856Sdes		*perm_ok = 1;
684221420Sdes
685221420Sdes	buffer_init(&buffer);
686221420Sdes	if (!key_load_file(fd, filename, &buffer)) {
687221420Sdes		buffer_free(&buffer);
68876262Sgreen		close(fd);
689221420Sdes		return NULL;
69060576Skris	}
691221420Sdes	close(fd);
692221420Sdes	ret = key_parse_private_type(&buffer, type, passphrase, commentp);
693221420Sdes	buffer_free(&buffer);
694221420Sdes	return ret;
69560576Skris}
69665674Skris
69776262SgreenKey *
698226046Sdeskey_parse_private(Buffer *buffer, const char *filename,
699226046Sdes    const char *passphrase, char **commentp)
700226046Sdes{
701226046Sdes	Key *pub, *prv;
702226046Sdes
703226046Sdes	/* it's a SSH v1 key if the public key part is readable */
704226046Sdes	pub = key_parse_public_rsa1(buffer, commentp);
705226046Sdes	if (pub == NULL) {
706226046Sdes		prv = key_parse_private_type(buffer, KEY_UNSPEC,
707226046Sdes		    passphrase, NULL);
708226046Sdes		/* use the filename as a comment for PEM */
709226046Sdes		if (commentp && prv)
710226046Sdes			*commentp = xstrdup(filename);
711226046Sdes	} else {
712226046Sdes		key_free(pub);
713226046Sdes		/* key_parse_public_rsa1() has already loaded the comment */
714226046Sdes		prv = key_parse_private_type(buffer, KEY_RSA1, passphrase,
715226046Sdes		    NULL);
716226046Sdes	}
717226046Sdes	return prv;
718226046Sdes}
719226046Sdes
720226046SdesKey *
72176262Sgreenkey_load_private(const char *filename, const char *passphrase,
72276262Sgreen    char **commentp)
72376262Sgreen{
724226046Sdes	Key *prv;
725226046Sdes	Buffer buffer;
72676262Sgreen	int fd;
72776262Sgreen
72876262Sgreen	fd = open(filename, O_RDONLY);
729204917Sdes	if (fd < 0) {
730204917Sdes		debug("could not open key file '%s': %s", filename,
731204917Sdes		    strerror(errno));
73276262Sgreen		return NULL;
733204917Sdes	}
73476262Sgreen	if (!key_perm_ok(fd, filename)) {
73576262Sgreen		error("bad permissions: ignore key: %s", filename);
73676262Sgreen		close(fd);
73776262Sgreen		return NULL;
73876262Sgreen	}
739221420Sdes
740221420Sdes	buffer_init(&buffer);
741221420Sdes	if (!key_load_file(fd, filename, &buffer)) {
742221420Sdes		buffer_free(&buffer);
743221420Sdes		close(fd);
744221420Sdes		return NULL;
745221420Sdes	}
746221420Sdes	close(fd);
747221420Sdes
748226046Sdes	prv = key_parse_private(&buffer, filename, passphrase, commentp);
749221420Sdes	buffer_free(&buffer);
75092559Sdes	return prv;
75176262Sgreen}
75276262Sgreen
75392559Sdesstatic int
75476262Sgreenkey_try_load_public(Key *k, const char *filename, char **commentp)
75565674Skris{
75665674Skris	FILE *f;
757147005Sdes	char line[SSH_MAX_PUBKEY_BYTES];
75865674Skris	char *cp;
759147005Sdes	u_long linenum = 0;
76065674Skris
76165674Skris	f = fopen(filename, "r");
76265674Skris	if (f != NULL) {
763147005Sdes		while (read_keyfile_line(f, filename, line, sizeof(line),
764147005Sdes			    &linenum) != -1) {
76565674Skris			cp = line;
76692559Sdes			switch (*cp) {
76765674Skris			case '#':
76865674Skris			case '\n':
76965674Skris			case '\0':
77065674Skris				continue;
77165674Skris			}
772226046Sdes			/* Abort loading if this looks like a private key */
773226046Sdes			if (strncmp(cp, "-----BEGIN", 10) == 0)
774226046Sdes				break;
77565674Skris			/* Skip leading whitespace. */
77665674Skris			for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
77765674Skris				;
77865674Skris			if (*cp) {
77976262Sgreen				if (key_read(k, &cp) == 1) {
780226046Sdes					cp[strcspn(cp, "\r\n")] = '\0';
781226046Sdes					if (commentp) {
782226046Sdes						*commentp = xstrdup(*cp ?
783226046Sdes						    cp : filename);
784226046Sdes					}
78565674Skris					fclose(f);
78665674Skris					return 1;
78765674Skris				}
78865674Skris			}
78965674Skris		}
79065674Skris		fclose(f);
79165674Skris	}
79265674Skris	return 0;
79365674Skris}
79465674Skris
79576262Sgreen/* load public key from ssh v1 private or any pubkey file */
79676262SgreenKey *
79776262Sgreenkey_load_public(const char *filename, char **commentp)
79865674Skris{
79976262Sgreen	Key *pub;
80076262Sgreen	char file[MAXPATHLEN];
80165674Skris
802124211Sdes	/* try rsa1 private key */
80376262Sgreen	pub = key_load_public_type(KEY_RSA1, filename, commentp);
80476262Sgreen	if (pub != NULL)
80576262Sgreen		return pub;
806124211Sdes
807124211Sdes	/* try rsa1 public key */
808124211Sdes	pub = key_new(KEY_RSA1);
809124211Sdes	if (key_try_load_public(pub, filename, commentp) == 1)
810124211Sdes		return pub;
811124211Sdes	key_free(pub);
812124211Sdes
813124211Sdes	/* try ssh2 public key */
81476262Sgreen	pub = key_new(KEY_UNSPEC);
81576262Sgreen	if (key_try_load_public(pub, filename, commentp) == 1)
81676262Sgreen		return pub;
81776262Sgreen	if ((strlcpy(file, filename, sizeof file) < sizeof(file)) &&
81876262Sgreen	    (strlcat(file, ".pub", sizeof file) < sizeof(file)) &&
81976262Sgreen	    (key_try_load_public(pub, file, commentp) == 1))
82076262Sgreen		return pub;
82176262Sgreen	key_free(pub);
82276262Sgreen	return NULL;
82365674Skris}
824204917Sdes
825215116Sdes/* Load the certificate associated with the named private key */
826215116SdesKey *
827215116Sdeskey_load_cert(const char *filename)
828215116Sdes{
829215116Sdes	Key *pub;
830215116Sdes	char *file;
831215116Sdes
832215116Sdes	pub = key_new(KEY_UNSPEC);
833215116Sdes	xasprintf(&file, "%s-cert.pub", filename);
834215116Sdes	if (key_try_load_public(pub, file, NULL) == 1) {
835255767Sdes		free(file);
836215116Sdes		return pub;
837215116Sdes	}
838255767Sdes	free(file);
839215116Sdes	key_free(pub);
840215116Sdes	return NULL;
841215116Sdes}
842215116Sdes
843215116Sdes/* Load private key and certificate */
844215116SdesKey *
845215116Sdeskey_load_private_cert(int type, const char *filename, const char *passphrase,
846215116Sdes    int *perm_ok)
847215116Sdes{
848215116Sdes	Key *key, *pub;
849215116Sdes
850215116Sdes	switch (type) {
851215116Sdes	case KEY_RSA:
852215116Sdes	case KEY_DSA:
853221420Sdes	case KEY_ECDSA:
854215116Sdes		break;
855215116Sdes	default:
856215116Sdes		error("%s: unsupported key type", __func__);
857215116Sdes		return NULL;
858215116Sdes	}
859215116Sdes
860215116Sdes	if ((key = key_load_private_type(type, filename,
861215116Sdes	    passphrase, NULL, perm_ok)) == NULL)
862215116Sdes		return NULL;
863215116Sdes
864215116Sdes	if ((pub = key_load_cert(filename)) == NULL) {
865215116Sdes		key_free(key);
866215116Sdes		return NULL;
867215116Sdes	}
868215116Sdes
869215116Sdes	/* Make sure the private key matches the certificate */
870215116Sdes	if (key_equal_public(key, pub) == 0) {
871215116Sdes		error("%s: certificate does not match private key %s",
872215116Sdes		    __func__, filename);
873215116Sdes	} else if (key_to_certified(key, key_cert_is_legacy(pub)) != 0) {
874215116Sdes		error("%s: key_to_certified failed", __func__);
875215116Sdes	} else {
876215116Sdes		key_cert_copy(pub, key);
877215116Sdes		key_free(pub);
878215116Sdes		return key;
879215116Sdes	}
880215116Sdes
881215116Sdes	key_free(key);
882215116Sdes	key_free(pub);
883215116Sdes	return NULL;
884215116Sdes}
885215116Sdes
886204917Sdes/*
887204917Sdes * Returns 1 if the specified "key" is listed in the file "filename",
888204917Sdes * 0 if the key is not listed or -1 on error.
889204917Sdes * If strict_type is set then the key type must match exactly,
890204917Sdes * otherwise a comparison that ignores certficiate data is performed.
891204917Sdes */
892204917Sdesint
893204917Sdeskey_in_file(Key *key, const char *filename, int strict_type)
894204917Sdes{
895204917Sdes	FILE *f;
896204917Sdes	char line[SSH_MAX_PUBKEY_BYTES];
897204917Sdes	char *cp;
898204917Sdes	u_long linenum = 0;
899204917Sdes	int ret = 0;
900204917Sdes	Key *pub;
901204917Sdes	int (*key_compare)(const Key *, const Key *) = strict_type ?
902204917Sdes	    key_equal : key_equal_public;
903204917Sdes
904204917Sdes	if ((f = fopen(filename, "r")) == NULL) {
905204917Sdes		if (errno == ENOENT) {
906204917Sdes			debug("%s: keyfile \"%s\" missing", __func__, filename);
907204917Sdes			return 0;
908204917Sdes		} else {
909204917Sdes			error("%s: could not open keyfile \"%s\": %s", __func__,
910204917Sdes			    filename, strerror(errno));
911204917Sdes			return -1;
912204917Sdes		}
913204917Sdes	}
914204917Sdes
915204917Sdes	while (read_keyfile_line(f, filename, line, sizeof(line),
916204917Sdes		    &linenum) != -1) {
917204917Sdes		cp = line;
918204917Sdes
919204917Sdes		/* Skip leading whitespace. */
920204917Sdes		for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
921204917Sdes			;
922204917Sdes
923204917Sdes		/* Skip comments and empty lines */
924204917Sdes		switch (*cp) {
925204917Sdes		case '#':
926204917Sdes		case '\n':
927204917Sdes		case '\0':
928204917Sdes			continue;
929204917Sdes		}
930204917Sdes
931204917Sdes		pub = key_new(KEY_UNSPEC);
932204917Sdes		if (key_read(pub, &cp) != 1) {
933204917Sdes			key_free(pub);
934204917Sdes			continue;
935204917Sdes		}
936204917Sdes		if (key_compare(key, pub)) {
937204917Sdes			ret = 1;
938204917Sdes			key_free(pub);
939204917Sdes			break;
940204917Sdes		}
941204917Sdes		key_free(pub);
942204917Sdes	}
943204917Sdes	fclose(f);
944204917Sdes	return ret;
945204917Sdes}
946204917Sdes
947