Annotation of src/usr.bin/ssh/key.c, Revision 1.10
1.1 markus 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"
1.2 markus 36: #include <openssl/rsa.h>
37: #include <openssl/dsa.h>
38: #include <openssl/evp.h>
1.1 markus 39: #include "xmalloc.h"
40: #include "key.h"
1.3 markus 41: #include "dsa.h"
42: #include "uuencode.h"
43:
1.10 ! markus 44: RCSID("$OpenBSD: key.c,v 1.9 2000/06/22 23:55:00 djm Exp $");
1.9 djm 45:
1.3 markus 46: #define SSH_DSS "ssh-dss"
1.1 markus 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;
1.3 markus 56: k->dsa = NULL;
57: k->rsa = NULL;
1.1 markus 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:
1.3 markus 120: fatal("key_equal: bad key type %d", a->type);
1.1 markus 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: {
1.8 markus 133: static char retval[(EVP_MAX_MD_SIZE+1)*3];
1.3 markus 134: unsigned char *blob = NULL;
1.1 markus 135: int len = 0;
1.3 markus 136: int nlen, elen;
1.1 markus 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;
1.3 markus 143: blob = xmalloc(len);
144: BN_bn2bin(k->rsa->n, blob);
145: BN_bn2bin(k->rsa->e, blob + nlen);
1.1 markus 146: break;
147: case KEY_DSA:
1.3 markus 148: dsa_make_key_blob(k, &blob, &len);
1.1 markus 149: break;
150: default:
151: fatal("key_fingerprint: bad key type %d", k->type);
152: break;
153: }
1.8 markus 154: retval[0] = '\0';
155:
1.3 markus 156: if (blob != NULL) {
1.8 markus 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';
1.3 markus 170: memset(blob, 0, len);
171: xfree(blob);
1.1 markus 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: }
1.3 markus 231: unsigned int
232: key_read(Key *ret, char **cpp)
1.1 markus 233: {
1.3 markus 234: Key *k;
235: unsigned int bits = 0;
236: char *cp;
237: int len, n;
238: unsigned char *blob;
239:
240: cp = *cpp;
241:
1.1 markus 242: switch(ret->type) {
243: case KEY_RSA:
1.3 markus 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';
1.1 markus 249: if (bits == 0)
250: return 0;
1.3 markus 251: *cpp = cp;
1.1 markus 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:
1.3 markus 259: if (strncmp(cp, SSH_DSS " ", 7) != 0)
1.1 markus 260: return 0;
1.3 markus 261: cp += 7;
262: len = 2*strlen(cp);
263: blob = xmalloc(len);
264: n = uudecode(cp, blob, len);
1.6 markus 265: if (n < 0) {
1.7 markus 266: error("key_read: uudecode %s failed", cp);
1.6 markus 267: return 0;
268: }
1.3 markus 269: k = dsa_key_from_blob(blob, n);
1.7 markus 270: if (k == NULL) {
271: error("key_read: dsa_key_from_blob %s failed", cp);
272: return 0;
273: }
1.3 markus 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);
1.7 markus 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;
1.1 markus 287: break;
288: default:
1.3 markus 289: fatal("key_read: bad key type: %d", ret->type);
1.1 markus 290: break;
291: }
1.3 markus 292: return bits;
1.1 markus 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) {
1.3 markus 311: int len, n;
312: unsigned char *blob, *uu;
313: dsa_make_key_blob(key, &blob, &len);
314: uu = xmalloc(2*len);
1.5 markus 315: n = uuencode(blob, len, uu, 2*len);
316: if (n > 0) {
317: fprintf(f, "%s %s", SSH_DSS, uu);
318: success = 1;
319: }
1.3 markus 320: xfree(blob);
321: xfree(uu);
1.1 markus 322: }
323: return success;
324: }
1.4 markus 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";
1.10 ! markus 337: }
! 338: unsigned int
! 339: key_size(Key *k){
! 340: switch (k->type) {
! 341: case KEY_RSA:
! 342: return BN_num_bits(k->rsa->n);
! 343: break;
! 344: case KEY_DSA:
! 345: return BN_num_bits(k->dsa->p);
! 346: break;
! 347: }
! 348: return 0;
1.4 markus 349: }