blob: 764f1f227fbba1c818348ba009632354dfa73b23 [file] [log] [blame]
Damien Miller450a7a12000-03-26 13:04:51 +10001/*
2 * Copyright (c) 2000 Markus Friedl. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. All advertising materials mentioning features or use of this software
13 * must display the following acknowledgement:
14 * This product includes software developed by Markus Friedl.
15 * 4. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29/*
30 * read_bignum():
31 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
32 */
33
34#include "includes.h"
Damien Miller5f056372000-04-16 12:31:48 +100035#include "ssh.h"
Damien Miller450a7a12000-03-26 13:04:51 +100036#include <openssl/rsa.h>
37#include <openssl/dsa.h>
38#include <openssl/evp.h>
Damien Miller450a7a12000-03-26 13:04:51 +100039#include "xmalloc.h"
40#include "key.h"
Damien Millereba71ba2000-04-29 23:57:08 +100041#include "dsa.h"
42#include "uuencode.h"
43
Damien Millerbf7f4662000-06-23 10:16:38 +100044RCSID("$OpenBSD: key.c,v 1.9 2000/06/22 23:55:00 djm Exp $");
45
Damien Millereba71ba2000-04-29 23:57:08 +100046#define SSH_DSS "ssh-dss"
Damien Miller450a7a12000-03-26 13:04:51 +100047
48Key *
49key_new(int type)
50{
51 Key *k;
52 RSA *rsa;
53 DSA *dsa;
54 k = xmalloc(sizeof(*k));
55 k->type = type;
Damien Millereba71ba2000-04-29 23:57:08 +100056 k->dsa = NULL;
57 k->rsa = NULL;
Damien Miller450a7a12000-03-26 13:04:51 +100058 switch (k->type) {
59 case KEY_RSA:
60 rsa = RSA_new();
61 rsa->n = BN_new();
62 rsa->e = BN_new();
63 k->rsa = rsa;
64 break;
65 case KEY_DSA:
66 dsa = DSA_new();
67 dsa->p = BN_new();
68 dsa->q = BN_new();
69 dsa->g = BN_new();
70 dsa->pub_key = BN_new();
71 k->dsa = dsa;
72 break;
73 case KEY_EMPTY:
Damien Miller450a7a12000-03-26 13:04:51 +100074 break;
75 default:
76 fatal("key_new: bad key type %d", k->type);
77 break;
78 }
79 return k;
80}
81void
82key_free(Key *k)
83{
84 switch (k->type) {
85 case KEY_RSA:
86 if (k->rsa != NULL)
87 RSA_free(k->rsa);
88 k->rsa = NULL;
89 break;
90 case KEY_DSA:
91 if (k->dsa != NULL)
92 DSA_free(k->dsa);
93 k->dsa = NULL;
94 break;
95 default:
96 fatal("key_free: bad key type %d", k->type);
97 break;
98 }
99 xfree(k);
100}
101int
102key_equal(Key *a, Key *b)
103{
104 if (a == NULL || b == NULL || a->type != b->type)
105 return 0;
106 switch (a->type) {
107 case KEY_RSA:
108 return a->rsa != NULL && b->rsa != NULL &&
109 BN_cmp(a->rsa->e, b->rsa->e) == 0 &&
110 BN_cmp(a->rsa->n, b->rsa->n) == 0;
111 break;
112 case KEY_DSA:
113 return a->dsa != NULL && b->dsa != NULL &&
114 BN_cmp(a->dsa->p, b->dsa->p) == 0 &&
115 BN_cmp(a->dsa->q, b->dsa->q) == 0 &&
116 BN_cmp(a->dsa->g, b->dsa->g) == 0 &&
117 BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0;
118 break;
119 default:
Damien Millereba71ba2000-04-29 23:57:08 +1000120 fatal("key_equal: bad key type %d", a->type);
Damien Miller450a7a12000-03-26 13:04:51 +1000121 break;
122 }
123 return 0;
124}
125
Damien Miller450a7a12000-03-26 13:04:51 +1000126/*
127 * Generate key fingerprint in ascii format.
128 * Based on ideas and code from Bjoern Groenvall <bg@sics.se>
129 */
130char *
131key_fingerprint(Key *k)
132{
Damien Miller6536c7d2000-06-22 21:32:31 +1000133 static char retval[(EVP_MAX_MD_SIZE+1)*3];
Damien Millereba71ba2000-04-29 23:57:08 +1000134 unsigned char *blob = NULL;
Damien Miller450a7a12000-03-26 13:04:51 +1000135 int len = 0;
Damien Millereba71ba2000-04-29 23:57:08 +1000136 int nlen, elen;
Damien Miller450a7a12000-03-26 13:04:51 +1000137
138 switch (k->type) {
139 case KEY_RSA:
140 nlen = BN_num_bytes(k->rsa->n);
141 elen = BN_num_bytes(k->rsa->e);
142 len = nlen + elen;
Damien Millereba71ba2000-04-29 23:57:08 +1000143 blob = xmalloc(len);
144 BN_bn2bin(k->rsa->n, blob);
145 BN_bn2bin(k->rsa->e, blob + nlen);
Damien Miller450a7a12000-03-26 13:04:51 +1000146 break;
147 case KEY_DSA:
Damien Millereba71ba2000-04-29 23:57:08 +1000148 dsa_make_key_blob(k, &blob, &len);
Damien Miller450a7a12000-03-26 13:04:51 +1000149 break;
150 default:
151 fatal("key_fingerprint: bad key type %d", k->type);
152 break;
153 }
Damien Miller6536c7d2000-06-22 21:32:31 +1000154 retval[0] = '\0';
155
Damien Millereba71ba2000-04-29 23:57:08 +1000156 if (blob != NULL) {
Damien Miller6536c7d2000-06-22 21:32:31 +1000157 int i;
158 unsigned char digest[EVP_MAX_MD_SIZE];
159 EVP_MD *md = EVP_md5();
160 EVP_MD_CTX ctx;
161 EVP_DigestInit(&ctx, md);
162 EVP_DigestUpdate(&ctx, blob, len);
163 EVP_DigestFinal(&ctx, digest, NULL);
164 for(i = 0; i < md->md_size; i++) {
165 char hex[4];
166 snprintf(hex, sizeof(hex), "%02x:", digest[i]);
167 strlcat(retval, hex, sizeof(retval));
168 }
169 retval[strlen(retval) - 1] = '\0';
Damien Millereba71ba2000-04-29 23:57:08 +1000170 memset(blob, 0, len);
171 xfree(blob);
Damien Miller450a7a12000-03-26 13:04:51 +1000172 }
173 return retval;
174}
175
176/*
177 * Reads a multiple-precision integer in decimal from the buffer, and advances
178 * the pointer. The integer must already be initialized. This function is
179 * permitted to modify the buffer. This leaves *cpp to point just beyond the
180 * last processed (and maybe modified) character. Note that this may modify
181 * the buffer containing the number.
182 */
183int
184read_bignum(char **cpp, BIGNUM * value)
185{
186 char *cp = *cpp;
187 int old;
188
189 /* Skip any leading whitespace. */
190 for (; *cp == ' ' || *cp == '\t'; cp++)
191 ;
192
193 /* Check that it begins with a decimal digit. */
194 if (*cp < '0' || *cp > '9')
195 return 0;
196
197 /* Save starting position. */
198 *cpp = cp;
199
200 /* Move forward until all decimal digits skipped. */
201 for (; *cp >= '0' && *cp <= '9'; cp++)
202 ;
203
204 /* Save the old terminating character, and replace it by \0. */
205 old = *cp;
206 *cp = 0;
207
208 /* Parse the number. */
209 if (BN_dec2bn(&value, *cpp) == 0)
210 return 0;
211
212 /* Restore old terminating character. */
213 *cp = old;
214
215 /* Move beyond the number and return success. */
216 *cpp = cp;
217 return 1;
218}
219int
220write_bignum(FILE *f, BIGNUM *num)
221{
222 char *buf = BN_bn2dec(num);
223 if (buf == NULL) {
224 error("write_bignum: BN_bn2dec() failed");
225 return 0;
226 }
227 fprintf(f, " %s", buf);
228 free(buf);
229 return 1;
230}
Damien Millereba71ba2000-04-29 23:57:08 +1000231unsigned int
232key_read(Key *ret, char **cpp)
Damien Miller450a7a12000-03-26 13:04:51 +1000233{
Damien Millereba71ba2000-04-29 23:57:08 +1000234 Key *k;
235 unsigned int bits = 0;
236 char *cp;
237 int len, n;
238 unsigned char *blob;
239
240 cp = *cpp;
241
Damien Miller450a7a12000-03-26 13:04:51 +1000242 switch(ret->type) {
243 case KEY_RSA:
Damien Millereba71ba2000-04-29 23:57:08 +1000244 /* Get number of bits. */
245 if (*cp < '0' || *cp > '9')
246 return 0; /* Bad bit count... */
247 for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
248 bits = 10 * bits + *cp - '0';
Damien Miller450a7a12000-03-26 13:04:51 +1000249 if (bits == 0)
250 return 0;
Damien Millereba71ba2000-04-29 23:57:08 +1000251 *cpp = cp;
Damien Miller450a7a12000-03-26 13:04:51 +1000252 /* Get public exponent, public modulus. */
253 if (!read_bignum(cpp, ret->rsa->e))
254 return 0;
255 if (!read_bignum(cpp, ret->rsa->n))
256 return 0;
257 break;
258 case KEY_DSA:
Damien Millereba71ba2000-04-29 23:57:08 +1000259 if (strncmp(cp, SSH_DSS " ", 7) != 0)
Damien Miller450a7a12000-03-26 13:04:51 +1000260 return 0;
Damien Millereba71ba2000-04-29 23:57:08 +1000261 cp += 7;
262 len = 2*strlen(cp);
263 blob = xmalloc(len);
264 n = uudecode(cp, blob, len);
Damien Millere247cc42000-05-07 12:03:14 +1000265 if (n < 0) {
Damien Millerb1715dc2000-05-30 13:44:51 +1000266 error("key_read: uudecode %s failed", cp);
Damien Millere247cc42000-05-07 12:03:14 +1000267 return 0;
268 }
Damien Millereba71ba2000-04-29 23:57:08 +1000269 k = dsa_key_from_blob(blob, n);
Damien Millerb1715dc2000-05-30 13:44:51 +1000270 if (k == NULL) {
271 error("key_read: dsa_key_from_blob %s failed", cp);
272 return 0;
273 }
Damien Millereba71ba2000-04-29 23:57:08 +1000274 xfree(blob);
275 if (ret->dsa != NULL)
276 DSA_free(ret->dsa);
277 ret->dsa = k->dsa;
278 k->dsa = NULL;
279 key_free(k);
280 bits = BN_num_bits(ret->dsa->p);
Damien Millerb1715dc2000-05-30 13:44:51 +1000281 /* advance cp: skip whitespace and data */
282 while (*cp == ' ' || *cp == '\t')
283 cp++;
284 while (*cp != '\0' && *cp != ' ' && *cp != '\t')
285 cp++;
286 *cpp = cp;
Damien Miller450a7a12000-03-26 13:04:51 +1000287 break;
288 default:
Damien Millereba71ba2000-04-29 23:57:08 +1000289 fatal("key_read: bad key type: %d", ret->type);
Damien Miller450a7a12000-03-26 13:04:51 +1000290 break;
291 }
Damien Millereba71ba2000-04-29 23:57:08 +1000292 return bits;
Damien Miller450a7a12000-03-26 13:04:51 +1000293}
294int
295key_write(Key *key, FILE *f)
296{
297 int success = 0;
298 unsigned int bits = 0;
299
300 if (key->type == KEY_RSA && key->rsa != NULL) {
301 /* size of modulus 'n' */
302 bits = BN_num_bits(key->rsa->n);
303 fprintf(f, "%u", bits);
304 if (write_bignum(f, key->rsa->e) &&
305 write_bignum(f, key->rsa->n)) {
306 success = 1;
307 } else {
308 error("key_write: failed for RSA key");
309 }
310 } else if (key->type == KEY_DSA && key->dsa != NULL) {
Damien Millereba71ba2000-04-29 23:57:08 +1000311 int len, n;
312 unsigned char *blob, *uu;
313 dsa_make_key_blob(key, &blob, &len);
314 uu = xmalloc(2*len);
Damien Millere247cc42000-05-07 12:03:14 +1000315 n = uuencode(blob, len, uu, 2*len);
316 if (n > 0) {
317 fprintf(f, "%s %s", SSH_DSS, uu);
318 success = 1;
319 }
Damien Millereba71ba2000-04-29 23:57:08 +1000320 xfree(blob);
321 xfree(uu);
Damien Miller450a7a12000-03-26 13:04:51 +1000322 }
323 return success;
324}
Damien Millere247cc42000-05-07 12:03:14 +1000325char *
326key_type(Key *k)
327{
328 switch (k->type) {
329 case KEY_RSA:
330 return "RSA";
331 break;
332 case KEY_DSA:
333 return "DSA";
334 break;
335 }
336 return "unknown";
337}