openssh/key.c
Damien Miller e247cc402b - Remove references to SSLeay.
- Big OpenBSD CVS update
  - markus@cvs.openbsd.org
    [clientloop.c]
    - typo
    [session.c]
    - update proctitle on pty alloc/dealloc, e.g. w/ windows client
    [session.c]
    - update proctitle for proto 1, too
    [channels.h nchan.c serverloop.c session.c sshd.c]
    - use c-style comments
  - deraadt@cvs.openbsd.org
    [scp.c]
    - more atomicio
  - markus@cvs.openbsd.org
    [channels.c]
    - set O_NONBLOCK
    [ssh.1]
    - update AUTHOR
    [readconf.c ssh-keygen.c ssh.h]
    - default DSA key file ~/.ssh/id_dsa
    [clientloop.c]
    - typo, rm verbose debug
  - deraadt@cvs.openbsd.org
    [ssh-keygen.1]
    - document DSA use of ssh-keygen
    [sshd.8]
    - a start at describing what i understand of the DSA side
    [ssh-keygen.1]
    - document -X and -x
    [ssh-keygen.c]
    - simplify usage
  - markus@cvs.openbsd.org
    [sshd.8]
    - there is no rhosts_dsa
    [ssh-keygen.1]
    - document -y, update -X,-x
    [nchan.c]
    - fix close for non-open ssh1 channels
    [servconf.c servconf.h ssh.h sshd.8 sshd.c ]
    - s/DsaKey/HostDSAKey/, document option
    [sshconnect2.c]
    - respect number_of_password_prompts
    [channels.c channels.h servconf.c servconf.h session.c sshd.8]
    - GatewayPorts for sshd, ok deraadt@
    [ssh-add.1 ssh-agent.1 ssh.1]
    - more doc on: DSA, id_dsa, known_hosts2, authorized_keys2
    [ssh.1]
    - more info on proto 2
    [sshd.8]
    - sync AUTHOR w/ ssh.1
    [key.c key.h sshconnect.c]
    - print key type when talking about host keys
    [packet.c]
    - clear padding in ssh2
    [dsa.c key.c radix.c ssh.h sshconnect1.c uuencode.c uuencode.h]
    - replace broken uuencode w/ libc b64_ntop
    [auth2.c]
    - log failure before sending the reply
    [key.c radix.c uuencode.c]
    - remote trailing comments before calling __b64_pton
    [auth2.c readconf.c readconf.h servconf.c servconf.h ssh.1]
    [sshconnect2.c sshd.8]
    - add DSAAuthetication option to ssh/sshd, document SSH2 in sshd.8
 - Bring in b64_ntop and b64_pton from OpenBSD libc (bsd-base64.[ch])
2000-05-07 12:03:14 +10:00

327 lines
7.5 KiB
C

/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Markus Friedl.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* read_bignum():
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
*/
#include "includes.h"
#include "ssh.h"
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include <openssl/evp.h>
#include "xmalloc.h"
#include "key.h"
#include "dsa.h"
#include "uuencode.h"
#define SSH_DSS "ssh-dss"
Key *
key_new(int type)
{
Key *k;
RSA *rsa;
DSA *dsa;
k = xmalloc(sizeof(*k));
k->type = type;
k->dsa = NULL;
k->rsa = NULL;
switch (k->type) {
case KEY_RSA:
rsa = RSA_new();
rsa->n = BN_new();
rsa->e = BN_new();
k->rsa = rsa;
break;
case KEY_DSA:
dsa = DSA_new();
dsa->p = BN_new();
dsa->q = BN_new();
dsa->g = BN_new();
dsa->pub_key = BN_new();
k->dsa = dsa;
break;
case KEY_EMPTY:
break;
default:
fatal("key_new: bad key type %d", k->type);
break;
}
return k;
}
void
key_free(Key *k)
{
switch (k->type) {
case KEY_RSA:
if (k->rsa != NULL)
RSA_free(k->rsa);
k->rsa = NULL;
break;
case KEY_DSA:
if (k->dsa != NULL)
DSA_free(k->dsa);
k->dsa = NULL;
break;
default:
fatal("key_free: bad key type %d", k->type);
break;
}
xfree(k);
}
int
key_equal(Key *a, Key *b)
{
if (a == NULL || b == NULL || a->type != b->type)
return 0;
switch (a->type) {
case KEY_RSA:
return a->rsa != NULL && b->rsa != NULL &&
BN_cmp(a->rsa->e, b->rsa->e) == 0 &&
BN_cmp(a->rsa->n, b->rsa->n) == 0;
break;
case KEY_DSA:
return a->dsa != NULL && b->dsa != NULL &&
BN_cmp(a->dsa->p, b->dsa->p) == 0 &&
BN_cmp(a->dsa->q, b->dsa->q) == 0 &&
BN_cmp(a->dsa->g, b->dsa->g) == 0 &&
BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0;
break;
default:
fatal("key_equal: bad key type %d", a->type);
break;
}
return 0;
}
#define FPRINT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
/*
* Generate key fingerprint in ascii format.
* Based on ideas and code from Bjoern Groenvall <bg@sics.se>
*/
char *
key_fingerprint(Key *k)
{
static char retval[80];
unsigned char *blob = NULL;
int len = 0;
int nlen, elen;
switch (k->type) {
case KEY_RSA:
nlen = BN_num_bytes(k->rsa->n);
elen = BN_num_bytes(k->rsa->e);
len = nlen + elen;
blob = xmalloc(len);
BN_bn2bin(k->rsa->n, blob);
BN_bn2bin(k->rsa->e, blob + nlen);
break;
case KEY_DSA:
dsa_make_key_blob(k, &blob, &len);
break;
default:
fatal("key_fingerprint: bad key type %d", k->type);
break;
}
if (blob != NULL) {
unsigned char d[16];
EVP_MD_CTX md;
EVP_DigestInit(&md, EVP_md5());
EVP_DigestUpdate(&md, blob, len);
EVP_DigestFinal(&md, d, NULL);
snprintf(retval, sizeof(retval), FPRINT,
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
memset(blob, 0, len);
xfree(blob);
}
return retval;
}
/*
* Reads a multiple-precision integer in decimal from the buffer, and advances
* the pointer. The integer must already be initialized. This function is
* permitted to modify the buffer. This leaves *cpp to point just beyond the
* last processed (and maybe modified) character. Note that this may modify
* the buffer containing the number.
*/
int
read_bignum(char **cpp, BIGNUM * value)
{
char *cp = *cpp;
int old;
/* Skip any leading whitespace. */
for (; *cp == ' ' || *cp == '\t'; cp++)
;
/* Check that it begins with a decimal digit. */
if (*cp < '0' || *cp > '9')
return 0;
/* Save starting position. */
*cpp = cp;
/* Move forward until all decimal digits skipped. */
for (; *cp >= '0' && *cp <= '9'; cp++)
;
/* Save the old terminating character, and replace it by \0. */
old = *cp;
*cp = 0;
/* Parse the number. */
if (BN_dec2bn(&value, *cpp) == 0)
return 0;
/* Restore old terminating character. */
*cp = old;
/* Move beyond the number and return success. */
*cpp = cp;
return 1;
}
int
write_bignum(FILE *f, BIGNUM *num)
{
char *buf = BN_bn2dec(num);
if (buf == NULL) {
error("write_bignum: BN_bn2dec() failed");
return 0;
}
fprintf(f, " %s", buf);
free(buf);
return 1;
}
unsigned int
key_read(Key *ret, char **cpp)
{
Key *k;
unsigned int bits = 0;
char *cp;
int len, n;
unsigned char *blob;
cp = *cpp;
switch(ret->type) {
case KEY_RSA:
/* Get number of bits. */
if (*cp < '0' || *cp > '9')
return 0; /* Bad bit count... */
for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
bits = 10 * bits + *cp - '0';
if (bits == 0)
return 0;
*cpp = cp;
/* Get public exponent, public modulus. */
if (!read_bignum(cpp, ret->rsa->e))
return 0;
if (!read_bignum(cpp, ret->rsa->n))
return 0;
break;
case KEY_DSA:
if (strncmp(cp, SSH_DSS " ", 7) != 0)
return 0;
cp += 7;
len = 2*strlen(cp);
blob = xmalloc(len);
n = uudecode(cp, blob, len);
if (n < 0) {
error("uudecode %s failed", cp);
return 0;
}
k = dsa_key_from_blob(blob, n);
if (k == NULL)
return 0;
xfree(blob);
if (ret->dsa != NULL)
DSA_free(ret->dsa);
ret->dsa = k->dsa;
k->dsa = NULL;
key_free(k);
bits = BN_num_bits(ret->dsa->p);
cp = strchr(cp, '=');
if (cp == NULL)
return 0;
*cpp = cp + 1;
break;
default:
fatal("key_read: bad key type: %d", ret->type);
break;
}
return bits;
}
int
key_write(Key *key, FILE *f)
{
int success = 0;
unsigned int bits = 0;
if (key->type == KEY_RSA && key->rsa != NULL) {
/* size of modulus 'n' */
bits = BN_num_bits(key->rsa->n);
fprintf(f, "%u", bits);
if (write_bignum(f, key->rsa->e) &&
write_bignum(f, key->rsa->n)) {
success = 1;
} else {
error("key_write: failed for RSA key");
}
} else if (key->type == KEY_DSA && key->dsa != NULL) {
int len, n;
unsigned char *blob, *uu;
dsa_make_key_blob(key, &blob, &len);
uu = xmalloc(2*len);
n = uuencode(blob, len, uu, 2*len);
if (n > 0) {
fprintf(f, "%s %s", SSH_DSS, uu);
success = 1;
}
xfree(blob);
xfree(uu);
}
return success;
}
char *
key_type(Key *k)
{
switch (k->type) {
case KEY_RSA:
return "RSA";
break;
case KEY_DSA:
return "DSA";
break;
}
return "unknown";
}