key.c revision 69591
1/*
2 * read_bignum():
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 *
5 * As far as I am concerned, the code I have written for this software
6 * can be used freely for any purpose.  Any derived versions of this
7 * software must be clearly marked as such, and if the derived work is
8 * incompatible with the protocol description in the RFC file, it must be
9 * called by a name other than "ssh" or "Secure Shell".
10 *
11 *
12 * Copyright (c) 2000 Markus Friedl.  All rights reserved.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 *    notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 *    notice, this list of conditions and the following disclaimer in the
21 *    documentation and/or other materials provided with the distribution.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#include "includes.h"
36#include "ssh.h"
37#include <openssl/rsa.h>
38#include <openssl/dsa.h>
39#include <openssl/evp.h>
40#include "xmalloc.h"
41#include "key.h"
42#include "dsa.h"
43#include "uuencode.h"
44
45RCSID("$OpenBSD: key.c,v 1.11 2000/09/07 20:27:51 deraadt Exp $");
46RCSID("$FreeBSD: head/crypto/openssh/key.c 65674 2000-09-10 09:35:38Z kris $");
47
48#define SSH_DSS "ssh-dss"
49
50Key *
51key_new(int type)
52{
53	Key *k;
54	RSA *rsa;
55	DSA *dsa;
56	k = xmalloc(sizeof(*k));
57	k->type = type;
58	k->dsa = NULL;
59	k->rsa = NULL;
60	switch (k->type) {
61	case KEY_RSA:
62		rsa = RSA_new();
63		rsa->n = BN_new();
64		rsa->e = BN_new();
65		k->rsa = rsa;
66		break;
67	case KEY_DSA:
68		dsa = DSA_new();
69		dsa->p = BN_new();
70		dsa->q = BN_new();
71		dsa->g = BN_new();
72		dsa->pub_key = BN_new();
73		k->dsa = dsa;
74		break;
75	case KEY_EMPTY:
76		break;
77	default:
78		fatal("key_new: bad key type %d", k->type);
79		break;
80	}
81	return k;
82}
83void
84key_free(Key *k)
85{
86	switch (k->type) {
87	case KEY_RSA:
88		if (k->rsa != NULL)
89			RSA_free(k->rsa);
90		k->rsa = NULL;
91		break;
92	case KEY_DSA:
93		if (k->dsa != NULL)
94			DSA_free(k->dsa);
95		k->dsa = NULL;
96		break;
97	default:
98		fatal("key_free: bad key type %d", k->type);
99		break;
100	}
101	xfree(k);
102}
103int
104key_equal(Key *a, Key *b)
105{
106	if (a == NULL || b == NULL || a->type != b->type)
107		return 0;
108	switch (a->type) {
109	case KEY_RSA:
110		return a->rsa != NULL && b->rsa != NULL &&
111		    BN_cmp(a->rsa->e, b->rsa->e) == 0 &&
112		    BN_cmp(a->rsa->n, b->rsa->n) == 0;
113		break;
114	case KEY_DSA:
115		return a->dsa != NULL && b->dsa != NULL &&
116		    BN_cmp(a->dsa->p, b->dsa->p) == 0 &&
117		    BN_cmp(a->dsa->q, b->dsa->q) == 0 &&
118		    BN_cmp(a->dsa->g, b->dsa->g) == 0 &&
119		    BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0;
120		break;
121	default:
122		fatal("key_equal: bad key type %d", a->type);
123		break;
124	}
125	return 0;
126}
127
128/*
129 * Generate key fingerprint in ascii format.
130 * Based on ideas and code from Bjoern Groenvall <bg@sics.se>
131 */
132char *
133key_fingerprint(Key *k)
134{
135	static char retval[(EVP_MAX_MD_SIZE+1)*3];
136	unsigned char *blob = NULL;
137	int len = 0;
138	int nlen, elen;
139
140	switch (k->type) {
141	case KEY_RSA:
142		nlen = BN_num_bytes(k->rsa->n);
143		elen = BN_num_bytes(k->rsa->e);
144		len = nlen + elen;
145		blob = xmalloc(len);
146		BN_bn2bin(k->rsa->n, blob);
147		BN_bn2bin(k->rsa->e, blob + nlen);
148		break;
149	case KEY_DSA:
150		dsa_make_key_blob(k, &blob, &len);
151		break;
152	default:
153		fatal("key_fingerprint: bad key type %d", k->type);
154		break;
155	}
156	retval[0] = '\0';
157
158	if (blob != NULL) {
159		int i;
160		unsigned char digest[EVP_MAX_MD_SIZE];
161		EVP_MD *md = EVP_md5();
162		EVP_MD_CTX ctx;
163		EVP_DigestInit(&ctx, md);
164		EVP_DigestUpdate(&ctx, blob, len);
165		EVP_DigestFinal(&ctx, digest, NULL);
166		for(i = 0; i < md->md_size; i++) {
167			char hex[4];
168			snprintf(hex, sizeof(hex), "%02x:", digest[i]);
169			strlcat(retval, hex, sizeof(retval));
170		}
171		retval[strlen(retval) - 1] = '\0';
172		memset(blob, 0, len);
173		xfree(blob);
174	}
175	return retval;
176}
177
178/*
179 * Reads a multiple-precision integer in decimal from the buffer, and advances
180 * the pointer.  The integer must already be initialized.  This function is
181 * permitted to modify the buffer.  This leaves *cpp to point just beyond the
182 * last processed (and maybe modified) character.  Note that this may modify
183 * the buffer containing the number.
184 */
185int
186read_bignum(char **cpp, BIGNUM * value)
187{
188	char *cp = *cpp;
189	int old;
190
191	/* Skip any leading whitespace. */
192	for (; *cp == ' ' || *cp == '\t'; cp++)
193		;
194
195	/* Check that it begins with a decimal digit. */
196	if (*cp < '0' || *cp > '9')
197		return 0;
198
199	/* Save starting position. */
200	*cpp = cp;
201
202	/* Move forward until all decimal digits skipped. */
203	for (; *cp >= '0' && *cp <= '9'; cp++)
204		;
205
206	/* Save the old terminating character, and replace it by \0. */
207	old = *cp;
208	*cp = 0;
209
210	/* Parse the number. */
211	if (BN_dec2bn(&value, *cpp) == 0)
212		return 0;
213
214	/* Restore old terminating character. */
215	*cp = old;
216
217	/* Move beyond the number and return success. */
218	*cpp = cp;
219	return 1;
220}
221int
222write_bignum(FILE *f, BIGNUM *num)
223{
224	char *buf = BN_bn2dec(num);
225	if (buf == NULL) {
226		error("write_bignum: BN_bn2dec() failed");
227		return 0;
228	}
229	fprintf(f, " %s", buf);
230	free(buf);
231	return 1;
232}
233unsigned int
234key_read(Key *ret, char **cpp)
235{
236	Key *k;
237	unsigned int bits = 0;
238	char *cp;
239	int len, n;
240	unsigned char *blob;
241
242	cp = *cpp;
243
244	switch(ret->type) {
245	case KEY_RSA:
246		/* Get number of bits. */
247		if (*cp < '0' || *cp > '9')
248			return 0;	/* Bad bit count... */
249		for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
250			bits = 10 * bits + *cp - '0';
251		if (bits == 0)
252			return 0;
253		*cpp = cp;
254		/* Get public exponent, public modulus. */
255		if (!read_bignum(cpp, ret->rsa->e))
256			return 0;
257		if (!read_bignum(cpp, ret->rsa->n))
258			return 0;
259		break;
260	case KEY_DSA:
261		if (strncmp(cp, SSH_DSS " ", 7) != 0)
262			return 0;
263		cp += 7;
264		len = 2*strlen(cp);
265		blob = xmalloc(len);
266		n = uudecode(cp, blob, len);
267		if (n < 0) {
268			error("key_read: uudecode %s failed", cp);
269			return 0;
270		}
271		k = dsa_key_from_blob(blob, n);
272		if (k == NULL) {
273			error("key_read: dsa_key_from_blob %s failed", cp);
274			return 0;
275		}
276		xfree(blob);
277		if (ret->dsa != NULL)
278			DSA_free(ret->dsa);
279		ret->dsa = k->dsa;
280		k->dsa = NULL;
281		key_free(k);
282		bits = BN_num_bits(ret->dsa->p);
283		/* advance cp: skip whitespace and data */
284		while (*cp == ' ' || *cp == '\t')
285			cp++;
286		while (*cp != '\0' && *cp != ' ' && *cp != '\t')
287			cp++;
288		*cpp = cp;
289		break;
290	default:
291		fatal("key_read: bad key type: %d", ret->type);
292		break;
293	}
294	return bits;
295}
296int
297key_write(Key *key, FILE *f)
298{
299	int success = 0;
300	unsigned int bits = 0;
301
302	if (key->type == KEY_RSA && key->rsa != NULL) {
303		/* size of modulus 'n' */
304		bits = BN_num_bits(key->rsa->n);
305		fprintf(f, "%u", bits);
306		if (write_bignum(f, key->rsa->e) &&
307		    write_bignum(f, key->rsa->n)) {
308			success = 1;
309		} else {
310			error("key_write: failed for RSA key");
311		}
312	} else if (key->type == KEY_DSA && key->dsa != NULL) {
313		int len, n;
314		unsigned char *blob, *uu;
315		dsa_make_key_blob(key, &blob, &len);
316		uu = xmalloc(2*len);
317		n = uuencode(blob, len, uu, 2*len);
318		if (n > 0) {
319			fprintf(f, "%s %s", SSH_DSS, uu);
320			success = 1;
321		}
322		xfree(blob);
323		xfree(uu);
324	}
325	return success;
326}
327char *
328key_type(Key *k)
329{
330	switch (k->type) {
331	case KEY_RSA:
332		return "RSA";
333		break;
334	case KEY_DSA:
335		return "DSA";
336		break;
337	}
338	return "unknown";
339}
340unsigned int
341key_size(Key *k){
342	switch (k->type) {
343	case KEY_RSA:
344		return BN_num_bits(k->rsa->n);
345		break;
346	case KEY_DSA:
347		return BN_num_bits(k->dsa->p);
348		break;
349	}
350	return 0;
351}
352