xref: /freebsd/crypto/openssh/authfile.c (revision e8aafc91b53498783b0584976940e992c36b4e31)
1511b41d2SMark Murray /*
2511b41d2SMark Murray  *
3511b41d2SMark Murray  * authfile.c
4511b41d2SMark Murray  *
5511b41d2SMark Murray  * Author: Tatu Ylonen <ylo@cs.hut.fi>
6511b41d2SMark Murray  *
7511b41d2SMark Murray  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8511b41d2SMark Murray  *                    All rights reserved
9511b41d2SMark Murray  *
10511b41d2SMark Murray  * Created: Mon Mar 27 03:52:05 1995 ylo
11511b41d2SMark Murray  *
12511b41d2SMark Murray  * This file contains functions for reading and writing identity files, and
13511b41d2SMark Murray  * for reading the passphrase from the user.
14511b41d2SMark Murray  *
1518a71195SBrian Feldman  * $FreeBSD$
16511b41d2SMark Murray  */
17511b41d2SMark Murray 
18511b41d2SMark Murray #include "includes.h"
19e8aafc91SKris Kennaway RCSID("$Id: authfile.c,v 1.16 2000/04/26 21:28:32 markus Exp $");
20511b41d2SMark Murray 
2118a71195SBrian Feldman #include <openssl/bn.h>
22e8aafc91SKris Kennaway #include <openssl/dsa.h>
23e8aafc91SKris Kennaway #include <openssl/rsa.h>
24e8aafc91SKris Kennaway #include <openssl/pem.h>
25e8aafc91SKris Kennaway #include <openssl/evp.h>
26e8aafc91SKris Kennaway 
27511b41d2SMark Murray #include "xmalloc.h"
28511b41d2SMark Murray #include "buffer.h"
29511b41d2SMark Murray #include "bufaux.h"
30511b41d2SMark Murray #include "cipher.h"
31511b41d2SMark Murray #include "ssh.h"
32e8aafc91SKris Kennaway #include "key.h"
33511b41d2SMark Murray 
34511b41d2SMark Murray /* Version identification string for identity files. */
35511b41d2SMark Murray #define AUTHFILE_ID_STRING "SSH PRIVATE KEY FILE FORMAT 1.1\n"
36511b41d2SMark Murray 
37511b41d2SMark Murray /*
38511b41d2SMark Murray  * Saves the authentication (private) key in a file, encrypting it with
39511b41d2SMark Murray  * passphrase.  The identification of the file (lowest 64 bits of n) will
40511b41d2SMark Murray  * precede the key to provide identification of the key without needing a
41511b41d2SMark Murray  * passphrase.
42511b41d2SMark Murray  */
43511b41d2SMark Murray 
44511b41d2SMark Murray int
45e8aafc91SKris Kennaway save_private_key_rsa(const char *filename, const char *passphrase,
46511b41d2SMark Murray     RSA *key, const char *comment)
47511b41d2SMark Murray {
48511b41d2SMark Murray 	Buffer buffer, encrypted;
49511b41d2SMark Murray 	char buf[100], *cp;
50511b41d2SMark Murray 	int fd, i;
51511b41d2SMark Murray 	CipherContext cipher;
52511b41d2SMark Murray 	int cipher_type;
53511b41d2SMark Murray 	u_int32_t rand;
54511b41d2SMark Murray 
55511b41d2SMark Murray 	/*
56511b41d2SMark Murray 	 * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting
57511b41d2SMark Murray 	 * to another cipher; otherwise use SSH_AUTHFILE_CIPHER.
58511b41d2SMark Murray 	 */
59511b41d2SMark Murray 	if (strcmp(passphrase, "") == 0)
60511b41d2SMark Murray 		cipher_type = SSH_CIPHER_NONE;
61511b41d2SMark Murray 	else
62511b41d2SMark Murray 		cipher_type = SSH_AUTHFILE_CIPHER;
63511b41d2SMark Murray 
64511b41d2SMark Murray 	/* This buffer is used to built the secret part of the private key. */
65511b41d2SMark Murray 	buffer_init(&buffer);
66511b41d2SMark Murray 
67511b41d2SMark Murray 	/* Put checkbytes for checking passphrase validity. */
68511b41d2SMark Murray 	rand = arc4random();
69511b41d2SMark Murray 	buf[0] = rand & 0xff;
70511b41d2SMark Murray 	buf[1] = (rand >> 8) & 0xff;
71511b41d2SMark Murray 	buf[2] = buf[0];
72511b41d2SMark Murray 	buf[3] = buf[1];
73511b41d2SMark Murray 	buffer_append(&buffer, buf, 4);
74511b41d2SMark Murray 
75511b41d2SMark Murray 	/*
76511b41d2SMark Murray 	 * Store the private key (n and e will not be stored because they
77511b41d2SMark Murray 	 * will be stored in plain text, and storing them also in encrypted
78511b41d2SMark Murray 	 * format would just give known plaintext).
79511b41d2SMark Murray 	 */
80511b41d2SMark Murray 	buffer_put_bignum(&buffer, key->d);
81511b41d2SMark Murray 	buffer_put_bignum(&buffer, key->iqmp);
82511b41d2SMark Murray 	buffer_put_bignum(&buffer, key->q);	/* reverse from SSL p */
83511b41d2SMark Murray 	buffer_put_bignum(&buffer, key->p);	/* reverse from SSL q */
84511b41d2SMark Murray 
85511b41d2SMark Murray 	/* Pad the part to be encrypted until its size is a multiple of 8. */
86511b41d2SMark Murray 	while (buffer_len(&buffer) % 8 != 0)
87511b41d2SMark Murray 		buffer_put_char(&buffer, 0);
88511b41d2SMark Murray 
89511b41d2SMark Murray 	/* This buffer will be used to contain the data in the file. */
90511b41d2SMark Murray 	buffer_init(&encrypted);
91511b41d2SMark Murray 
92511b41d2SMark Murray 	/* First store keyfile id string. */
93511b41d2SMark Murray 	cp = AUTHFILE_ID_STRING;
94511b41d2SMark Murray 	for (i = 0; cp[i]; i++)
95511b41d2SMark Murray 		buffer_put_char(&encrypted, cp[i]);
96511b41d2SMark Murray 	buffer_put_char(&encrypted, 0);
97511b41d2SMark Murray 
98511b41d2SMark Murray 	/* Store cipher type. */
99511b41d2SMark Murray 	buffer_put_char(&encrypted, cipher_type);
100511b41d2SMark Murray 	buffer_put_int(&encrypted, 0);	/* For future extension */
101511b41d2SMark Murray 
102511b41d2SMark Murray 	/* Store public key.  This will be in plain text. */
103511b41d2SMark Murray 	buffer_put_int(&encrypted, BN_num_bits(key->n));
104511b41d2SMark Murray 	buffer_put_bignum(&encrypted, key->n);
105511b41d2SMark Murray 	buffer_put_bignum(&encrypted, key->e);
106511b41d2SMark Murray 	buffer_put_string(&encrypted, comment, strlen(comment));
107511b41d2SMark Murray 
108511b41d2SMark Murray 	/* Allocate space for the private part of the key in the buffer. */
109511b41d2SMark Murray 	buffer_append_space(&encrypted, &cp, buffer_len(&buffer));
110511b41d2SMark Murray 
111e8aafc91SKris Kennaway 	cipher_set_key_string(&cipher, cipher_type, passphrase);
112511b41d2SMark Murray 	cipher_encrypt(&cipher, (unsigned char *) cp,
113511b41d2SMark Murray 		       (unsigned char *) buffer_ptr(&buffer),
114511b41d2SMark Murray 		       buffer_len(&buffer));
115511b41d2SMark Murray 	memset(&cipher, 0, sizeof(cipher));
116511b41d2SMark Murray 
117511b41d2SMark Murray 	/* Destroy temporary data. */
118511b41d2SMark Murray 	memset(buf, 0, sizeof(buf));
119511b41d2SMark Murray 	buffer_free(&buffer);
120511b41d2SMark Murray 
121511b41d2SMark Murray 	fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
122511b41d2SMark Murray 	if (fd < 0)
123511b41d2SMark Murray 		return 0;
124511b41d2SMark Murray 	if (write(fd, buffer_ptr(&encrypted), buffer_len(&encrypted)) !=
125511b41d2SMark Murray 	    buffer_len(&encrypted)) {
126511b41d2SMark Murray 		debug("Write to key file %.200s failed: %.100s", filename,
127511b41d2SMark Murray 		      strerror(errno));
128511b41d2SMark Murray 		buffer_free(&encrypted);
129511b41d2SMark Murray 		close(fd);
130511b41d2SMark Murray 		remove(filename);
131511b41d2SMark Murray 		return 0;
132511b41d2SMark Murray 	}
133511b41d2SMark Murray 	close(fd);
134511b41d2SMark Murray 	buffer_free(&encrypted);
135511b41d2SMark Murray 	return 1;
136511b41d2SMark Murray }
137511b41d2SMark Murray 
138e8aafc91SKris Kennaway /* save DSA key in OpenSSL PEM format */
139e8aafc91SKris Kennaway 
140e8aafc91SKris Kennaway int
141e8aafc91SKris Kennaway save_private_key_dsa(const char *filename, const char *passphrase,
142e8aafc91SKris Kennaway     DSA *dsa, const char *comment)
143e8aafc91SKris Kennaway {
144e8aafc91SKris Kennaway 	FILE *fp;
145e8aafc91SKris Kennaway 	int fd;
146e8aafc91SKris Kennaway 	int success = 1;
147e8aafc91SKris Kennaway 	int len = strlen(passphrase);
148e8aafc91SKris Kennaway 
149e8aafc91SKris Kennaway 	if (len > 0 && len <= 4) {
150e8aafc91SKris Kennaway 		error("passphrase too short: %d bytes", len);
151e8aafc91SKris Kennaway 		errno = 0;
152e8aafc91SKris Kennaway 		return 0;
153e8aafc91SKris Kennaway 	}
154e8aafc91SKris Kennaway 	fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
155e8aafc91SKris Kennaway 	if (fd < 0) {
156e8aafc91SKris Kennaway 		debug("open %s failed", filename);
157e8aafc91SKris Kennaway 		return 0;
158e8aafc91SKris Kennaway 	}
159e8aafc91SKris Kennaway 	fp = fdopen(fd, "w");
160e8aafc91SKris Kennaway 	if (fp == NULL ) {
161e8aafc91SKris Kennaway 		debug("fdopen %s failed", filename);
162e8aafc91SKris Kennaway 		close(fd);
163e8aafc91SKris Kennaway 		return 0;
164e8aafc91SKris Kennaway 	}
165e8aafc91SKris Kennaway 	if (len > 0) {
166e8aafc91SKris Kennaway 		if (!PEM_write_DSAPrivateKey(fp, dsa, EVP_des_ede3_cbc(),
167e8aafc91SKris Kennaway 		    (char *)passphrase, strlen(passphrase), NULL, NULL))
168e8aafc91SKris Kennaway 			success = 0;
169e8aafc91SKris Kennaway 	} else {
170e8aafc91SKris Kennaway 		if (!PEM_write_DSAPrivateKey(fp, dsa, NULL,
171e8aafc91SKris Kennaway 		    NULL, 0, NULL, NULL))
172e8aafc91SKris Kennaway 			success = 0;
173e8aafc91SKris Kennaway 	}
174e8aafc91SKris Kennaway 	fclose(fp);
175e8aafc91SKris Kennaway 	return success;
176e8aafc91SKris Kennaway }
177e8aafc91SKris Kennaway 
178e8aafc91SKris Kennaway int
179e8aafc91SKris Kennaway save_private_key(const char *filename, const char *passphrase, Key *key,
180e8aafc91SKris Kennaway     const char *comment)
181e8aafc91SKris Kennaway {
182e8aafc91SKris Kennaway 	switch (key->type) {
183e8aafc91SKris Kennaway 	case KEY_RSA:
184e8aafc91SKris Kennaway 		return save_private_key_rsa(filename, passphrase, key->rsa, comment);
185e8aafc91SKris Kennaway 		break;
186e8aafc91SKris Kennaway 	case KEY_DSA:
187e8aafc91SKris Kennaway 		return save_private_key_dsa(filename, passphrase, key->dsa, comment);
188e8aafc91SKris Kennaway 		break;
189e8aafc91SKris Kennaway 	default:
190e8aafc91SKris Kennaway 		break;
191e8aafc91SKris Kennaway 	}
192e8aafc91SKris Kennaway 	return 0;
193e8aafc91SKris Kennaway }
194e8aafc91SKris Kennaway 
195511b41d2SMark Murray /*
196511b41d2SMark Murray  * Loads the public part of the key file.  Returns 0 if an error was
197511b41d2SMark Murray  * encountered (the file does not exist or is not readable), and non-zero
198511b41d2SMark Murray  * otherwise.
199511b41d2SMark Murray  */
200511b41d2SMark Murray 
201511b41d2SMark Murray int
202e8aafc91SKris Kennaway load_public_key_rsa(const char *filename, RSA * pub, char **comment_return)
203511b41d2SMark Murray {
204511b41d2SMark Murray 	int fd, i;
205511b41d2SMark Murray 	off_t len;
206511b41d2SMark Murray 	Buffer buffer;
207511b41d2SMark Murray 	char *cp;
208511b41d2SMark Murray 
209511b41d2SMark Murray 	fd = open(filename, O_RDONLY);
210511b41d2SMark Murray 	if (fd < 0)
211511b41d2SMark Murray 		return 0;
212511b41d2SMark Murray 	len = lseek(fd, (off_t) 0, SEEK_END);
213511b41d2SMark Murray 	lseek(fd, (off_t) 0, SEEK_SET);
214511b41d2SMark Murray 
215511b41d2SMark Murray 	buffer_init(&buffer);
216511b41d2SMark Murray 	buffer_append_space(&buffer, &cp, len);
217511b41d2SMark Murray 
218511b41d2SMark Murray 	if (read(fd, cp, (size_t) len) != (size_t) len) {
219511b41d2SMark Murray 		debug("Read from key file %.200s failed: %.100s", filename,
220511b41d2SMark Murray 		    strerror(errno));
221511b41d2SMark Murray 		buffer_free(&buffer);
222511b41d2SMark Murray 		close(fd);
223511b41d2SMark Murray 		return 0;
224511b41d2SMark Murray 	}
225511b41d2SMark Murray 	close(fd);
226511b41d2SMark Murray 
227511b41d2SMark Murray 	/* Check that it is at least big enought to contain the ID string. */
228511b41d2SMark Murray 	if (len < strlen(AUTHFILE_ID_STRING) + 1) {
229511b41d2SMark Murray 		debug("Bad key file %.200s.", filename);
230511b41d2SMark Murray 		buffer_free(&buffer);
231511b41d2SMark Murray 		return 0;
232511b41d2SMark Murray 	}
233511b41d2SMark Murray 	/*
234511b41d2SMark Murray 	 * Make sure it begins with the id string.  Consume the id string
235511b41d2SMark Murray 	 * from the buffer.
236511b41d2SMark Murray 	 */
237511b41d2SMark Murray 	for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++)
238511b41d2SMark Murray 		if (buffer_get_char(&buffer) != (u_char) AUTHFILE_ID_STRING[i]) {
239511b41d2SMark Murray 			debug("Bad key file %.200s.", filename);
240511b41d2SMark Murray 			buffer_free(&buffer);
241511b41d2SMark Murray 			return 0;
242511b41d2SMark Murray 		}
243511b41d2SMark Murray 	/* Skip cipher type and reserved data. */
244511b41d2SMark Murray 	(void) buffer_get_char(&buffer);	/* cipher type */
245511b41d2SMark Murray 	(void) buffer_get_int(&buffer);		/* reserved */
246511b41d2SMark Murray 
247511b41d2SMark Murray 	/* Read the public key from the buffer. */
248511b41d2SMark Murray 	buffer_get_int(&buffer);
249e8aafc91SKris Kennaway 	/* XXX alloc */
250e8aafc91SKris Kennaway 	if (pub->n == NULL)
251511b41d2SMark Murray 		pub->n = BN_new();
252511b41d2SMark Murray 	buffer_get_bignum(&buffer, pub->n);
253e8aafc91SKris Kennaway 	/* XXX alloc */
254e8aafc91SKris Kennaway 	if (pub->e == NULL)
255511b41d2SMark Murray 		pub->e = BN_new();
256511b41d2SMark Murray 	buffer_get_bignum(&buffer, pub->e);
257511b41d2SMark Murray 	if (comment_return)
258511b41d2SMark Murray 		*comment_return = buffer_get_string(&buffer, NULL);
259511b41d2SMark Murray 	/* The encrypted private part is not parsed by this function. */
260511b41d2SMark Murray 
261511b41d2SMark Murray 	buffer_free(&buffer);
262511b41d2SMark Murray 
263511b41d2SMark Murray 	return 1;
264511b41d2SMark Murray }
265511b41d2SMark Murray 
266e8aafc91SKris Kennaway int
267e8aafc91SKris Kennaway load_public_key(const char *filename, Key * key, char **comment_return)
268e8aafc91SKris Kennaway {
269e8aafc91SKris Kennaway 	switch (key->type) {
270e8aafc91SKris Kennaway 	case KEY_RSA:
271e8aafc91SKris Kennaway 		return load_public_key_rsa(filename, key->rsa, comment_return);
272e8aafc91SKris Kennaway 		break;
273e8aafc91SKris Kennaway 	case KEY_DSA:
274e8aafc91SKris Kennaway 	default:
275e8aafc91SKris Kennaway 		break;
276e8aafc91SKris Kennaway 	}
277e8aafc91SKris Kennaway 	return 0;
278e8aafc91SKris Kennaway }
279e8aafc91SKris Kennaway 
280511b41d2SMark Murray /*
281511b41d2SMark Murray  * Loads the private key from the file.  Returns 0 if an error is encountered
282511b41d2SMark Murray  * (file does not exist or is not readable, or passphrase is bad). This
283511b41d2SMark Murray  * initializes the private key.
284511b41d2SMark Murray  * Assumes we are called under uid of the owner of the file.
285511b41d2SMark Murray  */
286511b41d2SMark Murray 
287511b41d2SMark Murray int
288e8aafc91SKris Kennaway load_private_key_rsa(int fd, const char *filename,
289e8aafc91SKris Kennaway     const char *passphrase, RSA * prv, char **comment_return)
290511b41d2SMark Murray {
291e8aafc91SKris Kennaway 	int i, check1, check2, cipher_type;
292511b41d2SMark Murray 	off_t len;
293511b41d2SMark Murray 	Buffer buffer, decrypted;
294511b41d2SMark Murray 	char *cp;
295511b41d2SMark Murray 	CipherContext cipher;
296511b41d2SMark Murray 	BN_CTX *ctx;
297511b41d2SMark Murray 	BIGNUM *aux;
298511b41d2SMark Murray 
299511b41d2SMark Murray 	len = lseek(fd, (off_t) 0, SEEK_END);
300511b41d2SMark Murray 	lseek(fd, (off_t) 0, SEEK_SET);
301511b41d2SMark Murray 
302511b41d2SMark Murray 	buffer_init(&buffer);
303511b41d2SMark Murray 	buffer_append_space(&buffer, &cp, len);
304511b41d2SMark Murray 
305511b41d2SMark Murray 	if (read(fd, cp, (size_t) len) != (size_t) len) {
306511b41d2SMark Murray 		debug("Read from key file %.200s failed: %.100s", filename,
307511b41d2SMark Murray 		      strerror(errno));
308511b41d2SMark Murray 		buffer_free(&buffer);
309511b41d2SMark Murray 		close(fd);
310511b41d2SMark Murray 		return 0;
311511b41d2SMark Murray 	}
312511b41d2SMark Murray 	close(fd);
313511b41d2SMark Murray 
314511b41d2SMark Murray 	/* Check that it is at least big enought to contain the ID string. */
315511b41d2SMark Murray 	if (len < strlen(AUTHFILE_ID_STRING) + 1) {
316511b41d2SMark Murray 		debug("Bad key file %.200s.", filename);
317511b41d2SMark Murray 		buffer_free(&buffer);
318511b41d2SMark Murray 		return 0;
319511b41d2SMark Murray 	}
320511b41d2SMark Murray 	/*
321511b41d2SMark Murray 	 * Make sure it begins with the id string.  Consume the id string
322511b41d2SMark Murray 	 * from the buffer.
323511b41d2SMark Murray 	 */
324511b41d2SMark Murray 	for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++)
325511b41d2SMark Murray 		if (buffer_get_char(&buffer) != (unsigned char) AUTHFILE_ID_STRING[i]) {
326511b41d2SMark Murray 			debug("Bad key file %.200s.", filename);
327511b41d2SMark Murray 			buffer_free(&buffer);
328511b41d2SMark Murray 			return 0;
329511b41d2SMark Murray 		}
330511b41d2SMark Murray 	/* Read cipher type. */
331511b41d2SMark Murray 	cipher_type = buffer_get_char(&buffer);
332511b41d2SMark Murray 	(void) buffer_get_int(&buffer);	/* Reserved data. */
333511b41d2SMark Murray 
334511b41d2SMark Murray 	/* Read the public key from the buffer. */
335511b41d2SMark Murray 	buffer_get_int(&buffer);
336511b41d2SMark Murray 	prv->n = BN_new();
337511b41d2SMark Murray 	buffer_get_bignum(&buffer, prv->n);
338511b41d2SMark Murray 	prv->e = BN_new();
339511b41d2SMark Murray 	buffer_get_bignum(&buffer, prv->e);
340511b41d2SMark Murray 	if (comment_return)
341511b41d2SMark Murray 		*comment_return = buffer_get_string(&buffer, NULL);
342511b41d2SMark Murray 	else
343511b41d2SMark Murray 		xfree(buffer_get_string(&buffer, NULL));
344511b41d2SMark Murray 
345511b41d2SMark Murray 	/* Check that it is a supported cipher. */
346e8aafc91SKris Kennaway 	if (((cipher_mask1() | SSH_CIPHER_NONE | SSH_AUTHFILE_CIPHER) &
347511b41d2SMark Murray 	     (1 << cipher_type)) == 0) {
348511b41d2SMark Murray 		debug("Unsupported cipher %.100s used in key file %.200s.",
349511b41d2SMark Murray 		      cipher_name(cipher_type), filename);
350511b41d2SMark Murray 		buffer_free(&buffer);
351511b41d2SMark Murray 		goto fail;
352511b41d2SMark Murray 	}
353511b41d2SMark Murray 	/* Initialize space for decrypted data. */
354511b41d2SMark Murray 	buffer_init(&decrypted);
355511b41d2SMark Murray 	buffer_append_space(&decrypted, &cp, buffer_len(&buffer));
356511b41d2SMark Murray 
357511b41d2SMark Murray 	/* Rest of the buffer is encrypted.  Decrypt it using the passphrase. */
358e8aafc91SKris Kennaway 	cipher_set_key_string(&cipher, cipher_type, passphrase);
359511b41d2SMark Murray 	cipher_decrypt(&cipher, (unsigned char *) cp,
360511b41d2SMark Murray 		       (unsigned char *) buffer_ptr(&buffer),
361511b41d2SMark Murray 		       buffer_len(&buffer));
362511b41d2SMark Murray 
363511b41d2SMark Murray 	buffer_free(&buffer);
364511b41d2SMark Murray 
365511b41d2SMark Murray 	check1 = buffer_get_char(&decrypted);
366511b41d2SMark Murray 	check2 = buffer_get_char(&decrypted);
367511b41d2SMark Murray 	if (check1 != buffer_get_char(&decrypted) ||
368511b41d2SMark Murray 	    check2 != buffer_get_char(&decrypted)) {
369511b41d2SMark Murray 		if (strcmp(passphrase, "") != 0)
370511b41d2SMark Murray 			debug("Bad passphrase supplied for key file %.200s.", filename);
371511b41d2SMark Murray 		/* Bad passphrase. */
372511b41d2SMark Murray 		buffer_free(&decrypted);
373511b41d2SMark Murray fail:
374511b41d2SMark Murray 		BN_clear_free(prv->n);
375e8aafc91SKris Kennaway 		prv->n = NULL;
376511b41d2SMark Murray 		BN_clear_free(prv->e);
377e8aafc91SKris Kennaway 		prv->e = NULL;
378511b41d2SMark Murray 		if (comment_return)
379511b41d2SMark Murray 			xfree(*comment_return);
380511b41d2SMark Murray 		return 0;
381511b41d2SMark Murray 	}
382511b41d2SMark Murray 	/* Read the rest of the private key. */
383511b41d2SMark Murray 	prv->d = BN_new();
384511b41d2SMark Murray 	buffer_get_bignum(&decrypted, prv->d);
385511b41d2SMark Murray 	prv->iqmp = BN_new();
386511b41d2SMark Murray 	buffer_get_bignum(&decrypted, prv->iqmp);	/* u */
387511b41d2SMark Murray 	/* in SSL and SSH p and q are exchanged */
388511b41d2SMark Murray 	prv->q = BN_new();
389511b41d2SMark Murray 	buffer_get_bignum(&decrypted, prv->q);		/* p */
390511b41d2SMark Murray 	prv->p = BN_new();
391511b41d2SMark Murray 	buffer_get_bignum(&decrypted, prv->p);		/* q */
392511b41d2SMark Murray 
393511b41d2SMark Murray 	ctx = BN_CTX_new();
394511b41d2SMark Murray 	aux = BN_new();
395511b41d2SMark Murray 
396511b41d2SMark Murray 	BN_sub(aux, prv->q, BN_value_one());
397511b41d2SMark Murray 	prv->dmq1 = BN_new();
398511b41d2SMark Murray 	BN_mod(prv->dmq1, prv->d, aux, ctx);
399511b41d2SMark Murray 
400511b41d2SMark Murray 	BN_sub(aux, prv->p, BN_value_one());
401511b41d2SMark Murray 	prv->dmp1 = BN_new();
402511b41d2SMark Murray 	BN_mod(prv->dmp1, prv->d, aux, ctx);
403511b41d2SMark Murray 
404511b41d2SMark Murray 	BN_clear_free(aux);
405511b41d2SMark Murray 	BN_CTX_free(ctx);
406511b41d2SMark Murray 
407511b41d2SMark Murray 	buffer_free(&decrypted);
408511b41d2SMark Murray 
409511b41d2SMark Murray 	return 1;
410511b41d2SMark Murray }
411e8aafc91SKris Kennaway 
412e8aafc91SKris Kennaway int
413e8aafc91SKris Kennaway load_private_key_dsa(int fd, const char *passphrase, Key *k, char **comment_return)
414e8aafc91SKris Kennaway {
415e8aafc91SKris Kennaway 	DSA *dsa;
416e8aafc91SKris Kennaway 	BIO *in;
417e8aafc91SKris Kennaway 	FILE *fp;
418e8aafc91SKris Kennaway 
419e8aafc91SKris Kennaway 	in = BIO_new(BIO_s_file());
420e8aafc91SKris Kennaway 	if (in == NULL) {
421e8aafc91SKris Kennaway 		error("BIO_new failed");
422e8aafc91SKris Kennaway 		return 0;
423e8aafc91SKris Kennaway 	}
424e8aafc91SKris Kennaway 	fp = fdopen(fd, "r");
425e8aafc91SKris Kennaway 	if (fp == NULL) {
426e8aafc91SKris Kennaway 		error("fdopen failed");
427e8aafc91SKris Kennaway 		return 0;
428e8aafc91SKris Kennaway 	}
429e8aafc91SKris Kennaway 	BIO_set_fp(in, fp, BIO_NOCLOSE);
430e8aafc91SKris Kennaway 	dsa = PEM_read_bio_DSAPrivateKey(in, NULL, NULL, (char *)passphrase);
431e8aafc91SKris Kennaway 	if (dsa == NULL) {
432e8aafc91SKris Kennaway 		debug("PEM_read_bio_DSAPrivateKey failed");
433e8aafc91SKris Kennaway 	} else {
434e8aafc91SKris Kennaway 		/* replace k->dsa with loaded key */
435e8aafc91SKris Kennaway 		DSA_free(k->dsa);
436e8aafc91SKris Kennaway 		k->dsa = dsa;
437e8aafc91SKris Kennaway 	}
438e8aafc91SKris Kennaway 	BIO_free(in);
439e8aafc91SKris Kennaway 	fclose(fp);
440e8aafc91SKris Kennaway 	if (comment_return)
441e8aafc91SKris Kennaway 		*comment_return = xstrdup("dsa w/o comment");
442e8aafc91SKris Kennaway 	debug("read DSA private key done");
443e8aafc91SKris Kennaway #ifdef DEBUG_DSS
444e8aafc91SKris Kennaway 	DSA_print_fp(stderr, dsa, 8);
445e8aafc91SKris Kennaway #endif
446e8aafc91SKris Kennaway 	return dsa != NULL ? 1 : 0;
447e8aafc91SKris Kennaway }
448e8aafc91SKris Kennaway 
449e8aafc91SKris Kennaway int
450e8aafc91SKris Kennaway load_private_key(const char *filename, const char *passphrase, Key *key,
451e8aafc91SKris Kennaway     char **comment_return)
452e8aafc91SKris Kennaway {
453e8aafc91SKris Kennaway 	int fd;
454e8aafc91SKris Kennaway 	int ret = 0;
455e8aafc91SKris Kennaway 	struct stat st;
456e8aafc91SKris Kennaway 
457e8aafc91SKris Kennaway 	fd = open(filename, O_RDONLY);
458e8aafc91SKris Kennaway 	if (fd < 0)
459e8aafc91SKris Kennaway 		return 0;
460e8aafc91SKris Kennaway 
461e8aafc91SKris Kennaway 	/* check owner and modes */
462e8aafc91SKris Kennaway 	if (fstat(fd, &st) < 0 ||
463e8aafc91SKris Kennaway 	    (st.st_uid != 0 && st.st_uid != getuid()) ||
464e8aafc91SKris Kennaway 	    (st.st_mode & 077) != 0) {
465e8aafc91SKris Kennaway 		close(fd);
466e8aafc91SKris Kennaway 		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
467e8aafc91SKris Kennaway 		error("@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @");
468e8aafc91SKris Kennaway 		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
469e8aafc91SKris Kennaway 		error("Bad ownership or mode(0%3.3o) for '%s'.",
470e8aafc91SKris Kennaway 		      st.st_mode & 0777, filename);
471e8aafc91SKris Kennaway 		error("It is recommended that your private key files are NOT accessible by others.");
472e8aafc91SKris Kennaway 		return 0;
473e8aafc91SKris Kennaway 	}
474e8aafc91SKris Kennaway 	switch (key->type) {
475e8aafc91SKris Kennaway 	case KEY_RSA:
476e8aafc91SKris Kennaway 		if (key->rsa->e != NULL) {
477e8aafc91SKris Kennaway 			BN_clear_free(key->rsa->e);
478e8aafc91SKris Kennaway 			key->rsa->e = NULL;
479e8aafc91SKris Kennaway 		}
480e8aafc91SKris Kennaway 		if (key->rsa->n != NULL) {
481e8aafc91SKris Kennaway 			BN_clear_free(key->rsa->n);
482e8aafc91SKris Kennaway 			key->rsa->n = NULL;
483e8aafc91SKris Kennaway 		}
484e8aafc91SKris Kennaway 		ret = load_private_key_rsa(fd, filename, passphrase,
485e8aafc91SKris Kennaway 		     key->rsa, comment_return);
486e8aafc91SKris Kennaway 		break;
487e8aafc91SKris Kennaway 	case KEY_DSA:
488e8aafc91SKris Kennaway 		ret = load_private_key_dsa(fd, passphrase, key, comment_return);
489e8aafc91SKris Kennaway 	default:
490e8aafc91SKris Kennaway 		break;
491e8aafc91SKris Kennaway 	}
492e8aafc91SKris Kennaway 	close(fd);
493e8aafc91SKris Kennaway 	return ret;
494e8aafc91SKris Kennaway }
495