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