diff options
-rw-r--r-- | ChangeLog | 14 | ||||
-rw-r--r-- | Makefile.in | 2 | ||||
-rw-r--r-- | README.Ylonen | 4 | ||||
-rw-r--r-- | auth-krb4.c | 2 | ||||
-rw-r--r-- | auth-rh-rsa.c | 49 | ||||
-rw-r--r-- | auth-rsa.c | 37 | ||||
-rw-r--r-- | cipher.c | 16 | ||||
-rw-r--r-- | cipher.h | 8 | ||||
-rw-r--r-- | hostfile.c | 202 | ||||
-rw-r--r-- | hostfile.h | 22 | ||||
-rw-r--r-- | key.c | 301 | ||||
-rw-r--r-- | key.h | 23 | ||||
-rw-r--r-- | match.c | 61 | ||||
-rw-r--r-- | match.h | 18 | ||||
-rw-r--r-- | scp.1 | 29 | ||||
-rw-r--r-- | ssh-add.1 | 33 | ||||
-rw-r--r-- | ssh-agent.1 | 52 | ||||
-rw-r--r-- | ssh-keygen.1 | 62 | ||||
-rw-r--r-- | ssh.1 | 36 | ||||
-rw-r--r-- | ssh.c | 13 | ||||
-rw-r--r-- | ssh.h | 36 | ||||
-rw-r--r-- | sshconnect.c | 72 | ||||
-rw-r--r-- | sshd.8 | 388 | ||||
-rw-r--r-- | sshd.c | 30 |
24 files changed, 965 insertions, 545 deletions
@@ -2,6 +2,20 @@ - Better tests for OpenSSL w/ RSAref - Added replacement setenv() function from OpenBSD libc. Suggested by Ben Lindstrom <mouring@pconline.com> + - OpenBSD CVS update + - [auth-krb4.c] + -Wall + - [auth-rh-rsa.c auth-rsa.c hostfile.c hostfile.h key.c key.h match.c] + [match.h ssh.c ssh.h sshconnect.c sshd.c] + initial support for DSA keys. ok deraadt@, niels@ + - [cipher.c cipher.h] + remove unused cipher_attack_detected code + - [scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh.1 sshd.8] + Fix some formatting problems I missed before. + - [ssh.1 sshd.8] + fix spelling errors, From: FreeBSD + - [ssh.c] + switch to raw mode only if he _get_ a pty (not if we _want_ a pty). 20000324 - Released 1.2.3 diff --git a/Makefile.in b/Makefile.in index 5db02beb..6fee608d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -31,7 +31,7 @@ LDFLAGS=-L. @LDFLAGS@ TARGETS=ssh sshd ssh-add ssh-keygen ssh-agent scp $(EXTRA_TARGETS) -LIBOBJS= atomicio.o authfd.o authfile.o bsd-bindresvport.o bsd-daemon.o bsd-misc.o bsd-mktemp.o bsd-rresvport.o bsd-setenv.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o fake-getaddrinfo.o fake-getnameinfo.o fingerprint.o hostfile.o log.o match.o mpaux.o nchan.o packet.o radix.o random.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o xmalloc.o +LIBOBJS= atomicio.o authfd.o authfile.o bsd-bindresvport.o bsd-daemon.o bsd-misc.o bsd-mktemp.o bsd-rresvport.o bsd-setenv.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o fake-getaddrinfo.o fake-getnameinfo.o fingerprint.o hostfile.o key.o log.o match.o mpaux.o nchan.o packet.o radix.o random.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o xmalloc.o SSHOBJS= ssh.o sshconnect.o log-client.o readconf.o clientloop.o diff --git a/README.Ylonen b/README.Ylonen index ed360844..38987b92 100644 --- a/README.Ylonen +++ b/README.Ylonen @@ -1,3 +1,7 @@ + +[ Please note that this file has not been updated for OpenSSH and + covers the ssh-1.2.12 release from Dec 1995 only. ] + Ssh (Secure Shell) is a program to log into another computer over a network, to execute commands in a remote machine, and to move files from one machine to another. It provides strong authentication and diff --git a/auth-krb4.c b/auth-krb4.c index 95fc7229..7e30646f 100644 --- a/auth-krb4.c +++ b/auth-krb4.c @@ -139,7 +139,7 @@ int krb4_init(uid_t uid) { static int cleanup_registered = 0; - char *tkt_root = TKT_ROOT; + const char *tkt_root = TKT_ROOT; struct stat st; int fd; diff --git a/auth-rh-rsa.c b/auth-rh-rsa.c index 1392455c..19782577 100644 --- a/auth-rh-rsa.c +++ b/auth-rh-rsa.c @@ -15,7 +15,18 @@ */ #include "includes.h" -RCSID("$Id: auth-rh-rsa.c,v 1.7 1999/11/25 00:54:57 damien Exp $"); +RCSID("$Id: auth-rh-rsa.c,v 1.8 2000/03/26 03:04:52 damien Exp $"); + +#ifdef HAVE_OPENSSL +#include <openssl/bn.h> +#include <openssl/rsa.h> +#include <openssl/dsa.h> +#endif +#ifdef HAVE_SSL +#include <ssl/bn.h> +#include <ssl/rsa.h> +#include <ssl/dsa.h> +#endif #include "packet.h" #include "ssh.h" @@ -23,37 +34,44 @@ RCSID("$Id: auth-rh-rsa.c,v 1.7 1999/11/25 00:54:57 damien Exp $"); #include "uidswap.h" #include "servconf.h" +#include "key.h" +#include "hostfile.h" + /* * Tries to authenticate the user using the .rhosts file and the host using * its host key. Returns true if authentication succeeds. */ int -auth_rhosts_rsa(struct passwd *pw, const char *client_user, - BIGNUM *client_host_key_e, BIGNUM *client_host_key_n) +auth_rhosts_rsa(struct passwd *pw, const char *client_user, RSA *client_host_key) { extern ServerOptions options; const char *canonical_hostname; HostStatus host_status; - BIGNUM *ke, *kn; + Key *client_key, *found; debug("Trying rhosts with RSA host authentication for %.100s", client_user); + if (client_host_key == NULL) + return 0; + /* Check if we would accept it using rhosts authentication. */ if (!auth_rhosts(pw, client_user)) return 0; canonical_hostname = get_canonical_hostname(); - debug("Rhosts RSA authentication: canonical host %.900s", - canonical_hostname); + debug("Rhosts RSA authentication: canonical host %.900s", canonical_hostname); + + /* wrap the RSA key into a 'generic' key */ + client_key = key_new(KEY_RSA); + BN_copy(client_key->rsa->e, client_host_key->e); + BN_copy(client_key->rsa->n, client_host_key->n); + found = key_new(KEY_RSA); /* Check if we know the host and its host key. */ - ke = BN_new(); - kn = BN_new(); host_status = check_host_in_hostfile(SSH_SYSTEM_HOSTFILE, canonical_hostname, - client_host_key_e, client_host_key_n, - ke, kn); + client_key, found); /* Check user host file unless ignored. */ if (host_status != HOST_OK && !options.ignore_user_known_hosts) { @@ -73,14 +91,13 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user, /* XXX race between stat and the following open() */ temporarily_use_uid(pw->pw_uid); host_status = check_host_in_hostfile(user_hostfile, canonical_hostname, - client_host_key_e, client_host_key_n, - ke, kn); + client_key, found); restore_uid(); } xfree(user_hostfile); } - BN_free(ke); - BN_free(kn); + key_free(client_key); + key_free(found); if (host_status != HOST_OK) { debug("Rhosts with RSA host authentication denied: unknown or invalid host key"); @@ -90,7 +107,7 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user, /* A matching host key was found and is known. */ /* Perform the challenge-response dialog with the client for the host key. */ - if (!auth_rsa_challenge_dialog(client_host_key_e, client_host_key_n)) { + if (!auth_rsa_challenge_dialog(client_host_key)) { log("Client on %.800s failed to respond correctly to host authentication.", canonical_hostname); return 0; @@ -101,7 +118,7 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user, */ verbose("Rhosts with RSA host authentication accepted for %.100s, %.100s on %.700s.", - pw->pw_name, client_user, canonical_hostname); + pw->pw_name, client_user, canonical_hostname); packet_send_debug("Rhosts with RSA host authentication accepted."); return 1; } @@ -16,7 +16,7 @@ */ #include "includes.h" -RCSID("$Id: auth-rsa.c,v 1.13 2000/03/09 10:27:50 damien Exp $"); +RCSID("$Id: auth-rsa.c,v 1.14 2000/03/26 03:04:52 damien Exp $"); #include "rsa.h" #include "packet.h" @@ -24,6 +24,7 @@ RCSID("$Id: auth-rsa.c,v 1.13 2000/03/09 10:27:50 damien Exp $"); #include "ssh.h" #include "mpaux.h" #include "uidswap.h" +#include "match.h" #include "servconf.h" #ifdef HAVE_OPENSSL @@ -66,10 +67,9 @@ extern unsigned char session_id[16]; */ int -auth_rsa_challenge_dialog(BIGNUM *e, BIGNUM *n) +auth_rsa_challenge_dialog(RSA *pk) { BIGNUM *challenge, *encrypted_challenge; - RSA *pk; BN_CTX *ctx; unsigned char buf[32], mdbuf[16], response[16]; MD5_CTX md; @@ -82,19 +82,11 @@ auth_rsa_challenge_dialog(BIGNUM *e, BIGNUM *n) /* Generate a random challenge. */ BN_rand(challenge, 256, 0, 0); ctx = BN_CTX_new(); - BN_mod(challenge, challenge, n, ctx); + BN_mod(challenge, challenge, pk->n, ctx); BN_CTX_free(ctx); - /* Create the public key data structure. */ - pk = RSA_new(); - pk->e = BN_new(); - BN_copy(pk->e, e); - pk->n = BN_new(); - BN_copy(pk->n, n); - /* Encrypt the challenge with the public key. */ rsa_public_encrypt(encrypted_challenge, challenge, pk); - RSA_free(pk); /* Send the encrypted challenge to the client. */ packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE); @@ -146,7 +138,7 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n) FILE *f; unsigned long linenum = 0; struct stat st; - BIGNUM *e, *n; + RSA *pk; /* Temporarily use the user's uid. */ temporarily_use_uid(pw->pw_uid); @@ -208,8 +200,9 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n) /* Flag indicating whether authentication has succeeded. */ authenticated = 0; - e = BN_new(); - n = BN_new(); + pk = RSA_new(); + pk->e = BN_new(); + pk->n = BN_new(); /* * Go though the accepted keys, looking for the current key. If @@ -247,7 +240,7 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n) options = NULL; /* Parse the key from the line. */ - if (!auth_rsa_read_key(&cp, &bits, e, n)) { + if (!auth_rsa_read_key(&cp, &bits, pk->e, pk->n)) { debug("%.100s, line %lu: bad key syntax", SSH_USER_PERMITTED_KEYS, linenum); packet_send_debug("%.100s, line %lu: bad key syntax", @@ -257,19 +250,20 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n) /* cp now points to the comment part. */ /* Check if the we have found the desired key (identified by its modulus). */ - if (BN_cmp(n, client_n) != 0) + if (BN_cmp(pk->n, client_n) != 0) continue; /* check the real bits */ - if (bits != BN_num_bits(n)) + if (bits != BN_num_bits(pk->n)) log("Warning: %s, line %ld: keysize mismatch: " "actual %d vs. announced %d.", - file, linenum, BN_num_bits(n), bits); + file, linenum, BN_num_bits(pk->n), bits); /* We have found the desired key. */ + /* Perform the challenge-response dialog for this key. */ - if (!auth_rsa_challenge_dialog(e, n)) { + if (!auth_rsa_challenge_dialog(pk)) { /* Wrong response. */ verbose("Wrong response to RSA authentication challenge."); packet_send_debug("Wrong response to RSA authentication challenge."); @@ -472,8 +466,7 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n) /* Close the file. */ fclose(f); - BN_clear_free(n); - BN_clear_free(e); + RSA_free(pk); if (authenticated) packet_send_debug("RSA authentication accepted."); @@ -12,7 +12,7 @@ */ #include "includes.h" -RCSID("$Id: cipher.c,v 1.13 2000/03/09 10:27:50 damien Exp $"); +RCSID("$Id: cipher.c,v 1.14 2000/03/26 03:04:52 damien Exp $"); #include "ssh.h" #include "cipher.h" @@ -110,18 +110,6 @@ swap_bytes(const unsigned char *src, unsigned char *dst_, int n) } } -void (*cipher_attack_detected) (const char *fmt,...) = fatal; - -static inline void -detect_cbc_attack(const unsigned char *src, - unsigned int len) -{ - return; - - log("CRC-32 CBC insertion attack detected"); - cipher_attack_detected("CRC-32 CBC insertion attack detected"); -} - /* * Names of all encryption algorithms. * These must match the numbers defined in cipher.h. @@ -304,7 +292,6 @@ cipher_decrypt(CipherContext *context, unsigned char *dest, break; case SSH_CIPHER_3DES: - /* CRC-32 attack? */ SSH_3CBC_DECRYPT(context->u.des3.key1, context->u.des3.key2, &context->u.des3.iv2, context->u.des3.key3, &context->u.des3.iv3, @@ -312,7 +299,6 @@ cipher_decrypt(CipherContext *context, unsigned char *dest, break; case SSH_CIPHER_BLOWFISH: - detect_cbc_attack(src, len); swap_bytes(src, dest, len); BF_cbc_encrypt((void *) dest, dest, len, &context->u.bf.key, context->u.bf.iv, @@ -11,7 +11,7 @@ * */ -/* RCSID("$Id: cipher.h,v 1.5 1999/11/25 00:54:58 damien Exp $"); */ +/* RCSID("$Id: cipher.h,v 1.6 2000/03/26 03:04:52 damien Exp $"); */ #ifndef CIPHER_H #define CIPHER_H @@ -96,10 +96,4 @@ void cipher_decrypt(CipherContext * context, unsigned char *dest, const unsigned char *src, unsigned int len); -/* - * If and CRC-32 attack is detected this function is called. Defaults to - * fatal, changed to packet_disconnect in sshd and ssh. - */ -extern void (*cipher_attack_detected) (const char *fmt, ...); - #endif /* CIPHER_H */ @@ -14,63 +14,32 @@ */ #include "includes.h" -RCSID("$OpenBSD: hostfile.c,v 1.13 2000/02/18 10:20:20 markus Exp $"); +RCSID("$OpenBSD: hostfile.c,v 1.14 2000/03/23 22:15:33 markus Exp $"); + +#ifdef HAVE_OPENSSL +#include <openssl/bn.h> +#include <openssl/rsa.h> +#include <openssl/dsa.h> +#endif +#ifdef HAVE_SSL +#include <ssl/bn.h> +#include <ssl/rsa.h> +#include <ssl/dsa.h> +#endif #include "packet.h" +#include "match.h" #include "ssh.h" +#include "key.h" +#include "hostfile.h" /* - * 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. + * Parses an RSA (number of bits, e, n) or DSA key from a string. Moves the + * pointer over the key. Skips any whitespace at the beginning and at end. */ int -auth_rsa_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; -} - -/* - * Parses an RSA key (number of bits, e, n) from a string. Moves the pointer - * over the key. Skips any whitespace at the beginning and at end. - */ - -int -auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n) +hostfile_read_key(char **cpp, unsigned int *bitsp, Key *ret) { unsigned int bits; char *cp; @@ -85,12 +54,7 @@ auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n) for (bits = 0; *cp >= '0' && *cp <= '9'; cp++) bits = 10 * bits + *cp - '0'; - /* Get public exponent. */ - if (!auth_rsa_read_bignum(&cp, e)) - return 0; - - /* Get public modulus. */ - if (!auth_rsa_read_bignum(&cp, n)) + if (!key_read(ret, bits, &cp)) return 0; /* Skip trailing whitespace. */ @@ -103,63 +67,30 @@ auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n) return 1; } -/* - * Tries to match the host name (which must be in all lowercase) against the - * comma-separated sequence of subpatterns (each possibly preceded by ! to - * indicate negation). Returns true if there is a positive match; zero - * otherwise. - */ - int -match_hostname(const char *host, const char *pattern, unsigned int len) +auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM * e, BIGNUM * n) { - char sub[1024]; - int negated; - int got_positive; - unsigned int i, subi; - - got_positive = 0; - for (i = 0; i < len;) { - /* Check if the subpattern is negated. */ - if (pattern[i] == '!') { - negated = 1; - i++; - } else - negated = 0; - - /* - * Extract the subpattern up to a comma or end. Convert the - * subpattern to lowercase. - */ - for (subi = 0; - i < len && subi < sizeof(sub) - 1 && pattern[i] != ','; - subi++, i++) - sub[subi] = isupper(pattern[i]) ? tolower(pattern[i]) : pattern[i]; - /* If subpattern too long, return failure (no match). */ - if (subi >= sizeof(sub) - 1) - return 0; - - /* If the subpattern was terminated by a comma, skip the comma. */ - if (i < len && pattern[i] == ',') - i++; - - /* Null-terminate the subpattern. */ - sub[subi] = '\0'; + Key *k = key_new(KEY_RSA); + int ret = hostfile_read_key(cpp, bitsp, k); + BN_copy(e, k->rsa->e); + BN_copy(n, k->rsa->n); + key_free(k); + return ret; +} - /* Try to match the subpattern against the host name. */ - if (match_pattern(host, sub)) { - if (negated) - return 0; /* Fail */ - else - got_positive = 1; - } +int +hostfile_check_key(int bits, Key *key, const char *host, const char *filename, int linenum) +{ + if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) + return 1; + if (bits != BN_num_bits(key->rsa->n)) { + error("Warning: %s, line %d: keysize mismatch for host %s: " + "actual %d vs. announced %d.", + filename, linenum, host, BN_num_bits(key->rsa->n), bits); + error("Warning: replace %d with %d in %s, line %d.", + bits, BN_num_bits(key->rsa->n), filename, linenum); } - - /* - * Return success if got a positive match. If there was a negative - * match, we have already returned zero and never get here. - */ - return got_positive; + return 1; } /* @@ -170,8 +101,7 @@ match_hostname(const char *host, const char *pattern, unsigned int len) */ HostStatus -check_host_in_hostfile(const char *filename, const char *host, - BIGNUM * e, BIGNUM * n, BIGNUM * ke, BIGNUM * kn) +check_host_in_hostfile(const char *filename, const char *host, Key *key, Key *found) { FILE *f; char line[8192]; @@ -180,6 +110,8 @@ check_host_in_hostfile(const char *filename, const char *host, char *cp, *cp2; HostStatus end_return; + if (key == NULL) + fatal("no key to look up"); /* Open the file containing the list of known hosts. */ f = fopen(filename, "r"); if (!f) @@ -221,18 +153,13 @@ check_host_in_hostfile(const char *filename, const char *host, * Extract the key from the line. This will skip any leading * whitespace. Ignore badly formatted lines. */ - if (!auth_rsa_read_key(&cp, &kbits, ke, kn)) + if (!hostfile_read_key(&cp, &kbits, found)) + continue; + if (!hostfile_check_key(kbits, found, host, filename, linenum)) continue; - if (kbits != BN_num_bits(kn)) { - error("Warning: %s, line %d: keysize mismatch for host %s: " - "actual %d vs. announced %d.", - filename, linenum, host, BN_num_bits(kn), kbits); - error("Warning: replace %d with %d in %s, line %d.", - kbits, BN_num_bits(kn), filename, linenum); - } /* Check if the current key is the same as the given key. */ - if (BN_cmp(ke, e) == 0 && BN_cmp(kn, n) == 0) { + if (key_equal(key, found)) { /* Ok, they match. */ fclose(f); return HOST_OK; @@ -260,41 +187,28 @@ check_host_in_hostfile(const char *filename, const char *host, */ int -add_host_to_hostfile(const char *filename, const char *host, - BIGNUM * e, BIGNUM * n) +add_host_to_hostfile(const char *filename, const char *host, Key *key) { FILE *f; - char *buf; - unsigned int bits; + int success = 0; + + if (key == NULL) + return 1; /* Open the file for appending. */ f = fopen(filename, "a"); if (!f) return 0; - /* size of modulus 'n' */ - bits = BN_num_bits(n); - - /* Print the host name and key to the file. */ - fprintf(f, "%s %u ", host, bits); - buf = BN_bn2dec(e); - if (buf == NULL) { - error("add_host_to_hostfile: BN_bn2dec(e) failed"); - fclose(f); - return 0; + fprintf(f, "%s ", host); + if (key_write(key, f)) { + fprintf(f, "\n"); + success = 1; + } else { + error("add_host_to_hostfile: saving key failed"); } - fprintf(f, "%s ", buf); - free(buf); - buf = BN_bn2dec(n); - if (buf == NULL) { - error("add_host_to_hostfile: BN_bn2dec(n) failed"); - fclose(f); - return 0; - } - fprintf(f, "%s\n", buf); - free(buf); /* Close the file. */ fclose(f); - return 1; + return success; } diff --git a/hostfile.h b/hostfile.h new file mode 100644 index 00000000..64fe185d --- /dev/null +++ b/hostfile.h @@ -0,0 +1,22 @@ +#ifndef HOSTFILE_H +#define HOSTFILE_H + +/* + * Checks whether the given host is already in the list of our known hosts. + * Returns HOST_OK if the host is known and has the specified key, HOST_NEW + * if the host is not known, and HOST_CHANGED if the host is known but used + * to have a different host key. The host must be in all lowercase. + */ +typedef enum { + HOST_OK, HOST_NEW, HOST_CHANGED +} HostStatus; +HostStatus +check_host_in_hostfile(const char *filename, const char *host, Key *key, Key *found); + +/* + * Appends an entry to the host file. Returns false if the entry could not + * be appended. + */ +int add_host_to_hostfile(const char *filename, const char *host, Key *key); + +#endif @@ -0,0 +1,301 @@ +/* + * 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" + +#ifdef HAVE_OPENSSL +#include <openssl/bn.h> +#include <openssl/rsa.h> +#include <openssl/dsa.h> +#include <openssl/evp.h> +#endif +#ifdef HAVE_SSL +#include <ssl/bn.h> +#include <ssl/rsa.h> +#include <ssl/dsa.h> +#include <ssl/evp.h> +#endif + +#include "ssh.h" +#include "xmalloc.h" +#include "key.h" + +Key * +key_new(int type) +{ + Key *k; + RSA *rsa; + DSA *dsa; + k = xmalloc(sizeof(*k)); + k->type = type; + 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: + k->dsa = NULL; + k->rsa = NULL; + 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_free: 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 *buf = NULL; + int len = 0; + int nlen, elen, plen, qlen, glen, publen; + + switch (k->type) { + case KEY_RSA: + nlen = BN_num_bytes(k->rsa->n); + elen = BN_num_bytes(k->rsa->e); + len = nlen + elen; + buf = xmalloc(len); + BN_bn2bin(k->rsa->n, buf); + BN_bn2bin(k->rsa->e, buf + nlen); + break; + case KEY_DSA: + plen = BN_num_bytes(k->dsa->p); + qlen = BN_num_bytes(k->dsa->q); + glen = BN_num_bytes(k->dsa->g); + publen = BN_num_bytes(k->dsa->pub_key); + len = qlen + qlen + glen + publen; + buf = xmalloc(len); + BN_bn2bin(k->dsa->p, buf); + BN_bn2bin(k->dsa->q, buf + plen); + BN_bn2bin(k->dsa->g, buf + plen + qlen); + BN_bn2bin(k->dsa->pub_key , buf + plen + qlen + glen); + break; + default: + fatal("key_fingerprint: bad key type %d", k->type); + break; + } + if (buf != NULL) { + unsigned char d[16]; + EVP_MD_CTX md; + EVP_DigestInit(&md, EVP_md5()); + EVP_DigestUpdate(&md, buf, 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(buf, 0, len); + xfree(buf); + } + 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; + } |