Annotation of src/usr.bin/ssh/key.c, Revision 1.11
1.1 markus 1: /*
1.11 ! deraadt 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: *
1.1 markus 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"
1.2 markus 37: #include <openssl/rsa.h>
38: #include <openssl/dsa.h>
39: #include <openssl/evp.h>
1.1 markus 40: #include "xmalloc.h"
41: #include "key.h"
1.3 markus 42: #include "dsa.h"
43: #include "uuencode.h"
44:
1.11 ! deraadt 45: RCSID("$OpenBSD: key.c,v 1.10 2000/08/19 21:34:43 markus Exp $");
1.9 djm 46:
1.3 markus 47: #define SSH_DSS "ssh-dss"
1.1 markus 48:
49: Key *
50: key_new(int type)
51: {
52: Key *k;
53: RSA *rsa;
54: DSA *dsa;
55: k = xmalloc(sizeof(*k));
56: k->type = type;
1.3 markus 57: k->dsa = NULL;
58: k->rsa = NULL;
1.1 markus 59: switch (k->type) {
60: case KEY_RSA:
61: rsa = RSA_new();
62: rsa->n = BN_new();
63: rsa->e = BN_new();
64: k->rsa = rsa;
65: break;
66: case KEY_DSA:
67: dsa = DSA_new();
68: dsa->p = BN_new();
69: dsa->q = BN_new();
70: dsa->g = BN_new();
71: dsa->pub_key = BN_new();
72: k->dsa = dsa;
73: break;
74: case KEY_EMPTY:
75: break;
76: default:
77: fatal("key_new: bad key type %d", k->type);
78: break;
79: }
80: return k;
81: }
82: void
83: key_free(Key *k)
84: {
85: switch (k->type) {
86: case KEY_RSA:
87: if (k->rsa != NULL)
88: RSA_free(k->rsa);
89: k->rsa = NULL;
90: break;
91: case KEY_DSA:
92: if (k->dsa != NULL)
93: DSA_free(k->dsa);
94: k->dsa = NULL;
95: break;
96: default:
97: fatal("key_free: bad key type %d", k->type);
98: break;
99: }
100: xfree(k);
101: }
102: int
103: key_equal(Key *a, Key *b)
104: {
105: if (a == NULL || b == NULL || a->type != b->type)
106: return 0;
107: switch (a->type) {
108: case KEY_RSA:
109: return a->rsa != NULL && b->rsa != NULL &&
110: BN_cmp(a->rsa->e, b->rsa->e) == 0 &&
111: BN_cmp(a->rsa->n, b->rsa->n) == 0;
112: break;
113: case KEY_DSA:
114: return a->dsa != NULL && b->dsa != NULL &&
115: BN_cmp(a->dsa->p, b->dsa->p) == 0 &&
116: BN_cmp(a->dsa->q, b->dsa->q) == 0 &&
117: BN_cmp(a->dsa->g, b->dsa->g) == 0 &&
118: BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0;
119: break;
120: default:
1.3 markus 121: fatal("key_equal: bad key type %d", a->type);
1.1 markus 122: break;
123: }
124: return 0;
125: }
126:
127: /*
128: * Generate key fingerprint in ascii format.
129: * Based on ideas and code from Bjoern Groenvall <bg@sics.se>
130: */
131: char *
132: key_fingerprint(Key *k)
133: {
1.8 markus 134: static char retval[(EVP_MAX_MD_SIZE+1)*3];
1.3 markus 135: unsigned char *blob = NULL;
1.1 markus 136: int len = 0;
1.3 markus 137: int nlen, elen;
1.1 markus 138:
139: switch (k->type) {
140: case KEY_RSA:
141: nlen = BN_num_bytes(k->rsa->n);
142: elen = BN_num_bytes(k->rsa->e);
143: len = nlen + elen;
1.3 markus 144: blob = xmalloc(len);
145: BN_bn2bin(k->rsa->n, blob);
146: BN_bn2bin(k->rsa->e, blob + nlen);
1.1 markus 147: break;
148: case KEY_DSA:
1.3 markus 149: dsa_make_key_blob(k, &blob, &len);
1.1 markus 150: break;
151: default:
152: fatal("key_fingerprint: bad key type %d", k->type);
153: break;
154: }
1.8 markus 155: retval[0] = '\0';
156:
1.3 markus 157: if (blob != NULL) {
1.8 markus 158: int i;
159: unsigned char digest[EVP_MAX_MD_SIZE];
160: EVP_MD *md = EVP_md5();
161: EVP_MD_CTX ctx;
162: EVP_DigestInit(&ctx, md);
163: EVP_DigestUpdate(&ctx, blob, len);
164: EVP_DigestFinal(&ctx, digest, NULL);
165: for(i = 0; i < md->md_size; i++) {
166: char hex[4];
167: snprintf(hex, sizeof(hex), "%02x:", digest[i]);
168: strlcat(retval, hex, sizeof(retval));
169: }
170: retval[strlen(retval) - 1] = '\0';
1.3 markus 171: memset(blob, 0, len);
172: xfree(blob);
1.1 markus 173: }
174: return retval;
175: }
176:
177: /*
178: * Reads a multiple-precision integer in decimal from the buffer, and advances
179: * the pointer. The integer must already be initialized. This function is
180: * permitted to modify the buffer. This leaves *cpp to point just beyond the
181: * last processed (and maybe modified) character. Note that this may modify
182: * the buffer containing the number.
183: */
184: int
185: read_bignum(char **cpp, BIGNUM * value)
186: {
187: char *cp = *cpp;
188: int old;
189:
190: /* Skip any leading whitespace. */
191: for (; *cp == ' ' || *cp == '\t'; cp++)
192: ;
193:
194: /* Check that it begins with a decimal digit. */
195: if (*cp < '0' || *cp > '9')
196: return 0;
197:
198: /* Save starting position. */
199: *cpp = cp;
200:
201: /* Move forward until all decimal digits skipped. */
202: for (; *cp >= '0' && *cp <= '9'; cp++)
203: ;
204:
205: /* Save the old terminating character, and replace it by \0. */
206: old = *cp;
207: *cp = 0;
208:
209: /* Parse the number. */
210: if (BN_dec2bn(&value, *cpp) == 0)
211: return 0;
212:
213: /* Restore old terminating character. */
214: *cp = old;
215:
216: /* Move beyond the number and return success. */
217: *cpp = cp;
218: return 1;
219: }
220: int
221: write_bignum(FILE *f, BIGNUM *num)
222: {
223: char *buf = BN_bn2dec(num);
224: if (buf == NULL) {
225: error("write_bignum: BN_bn2dec() failed");
226: return 0;
227: }
228: fprintf(f, " %s", buf);
229: free(buf);
230: return 1;
231: }
1.3 markus 232: unsigned int
233: key_read(Key *ret, char **cpp)
1.1 markus 234: {
1.3 markus 235: Key *k;
236: unsigned int bits = 0;
237: char *cp;
238: int len, n;
239: unsigned char *blob;
240:
241: cp = *cpp;
242:
1.1 markus 243: switch(ret->type) {
244: case KEY_RSA:
1.3 markus 245: /* Get number of bits. */
246: if (*cp < '0' || *cp > '9')
247: return 0; /* Bad bit count... */
248: for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
249: bits = 10 * bits + *cp - '0';
1.1 markus 250: if (bits == 0)
251: return 0;
1.3 markus 252: *cpp = cp;
1.1 markus 253: /* Get public exponent, public modulus. */
254: if (!read_bignum(cpp, ret->rsa->e))
255: return 0;
256: if (!read_bignum(cpp, ret->rsa->n))
257: return 0;
258: break;
259: case KEY_DSA:
1.3 markus 260: if (strncmp(cp, SSH_DSS " ", 7) != 0)
1.1 markus 261: return 0;
1.3 markus 262: cp += 7;
263: len = 2*strlen(cp);
264: blob = xmalloc(len);
265: n = uudecode(cp, blob, len);
1.6 markus 266: if (n < 0) {
1.7 markus 267: error("key_read: uudecode %s failed", cp);
1.6 markus 268: return 0;
269: }
1.3 markus 270: k = dsa_key_from_blob(blob, n);
1.7 markus 271: if (k == NULL) {
272: error("key_read: dsa_key_from_blob %s failed", cp);
273: return 0;
274: }
1.3 markus 275: xfree(blob);
276: if (ret->dsa != NULL)
277: DSA_free(ret->dsa);
278: ret->dsa = k->dsa;
279: k->dsa = NULL;
280: key_free(k);
281: bits = BN_num_bits(ret->dsa->p);
1.7 markus 282: /* advance cp: skip whitespace and data */
283: while (*cp == ' ' || *cp == '\t')
284: cp++;
285: while (*cp != '\0' && *cp != ' ' && *cp != '\t')
286: cp++;
287: *cpp = cp;
1.1 markus 288: break;
289: default:
1.3 markus 290: fatal("key_read: bad key type: %d", ret->type);
1.1 markus 291: break;
292: }
1.3 markus 293: return bits;
1.1 markus 294: }
295: int
296: key_write(Key *key, FILE *f)
297: {
298: int success = 0;
299: unsigned int bits = 0;
300:
301: if (key->type == KEY_RSA && key->rsa != NULL) {
302: /* size of modulus 'n' */
303: bits = BN_num_bits(key->rsa->n);
304: fprintf(f, "%u", bits);
305: if (write_bignum(f, key->rsa->e) &&
306: write_bignum(f, key->rsa->n)) {
307: success = 1;
308: } else {
309: error("key_write: failed for RSA key");
310: }
311: } else if (key->type == KEY_DSA && key->dsa != NULL) {
1.3 markus 312: int len, n;
313: unsigned char *blob, *uu;
314: dsa_make_key_blob(key, &blob, &len);
315: uu = xmalloc(2*len);
1.5 markus 316: n = uuencode(blob, len, uu, 2*len);
317: if (n > 0) {
318: fprintf(f, "%s %s", SSH_DSS, uu);
319: success = 1;
320: }
1.3 markus 321: xfree(blob);
322: xfree(uu);
1.1 markus 323: }
324: return success;
325: }
1.4 markus 326: char *
327: key_type(Key *k)
328: {
329: switch (k->type) {
330: case KEY_RSA:
331: return "RSA";
332: break;
333: case KEY_DSA:
334: return "DSA";
335: break;
336: }
337: return "unknown";
1.10 markus 338: }
339: unsigned int
340: key_size(Key *k){
341: switch (k->type) {
342: case KEY_RSA:
343: return BN_num_bits(k->rsa->n);
344: break;
345: case KEY_DSA:
346: return BN_num_bits(k->dsa->p);
347: break;
348: }
349: return 0;
1.4 markus 350: }