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