]> andersk Git - openssh.git/blob - key.c
764f1f227fbba1c818348ba009632354dfa73b23
[openssh.git] / key.c
1 /*
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"
35 #include "ssh.h"
36 #include <openssl/rsa.h>
37 #include <openssl/dsa.h>
38 #include <openssl/evp.h>
39 #include "xmalloc.h"
40 #include "key.h"
41 #include "dsa.h"
42 #include "uuencode.h"
43
44 RCSID("$OpenBSD: key.c,v 1.9 2000/06/22 23:55:00 djm Exp $");
45
46 #define SSH_DSS "ssh-dss"
47
48 Key *
49 key_new(int type)
50 {
51         Key *k;
52         RSA *rsa;
53         DSA *dsa;
54         k = xmalloc(sizeof(*k));
55         k->type = type;
56         k->dsa = NULL;
57         k->rsa = NULL;
58         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:
74                 break;
75         default:
76                 fatal("key_new: bad key type %d", k->type);
77                 break;
78         }
79         return k;
80 }
81 void
82 key_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 }
101 int
102 key_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:
120                 fatal("key_equal: bad key type %d", a->type);
121                 break;
122         }
123         return 0;
124 }
125
126 /*
127  * Generate key fingerprint in ascii format.
128  * Based on ideas and code from Bjoern Groenvall <bg@sics.se>
129  */
130 char *
131 key_fingerprint(Key *k)
132 {
133         static char retval[(EVP_MAX_MD_SIZE+1)*3];
134         unsigned char *blob = NULL;
135         int len = 0;
136         int nlen, elen;
137
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;
143                 blob = xmalloc(len);
144                 BN_bn2bin(k->rsa->n, blob);
145                 BN_bn2bin(k->rsa->e, blob + nlen);
146                 break;
147         case KEY_DSA:
148                 dsa_make_key_blob(k, &blob, &len);
149                 break;
150         default:
151                 fatal("key_fingerprint: bad key type %d", k->type);
152                 break;
153         }
154         retval[0] = '\0';
155
156         if (blob != NULL) {
157                 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';
170                 memset(blob, 0, len);
171                 xfree(blob);
172         }
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  */
183 int
184 read_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 }
219 int
220 write_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 }
231 unsigned int
232 key_read(Key *ret, char **cpp)
233 {
234         Key *k;
235         unsigned int bits = 0;
236         char *cp;
237         int len, n;
238         unsigned char *blob;
239
240         cp = *cpp;
241
242         switch(ret->type) {
243         case KEY_RSA:
244                 /* 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';
249                 if (bits == 0)
250                         return 0;
251                 *cpp = cp;
252                 /* 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:
259                 if (strncmp(cp, SSH_DSS " ", 7) != 0)
260                         return 0;
261                 cp += 7;
262                 len = 2*strlen(cp);
263                 blob = xmalloc(len);
264                 n = uudecode(cp, blob, len);
265                 if (n < 0) {
266                         error("key_read: uudecode %s failed", cp);
267                         return 0;
268                 }
269                 k = dsa_key_from_blob(blob, n);
270                 if (k == NULL) {
271                         error("key_read: dsa_key_from_blob %s failed", cp);
272                         return 0;
273                 }
274                 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);
281                 /* 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;
287                 break;
288         default:
289                 fatal("key_read: bad key type: %d", ret->type);
290                 break;
291         }
292         return bits;
293 }
294 int
295 key_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) {
311                 int len, n;
312                 unsigned char *blob, *uu;
313                 dsa_make_key_blob(key, &blob, &len);
314                 uu = xmalloc(2*len);
315                 n = uuencode(blob, len, uu, 2*len);
316                 if (n > 0) {
317                         fprintf(f, "%s %s", SSH_DSS, uu);
318                         success = 1;
319                 }
320                 xfree(blob);
321                 xfree(uu);
322         }
323         return success;
324 }
325 char *
326 key_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 }
This page took 0.052461 seconds and 3 git commands to generate.