key.c revision 60576
158582Skris/* 258582Skris * Copyright (c) 2000 Markus Friedl. All rights reserved. 358582Skris * 458582Skris * Redistribution and use in source and binary forms, with or without 558582Skris * modification, are permitted provided that the following conditions 658582Skris * are met: 758582Skris * 1. Redistributions of source code must retain the above copyright 858582Skris * notice, this list of conditions and the following disclaimer. 958582Skris * 2. Redistributions in binary form must reproduce the above copyright 1058582Skris * notice, this list of conditions and the following disclaimer in the 1158582Skris * documentation and/or other materials provided with the distribution. 1258582Skris * 3. All advertising materials mentioning features or use of this software 1358582Skris * must display the following acknowledgement: 1458582Skris * This product includes software developed by Markus Friedl. 1558582Skris * 4. The name of the author may not be used to endorse or promote products 1658582Skris * derived from this software without specific prior written permission. 1758582Skris * 1858582Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1958582Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2058582Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2158582Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2258582Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2358582Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2458582Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2558582Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2658582Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2758582Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2858592Skris * 2958592Skris * $FreeBSD: head/crypto/openssh/key.c 60576 2000-05-15 05:24:25Z kris $ 3058582Skris */ 3158582Skris/* 3258582Skris * read_bignum(): 3358582Skris * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 3458582Skris */ 3558582Skris 3658582Skris#include "includes.h" 3758582Skris#include "ssh.h" 3858592Skris#include <openssl/rsa.h> 3958592Skris#include <openssl/dsa.h> 4058592Skris#include <openssl/evp.h> 4158582Skris#include "xmalloc.h" 4258582Skris#include "key.h" 4360576Skris#include "dsa.h" 4460576Skris#include "uuencode.h" 4558582Skris 4660576Skris#define SSH_DSS "ssh-dss" 4760576Skris 4858582SkrisKey * 4958582Skriskey_new(int type) 5058582Skris{ 5158582Skris Key *k; 5258582Skris RSA *rsa; 5358582Skris DSA *dsa; 5458582Skris k = xmalloc(sizeof(*k)); 5558582Skris k->type = type; 5660576Skris k->dsa = NULL; 5760576Skris k->rsa = NULL; 5858582Skris switch (k->type) { 5958582Skris case KEY_RSA: 6058582Skris rsa = RSA_new(); 6158582Skris rsa->n = BN_new(); 6258582Skris rsa->e = BN_new(); 6358582Skris k->rsa = rsa; 6458582Skris break; 6558582Skris case KEY_DSA: 6658582Skris dsa = DSA_new(); 6758582Skris dsa->p = BN_new(); 6858582Skris dsa->q = BN_new(); 6958582Skris dsa->g = BN_new(); 7058582Skris dsa->pub_key = BN_new(); 7158582Skris k->dsa = dsa; 7258582Skris break; 7358582Skris case KEY_EMPTY: 7458582Skris break; 7558582Skris default: 7658582Skris fatal("key_new: bad key type %d", k->type); 7758582Skris break; 7858582Skris } 7958582Skris return k; 8058582Skris} 8158582Skrisvoid 8258582Skriskey_free(Key *k) 8358582Skris{ 8458582Skris switch (k->type) { 8558582Skris case KEY_RSA: 8658582Skris if (k->rsa != NULL) 8758582Skris RSA_free(k->rsa); 8858582Skris k->rsa = NULL; 8958582Skris break; 9058582Skris case KEY_DSA: 9158582Skris if (k->dsa != NULL) 9258582Skris DSA_free(k->dsa); 9358582Skris k->dsa = NULL; 9458582Skris break; 9558582Skris default: 9658582Skris fatal("key_free: bad key type %d", k->type); 9758582Skris break; 9858582Skris } 9958582Skris xfree(k); 10058582Skris} 10158582Skrisint 10258582Skriskey_equal(Key *a, Key *b) 10358582Skris{ 10458582Skris if (a == NULL || b == NULL || a->type != b->type) 10558582Skris return 0; 10658582Skris switch (a->type) { 10758582Skris case KEY_RSA: 10858582Skris return a->rsa != NULL && b->rsa != NULL && 10958582Skris BN_cmp(a->rsa->e, b->rsa->e) == 0 && 11058582Skris BN_cmp(a->rsa->n, b->rsa->n) == 0; 11158582Skris break; 11258582Skris case KEY_DSA: 11358582Skris return a->dsa != NULL && b->dsa != NULL && 11458582Skris BN_cmp(a->dsa->p, b->dsa->p) == 0 && 11558582Skris BN_cmp(a->dsa->q, b->dsa->q) == 0 && 11658582Skris BN_cmp(a->dsa->g, b->dsa->g) == 0 && 11758582Skris BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0; 11858582Skris break; 11958582Skris default: 12060576Skris fatal("key_equal: bad key type %d", a->type); 12158582Skris break; 12258582Skris } 12358582Skris return 0; 12458582Skris} 12558582Skris 12658582Skris#define FPRINT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x" 12758582Skris 12858582Skris/* 12958582Skris * Generate key fingerprint in ascii format. 13058582Skris * Based on ideas and code from Bjoern Groenvall <bg@sics.se> 13158582Skris */ 13258582Skrischar * 13358582Skriskey_fingerprint(Key *k) 13458582Skris{ 13558582Skris static char retval[80]; 13660576Skris unsigned char *blob = NULL; 13758582Skris int len = 0; 13860576Skris int nlen, elen; 13958582Skris 14058582Skris switch (k->type) { 14158582Skris case KEY_RSA: 14258582Skris nlen = BN_num_bytes(k->rsa->n); 14358582Skris elen = BN_num_bytes(k->rsa->e); 14458582Skris len = nlen + elen; 14560576Skris blob = xmalloc(len); 14660576Skris BN_bn2bin(k->rsa->n, blob); 14760576Skris BN_bn2bin(k->rsa->e, blob + nlen); 14858582Skris break; 14958582Skris case KEY_DSA: 15060576Skris dsa_make_key_blob(k, &blob, &len); 15158582Skris break; 15258582Skris default: 15358582Skris fatal("key_fingerprint: bad key type %d", k->type); 15458582Skris break; 15558582Skris } 15660576Skris if (blob != NULL) { 15758582Skris unsigned char d[16]; 15858582Skris EVP_MD_CTX md; 15958582Skris EVP_DigestInit(&md, EVP_md5()); 16060576Skris EVP_DigestUpdate(&md, blob, len); 16158582Skris EVP_DigestFinal(&md, d, NULL); 16258582Skris snprintf(retval, sizeof(retval), FPRINT, 16358582Skris d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], 16458582Skris d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]); 16560576Skris memset(blob, 0, len); 16660576Skris xfree(blob); 16758582Skris } 16858582Skris return retval; 16958582Skris} 17058582Skris 17158582Skris/* 17258582Skris * Reads a multiple-precision integer in decimal from the buffer, and advances 17358582Skris * the pointer. The integer must already be initialized. This function is 17458582Skris * permitted to modify the buffer. This leaves *cpp to point just beyond the 17558582Skris * last processed (and maybe modified) character. Note that this may modify 17658582Skris * the buffer containing the number. 17758582Skris */ 17858582Skrisint 17958582Skrisread_bignum(char **cpp, BIGNUM * value) 18058582Skris{ 18158582Skris char *cp = *cpp; 18258582Skris int old; 18358582Skris 18458582Skris /* Skip any leading whitespace. */ 18558582Skris for (; *cp == ' ' || *cp == '\t'; cp++) 18658582Skris ; 18758582Skris 18858582Skris /* Check that it begins with a decimal digit. */ 18958582Skris if (*cp < '0' || *cp > '9') 19058582Skris return 0; 19158582Skris 19258582Skris /* Save starting position. */ 19358582Skris *cpp = cp; 19458582Skris 19558582Skris /* Move forward until all decimal digits skipped. */ 19658582Skris for (; *cp >= '0' && *cp <= '9'; cp++) 19758582Skris ; 19858582Skris 19958582Skris /* Save the old terminating character, and replace it by \0. */ 20058582Skris old = *cp; 20158582Skris *cp = 0; 20258582Skris 20358582Skris /* Parse the number. */ 20458582Skris if (BN_dec2bn(&value, *cpp) == 0) 20558582Skris return 0; 20658582Skris 20758582Skris /* Restore old terminating character. */ 20858582Skris *cp = old; 20958582Skris 21058582Skris /* Move beyond the number and return success. */ 21158582Skris *cpp = cp; 21258582Skris return 1; 21358582Skris} 21458582Skrisint 21558582Skriswrite_bignum(FILE *f, BIGNUM *num) 21658582Skris{ 21758582Skris char *buf = BN_bn2dec(num); 21858582Skris if (buf == NULL) { 21958582Skris error("write_bignum: BN_bn2dec() failed"); 22058582Skris return 0; 22158582Skris } 22258582Skris fprintf(f, " %s", buf); 22358582Skris free(buf); 22458582Skris return 1; 22558582Skris} 22660576Skrisunsigned int 22760576Skriskey_read(Key *ret, char **cpp) 22858582Skris{ 22960576Skris Key *k; 23060576Skris unsigned int bits = 0; 23160576Skris char *cp; 23260576Skris int len, n; 23360576Skris unsigned char *blob; 23460576Skris 23560576Skris cp = *cpp; 23660576Skris 23758582Skris switch(ret->type) { 23858582Skris case KEY_RSA: 23960576Skris /* Get number of bits. */ 24060576Skris if (*cp < '0' || *cp > '9') 24160576Skris return 0; /* Bad bit count... */ 24260576Skris for (bits = 0; *cp >= '0' && *cp <= '9'; cp++) 24360576Skris bits = 10 * bits + *cp - '0'; 24458582Skris if (bits == 0) 24558582Skris return 0; 24660576Skris *cpp = cp; 24758582Skris /* Get public exponent, public modulus. */ 24858582Skris if (!read_bignum(cpp, ret->rsa->e)) 24958582Skris return 0; 25058582Skris if (!read_bignum(cpp, ret->rsa->n)) 25158582Skris return 0; 25258582Skris break; 25358582Skris case KEY_DSA: 25460576Skris if (strncmp(cp, SSH_DSS " ", 7) != 0) 25558582Skris return 0; 25660576Skris cp += 7; 25760576Skris len = 2*strlen(cp); 25860576Skris blob = xmalloc(len); 25960576Skris n = uudecode(cp, blob, len); 26060576Skris if (n < 0) { 26160576Skris error("uudecode %s failed", cp); 26258582Skris return 0; 26360576Skris } 26460576Skris k = dsa_key_from_blob(blob, n); 26560576Skris if (k == NULL) 26660576Skris return 0; 26760576Skris xfree(blob); 26860576Skris if (ret->dsa != NULL) 26960576Skris DSA_free(ret->dsa); 27060576Skris ret->dsa = k->dsa; 27160576Skris k->dsa = NULL; 27260576Skris key_free(k); 27360576Skris bits = BN_num_bits(ret->dsa->p); 27460576Skris cp = strchr(cp, '='); 27560576Skris if (cp == NULL) 27658582Skris return 0; 27760576Skris *cpp = cp + 1; 27858582Skris break; 27958582Skris default: 28060576Skris fatal("key_read: bad key type: %d", ret->type); 28158582Skris break; 28258582Skris } 28360576Skris return bits; 28458582Skris} 28558582Skrisint 28658582Skriskey_write(Key *key, FILE *f) 28758582Skris{ 28858582Skris int success = 0; 28958582Skris unsigned int bits = 0; 29058582Skris 29158582Skris if (key->type == KEY_RSA && key->rsa != NULL) { 29258582Skris /* size of modulus 'n' */ 29358582Skris bits = BN_num_bits(key->rsa->n); 29458582Skris fprintf(f, "%u", bits); 29558582Skris if (write_bignum(f, key->rsa->e) && 29658582Skris write_bignum(f, key->rsa->n)) { 29758582Skris success = 1; 29858582Skris } else { 29958582Skris error("key_write: failed for RSA key"); 30058582Skris } 30158582Skris } else if (key->type == KEY_DSA && key->dsa != NULL) { 30260576Skris int len, n; 30360576Skris unsigned char *blob, *uu; 30460576Skris dsa_make_key_blob(key, &blob, &len); 30560576Skris uu = xmalloc(2*len); 30660576Skris n = uuencode(blob, len, uu, 2*len); 30760576Skris if (n > 0) { 30860576Skris fprintf(f, "%s %s", SSH_DSS, uu); 30958582Skris success = 1; 31058582Skris } 31160576Skris xfree(blob); 31260576Skris xfree(uu); 31358582Skris } 31458582Skris return success; 31558582Skris} 31660576Skrischar * 31760576Skriskey_type(Key *k) 31860576Skris{ 31960576Skris switch (k->type) { 32060576Skris case KEY_RSA: 32160576Skris return "RSA"; 32260576Skris break; 32360576Skris case KEY_DSA: 32460576Skris return "DSA"; 32560576Skris break; 32660576Skris } 32760576Skris return "unknown"; 32860576Skris} 329