diff options
Diffstat (limited to 'usr.bin/ssh')
39 files changed, 1516 insertions, 1678 deletions
diff --git a/usr.bin/ssh/auth-rh-rsa.c b/usr.bin/ssh/auth-rh-rsa.c new file mode 100644 index 00000000000..bcb43126488 --- /dev/null +++ b/usr.bin/ssh/auth-rh-rsa.c @@ -0,0 +1,76 @@ +/* + +auth-rh-rsa.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Sun May 7 03:08:06 1995 ylo + +Rhosts or /etc/hosts.equiv authentication combined with RSA host +authentication. + +*/ + +#include "includes.h" +RCSID("$Id: auth-rh-rsa.c,v 1.1 1999/09/28 04:45:35 provos Exp $"); + +#include "packet.h" +#include "ssh.h" +#include "xmalloc.h" +#include "uidswap.h" + +/* Tries to authenticate the user using the .rhosts file and the host using + its host key. Returns true if authentication succeeds. + .rhosts and .shosts will be ignored if ignore_rhosts is non-zero. */ + +int auth_rhosts_rsa(struct passwd *pw, const char *client_user, + unsigned int client_host_key_bits, + BIGNUM *client_host_key_e, BIGNUM *client_host_key_n, + int ignore_rhosts, int strict_modes) +{ + const char *canonical_hostname; + + debug("Trying rhosts with RSA host authentication for %.100s", client_user); + + /* Check if we would accept it using rhosts authentication. */ + if (!auth_rhosts(pw, client_user, ignore_rhosts, strict_modes)) + return 0; + + canonical_hostname = get_canonical_hostname(); + + debug("Rhosts RSA authentication: canonical host %.900s", + canonical_hostname); + + /* Check if we know the host and its host key. */ + /* Check system-wide host file. */ + if (check_host_in_hostfile(SSH_SYSTEM_HOSTFILE, canonical_hostname, + client_host_key_bits, client_host_key_e, + client_host_key_n) != HOST_OK) + { + /* The host key was not found. */ + debug("Rhosts with RSA host authentication denied: unknown or invalid host key"); + packet_send_debug("Your host key cannot be verified: unknown or invalid host key."); + return 0; + } + /* 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_bits, + client_host_key_e, client_host_key_n)) + { + log("Client on %.800s failed to respond correctly to host authentication.", + canonical_hostname); + return 0; + } + + /* We have authenticated the user using .rhosts or /etc/hosts.equiv, and + the host using RSA. We accept the authentication. */ + + log("Rhosts with RSA host authentication accepted for %.100s, %.100s on %.700s.", + pw->pw_name, client_user, canonical_hostname); + packet_send_debug("Rhosts with RSA host authentication accepted."); + return 1; +} diff --git a/usr.bin/ssh/auth-rhosts.c b/usr.bin/ssh/auth-rhosts.c index 0d325bb04df..3ad2d5d8e45 100644 --- a/usr.bin/ssh/auth-rhosts.c +++ b/usr.bin/ssh/auth-rhosts.c @@ -16,7 +16,7 @@ the login based on rhosts authentication. This file also processes */ #include "includes.h" -RCSID("$Id: auth-rhosts.c,v 1.1 1999/09/26 20:53:33 deraadt Exp $"); +RCSID("$Id: auth-rhosts.c,v 1.2 1999/09/28 04:45:35 provos Exp $"); #include "packet.h" #include "ssh.h" diff --git a/usr.bin/ssh/auth-rsa.c b/usr.bin/ssh/auth-rsa.c new file mode 100644 index 00000000000..a0cd3470816 --- /dev/null +++ b/usr.bin/ssh/auth-rsa.c @@ -0,0 +1,437 @@ +/* + +auth-rsa.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Mon Mar 27 01:46:52 1995 ylo + +RSA-based authentication. This code determines whether to admit a login +based on RSA authentication. This file also contains functions to check +validity of the host key. + +*/ + +#include "includes.h" +RCSID("$Id: auth-rsa.c,v 1.1 1999/09/28 04:45:35 provos Exp $"); + +#include "rsa.h" +#include "packet.h" +#include "xmalloc.h" +#include "ssh.h" +#include "ssh_md5.h" +#include "mpaux.h" +#include "uidswap.h" + +#include <ssl/rsa.h> + +/* Flags that may be set in authorized_keys options. */ +extern int no_port_forwarding_flag; +extern int no_agent_forwarding_flag; +extern int no_x11_forwarding_flag; +extern int no_pty_flag; +extern char *forced_command; +extern struct envstring *custom_environment; + +/* Session identifier that is used to bind key exchange and authentication + responses to a particular session. */ +extern unsigned char session_id[16]; + +/* The .ssh/authorized_keys file contains public keys, one per line, in the + following format: + options bits e n comment + where bits, e and n are decimal numbers, + and comment is any string of characters up to newline. The maximum + length of a line is 8000 characters. See the documentation for a + description of the options. +*/ + +/* Performs the RSA authentication challenge-response dialog with the client, + and returns true (non-zero) if the client gave the correct answer to + our challenge; returns zero if the client gives a wrong answer. */ + +int +auth_rsa_challenge_dialog(unsigned int bits, BIGNUM *e, BIGNUM *n) +{ + BIGNUM *challenge, *encrypted_challenge, *aux; + RSA *pk; + BN_CTX *ctx = BN_CTX_new(); + unsigned char buf[32], mdbuf[16], response[16]; + struct MD5Context md; + unsigned int i; + int plen, len; + + encrypted_challenge = BN_new(); + challenge = BN_new(); + aux = BN_new(); + + /* Generate a random challenge. */ + BN_rand(challenge, 256, 0, 0); + BN_mod(challenge, challenge, n, 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); + packet_put_bignum(encrypted_challenge); + packet_send(); + packet_write_wait(); + + /* The response is MD5 of decrypted challenge plus session id. */ + len = (BN_num_bits(challenge) + 7) / 8; + assert(len <= 32 && len); + memset(buf, 0, 32); + BN_bn2bin(challenge, buf + 32 - len); + MD5Init(&md); + MD5Update(&md, buf, 32); + MD5Update(&md, session_id, 16); + MD5Final(mdbuf, &md); + + /* We will no longer need these. */ + BN_clear_free(encrypted_challenge); + BN_clear_free(challenge); + BN_clear_free(aux); + BN_CTX_free(ctx); + + /* Wait for a response. */ + packet_read_expect(&plen, SSH_CMSG_AUTH_RSA_RESPONSE); + packet_integrity_check(plen, 16, SSH_CMSG_AUTH_RSA_RESPONSE); + for (i = 0; i < 16; i++) + response[i] = packet_get_char(); + + /* Verify that the response is the original challenge. */ + if (memcmp(response, mdbuf, 16) != 0) + { + /* Wrong answer. */ + return 0; + } + + /* Correct answer. */ + return 1; +} + +/* Performs the RSA authentication dialog with the client. This returns + 0 if the client could not be authenticated, and 1 if authentication was + successful. This may exit if there is a serious protocol violation. */ + +int +auth_rsa(struct passwd *pw, BIGNUM *client_n) +{ + char line[8192]; + int authenticated; + unsigned int bits; + FILE *f; + unsigned long linenum = 0; + struct stat st; + BIGNUM *e, *n; + + /* Open the file containing the authorized keys. */ + sprintf(line, "%.500s/%.100s", pw->pw_dir, SSH_USER_PERMITTED_KEYS); + + /* Temporarily use the user's uid. */ + temporarily_use_uid(pw->pw_uid); + if (stat(line, &st) < 0) + { + /* Restore the privileged uid. */ + restore_uid(); + return 0; + } + f = fopen(line, "r"); + if (!f) + { + /* Restore the privileged uid. */ + restore_uid(); + packet_send_debug("Could not open %.900s for reading.", line); + packet_send_debug("If your home is on an NFS volume, it may need to be world-readable."); + return 0; + } + + /* Flag indicating whether authentication has succeeded. */ + authenticated = 0; + + /* Initialize mp-int variables. */ + e = BN_new(); + n = BN_new(); + + /* Go though the accepted keys, looking for the current key. If found, + perform a challenge-response dialog to verify that the user really has + the corresponding private key. */ + while (fgets(line, sizeof(line), f)) + { + char *cp; + char *options; + + linenum++; + + /* Skip leading whitespace. */ + for (cp = line; *cp == ' ' || *cp == '\t'; cp++) + ; + + /* Skip empty and comment lines. */ + if (!*cp || *cp == '\n' || *cp == '#') + continue; + + /* Check if there are options for this key, and if so, save their + starting address and skip the option part for now. If there are no + options, set the starting address to NULL. */ + if (*cp < '0' || *cp > '9') + { + int quoted = 0; + options = cp; + for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) + { + if (*cp == '\\' && cp[1] == '"') + cp++; /* Skip both */ + else + if (*cp == '"') + quoted = !quoted; + } + } + else + options = NULL; + + /* Parse the key from the line. */ + if (!auth_rsa_read_key(&cp, &bits, e, n)) + { + debug("%.100s, line %lu: bad key syntax", + SSH_USER_PERMITTED_KEYS, linenum); + packet_send_debug("%.100s, line %lu: bad key syntax", + SSH_USER_PERMITTED_KEYS, linenum); + continue; + } + /* 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) + continue; /* Wrong key. */ + + /* We have found the desired key. */ + + /* Perform the challenge-response dialog for this key. */ + if (!auth_rsa_challenge_dialog(bits, e, n)) + { + /* Wrong response. */ + log("Wrong response to RSA authentication challenge."); + packet_send_debug("Wrong response to RSA authentication challenge."); + continue; + } + + /* Correct response. The client has been successfully authenticated. + Note that we have not yet processed the options; this will be reset + if the options cause the authentication to be rejected. */ + authenticated = 1; + + /* RSA part of authentication was accepted. Now process the options. */ + if (options) + { + while (*options && *options != ' ' && *options != '\t') + { + cp = "no-port-forwarding"; + if (strncmp(options, cp, strlen(cp)) == 0) + { + packet_send_debug("Port forwarding disabled."); + no_port_forwarding_flag = 1; + options += strlen(cp); + goto next_option; + } + cp = "no-agent-forwarding"; + if (strncmp(options, cp, strlen(cp)) == 0) + { + packet_send_debug("Agent forwarding disabled."); + no_agent_forwarding_flag = 1; + options += strlen(cp); + goto next_option; + } + cp = "no-X11-forwarding"; + if (strncmp(options, cp, strlen(cp)) == 0) + { + packet_send_debug("X11 forwarding disabled."); + no_x11_forwarding_flag = 1; + options += strlen(cp); + goto next_option; + } + cp = "no-pty"; + if (strncmp(options, cp, strlen(cp)) == 0) + { + packet_send_debug("Pty allocation disabled."); + no_pty_flag = 1; + options += strlen(cp); + goto next_option; + } + cp = "command=\""; + if (strncmp(options, cp, strlen(cp)) == 0) + { + int i; + options += strlen(cp); + forced_command = xmalloc(strlen(options) + 1); + i = 0; + while (*options) + { + if (*options == '"') + break; + if (*options == '\\' && options[1] == '"') + { + options += 2; + forced_command[i++] = '"'; + continue; + } + forced_command[i++] = *options++; + } + if (!*options) + { + debug("%.100s, line %lu: missing end quote", + SSH_USER_PERMITTED_KEYS, linenum); + packet_send_debug("%.100s, line %lu: missing end quote", + SSH_USER_PERMITTED_KEYS, linenum); + continue; + } + forced_command[i] = 0; + packet_send_debug("Forced command: %.900s", forced_command); + options++; + goto next_option; + } + cp = "environment=\""; + if (strncmp(options, cp, strlen(cp)) == 0) + { + int i; + char *s; + struct envstring *new_envstring; + options += strlen(cp); + s = xmalloc(strlen(options) + 1); + i = 0; + while (*options) + { + if (*options == '"') + break; + if (*options == '\\' && options[1] == '"') + { + options += 2; + s[i++] = '"'; + continue; + } + s[i++] = *options++; + } + if (!*options) + { + debug("%.100s, line %lu: missing end quote", + SSH_USER_PERMITTED_KEYS, linenum); + packet_send_debug("%.100s, line %lu: missing end quote", + SSH_USER_PERMITTED_KEYS, linenum); + continue; + } + s[i] = 0; + packet_send_debug("Adding to environment: %.900s", s); + debug("Adding to environment: %.900s", s); + options++; + new_envstring = xmalloc(sizeof(struct envstring)); + new_envstring->s = s; + new_envstring->next = custom_environment; + custom_environment = new_envstring; + goto next_option; + } + cp = "from=\""; + if (strncmp(options, cp, strlen(cp)) == 0) + { + char *patterns = xmalloc(strlen(options) + 1); + int i; + options += strlen(cp); + i = 0; + while (*options) + { + if (*options == '"') + break; + if (*options == '\\' && options[1] == '"') + { + options += 2; + patterns[i++] = '"'; + continue; + } + patterns[i++] = *options++; + } + if (!*options) + { + debug("%.100s, line %lu: missing end quote", + SSH_USER_PERMITTED_KEYS, linenum); + packet_send_debug("%.100s, line %lu: missing end quote", + SSH_USER_PERMITTED_KEYS, linenum); + continue; + } + patterns[i] = 0; + options++; + if (!match_hostname(get_canonical_hostname(), patterns, + strlen(patterns)) && + !match_hostname(get_remote_ipaddr(), patterns, + strlen(patterns))) + { + log("RSA authentication tried for %.100s with correct key but not from a permitted host (host=%.200s, ip=%.200s).", + pw->pw_name, get_canonical_hostname(), + get_remote_ipaddr()); + packet_send_debug("Your host '%.200s' is not permitted to use this key for login.", + get_canonical_hostname()); + xfree(patterns); + authenticated = 0; + break; + } + xfree(patterns); + /* Host name matches. */ + goto next_option; + } + bad_option: + /* Unknown option. */ + log("Bad options in %.100s file, line %lu: %.50s", + SSH_USER_PERMITTED_KEYS, linenum, options); + packet_send_debug("Bad options in %.100s file, line %lu: %.50s", + SSH_USER_PERMITTED_KEYS, linenum, options); + authenticated = 0; + break; + + next_option: + /* Skip the comma, and move to the next option (or break out + if there are no more). */ + if (!*options) + fatal("Bugs in auth-rsa.c option processing."); + if (*options == ' ' || *options == '\t') + break; /* End of options. */ + if (*options != ',') + goto bad_option; + options++; + /* Process the next option. */ + continue; + } + } + + /* Break out of the loop if authentication was successful; otherwise + continue searching. */ + if (authenticated) + break; + } + + /* Restore the privileged uid. */ + restore_uid(); + + /* Close the file. */ + fclose(f); + + /* Clear any mp-int variables. */ + BN_clear_free(n); + BN_clear_free(e); + + if (authenticated) + packet_send_debug("RSA authentication accepted."); + + /* Return authentication result. */ + return authenticated; +} diff --git a/usr.bin/ssh/authfd.c b/usr.bin/ssh/authfd.c index a09dc4c2541..77a2478191c 100644 --- a/usr.bin/ssh/authfd.c +++ b/usr.bin/ssh/authfd.c @@ -14,7 +14,7 @@ Functions for connecting the local authentication agent. */ #include "includes.h" -RCSID("$Id: authfd.c,v 1.1 1999/09/26 20:53:33 deraadt Exp $"); +RCSID("$Id: authfd.c,v 1.2 1999/09/28 04:45:35 provos Exp $"); #include "ssh.h" #include "rsa.h" @@ -24,9 +24,12 @@ RCSID("$Id: authfd.c,v 1.1 1999/09/26 20:53:33 deraadt Exp $"); #include "xmalloc.h" #include "getput.h" +#include <ssl/rsa.h> + /* Returns the number of the authentication fd, or -1 if there is none. */ -int ssh_get_authentication_fd() +int +ssh_get_authentication_fd() { const char *authfd, *authsocket; int sock; @@ -202,8 +205,9 @@ void ssh_close_authentication_connection(AuthenticationConnection *ac) The caller must initialize the integers before the call, and free the comment after a successful call (before calling ssh_get_next_identity). */ -int ssh_get_first_identity(AuthenticationConnection *auth, - int *bitsp, MP_INT *e, MP_INT *n, char **comment) +int +ssh_get_first_identity(AuthenticationConnection *auth, + int *bitsp, BIGNUM *e, BIGNUM *n, char **comment) { unsigned char msg[8192]; int len, l; @@ -273,8 +277,9 @@ int ssh_get_first_identity(AuthenticationConnection *auth, function. This returns 0 if there are no more identities. The caller must free comment after a successful return. */ -int ssh_get_next_identity(AuthenticationConnection *auth, - int *bitsp, MP_INT *e, MP_INT *n, char **comment) +int +ssh_get_next_identity(AuthenticationConnection *auth, + int *bitsp, BIGNUM *e, BIGNUM *n, char **comment) { /* Return failure if no more entries. */ if (auth->howmany <= 0) @@ -283,8 +288,8 @@ int ssh_get_next_identity(AuthenticationConnection *auth, /* Get the next entry from the packet. These will abort with a fatal error if the packet is too short or contains corrupt data. */ *bitsp = buffer_get_int(&auth->identities); - buffer_get_mp_int(&auth->identities, e); - buffer_get_mp_int(&auth->identities, n); + buffer_get_bignum(&auth->identities, e); + buffer_get_bignum(&auth->identities, n); *comment = buffer_get_string(&auth->identities, NULL); /* Decrement the number of remaining entries. */ @@ -299,11 +304,12 @@ int ssh_get_next_identity(AuthenticationConnection *auth, desired, with 0 corresponding to protocol version 1.0 (no longer supported) and 1 corresponding to protocol version 1.1. */ -int ssh_decrypt_challenge(AuthenticationConnection *auth, - int bits, MP_INT *e, MP_INT *n, MP_INT *challenge, - unsigned char session_id[16], - unsigned int response_type, - unsigned char response[16]) +int +ssh_decrypt_challenge(AuthenticationConnection *auth, + int bits, BIGNUM *e, BIGNUM *n, BIGNUM *challenge, + unsigned char session_id[16], + unsigned int response_type, + unsigned char response[16]) { Buffer buffer; unsigned char buf[8192]; @@ -318,9 +324,9 @@ int ssh_decrypt_challenge(AuthenticationConnection *auth, buffer_init(&buffer); buffer_append(&buffer, (char *)buf, 1); buffer_put_int(&buffer, bits); - buffer_put_mp_int(&buffer, e); - buffer_put_mp_int(&buffer, n); - buffer_put_mp_int(&buffer, challenge); + buffer_put_bignum(&buffer, e); + buffer_put_bignum(&buffer, n); + buffer_put_bignum(&buffer, challenge); buffer_append(&buffer, (char *)session_id, 16); buffer_put_int(&buffer, response_type); @@ -405,7 +411,7 @@ int ssh_decrypt_challenge(AuthenticationConnection *auth, be used by normal applications. */ int ssh_add_identity(AuthenticationConnection *auth, - RSAPrivateKey *key, const char *comment) + RSA *key, const char *comment) { Buffer buffer; unsigned char buf[8192]; @@ -414,13 +420,14 @@ int ssh_add_identity(AuthenticationConnection *auth, /* Format a message to the agent. */ buffer_init(&buffer); buffer_put_char(&buffer, SSH_AGENTC_ADD_RSA_IDENTITY); - buffer_put_int(&buffer, key->bits); - buffer_put_mp_int(&buffer, &key->n); - buffer_put_mp_int(&buffer, &key->e); - buffer_put_mp_int(&buffer, &key->d); - buffer_put_mp_int(&buffer, &key->u); - buffer_put_mp_int(&buffer, &key->p); - buffer_put_mp_int(&buffer, &key->q); + buffer_put_int(&buffer, BN_num_bits(key->n)); + buffer_put_bignum(&buffer, key->n); + buffer_put_bignum(&buffer, key->e); + buffer_put_bignum(&buffer, key->d); + /* To keep within the protocol: p < q for ssh. in SSL p > q */ + buffer_put_bignum(&buffer, key->iqmp); /* ssh key->u */ + buffer_put_bignum(&buffer, key->q); /* ssh key->p, SSL key->q */ + buffer_put_bignum(&buffer, key->p); /* ssh key->q, SSL key->p */ buffer_put_string(&buffer, comment, strlen(comment)); /* Get the length of the message, and format it in the buffer. */ @@ -495,7 +502,7 @@ int ssh_add_identity(AuthenticationConnection *auth, /* Removes an identity from the authentication server. This call is not meant to be used by normal applications. */ -int ssh_remove_identity(AuthenticationConnection *auth, RSAPublicKey *key) +int ssh_remove_identity(AuthenticationConnection *auth, RSA *key) { Buffer buffer; unsigned char buf[8192]; @@ -504,9 +511,9 @@ int ssh_remove_identity(AuthenticationConnection *auth, RSAPublicKey *key) /* Format a message to the agent. */ buffer_init(&buffer); buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY); - buffer_put_int(&buffer, key->bits); - buffer_put_mp_int(&buffer, &key->e); - buffer_put_mp_int(&buffer, &key->n); + buffer_put_int(&buffer, BN_num_bits(key->n)); + buffer_put_bignum(&buffer, key->e); + buffer_put_bignum(&buffer, key->n); /* Get the length of the message, and format it in the buffer. */ len = buffer_len(&buffer); diff --git a/usr.bin/ssh/authfd.h b/usr.bin/ssh/authfd.h index 77f92b85b89..f889830b820 100644 --- a/usr.bin/ssh/authfd.h +++ b/usr.bin/ssh/authfd.h @@ -13,7 +13,7 @@ Functions to interface with the SSH_AUTHENTICATION_FD socket. */ -/* RCSID("$Id: authfd.h,v 1.1 1999/09/26 20:53:33 deraadt Exp $"); */ +/* RCSID("$Id: authfd.h,v 1.2 1999/09/28 04:45:35 provos Exp $"); */ #ifndef AUTHFD_H #define AUTHFD_H @@ -69,19 +69,19 @@ void ssh_close_authentication_connection(AuthenticationConnection *ac); The caller must initialize the integers before the call, and free the comment after a successful call (before calling ssh_get_next_identity). */ int ssh_get_first_identity(AuthenticationConnection *connection, - int *bitsp, MP_INT *e, MP_INT *n, char **comment); + int *bitsp, BIGNUM *e, BIGNUM *n, char **comment); /* Returns the next authentication identity for the agent. Other functions can be called between this and ssh_get_first_identity or two calls of this function. This returns 0 if there are no more identities. The caller must free comment after a successful return. */ int ssh_get_next_identity(AuthenticationConnection *connection, - int *bitsp, MP_INT *e, MP_INT *n, char **comment); + int *bitsp, BIGNUM *e, BIGNUM *n, char **comment); /* Requests the agent to decrypt the given challenge. Returns true if the agent claims it was able to decrypt it. */ int ssh_decrypt_challenge(AuthenticationConnection *auth, - int bits, MP_INT *e, MP_INT *n, MP_INT *challenge, + int bits, BIGNUM *e, BIGNUM *n, BIGNUM *challenge, unsigned char session_id[16], unsigned int response_type, unsigned char response[16]); @@ -90,13 +90,13 @@ int ssh_decrypt_challenge(AuthenticationConnection *auth, be used by normal applications. This returns true if the identity was successfully added. */ int ssh_add_identity(AuthenticationConnection *connection, - RSAPrivateKey *key, const char *comment); + RSA *key, const char *comment); /* Removes the identity from the authentication server. This call is not meant to be used by normal applications. This returns true if the identity was successfully added. */ int ssh_remove_identity(AuthenticationConnection *connection, - RSAPublicKey *key); + RSA *key); /* Removes all identities from the authentication agent. This call is not meant to be used by normal applications. This returns true if the diff --git a/usr.bin/ssh/authfile.c b/usr.bin/ssh/authfile.c index 5238a8f4af1..bd7b88b8ebc 100644 --- a/usr.bin/ssh/authfile.c +++ b/usr.bin/ssh/authfile.c @@ -15,9 +15,9 @@ for reading the passphrase from the user. */ #include "includes.h" -RCSID("$Id: authfile.c,v 1.2 1999/09/26 21:02:15 deraadt Exp $"); +RCSID("$Id: authfile.c,v 1.3 1999/09/28 04:45:35 provos Exp $"); -#include <gmp.h> +#include <ssl/bn.h> #include "xmalloc.h" #include "buffer.h" #include "bufaux.h" @@ -32,15 +32,16 @@ RCSID("$Id: authfile.c,v 1.2 1999/09/26 21:02:15 deraadt Exp $"); will precede the key to provide identification of the key without needing a passphrase. */ -int save_private_key(const char *filename, const char *passphrase, - RSAPrivateKey *key, const char *comment, - RandomState *state) +int +save_private_key(const char *filename, const char *passphrase, + RSA *key, const char *comment) { Buffer buffer, encrypted; char buf[100], *cp; int f, i; CipherContext cipher; int cipher_type; + u_int32_t rand; /* If the passphrase is empty, use SSH_CIPHER_NONE to ease converting to another cipher; otherwise use SSH_AUTHFILE_CIPHER. */ @@ -53,8 +54,9 @@ int save_private_key(const char *filename, const char *passphrase, buffer_init(&buffer); /* Put checkbytes for checking passphrase validity. */ - buf[0] = random_get_byte(state); - buf[1] = random_get_byte(state); + rand = arc4random(); + buf[0] = rand & 0xff; + buf[1] = (rand >> 8) & 0xff; buf[2] = buf[0]; buf[3] = buf[1]; buffer_append(&buffer, buf, 4); @@ -62,10 +64,10 @@ int save_private_key(const char *filename, const char *passphrase, /* Store the private key (n and e will not be stored because they will be stored in plain text, and storing them also in encrypted format would just give known plaintext). */ - buffer_put_mp_int(&buffer, &key->d); - buffer_put_mp_int(&buffer, &key->u); - buffer_put_mp_int(&buffer, &key->p); - buffer_put_mp_int(&buffer, &key->q); + buffer_put_bignum(&buffer, key->d); + buffer_put_bignum(&buffer, key->iqmp); + buffer_put_bignum(&buffer, key->q); /* reverse from SSL p */ + buffer_put_bignum(&buffer, key->p); /* reverse from SSL q */ /* Pad the part to be encrypted until its size is a multiple of 8. */ while (buffer_len(&buffer) % 8 != 0) @@ -85,9 +87,9 @@ int save_private_key(const char *filename, const char *passphrase, buffer_put_int(&encrypted, 0); /* For future extension */ /* Store public key. This will be in plain text. */ - buffer_put_int(&encrypted, key->bits); - buffer_put_mp_int(&encrypted, &key->n); - buffer_put_mp_int(&encrypted, &key->e); + buffer_put_int(&encrypted, BN_num_bits(key->n)); + buffer_put_bignum(&encrypted, key->n); + buffer_put_bignum(&encrypted, key->e); buffer_put_string(&encrypted, comment, strlen(comment)); /* Allocate space for the private part of the key in the buffer. */ @@ -127,8 +129,9 @@ int save_private_key(const char *filename, const char *passphrase, was encountered (the file does not exist or is not readable), and non-zero otherwise. */ -int load_public_key(const char *filename, RSAPublicKey *pub, - char **comment_return) +int +load_public_key(const char *filename, RSA *pub, + char **comment_return) { int f, i; unsigned long len; @@ -179,11 +182,11 @@ int load_public_key(const char *filename, RSAPublicKey *pub, (void)buffer_get_int(&buffer); /* reserved */ /* Read the public key from the buffer. */ - pub->bits = buffer_get_int(&buffer); - mpz_init(&pub->n); - buffer_get_mp_int(&buffer, &pub->n); - mpz_init(&pub->e); - buffer_get_mp_int(&buffer, &pub->e); + buffer_get_int(&buffer); + pub->n = BN_new(); + buffer_get_bignum(&buffer, pub->n); + pub->e = BN_new(); + buffer_get_bignum(&buffer, pub->e); if (comment_return) *comment_return = buffer_get_string(&buffer, NULL); /* The encrypted private part is not parsed by this function. */ @@ -197,14 +200,17 @@ int load_public_key(const char *filename, RSAPublicKey *pub, (file does not exist or is not readable, or passphrase is bad). This initializes the private key. */ -int load_private_key(const char *filename, const char *passphrase, - RSAPrivateKey *prv, char **comment_return) +int +load_private_key(const char *filename, const char *passphrase, + RSA *prv, char **comment_return) { int f, i, check1, check2, cipher_type; unsigned long len; Buffer buffer, decrypted; char *cp; CipherContext cipher; + BN_CTX *ctx; + BIGNUM *aux; /* Read the file into the buffer. */ f = open(filename, O_RDONLY); @@ -250,11 +256,11 @@ int load_private_key(const char *filename, const char *passphrase, (void)buffer_get_int(&buffer); /* Reserved data. */ /* Read the public key from the buffer. */ - prv->bits = buffer_get_int(&buffer); - mpz_init(&prv->n); - buffer_get_mp_int(&buffer, &prv->n); - mpz_init(&prv->e); - buffer_get_mp_int(&buffer, &prv->e); + buffer_get_int(&buffer); + prv->n = BN_new(); + buffer_get_bignum(&buffer, prv->n); + prv->e = BN_new(); + buffer_get_bignum(&buffer, prv->e); if (comment_return) *comment_return = buffer_get_string(&buffer, NULL); else @@ -291,22 +297,37 @@ int load_private_key(const char *filename, const char *passphrase, /* Bad passphrase. */ buffer_free(&decrypted); fail: - mpz_clear(&prv->n); - mpz_clear(&prv->e); + BN_clear_free(prv->n); + BN_clear_free(prv->e); if (comment_return) xfree(*comment_return); return 0; } /* Read the rest of the private key. */ - mpz_init(&prv->d); - buffer_get_mp_int(&decrypted, &prv->d); - mpz_init(&prv->u); - buffer_get_mp_int(&decrypted, &prv->u); - mpz_init(&prv->p); - buffer_get_mp_int(&decrypted, &prv->p); - mpz_init(&prv->q); - buffer_get_mp_int(&decrypted, &prv->q); + prv->d = BN_new(); + buffer_get_bignum(&decrypted, prv->d); + prv->iqmp = BN_new(); + buffer_get_bignum(&decrypted, prv->iqmp); /* u */ + /* in SSL and SSH p and q are exchanged */ + prv->q = BN_new(); + buffer_get_bignum(&decrypted, prv->q); /* p */ + prv->p = BN_new(); + buffer_get_bignum(&decrypted, prv->p); /* q */ + + ctx = BN_CTX_new(); + aux = BN_new(); + + BN_sub(aux, prv->q, BN_value_one()); + prv->dmq1 = BN_new(); + BN_mod(prv->dmq1, prv->d, aux, ctx); + + BN_sub(aux, prv->p, BN_value_one()); + prv->dmp1 = BN_new(); + BN_mod(prv->dmp1, prv->d, aux, ctx); + + BN_clear_free(aux); + BN_CTX_free(ctx); buffer_free(&decrypted); diff --git a/usr.bin/ssh/bufaux.c b/usr.bin/ssh/bufaux.c index 4bc77f6684b..040a730af5a 100644 --- a/usr.bin/ssh/bufaux.c +++ b/usr.bin/ssh/bufaux.c @@ -15,87 +15,58 @@ Buffers. */ #include "includes.h" -RCSID("$Id: bufaux.c,v 1.1 1999/09/26 20:53:33 deraadt Exp $"); +RCSID("$Id: bufaux.c,v 1.2 1999/09/28 04:45:36 provos Exp $"); #include "ssh.h" -#include "gmp.h" +#include <ssl/bn.h> #include "bufaux.h" #include "xmalloc.h" #include "getput.h" -/* Stores an MP_INT in the buffer with a 2-byte msb first bit count, followed +/* Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed by (bits+7)/8 bytes of binary data, msb first. */ -void buffer_put_mp_int(Buffer *buffer, MP_INT *value) +void +buffer_put_bignum(Buffer *buffer, BIGNUM *value) { - int bits = mpz_sizeinbase(value, 2); - int hex_size = mpz_sizeinbase(value, 16); - char *buf = xmalloc(hex_size + 2); - int i, oi, byte; + int bits = BN_num_bits(value); + int bin_size = (bits + 7) / 8; + char *buf = xmalloc(bin_size); + int oi; char msg[2]; - /* Get the value of the number in hex. Too bad that gmp does not allow - us to get it in binary. */ - mpz_get_str(buf, 16, value); - - /* i is "input index", oi is "output index". Both point to the same array, - and start from the beginning. "input index" moves twice as fast. */ - i = 0; - oi = 0; - /* Check for an odd number of hex digits. Process the odd digit - separately. */ - if (hex_size & 1) - { - sscanf(buf, "%1x", &byte); - buf[oi++] = byte; - i = 1; - } - - /* Convert the hex number into binary representation. */ - for (; i < hex_size; i += 2) - { - sscanf(buf + i, "%2x", &byte); - buf[oi++] = byte; - } - - assert(oi == ((bits + 7) / 8)); + /* Get the value of in binary */ + oi = BN_bn2bin(value, buf); + assert(oi == bin_size); + /* Store the number of bits in the buffer in two bytes, msb first. */ PUT_16BIT(msg, bits); buffer_append(buffer, msg, 2); /* Store the binary data. */ buffer_append(buffer, buf, oi); /* Clear the temporary data. */ - memset(buf, 0, hex_size); + memset(buf, 0, bin_size); xfree(buf); } -/* Retrieves an MP_INT from the buffer. */ +/* Retrieves an BIGNUM from the buffer. */ -int buffer_get_mp_int(Buffer *buffer, MP_INT *value) +int +buffer_get_bignum(Buffer *buffer, BIGNUM *value) { - int i, bits, bytes; - char *hex; - unsigned char buf[2]; + int bits, bytes; + unsigned char buf[2], *bin; /* Get the number for bits. */ buffer_get(buffer, (char *)buf, 2); bits = GET_16BIT(buf); /* Compute the number of binary bytes that follow. */ bytes = (bits + 7) / 8; - /* Allocate space for a corresponding hex string. */ - hex = xmalloc(2 * bytes + 1); - - /* Read and convert the binary bytes into a hex string. */ - for (i = 0; i < bytes; i++) - { - unsigned char byte; - buffer_get(buffer, (char *)&byte, 1); - sprintf(hex + 2 * i, "%02x", byte); - } - /* Read the hex string into a mp-int. */ - mpz_set_str(value, hex, 16); - /* Free the string. */ - xfree(hex); + bin = xmalloc(bytes); + buffer_get(buffer, bin, bytes); + BN_bin2bn(bin, bytes, value); + xfree(bin); + return 2 + bytes; } diff --git a/usr.bin/ssh/bufaux.h b/usr.bin/ssh/bufaux.h index 052cb14d630..06f3dfc5008 100644 --- a/usr.bin/ssh/bufaux.h +++ b/usr.bin/ssh/bufaux.h @@ -11,19 +11,19 @@ Created: Wed Mar 29 02:18:23 1995 ylo */ -/* RCSID("$Id: bufaux.h,v 1.1 1999/09/26 20:53:34 deraadt Exp $"); */ +/* RCSID("$Id: bufaux.h,v 1.2 1999/09/28 04:45:36 provos Exp $"); */ #ifndef BUFAUX_H #define BUFAUX_H #include "buffer.h" -/* Stores an MP_INT in the buffer with a 2-byte msb first bit count, followed +/* Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed by (bits+7)/8 bytes of binary data, msb first. */ -void buffer_put_mp_int(Buffer *buffer, MP_INT *value); +void buffer_put_bignum(Buffer *buffer, BIGNUM *value); -/* Retrieves an MP_INT from the buffer. */ -int buffer_get_mp_int(Buffer *buffer, MP_INT *value); +/* Retrieves an BIGNUM from the buffer. */ +int buffer_get_bignum(Buffer *buffer, BIGNUM *value); /* Returns an integer from the buffer (4 bytes, msb first). */ unsigned int buffer_get_int(Buffer *buffer); diff --git a/usr.bin/ssh/channels.c b/usr.bin/ssh/channels.c index c6b2e21a3b9..75ad8d19a4f 100644 --- a/usr.bin/ssh/channels.c +++ b/usr.bin/ssh/channels.c @@ -16,7 +16,7 @@ arbitrary tcp/ip connections, and the authentication agent connection. */ #include "includes.h" -RCSID("$Id: channels.c,v 1.1 1999/09/26 20:53:34 deraadt Exp $"); +RCSID("$Id: channels.c,v 1.2 1999/09/28 04:45:36 provos Exp $"); #ifndef HAVE_GETHOSTNAME #include <sys/utsname.h> @@ -1334,14 +1334,14 @@ void x11_input_open(int payload_len) /* Requests forwarding of X11 connections, generates fake authentication data, and enables authentication spoofing. */ -void x11_request_forwarding_with_spoofing(RandomState *state, - const char *proto, const char *data) +void x11_request_forwarding_with_spoofing(const char *proto, const char *data) { unsigned int data_len = (unsigned int)strlen(data) / 2; unsigned int i, value; char *new_data; int screen_number; const char *cp; + u_int32_t rand; cp = getenv("DISPLAY"); if (cp) @@ -1364,8 +1364,11 @@ void x11_request_forwarding_with_spoofing(RandomState *state, { if (sscanf(data + 2 * i, "%2x", &value) != 1) fatal("x11_request_forwarding: bad authentication data: %.100s", data); + if (i % 4 == 0) + rand = arc4random(); x11_saved_data[i] = value; - x11_fake_data[i] = random_get_byte(state); + x11_fake_data[i] = rand & 0xff; + rand >>= 8; } x11_saved_data_len = data_len; x11_fake_data_len = data_len; diff --git a/usr.bin/ssh/cipher.c b/usr.bin/ssh/cipher.c index dfe874ffebb..72be90a4068 100644 --- a/usr.bin/ssh/cipher.c +++ b/usr.bin/ssh/cipher.c @@ -12,10 +12,11 @@ Created: Wed Apr 19 17:41:39 1995 ylo */ #include "includes.h" -RCSID("$Id: cipher.c,v 1.3 1999/09/26 22:53:25 deraadt Exp $"); +RCSID("$Id: cipher.c,v 1.4 1999/09/28 04:45:36 provos Exp $"); #include "ssh.h" #include "cipher.h" +#include "ssh_md5.h" /* * What kind of tripple DES are these 2 routines? @@ -120,7 +121,8 @@ detect_cbc_attack(const unsigned char *src, /* Names of all encryption algorithms. These must match the numbers defined int cipher.h. */ static char *cipher_names[] = -{ "none", +{ + "none", "no idea", #ifdef WITH_DES "des", @@ -129,11 +131,7 @@ static char *cipher_names[] = #endif "3des", "no tss", -#ifdef WITH_RC4 - "rc4", -#else "no rc4", -#endif "blowfish" }; @@ -149,16 +147,14 @@ unsigned int cipher_mask() mask |= 1 << SSH_CIPHER_DES; #endif mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */ -#ifdef WITH_RC4 - mask |= 1 << SSH_CIPHER_RC4; -#endif mask |= 1 << SSH_CIPHER_BLOWFISH; return mask; } /* Returns the name of the cipher. */ -const char *cipher_name(int cipher) +const +char *cipher_name(int cipher) { if (cipher < 0 || cipher >= sizeof(cipher_names) / sizeof(cipher_names[0])) fatal("cipher_name: bad cipher number: %d", cipher); @@ -168,7 +164,8 @@ const char *cipher_name(int cipher) /* Parses the name of the cipher. Returns the number of the corresponding cipher, or -1 on error. */ -int cipher_number(const char *name) +int +cipher_number(const char *name) { int i; for (i = 0; i < sizeof(cipher_names) / sizeof(cipher_names[0]); i++) @@ -245,12 +242,6 @@ void cipher_set_key(CipherContext *context, int cipher, memset(context->u.des3.iv3, 0, sizeof(context->u.des3.iv3)); break; -#ifdef WITH_RC4 - case SSH_CIPHER_RC4: - rc4_init(&context->u.rc4, key, keylen); - break; -#endif /* WITH_RC4 */ - case SSH_CIPHER_BLOWFISH: BF_set_key(&context->u.bf.key, keylen, padded); memset(context->u.bf.iv, 0, 8); @@ -290,12 +281,6 @@ void cipher_encrypt(CipherContext *context, unsigned char *dest, dest, (void*)src, len); break; -#ifdef WITH_RC4 - case SSH_CIPHER_RC4: - rc4_encrypt(&context->u.rc4, dest, src, len); - break; -#endif /* WITH_RC4 */ - case SSH_CIPHER_BLOWFISH: swap_bytes(src, dest, len); BF_cbc_encrypt(dest, dest, len, @@ -338,13 +323,6 @@ void cipher_decrypt(CipherContext *context, unsigned char *dest, dest, (void*)src, len); break; -#ifdef WITH_RC4 - case SSH_CIPHER_RC4: - /* CRC-32 attack? */ - rc4_decrypt(&context->u.rc4, dest, src, len); - break; -#endif /* WITH_RC4 */ - case SSH_CIPHER_BLOWFISH: detect_cbc_attack(src, len); swap_bytes(src, dest, len); diff --git a/usr.bin/ssh/cipher.h b/usr.bin/ssh/cipher.h index d47c8eb7c91..988446c4880 100644 --- a/usr.bin/ssh/cipher.h +++ b/usr.bin/ssh/cipher.h @@ -11,22 +11,19 @@ Created: Wed Apr 19 16:50:42 1995 ylo */ -/* RCSID("$Id: cipher.h,v 1.3 1999/09/26 22:53:25 deraadt Exp $"); */ +/* RCSID("$Id: cipher.h,v 1.4 1999/09/28 04:45:36 provos Exp $"); */ #ifndef CIPHER_H #define CIPHER_H #include "des.h" -#ifdef WITH_RC4 -#include "rc4.h" -#endif #include "blowfish.h" /* Cipher types. New types can be added, but old types should not be removed for compatibility. The maximum allowed value is 31. */ #define SSH_CIPHER_NOT_SET -1 /* None selected (invalid number). */ #define SSH_CIPHER_NONE 0 /* no encryption */ -#define SSH_CIPHER_IDEA 1 /* IDEA CFB -- not implemented */ +#define SSH_CIPHER_IDEA 1 /* IDEA CFB */ #define SSH_CIPHER_DES 2 /* DES CBC */ #define SSH_CIPHER_3DES 3 /* 3DES CBC */ #define SSH_CIPHER_TSS 4 /* TRI's Simple Stream encryption CBC */ @@ -49,9 +46,6 @@ typedef struct { des_key_schedule key3; des_cblock iv3; } des3; -#ifdef WITH_RC4 - RC4Context rc4; -#endif struct { struct bf_key_st key; unsigned char iv[8]; diff --git a/usr.bin/ssh/clientloop.c b/usr.bin/ssh/clientloop.c index 6813f2cee3e..e51e3925d7a 100644 --- a/usr.bin/ssh/clientloop.c +++ b/usr.bin/ssh/clientloop.c @@ -15,10 +15,9 @@ The main loop for the interactive session (client side). */ #include "includes.h" -RCSID("$Id: clientloop.c,v 1.1 1999/09/26 20:53:34 deraadt Exp $"); +RCSID("$Id: clientloop.c,v 1.2 1999/09/28 04:45:36 provos Exp $"); #include "xmalloc.h" -#include "randoms.h" #include "ssh.h" #include "packet.h" #include "buffer.h" @@ -786,7 +785,7 @@ void client_process_output(fd_set *writeset) /* Write as much data as possible. */ len = write(fileno(stderr), buffer_ptr(&stderr_buffer), buffer_len(&stderr_buffer)); - if (len <= 0) + if (len <= 0) { if (errno == EAGAIN) len = 0; else @@ -795,6 +794,7 @@ void client_process_output(fd_set *writeset) quit_pending = 1; return; } + } /* Consume printed characters from the buffer. */ buffer_consume(&stderr_buffer, len); } diff --git a/usr.bin/ssh/config.h b/usr.bin/ssh/config.h index 3d3d93b83e4..848930f9813 100644 --- a/usr.bin/ssh/config.h +++ b/usr.bin/ssh/config.h @@ -123,9 +123,6 @@ static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg } /* Define to use RSAREF. */ /* #undef RSAREF */ -/* Define to use SSL. */ -#define DO_SSL 1 - /* Define this to be the path of the rsh program to support executing rsh. */ #define RSH_PATH "/usr/bin/rsh" @@ -307,9 +304,6 @@ static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg } /* Define if you have the setsid function. */ #define HAVE_SETSID 1 -/* Define if you have the socketpair function. */ -#define HAVE_SOCKETPAIR 1 - /* Define if you have the strchr function. */ #define HAVE_STRCHR 1 @@ -334,9 +328,6 @@ static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg } /* Define if you have the <dirent.h> header file. */ #define HAVE_DIRENT_H 1 -/* Define if you have the <gmp.h> header file. */ -#define HAVE_GMP_H 1 - /* Define if you have the <krb.h> header file. */ /* #undef HAVE_KRB_H */ @@ -409,9 +400,6 @@ static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg } /* Define if you have the gen library (-lgen). */ /* #undef HAVE_LIBGEN */ -/* Define if you have the gmp library (-lgmp). */ -#define HAVE_LIBGMP 1 - /* Define if you have the krb library (-lkrb). */ #define HAVE_LIBKRB 1 diff --git a/usr.bin/ssh/hostfile.c b/usr.bin/ssh/hostfile.c index 27c56af2eb7..9b36e39e828 100644 --- a/usr.bin/ssh/hostfile.c +++ b/usr.bin/ssh/hostfile.c @@ -14,7 +14,7 @@ Functions for manipulating the known hosts files. */ #include "includes.h" -RCSID("$Id: hostfile.c,v 1.1 1999/09/26 20:53:36 deraadt Exp $"); +RCSID("$Id: hostfile.c,v 1.2 1999/09/28 04:45:36 provos Exp $"); #include "packet.h" #include "ssh.h" @@ -25,7 +25,8 @@ RCSID("$Id: hostfile.c,v 1.1 1999/09/26 20:53:36 deraadt Exp $"); the last processed (and maybe modified) character. Note that this may modify the buffer containing the number. */ -int auth_rsa_read_mp_int(char **cpp, MP_INT *value) +int +auth_rsa_read_bignum(char **cpp, BIGNUM *value) { char *cp = *cpp; int len, old; @@ -52,8 +53,9 @@ int auth_rsa_read_mp_int(char **cpp, MP_INT *value) old = *cp; *cp = 0; + /* Parse the number. */ - if (mpz_set_str(value, *cpp, 10) != 0) + if (BN_dec2bn(&value, *cpp) == 0) return 0; /* Restore old terminating character. */ @@ -67,7 +69,8 @@ int auth_rsa_read_mp_int(char **cpp, MP_INT *value) /* 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, MP_INT *e, MP_INT *n) +int +auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM *e, BIGNUM *n) { unsigned int bits; char *cp; @@ -83,11 +86,11 @@ int auth_rsa_read_key(char **cpp, unsigned int *bitsp, MP_INT *e, MP_INT *n) bits = 10 * bits + *cp - '0'; /* Get public exponent. */ - if (!auth_rsa_read_mp_int(&cp, e)) + if (!auth_rsa_read_bignum(&cp, e)) return 0; /* Get public modulus. */ - if (!auth_rsa_read_mp_int(&cp, n)) + if (!auth_rsa_read_bignum(&cp, n)) return 0; /* Skip trailing whitespace. */ @@ -105,7 +108,8 @@ int auth_rsa_read_key(char **cpp, unsigned int *bitsp, MP_INT *e, MP_INT *n) indicate negation). Returns true if there is a positive match; zero otherwise. */ -int match_hostname(const char *host, const char *pattern, unsigned int len) +int +match_hostname(const char *host, const char *pattern, unsigned int len) { char sub[1024]; int negated; @@ -142,11 +146,12 @@ int match_hostname(const char *host, const char *pattern, unsigned int len) sub[subi] = '\0'; /* Try to match the subpattern against the host name. */ - if (match_pattern(host, sub)) + if (match_pattern(host, sub)) { if (negated) return 0; /* Fail if host matches any negated subpattern. */ else got_positive = 1; + } } /* Return success if got a positive match. If there was a negative match, @@ -160,17 +165,18 @@ int match_hostname(const char *host, const char *pattern, unsigned int len) HOST_NEW if the host is not known, and HOST_CHANGED if the host is known but used to have a different host key. */ -HostStatus check_host_in_hostfile(const char *filename, - const char *host, unsigned int bits, - MP_INT *e, MP_INT *n) +HostStatus +check_host_in_hostfile(const char *filename, + const char *host, unsigned int bits, + BIGNUM *e, BIGNUM *n) { FILE *f; char line[8192]; - MP_INT ke, kn; unsigned int kbits, hostlen; char *cp, *cp2; HostStatus end_return; struct stat st; + BIGNUM *ke, *kn; /* Open the file containing the list of known hosts. */ f = fopen(filename, "r"); @@ -185,8 +191,8 @@ HostStatus check_host_in_hostfile(const char *filename, } /* Initialize mp-int variables. */ - mpz_init(&ke); - mpz_init(&kn); + ke = BN_new(); + kn = BN_new(); /* Cache the length of the host name. */ hostlen = strlen(host); @@ -222,15 +228,15 @@ HostStatus check_host_in_hostfile(const char *filename, /* 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 (!auth_rsa_read_key(&cp, &kbits, ke, kn)) continue; /* Check if the current key is the same as the previous one. */ - if (kbits == bits && mpz_cmp(&ke, e) == 0 && mpz_cmp(&kn, n) == 0) + if (kbits == bits && BN_cmp(ke, e) == 0 && BN_cmp(kn, n) == 0) { /* Ok, they match. */ - mpz_clear(&ke); - mpz_clear(&kn); + BN_clear_free(ke); + BN_clear_free(kn); fclose(f); return HOST_OK; } @@ -240,8 +246,8 @@ HostStatus check_host_in_hostfile(const char *filename, end_return = HOST_CHANGED; } /* Clear variables and close the file. */ - mpz_clear(&ke); - mpz_clear(&kn); + BN_clear_free(ke); + BN_clear_free(kn); fclose(f); /* Return either HOST_NEW or HOST_CHANGED, depending on whether we saw a @@ -252,10 +258,12 @@ HostStatus check_host_in_hostfile(const char *filename, /* 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, - unsigned int bits, MP_INT *e, MP_INT *n) +int +add_host_to_hostfile(const char *filename, const char *host, + unsigned int bits, BIGNUM *e, BIGNUM *n) { FILE *f; + char *buf; /* Open the file for appending. */ f = fopen(filename, "a"); @@ -264,10 +272,14 @@ int add_host_to_hostfile(const char *filename, const char *host, /* Print the host name and key to the file. */ fprintf(f, "%s %u ", host, bits); - mpz_out_str(f, 10, e); - fprintf(f, " "); - mpz_out_str(f, 10, n); - fprintf(f, "\n"); + buf = BN_bn2dec(e); + assert(buf != NULL); + fprintf(f, "%s ", buf); + free (buf); + buf = BN_bn2dec(n); + assert(buf != NULL); + fprintf(f, "%s\n", buf); + free (buf); /* Close the file. */ fclose(f); diff --git a/usr.bin/ssh/mpaux.c b/usr.bin/ssh/mpaux.c index 78ff1f93d68..2f7836baf7b 100644 --- a/usr.bin/ssh/mpaux.c +++ b/usr.bin/ssh/mpaux.c @@ -15,75 +15,27 @@ precision integers. */ #include "includes.h" -RCSID("$Id: mpaux.c,v 1.1 1999/09/26 20:53:36 deraadt Exp $"); +RCSID("$Id: mpaux.c,v 1.2 1999/09/28 04:45:36 provos Exp $"); -#include <gmp.h> +#include <ssl/bn.h> #include "getput.h" #include "xmalloc.h" #include "ssh_md5.h" -/* Converts a multiple-precision integer into bytes to be stored in the buffer. - The buffer will contain the value of the integer, msb first. */ - -void mp_linearize_msb_first(unsigned char *buf, unsigned int len, - MP_INT *value) -{ - unsigned int i; - MP_INT aux; - mpz_init_set(&aux, value); - for (i = len; i >= 4; i -= 4) - { - unsigned int limb = mpz_get_ui(&aux); - PUT_32BIT(buf + i - 4, limb); - mpz_div_2exp(&aux, &aux, 32); - } - for (; i > 0; i--) - { - buf[i - 1] = mpz_get_ui(&aux); - mpz_div_2exp(&aux, &aux, 8); - } - mpz_clear(&aux); -} - -/* Extract a multiple-precision integer from buffer. The value is stored - in the buffer msb first. */ - -void mp_unlinearize_msb_first(MP_INT *value, const unsigned char *buf, - unsigned int len) -{ - unsigned int i; - mpz_set_ui(value, 0); - for (i = 0; i + 4 <= len; i += 4) - { - unsigned int limb = GET_32BIT(buf + i); - mpz_mul_2exp(value, value, 32); - mpz_add_ui(value, value, limb); - } - for (; i < len; i++) - { - mpz_mul_2exp(value, value, 8); - mpz_add_ui(value, value, buf[i]); - } -} - -/* Computes a 16-byte session id in the global variable session_id. - The session id is computed by concatenating the linearized, msb - first representations of host_key_n, session_key_n, and the cookie. */ - -void compute_session_id(unsigned char session_id[16], - unsigned char cookie[8], - unsigned int host_key_bits, - MP_INT *host_key_n, - unsigned int session_key_bits, - MP_INT *session_key_n) +void +compute_session_id(unsigned char session_id[16], + unsigned char cookie[8], + unsigned int host_key_bits, + BIGNUM *host_key_n, + unsigned int session_key_bits, + BIGNUM *session_key_n) { unsigned int bytes = (host_key_bits + 7) / 8 + (session_key_bits + 7) / 8 + 8; unsigned char *buf = xmalloc(bytes); struct MD5Context md; - mp_linearize_msb_first(buf, (host_key_bits + 7 ) / 8, host_key_n); - mp_linearize_msb_first(buf + (host_key_bits + 7 ) / 8, - (session_key_bits + 7) / 8, session_key_n); + BN_bn2bin(host_key_n, buf); + BN_bn2bin(session_key_n, buf + (host_key_bits + 7 ) / 8); memcpy(buf + (host_key_bits + 7) / 8 + (session_key_bits + 7) / 8, cookie, 8); MD5Init(&md); diff --git a/usr.bin/ssh/mpaux.h b/usr.bin/ssh/mpaux.h index 1a310901786..96bb68d3030 100644 --- a/usr.bin/ssh/mpaux.h +++ b/usr.bin/ssh/mpaux.h @@ -14,29 +14,19 @@ precision integers. */ -/* RCSID("$Id: mpaux.h,v 1.1 1999/09/26 20:53:36 deraadt Exp $"); */ +/* RCSID("$Id: mpaux.h,v 1.2 1999/09/28 04:45:36 provos Exp $"); */ #ifndef MPAUX_H #define MPAUX_H -/* Converts a multiple-precision integer into bytes to be stored in the buffer. - The buffer will contain the value of the integer, msb first. */ -void mp_linearize_msb_first(unsigned char *buf, unsigned int len, - MP_INT *value); - -/* Extract a multiple-precision integer from buffer. The value is stored - in the buffer msb first. */ -void mp_unlinearize_msb_first(MP_INT *value, const unsigned char *buf, - unsigned int len); - /* Computes a 16-byte session id in the global variable session_id. The session id is computed by concatenating the linearized, msb first representations of host_key_n, session_key_n, and the cookie. */ void compute_session_id(unsigned char session_id[16], unsigned char cookie[8], unsigned int host_key_bits, - MP_INT *host_key_n, + BIGNUM *host_key_n, unsigned int session_key_bits, - MP_INT *session_key_n); + BIGNUM *session_key_n); #endif /* MPAUX_H */ diff --git a/usr.bin/ssh/packet.c b/usr.bin/ssh/packet.c index 8b3fd513fc3..47594bb47ec 100644 --- a/usr.bin/ssh/packet.c +++ b/usr.bin/ssh/packet.c @@ -15,10 +15,9 @@ with the other side. This same code is used both on client and server side. */ #include "includes.h" -RCSID("$Id: packet.c,v 1.1 1999/09/26 20:53:36 deraadt Exp $"); +RCSID("$Id: packet.c,v 1.2 1999/09/28 04:45:36 provos Exp $"); #include "xmalloc.h" -#include "randoms.h" #include "buffer.h" #include "packet.h" #include "bufaux.h" @@ -70,9 +69,6 @@ static Buffer compression_buffer; static int packet_compression = 0; #endif /* WITH_ZLIB */ -/* Pointer to the random number generator state. */ -static RandomState *random_state; - /* Flag indicating whether this module has been initialized. */ static int initialized = 0; @@ -82,11 +78,11 @@ static int interactive_mode = 0; /* Sets the descriptors used for communication. Disables encryption until packet_set_encryption_key is called. */ -void packet_set_connection(int fd_in, int fd_out, RandomState *state) +void +packet_set_connection(int fd_in, int fd_out) { connection_in = fd_in; connection_out = fd_out; - random_state = state; cipher_type = SSH_CIPHER_NONE; cipher_set_key(&send_context, SSH_CIPHER_NONE, (unsigned char *)"", 0, 1); cipher_set_key(&receive_context, SSH_CIPHER_NONE, (unsigned char *)"", 0, 0); @@ -105,7 +101,8 @@ void packet_set_connection(int fd_in, int fd_out, RandomState *state) /* Sets the connection into non-blocking mode. */ -void packet_set_nonblocking() +void +packet_set_nonblocking() { /* Set the socket into non-blocking mode. */ #if defined(O_NONBLOCK) && !defined(O_NONBLOCK_BROKEN) @@ -130,21 +127,24 @@ void packet_set_nonblocking() /* Returns the socket used for reading. */ -int packet_get_connection_in() +int +packet_get_connection_in() { return connection_in; } /* Returns the descriptor used for writing. */ -int packet_get_connection_out() +int +packet_get_connection_out() { return connection_out; } /* Closes the connection and clears and frees internal data structures. */ -void packet_close() +void +packet_close() { if (!initialized) return; @@ -174,7 +174,8 @@ void packet_close() /* Sets remote side protocol flags. */ -void packet_set_protocol_flags(unsigned int protocol_flags) +void +packet_set_protocol_flags(unsigned int protocol_flags) { remote_protocol_flags = protocol_flags; channel_set_options((protocol_flags & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) != 0); @@ -182,7 +183,8 @@ void packet_set_protocol_flags(unsigned int protocol_flags) /* Returns the remote protocol flags set earlier by the above function. */ -unsigned int packet_get_protocol_flags() +unsigned int +packet_get_protocol_flags() { return remote_protocol_flags; } @@ -191,7 +193,8 @@ unsigned int packet_get_protocol_flags() /* Starts packet compression from the next packet on in both directions. Level is compression level 1 (fastest) - 9 (slow, best) as in gzip. */ -void packet_start_compression(int level) +void +packet_start_compression(int level) { if (packet_compression) fatal("Compression already enabled."); @@ -204,8 +207,9 @@ void packet_start_compression(int level) /* Encrypts the given number of bytes, copying from src to dest. bytes is known to be a multiple of 8. */ -void packet_encrypt(CipherContext *cc, void *dest, void *src, - unsigned int bytes) +void +packet_encrypt(CipherContext *cc, void *dest, void *src, + unsigned int bytes) { assert((bytes % 8) == 0); cipher_encrypt(cc, dest, src, bytes); @@ -214,8 +218,9 @@ void packet_encrypt(CipherContext *cc, void *dest, void *src, /* Decrypts the given number of bytes, copying from src to dest. bytes is known to be a multiple of 8. */ -void packet_decrypt(CipherContext *cc, void *dest, void *src, - unsigned int bytes) +void +packet_decrypt(CipherContext *cc, void *dest, void *src, + unsigned int bytes) { assert((bytes % 8) == 0); cipher_decrypt(cc, dest, src, bytes); @@ -225,8 +230,9 @@ void packet_decrypt(CipherContext *cc, void *dest, void *src, key is used for both sending and reception. However, both directions are encrypted independently of each other. */ -void packet_set_encryption_key(const unsigned char *key, unsigned int keylen, - int cipher, int is_client) +void +packet_set_encryption_key(const unsigned char *key, unsigned int keylen, + int cipher, int is_client) { cipher_type = cipher; if (cipher == SSH_CIPHER_RC4) @@ -254,7 +260,8 @@ void packet_set_encryption_key(const unsigned char *key, unsigned int keylen, /* Starts constructing a packet to send. */ -void packet_start(int type) +void +packet_start(int type) { char buf[9]; @@ -266,7 +273,8 @@ void packet_start(int type) /* Appends a character to the packet data. */ -void packet_put_char(int value) +void +packet_put_char(int value) { char ch = value; buffer_append(&outgoing_packet, &ch, 1); @@ -274,33 +282,38 @@ void packet_put_char(int value) /* Appends an integer to the packet data. */ -void packet_put_int(unsigned int value) +void +packet_put_int(unsigned int value) { buffer_put_int(&outgoing_packet, value); } /* Appends a string to packet data. */ -void packet_put_string(const char *buf, unsigned int len) +void +packet_put_string(const char *buf, unsigned int len) { buffer_put_string(&outgoing_packet, buf, len); } /* Appends an arbitrary precision integer to packet data. */ -void packet_put_mp_int(MP_INT *value) +void +packet_put_bignum(BIGNUM *value) { - buffer_put_mp_int(&outgoing_packet, value); + buffer_put_bignum(&outgoing_packet, value); } /* Finalizes and sends the packet. If the encryption key has been set, encrypts the packet before sending. */ -void packet_send() +void +packet_send() { char buf[8], *cp; int i, padding, len; unsigned long checksum; + u_int32_t rand; #ifdef WITH_ZLIB /* If using packet compression, compress the payload of the outgoing @@ -325,8 +338,12 @@ void packet_send() if (cipher_type != SSH_CIPHER_NONE) { cp = buffer_ptr(&outgoing_packet); - for (i = 0; i < padding; i++) - cp[7 - i] = random_get_byte(random_state); + for (i = 0; i < padding; i++) { + if (i % 4 == 0) + rand = arc4random(); + cp[7 - i] = rand & 0xff; + rand >>= 8; + } } buffer_consume(&outgoing_packet, 8 - padding); @@ -362,7 +379,8 @@ void packet_send() no other data is processed until this returns, so this function should not be used during the interactive session. */ -int packet_read(int *payload_len_ptr) +int +packet_read(int *payload_len_ptr) { int type, len; fd_set set; @@ -405,7 +423,8 @@ int packet_read(int *payload_len_ptr) /* Waits until a packet has been received, verifies that its type matches that given, and gives a fatal error and exits if there is a mismatch. */ -void packet_read_expect(int *payload_len_ptr, int expected_type) +void +packet_read_expect(int *payload_len_ptr, int expected_type) { int type; @@ -432,7 +451,8 @@ void packet_read_expect(int *payload_len_ptr, int expected_type) */ -int packet_read_poll(int *payload_len_ptr) +int +packet_read_poll(int *payload_len_ptr) { unsigned int len, padded_len; unsigned char *ucp; @@ -525,14 +545,16 @@ int packet_read_poll(int *payload_len_ptr) /* Buffers the given amount of input characters. This is intended to be used together with packet_read_poll. */ -void packet_process_incoming(const char *buf, unsigned int len) +void +packet_process_incoming(const char *buf, unsigned int len) { buffer_append(&input, buf, len); } /* Returns a character from the packet. */ -unsigned int packet_get_char() +unsigned int +packet_get_char() { char ch; buffer_get(&incoming_packet, &ch, 1); @@ -541,7 +563,8 @@ unsigned int packet_get_char() /* Returns an integer from the packet data. */ -unsigned int packet_get_int() +unsigned int +packet_get_int() { return buffer_get_int(&incoming_packet); } @@ -549,9 +572,10 @@ unsigned int packet_get_int() /* Returns an arbitrary precision integer from the packet data. The integer must have been initialized before this call. */ -void packet_get_mp_int(MP_INT *value, int *length_ptr) +void +packet_get_bignum(BIGNUM *value, int *length_ptr) { - *length_ptr = buffer_get_mp_int(&incoming_packet, value); + *length_ptr = buffer_get_bignum(&incoming_packet, value); } /* Returns a string from the packet data. The string is allocated using @@ -559,7 +583,8 @@ void packet_get_mp_int(MP_INT *value, int *length_ptr) no longer needed. The length_ptr argument may be NULL, or point to an integer into which the length of the string is stored. */ -char *packet_get_string(unsigned int *length_ptr) +char +*packet_get_string(unsigned int *length_ptr) { return buffer_get_string(&incoming_packet, length_ptr); } @@ -572,7 +597,8 @@ char *packet_get_string(unsigned int *length_ptr) message must not exceed 1024 bytes. This will automatically call packet_write_wait. */ -void packet_send_debug(const char *fmt, ...) +void +packet_send_debug(const char *fmt, ...) { char buf[1024]; va_list args; @@ -592,7 +618,8 @@ void packet_send_debug(const char *fmt, ...) The error message should not contain a newline. The length of the formatted message must not exceed 1024 bytes. */ -void packet_disconnect(const char *fmt, ...) +void +packet_disconnect(const char *fmt, ...) { char buf[1024]; va_list args; @@ -627,17 +654,19 @@ void packet_disconnect(const char *fmt, ...) /* Checks if there is any buffered output, and tries to write some of the output. */ -void packet_write_poll() +void +packet_write_poll() { int len = buffer_len(&output); if (len > 0) { len = write(connection_out, buffer_ptr(&output), len); - if (len <= 0) + if (len <= 0) { if (errno == EAGAIN) return; else fatal("Write failed: %.100s", strerror(errno)); + } buffer_consume(&output, len); } } @@ -645,7 +674,8 @@ void packet_write_poll() /* Calls packet_write_poll repeatedly until all pending output data has been written. */ -void packet_write_wait() +void +packet_write_wait() { packet_write_poll(); while (packet_have_data_to_write()) @@ -660,14 +690,16 @@ void packet_write_wait() /* Returns true if there is buffered data to write to the connection. */ -int packet_have_data_to_write() +int +packet_have_data_to_write() { return buffer_len(&output) != 0; } /* Returns true if there is not too much data to write to the connection. */ -int packet_not_very_much_data_to_write() +int +packet_not_very_much_data_to_write() { if (interactive_mode) return buffer_len(&output) < 16384; @@ -677,7 +709,8 @@ int packet_not_very_much_data_to_write() /* Informs that the current session is interactive. Sets IP flags for that. */ -void packet_set_interactive(int interactive, int keepalives) +void +packet_set_interactive(int interactive, int keepalives) { int on = 1; @@ -726,7 +759,8 @@ void packet_set_interactive(int interactive, int keepalives) /* Returns true if the current connection is interactive. */ -int packet_is_interactive() +int +packet_is_interactive() { return interactive_mode; } diff --git a/usr.bin/ssh/packet.h b/usr.bin/ssh/packet.h index 9a39bb9b637..2f8d74510d6 100644 --- a/usr.bin/ssh/packet.h +++ b/usr.bin/ssh/packet.h @@ -13,19 +13,18 @@ Interface for the packet protocol functions. */ -/* RCSID("$Id: packet.h,v 1.1 1999/09/26 20:53:36 deraadt Exp $"); */ +/* RCSID("$Id: packet.h,v 1.2 1999/09/28 04:45:36 provos Exp $"); */ #ifndef PACKET_H #define PACKET_H -#include <gmp.h> -#include "randoms.h" +#include <ssl/bn.h> /* Sets the socket used for communication. Disables encryption until packet_set_encryption_key is called. It is permissible that fd_in and fd_out are the same descriptor; in that case it is assumed to be a socket. */ -void packet_set_connection(int fd_in, int fd_out, RandomState *state); +void packet_set_connection(int fd_in, int fd_out); /* Puts the connection file descriptors into non-blocking mode. */ void packet_set_nonblocking(void); @@ -74,7 +73,7 @@ void packet_put_char(int ch); void packet_put_int(unsigned int value); /* Appends an arbitrary precision integer to packet data. */ -void packet_put_mp_int(MP_INT *value); +void packet_put_bignum(BIGNUM *value); /* Appends a string to packet data. */ void packet_put_string(const char *buf, unsigned int len); @@ -111,7 +110,7 @@ unsigned int packet_get_int(void); /* Returns an arbitrary precision integer from the packet data. The integer must have been initialized before this call. */ -void packet_get_mp_int(MP_INT *value, int *length_ptr); +void packet_get_bignum(BIGNUM *value, int *length_ptr); /* Returns a string from the packet data. The string is allocated using xmalloc; it is the responsibility of the calling program to free it when diff --git a/usr.bin/ssh/random.c b/usr.bin/ssh/random.c deleted file mode 100644 index 1487764601b..00000000000 --- a/usr.bin/ssh/random.c +++ /dev/null @@ -1,370 +0,0 @@ -/* Note: file is included because gmp uses functions that use random in its - primality testing functions. //ylo */ - -/* - * Copyright (c) 1983 Regents of the University of California. - * 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 the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)random.c 5.9 (Berkeley) 2/23/91"; -#endif /* LIBC_SCCS and not lint */ - -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> - -/* - * random.c: - * - * An improved random number generation package. In addition to the standard - * rand()/srand() like interface, this package also has a special state info - * interface. The initstate() routine is called with a seed, an array of - * bytes, and a count of how many bytes are being passed in; this array is - * then initialized to contain information for random number generation with - * that much state information. Good sizes for the amount of state - * information are 32, 64, 128, and 256 bytes. The state can be switched by - * calling the setstate() routine with the same array as was initiallized - * with initstate(). By default, the package runs with 128 bytes of state - * information and generates far better random numbers than a linear - * congruential generator. If the amount of state information is less than - * 32 bytes, a simple linear congruential R.N.G. is used. - * - * Internally, the state information is treated as an array of longs; the - * zeroeth element of the array is the type of R.N.G. being used (small - * integer); the remainder of the array is the state information for the - * R.N.G. Thus, 32 bytes of state information will give 7 longs worth of - * state information, which will allow a degree seven polynomial. (Note: - * the zeroeth word of state information also has some other information - * stored in it -- see setstate() for details). - * - * The random number generation technique is a linear feedback shift register - * approach, employing trinomials (since there are fewer terms to sum up that - * way). In this approach, the least significant bit of all the numbers in - * the state table will act as a linear feedback shift register, and will - * have period 2^deg - 1 (where deg is the degree of the polynomial being - * used, assuming that the polynomial is irreducible and primitive). The - * higher order bits will have longer periods, since their values are also - * influenced by pseudo-random carries out of the lower bits. The total - * period of the generator is approximately deg*(2**deg - 1); thus doubling - * the amount of state information has a vast influence on the period of the - * generator. Note: the deg*(2**deg - 1) is an approximation only good for - * large deg, when the period of the shift register is the dominant factor. - * With deg equal to seven, the period is actually much longer than the - * 7*(2**7 - 1) predicted by this formula. - */ - -/* - * For each of the currently supported random number generators, we have a - * break value on the amount of state information (you need at least this - * many bytes of state info to support this random number generator), a degree - * for the polynomial (actually a trinomial) that the R.N.G. is based on, and - * the separation between the two lower order coefficients of the trinomial. - */ -#define TYPE_0 0 /* linear congruential */ -#define BREAK_0 8 -#define DEG_0 0 -#define SEP_0 0 - -#define TYPE_1 1 /* x**7 + x**3 + 1 */ -#define BREAK_1 32 -#define DEG_1 7 -#define SEP_1 3 - -#define TYPE_2 2 /* x**15 + x + 1 */ -#define BREAK_2 64 -#define DEG_2 15 -#define SEP_2 1 - -#define TYPE_3 3 /* x**31 + x**3 + 1 */ -#define BREAK_3 128 -#define DEG_3 31 -#define SEP_3 3 - -#define TYPE_4 4 /* x**63 + x + 1 */ -#define BREAK_4 256 -#define DEG_4 63 -#define SEP_4 1 - -/* - * Array versions of the above information to make code run faster -- - * relies on fact that TYPE_i == i. - */ -#define MAX_TYPES 5 /* max number of types above */ - -static int degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 }; -static int seps [MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }; - -/* - * Initially, everything is set up as if from: - * - * initstate(1, &randtbl, 128); - * - * Note that this initialization takes advantage of the fact that srandom() - * advances the front and rear pointers 10*rand_deg times, and hence the - * rear pointer which starts at 0 will also end up at zero; thus the zeroeth - * element of the state information, which contains info about the current - * position of the rear pointer is just - * - * MAX_TYPES * (rptr - state) + TYPE_3 == TYPE_3. - */ - -static long randtbl[DEG_3 + 1] = { - TYPE_3, - 0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, 0xde3b81e0, 0xdf0a6fb5, - 0xf103bc02, 0x48f340fb, 0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd, - 0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86, 0xda672e2a, 0x1588ca88, - 0xe369735d, 0x904f35f7, 0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc, - 0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, 0xf5ad9d0e, 0x8999220b, - 0x27fb47b9, -}; - -/* - * fptr and rptr are two pointers into the state info, a front and a rear - * pointer. These two pointers are always rand_sep places aparts, as they - * cycle cyclically through the state information. (Yes, this does mean we - * could get away with just one pointer, but the code for random() is more - * efficient this way). The pointers are left positioned as they would be - * from the call - * - * initstate(1, randtbl, 128); - * - * (The position of the rear pointer, rptr, is really 0 (as explained above - * in the initialization of randtbl) because the state table pointer is set - * to point to randtbl[1] (as explained below). - */ -static long *fptr = &randtbl[SEP_3 + 1]; -static long *rptr = &randtbl[1]; - -/* - * The following things are the pointer to the state information table, the - * type of the current generator, the degree of the current polynomial being - * used, and the separation between the two pointers. Note that for efficiency - * of random(), we remember the first location of the state information, not - * the zeroeth. Hence it is valid to access state[-1], which is used to - * store the type of the R.N.G. Also, we remember the last location, since - * this is more efficient than indexing every time to find the address of - * the last element to see if the front and rear pointers have wrapped. - */ -static long *state = &randtbl[1]; -static int rand_type = TYPE_3; -static int rand_deg = DEG_3; -static int rand_sep = SEP_3; -static long *end_ptr = &randtbl[DEG_3 + 1]; - -long random(); - -/* - * srandom: - * - * Initialize the random number generator based on the given seed. If the - * type is the trivial no-state-information type, just remember the seed. - * Otherwise, initializes state[] based on the given "seed" via a linear - * congruential generator. Then, the pointers are set to known locations - * that are exactly rand_sep places apart. Lastly, it cycles the state - * information a given number of times to get rid of any initial dependencies - * introduced by the L.C.R.N.G. Note that the initialization of randtbl[] - * for default usage relies on values produced by this routine. - */ -void -srandom(x) - u_int x; -{ - register int i, j; - - if (rand_type == TYPE_0) - state[0] = x; - else { - j = 1; - state[0] = x; - for (i = 1; i < rand_deg; i++) - state[i] = 1103515245 * state[i - 1] + 12345; - fptr = &state[rand_sep]; - rptr = &state[0]; - for (i = 0; i < 10 * rand_deg; i++) - (void)random(); - } -} - -/* - * initstate: - * - * Initialize the state information in the given array of n bytes for future - * random number generation. Based on the number of bytes we are given, and - * the break values for the different R.N.G.'s, we choose the best (largest) - * one we can and set things up for it. srandom() is then called to - * initialize the state information. - * - * Note that on return from srandom(), we set state[-1] to be the type - * multiplexed with the current value of the rear pointer; this is so - * successive calls to initstate() won't lose this information and will be - * able to restart with setstate(). - * - * Note: the first thing we do is save the current state, if any, just like - * setstate() so that it doesn't matter when initstate is called. - * - * Returns a pointer to the old state. - */ -char * -initstate(seed, arg_state, n) - u_int seed; /* seed for R.N.G. */ - char *arg_state; /* pointer to state array */ - int n; /* # bytes of state info */ -{ - register char *ostate = (char *)(&state[-1]); - - if (rand_type == TYPE_0) - state[-1] = rand_type; - else - state[-1] = MAX_TYPES * (rptr - state) + rand_type; - if (n < BREAK_0) { - (void)fprintf(stderr, - "random: not enough state (%d bytes); ignored.\n", n); - return(0); - } - if (n < BREAK_1) { - rand_type = TYPE_0; - rand_deg = DEG_0; - rand_sep = SEP_0; - } else if (n < BREAK_2) { - rand_type = TYPE_1; - rand_deg = DEG_1; - rand_sep = SEP_1; - } else if (n < BREAK_3) { - rand_type = TYPE_2; - rand_deg = DEG_2; - rand_sep = SEP_2; - } else if (n < BREAK_4) { - rand_type = TYPE_3; - rand_deg = DEG_3; - rand_sep = SEP_3; - } else { - rand_type = TYPE_4; - rand_deg = DEG_4; - rand_sep = SEP_4; - } - state = &(((long *)arg_state)[1]); /* first location */ - end_ptr = &state[rand_deg]; /* must set end_ptr before srandom */ - srandom(seed); - if (rand_type == TYPE_0) - state[-1] = rand_type; - else - state[-1] = MAX_TYPES*(rptr - state) + rand_type; - return(ostate); -} - -/* - * setstate: - * - * Restore the state from the given state array. - * - * Note: it is important that we also remember the locations of the pointers - * in the current state information, and restore the locations of the pointers - * from the old state information. This is done by multiplexing the pointer - * location into the zeroeth word of the state information. - * - * Note that due to the order in which things are done, it is OK to call - * setstate() with the same state as the current state. - * - * Returns a pointer to the old state information. - */ -char * -setstate(arg_state) - char *arg_state; -{ - register long *new_state = (long *)arg_state; - register int type = new_state[0] % MAX_TYPES; - register int rear = new_state[0] / MAX_TYPES; - char *ostate = (char *)(&state[-1]); - - if (rand_type == TYPE_0) - state[-1] = rand_type; - else - state[-1] = MAX_TYPES * (rptr - state) + rand_type; - switch(type) { - case TYPE_0: - case TYPE_1: - case TYPE_2: - case TYPE_3: - case TYPE_4: - rand_type = type; - rand_deg = degrees[type]; - rand_sep = seps[type]; - break; - default: - (void)fprintf(stderr, - "random: state info corrupted; not changed.\n"); - } - state = &new_state[1]; - if (rand_type != TYPE_0) { - rptr = &state[rear]; - fptr = &state[(rear + rand_sep) % rand_deg]; - } - end_ptr = &state[rand_deg]; /* set end_ptr too */ - return(ostate); -} - -/* - * random: - * - * If we are using the trivial TYPE_0 R.N.G., just do the old linear - * congruential bit. Otherwise, we do our fancy trinomial stuff, which is - * the same in all the other cases due to all the global variables that have - * been set up. The basic operation is to add the number at the rear pointer - * into the one at the front pointer. Then both pointers are advanced to - * the next location cyclically in the table. The value returned is the sum - * generated, reduced to 31 bits by throwing away the "least random" low bit. - * - * Note: the code takes advantage of the fact that both the front and - * rear pointers can't wrap on the same call by not testing the rear - * pointer if the front one has wrapped. - * - * Returns a 31-bit random number. - */ -long -random() -{ - long i; - - if (rand_type == TYPE_0) - i = state[0] = (state[0] * 1103515245 + 12345) & 0x7fffffff; - else { - *fptr += *rptr; - i = (*fptr >> 1) & 0x7fffffff; /* chucking least random bit */ - if (++fptr >= end_ptr) { - fptr = state; - ++rptr; - } else if (++rptr >= end_ptr) - rptr = state; - } - return(i); -} - diff --git a/usr.bin/ssh/randoms.c b/usr.bin/ssh/randoms.c deleted file mode 100644 index 249e106293f..00000000000 --- a/usr.bin/ssh/randoms.c +++ /dev/null @@ -1,365 +0,0 @@ -/* - -random.c - -Author: Tatu Ylonen <ylo@cs.hut.fi> - -Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland - All rights reserved - -Created: Sat Mar 4 14:55:57 1995 ylo - -Cryptographically strong random number generation. - -*/ - -#include "includes.h" -RCSID("$Id: randoms.c,v 1.1 1999/09/26 20:53:36 deraadt Exp $"); - -#include "randoms.h" -#include "getput.h" -#include "ssh_md5.h" - -#ifdef HAVE_GETRUSAGE -#include <sys/resource.h> -#ifdef HAVE_RUSAGE_H -#include <sys/rusage.h> -#endif /* HAVE_RUSAGE_H */ -#endif /* HAVE_GETRUSAGE */ - -#ifdef HAVE_TIMES -#include <sys/times.h> -#endif /* HAVE_TIMES */ - -/* Initializes the random number generator, loads any random information - from the given file, and acquires as much environmental noise as it - can to initialize the random number generator. More noise can be - acquired later by calling random_add_noise + random_stir, or by - calling random_get_environmental_noise again later when the environmental - situation has changed. */ - -void random_initialize(RandomState *state, const char *filename) -{ - char buf[8192]; - int f, bytes; - - state->add_position = 0; - state->next_available_byte = sizeof(state->stir_key); - - /* This isn't strictly necessary, but will keep programs like 3rd degree or - purify silent. */ - memset(state, 0, sizeof(state)); - - /* Get noise from the file. */ - random_add_noise(state, filename, strlen(filename)); /* Use the path. */ - f = open(filename, O_RDONLY); - if (f >= 0) - { - state->state[0] += f; - bytes = read(f, buf, sizeof(buf)); - close(f); - if (bytes > 0) - random_add_noise(state, buf, bytes); - memset(buf, 0, sizeof(buf)); - } - else - { - /* Get all possible noise since we have no seed. */ - random_acquire_environmental_noise(state); - random_save(state, filename); - } - - /* Get easily available noise from the environment. */ - random_acquire_light_environmental_noise(state); -} - -void random_xor_noise(RandomState *state, unsigned int i, word32 value) -{ - value ^= GET_32BIT(state->state + 4 * i); - PUT_32BIT(state->state + 4 * i, value); -} - -/* Acquires as much environmental noise as it can. This is probably quite - sufficient on a unix machine, but might be grossly inadequate on a - single-user PC or a Macintosh. - - We test the elapsed real time after each command, and abort if we have - consumed over 30 seconds. */ - -void random_acquire_environmental_noise(RandomState *state) -{ - time_t start_time; - - /* Record the start time. */ - start_time = time(NULL); - - /* Run these first so that other statistics accumulate from these. We stop - collecting more noise when we have spent 30 seconds real time; on a large - system a single executed command is probably enough, whereas on small - systems we must use all possible noise sources. */ - random_get_noise_from_command(state, "ps laxww 2>/dev/null"); - if (time(NULL) - start_time < 30) - random_get_noise_from_command(state, "ps -al 2>/dev/null"); - if (time(NULL) - start_time < 30) - random_get_noise_from_command(state, "ls -alni /tmp/. 2>/dev/null"); - if (time(NULL) - start_time < 30) - random_get_noise_from_command(state, "w 2>/dev/null"); - if (time(NULL) - start_time < 30) - random_get_noise_from_command(state, "netstat -s 2>/dev/null"); - if (time(NULL) - start_time < 30) - random_get_noise_from_command(state, "netstat -an 2>/dev/null"); - if (time(NULL) - start_time < 30) - random_get_noise_from_command(state, "netstat -in 2>/dev/null"); - - /* Get other easily available noise. */ - random_acquire_light_environmental_noise(state); -} - -/* Acquires easily available environmental noise. */ - -void random_acquire_light_environmental_noise(RandomState *state) -{ - int f; - char buf[32]; - int len; - - /* If /dev/random is available, read some data from there in non-blocking - mode and mix it into the pool. */ - f = open("/dev/random", O_RDONLY); - if (f >= 0) - { - /* Set the descriptor into non-blocking mode. */ -#if defined(O_NONBLOCK) && !defined(O_NONBLOCK_BROKEN) - fcntl(f, F_SETFL, O_NONBLOCK); -#else /* O_NONBLOCK && !O_NONBLOCK_BROKEN */ - fcntl(f, F_SETFL, O_NDELAY); -#endif /* O_NONBLOCK && !O_NONBLOCK_BROKEN */ - len = read(f, buf, sizeof(buf)); - close(f); - if (len > 0) - random_add_noise(state, buf, len); - } - - /* Get miscellaneous noise from various system parameters and statistics. */ - random_xor_noise(state, - (unsigned int)(state->state[0] + 256*state->state[1]) % - (RANDOM_STATE_BYTES / 4), - (word32)time(NULL)); - -#ifdef HAVE_GETTIMEOFDAY - { - struct timeval tv; - gettimeofday(&tv, NULL); - random_xor_noise(state, 0, (word32)tv.tv_usec); - random_xor_noise(state, 1, (word32)tv.tv_sec); -#ifdef HAVE_CLOCK - random_xor_noise(state, 3, (word32)clock()); -#endif /* HAVE_CLOCK */ - } -#endif /* HAVE_GETTIMEOFDAY */ -#ifdef HAVE_TIMES - { - struct tms tm; - random_xor_noise(state, 2, (word32)times(&tm)); - random_xor_noise(state, 4, (word32)(tm.tms_utime ^ (tm.tms_stime << 8) ^ - (tm.tms_cutime << 16) ^ - (tm.tms_cstime << 24))); - } -#endif /* HAVE_TIMES */ -#ifdef HAVE_GETRUSAGE - { - struct rusage ru, cru; - getrusage(RUSAGE_SELF, &ru); - getrusage(RUSAGE_CHILDREN, &cru); - random_xor_noise(state, 0, (word32)(ru.ru_utime.tv_usec + - cru.ru_utime.tv_usec)); - random_xor_noise(state, 2, (word32)(ru.ru_stime.tv_usec + - cru.ru_stime.tv_usec)); - random_xor_noise(state, 5, (word32)(ru.ru_maxrss + cru.ru_maxrss)); - random_xor_noise(state, 6, (word32)(ru.ru_ixrss + cru.ru_ixrss)); - random_xor_noise(state, 7, (word32)(ru.ru_idrss + cru.ru_idrss)); - random_xor_noise(state, 8, (word32)(ru.ru_minflt + cru.ru_minflt)); - random_xor_noise(state, 9, (word32)(ru.ru_majflt + cru.ru_majflt)); - random_xor_noise(state, 10, (word32)(ru.ru_nswap + cru.ru_nswap)); - random_xor_noise(state, 11, (word32)(ru.ru_inblock + cru.ru_inblock)); - random_xor_noise(state, 12, (word32)(ru.ru_oublock + cru.ru_oublock)); - random_xor_noise(state, 13, (word32)((ru.ru_msgsnd ^ ru.ru_msgrcv ^ - ru.ru_nsignals) + - (cru.ru_msgsnd ^ cru.ru_msgrcv ^ - cru.ru_nsignals))); - random_xor_noise(state, 14, (word32)(ru.ru_nvcsw + cru.ru_nvcsw)); - random_xor_noise(state, 15, (word32)(ru.ru_nivcsw + cru.ru_nivcsw)); - } -#endif /* HAVE_GETRUSAGE */ - random_xor_noise(state, 11, (word32)getpid()); - random_xor_noise(state, 12, (word32)getppid()); - random_xor_noise(state, 10, (word32)getuid()); - random_xor_noise(state, 10, (word32)(getgid() << 16)); -#ifdef _POSIX_CHILD_MAX - random_xor_noise(state, 13, (word32)(_POSIX_CHILD_MAX << 16)); -#endif /* _POSIX_CHILD_MAX */ -#ifdef CLK_TCK - random_xor_noise(state, 14, (word32)(CLK_TCK << 16)); -#endif /* CLK_TCK */ - - random_stir(state); -} - -/* Executes the given command, and processes its output as noise. */ - -void random_get_noise_from_command(RandomState *state, const char *cmd) -{ -#ifdef HAVE_POPEN - char line[1000]; - FILE *f; - - f = popen(cmd, "r"); - if (!f) - return; - while (fgets(line, sizeof(line), f)) - random_add_noise(state, line, strlen(line)); - pclose(f); - memset(line, 0, sizeof(line)); -#endif /* HAVE_POPEN */ -} - -/* Adds the contents of the buffer as noise. */ - -void random_add_noise(RandomState *state, const void *buf, unsigned int bytes) -{ - unsigned int pos = state->add_position; - const char *input = buf; - while (bytes > 0) - { - if (pos >= RANDOM_STATE_BYTES) - { - pos = 0; - random_stir(state); - } - state->state[pos] ^= *input; - input++; - bytes--; - pos++; - } - state->add_position = pos; -} - -/* Stirs the random pool to consume any newly acquired noise or to get more - random numbers. - - This works by encrypting the data in the buffer in CFB mode with MD5 as - the cipher. */ - -void random_stir(RandomState *state) -{ - uint32 iv[4]; - unsigned int i; - - /* Start IV from last block of random pool. */ - iv[0] = GET_32BIT(state->state); - iv[1] = GET_32BIT(state->state + 4); - iv[2] = GET_32BIT(state->state + 8); - iv[3] = GET_32BIT(state->state + 12); - - /* First CFB pass. */ - for (i = 0; i < RANDOM_STATE_BYTES; i += 16) - { - MD5Transform(iv, state->stir_key); - iv[0] ^= GET_32BIT(state->state + i); - PUT_32BIT(state->state + i, iv[0]); - iv[1] ^= GET_32BIT(state->state + i + 4); - PUT_32BIT(state->state + i + 4, iv[1]); - iv[2] ^= GET_32BIT(state->state + i + 8); - PUT_32BIT(state->state + i + 8, iv[2]); - iv[3] ^= GET_32BIT(state->state + i + 12); - PUT_32BIT(state->state + i + 12, iv[3]); - } - - /* Get new key. */ - memcpy(state->stir_key, state->state, sizeof(state->stir_key)); - - /* Second CFB pass. */ - for (i = 0; i < RANDOM_STATE_BYTES; i += 16) - { - MD5Transform(iv, state->stir_key); - iv[0] ^= GET_32BIT(state->state + i); - PUT_32BIT(state->state + i, iv[0]); - iv[1] ^= GET_32BIT(state->state + i + 4); - PUT_32BIT(state->state + i + 4, iv[1]); - iv[2] ^= GET_32BIT(state->state + i + 8); - PUT_32BIT(state->state + i + 8, iv[2]); - iv[3] ^= GET_32BIT(state->state + i + 12); - PUT_32BIT(state->state + i + 12, iv[3]); - } - - memset(iv, 0, sizeof(iv)); - - state->add_position = 0; - - /* Some data in the beginning is not returned to aboid giving an observer - complete knowledge of the contents of our random pool. */ - state->next_available_byte = sizeof(state->stir_key); -} - -/* Returns a random byte. Stirs the random pool if necessary. Acquires - new environmental noise approximately every five minutes. */ - -unsigned int random_get_byte(RandomState *state) -{ - if (state->next_available_byte >= RANDOM_STATE_BYTES) - { - /* Get some easily available noise. More importantly, this stirs - the pool. */ - random_acquire_light_environmental_noise(state); - } - assert(state->next_available_byte < RANDOM_STATE_BYTES); - return state->state[state->next_available_byte++]; -} - -/* Saves random data in a disk file. This is used to create a file that - can be used as a random seed on future runs. Only half of the random - data in our pool is written to the file to avoid an observer being - able to deduce the contents of our random pool from the file. */ - -void random_save(RandomState *state, const char *filename) -{ - char buf[RANDOM_STATE_BYTES / 2]; /* Save only half of its bits. */ - int i, f; - - /* Get some environmental noise to make it harder to predict previous - values from saved bits (besides, we have now probably consumed some - resources so the noise may be really useful). This also stirs - the pool. */ - random_acquire_light_environmental_noise(state); - - /* Get as many bytes as is half the size of the pool. I am assuming - this will get enough randomness for it to be very useful, but will - not reveal enough to make it possible to determine previous or future - returns by the generator. */ - for (i = 0; i < sizeof(buf); i++) - buf[i] = random_get_byte(state); - - /* Again get a little noise and stir it to mix the unrevealed half with - those bits that have been saved to a file. There should be enough - unrevealed bits (plus the new noise) to make it infeasible to try to - guess future values from the saved bits. */ - random_acquire_light_environmental_noise(state); - - /* Create and write the file. Failure to create the file is silently - ignored. */ - f = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0600); - if (f >= 0) - { - /* Creation successful. Write data to the file. */ - write(f, buf, sizeof(buf)); - close(f); - } - memset(buf, 0, sizeof(buf)); -} - -/* Clears the random number generator data structures. */ - -void random_clear(RandomState *state) -{ - memset(state, 0, sizeof(*state)); -} diff --git a/usr.bin/ssh/randoms.h b/usr.bin/ssh/randoms.h deleted file mode 100644 index 1e99f84a95b..00000000000 --- a/usr.bin/ssh/randoms.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - -random.h - -Author: Tatu Ylonen <ylo@cs.hut.fi> - -Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland - All rights reserved - -Created: Sat Mar 4 14:49:05 1995 ylo - -Cryptographically strong random number generator. - -*/ - -/* RCSID("$Id: randoms.h,v 1.1 1999/09/26 20:53:37 deraadt Exp $"); */ - -#ifndef RANDOM_H -#define RANDOM_H - -#include "ssh_md5.h" - -#define RANDOM_STATE_BITS 8192 -#define RANDOM_STATE_BYTES (RANDOM_STATE_BITS / 8) - -/* Structure for the random state. */ -typedef struct -{ - unsigned char state[RANDOM_STATE_BYTES];/* Pool of random data. */ - unsigned char stir_key[64]; /* Extra data for next stirring. */ - unsigned int next_available_byte; /* Index of next available byte. */ - unsigned int add_position; /* Index to add noise. */ -} RandomState; - -/* Initializes the random number generator, loads any random information - from the given file, and acquires as much environmental noise as it - can to initialize the random number generator. More noise can be - acquired later by calling random_add_noise + random_stir, or by - calling random_get_environmental_noise again later when the environmental - situation has changed. */ -void random_initialize(RandomState *state, const char *filename); - -/* Acquires as much environmental noise as it can. This is probably quite - sufficient on a unix machine, but might be grossly inadequate on a - single-user PC or a Macintosh. This call random_stir automatically. - This call may take many seconds to complete on a busy system. */ -void random_acquire_environmental_noise(RandomState *state); - -/* Acquires easily available noise from the environment. */ -void random_acquire_light_environmental_noise(RandomState *state); - -/* Executes the given command, and processes its output as noise. - random_stir should be called after this. */ -void random_get_noise_from_command(RandomState *state, const char *cmd); - -/* Adds the contents of the buffer as noise. random_stir should be called - after this. */ -void random_add_noise(RandomState *state, const void *buf, unsigned int bytes); - -/* Stirs the random pool to consume any newly acquired noise or to get more - random numbers. This should be called after adding noise to properly - mix the noise into the random pool. */ -void random_stir(RandomState *state); - -/* Returns a random byte. Stirs the random pool if necessary. Acquires - new environmental noise approximately every five minutes. */ -unsigned int random_get_byte(RandomState *state); - -/* Saves some random bits in the file so that it can be used as a source - of randomness for later runs. */ -void random_save(RandomState *state, const char *filename); - -/* Zeroes and frees any data structures associated with the random number - generator. */ -void random_clear(RandomState *state); - -#endif /* RANDOM_H */ diff --git a/usr.bin/ssh/readconf.c b/usr.bin/ssh/readconf.c index 48bad9714a7..8d74d5ac754 100644 --- a/usr.bin/ssh/readconf.c +++ b/usr.bin/ssh/readconf.c @@ -14,7 +14,7 @@ Functions for reading the configuration files. */ #include "includes.h" -RCSID("$Id: readconf.c,v 1.1 1999/09/26 20:53:37 deraadt Exp $"); +RCSID("$Id: readconf.c,v 1.2 1999/09/28 04:45:36 provos Exp $"); #include "ssh.h" #include "cipher.h" @@ -80,7 +80,6 @@ RCSID("$Id: readconf.c,v 1.1 1999/09/26 20:53:37 deraadt Exp $"); KeepAlives no IdentityFile ~/.ssh/identity Port 22 - Cipher idea EscapeChar ~ */ diff --git a/usr.bin/ssh/rsa.c b/usr.bin/ssh/rsa.c new file mode 100644 index 00000000000..f578e631184 --- /dev/null +++ b/usr.bin/ssh/rsa.c @@ -0,0 +1,149 @@ +/* + +rsa.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Fri Mar 3 22:07:06 1995 ylo + +Description of the RSA algorithm can be found e.g. from the following sources: + + Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1994. + + Jennifer Seberry and Josed Pieprzyk: Cryptography: An Introduction to + Computer Security. Prentice-Hall, 1989. + + Man Young Rhee: Cryptography and Secure Data Communications. McGraw-Hill, + 1994. + + R. Rivest, A. Shamir, and L. M. Adleman: Cryptographic Communications + System and Method. US Patent 4,405,829, 1983. + + Hans Riesel: Prime Numbers and Computer Methods for Factorization. + Birkhauser, 1994. + + The RSA Frequently Asked Questions document by RSA Data Security, Inc., 1995. + + RSA in 3 lines of perl by Adam Back <aba@atlax.ex.ac.uk>, 1995, as included + below: + + gone - had to be deleted - what a pity + +*/ + +#include "includes.h" +RCSID("$Id: rsa.c,v 1.1 1999/09/28 04:45:37 provos Exp $"); + +#include "rsa.h" +#include "ssh.h" +#include "xmalloc.h" + +int rsa_verbose = 1; + +/* Generates RSA public and private keys. This initializes the data + structures; they should be freed with rsa_clear_private_key and + rsa_clear_public_key. */ + +void +rsa_generate_key(RSA *prv, RSA *pub, unsigned int bits) +{ + RSA *key; + + if (rsa_verbose) { + printf("Generating RSA keys: "); + fflush(stdout); + } + + key = RSA_generate_key(bits, 35, NULL, NULL); + + assert(key != NULL); + + /* Copy public key parameters */ + pub->n = BN_new(); + BN_copy(pub->n, key->n); + pub->e = BN_new(); + BN_copy(pub->e, key->e); + + /* Copy private key parameters */ + prv->n = BN_new(); + BN_copy(prv->n, key->n); + prv->e = BN_new(); + BN_copy(prv->e, key->e); + prv->d = BN_new(); + BN_copy(prv->d, key->d); + prv->p = BN_new(); + BN_copy(prv->p, key->p); + prv->q = BN_new(); + BN_copy(prv->q, key->q); + + prv->dmp1 = BN_new(); + BN_copy(prv->dmp1, key->dmp1); + + prv->dmq1 = BN_new(); + BN_copy(prv->dmq1, key->dmq1); + + prv->iqmp = BN_new(); + BN_copy(prv->iqmp, key->iqmp); + + RSA_free(key); + + if (rsa_verbose) + printf("Key generation complete.\n"); +} + +void +rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA* key) +{ + char *inbuf, *outbuf; + int len; + + len = BN_num_bytes(key->n); + outbuf = xmalloc(len); + + len = BN_num_bytes(in); + inbuf = xmalloc(len); + BN_bn2bin(in, inbuf); + + if ((len = RSA_public_encrypt(len, inbuf, outbuf, key, + RSA_PKCS1_PADDING)) <= 0) + fatal("rsa_public_encrypt() failed"); + + BN_bin2bn(outbuf, len, out); + + xfree(outbuf); + xfree(inbuf); +} + +void +rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key) +{ + char *inbuf, *outbuf; + int len; + + len = BN_num_bytes(key->n); + outbuf = xmalloc(len); + + len = BN_num_bytes(in); + inbuf = xmalloc(len); + BN_bn2bin(in, inbuf); + + if ((len = RSA_private_decrypt(len, inbuf, outbuf, key, + RSA_SSLV23_PADDING)) <= 0) + fatal("rsa_private_decrypt() failed"); + + BN_bin2bn(outbuf, len, out); + + xfree(outbuf); + xfree(inbuf); +} + +/* Set whether to output verbose messages during key generation. */ + +void +rsa_set_verbose(int verbose) +{ + rsa_verbose = verbose; +} diff --git a/usr.bin/ssh/rsa.h b/usr.bin/ssh/rsa.h new file mode 100644 index 00000000000..a775c824fce --- /dev/null +++ b/usr.bin/ssh/rsa.h @@ -0,0 +1,34 @@ +/* + +rsa.h + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Fri Mar 3 22:01:06 1995 ylo + +RSA key generation, encryption and decryption. + +*/ + +/* RCSID("$Id: rsa.h,v 1.1 1999/09/28 04:45:37 provos Exp $"); */ + +#ifndef RSA_H +#define RSA_H + +#include <ssl/bn.h> +#include <ssl/rsa.h> + +/* Calls SSL RSA_generate_key, only copies to prv and pub */ +void rsa_generate_key(RSA *prv, RSA *pub, unsigned int bits); + +/* Indicates whether the rsa module is permitted to show messages on + the terminal. */ +void rsa_set_verbose(int verbose); + +void rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *prv); +void rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *prv); + +#endif /* RSA_H */ diff --git a/usr.bin/ssh/scp/Makefile b/usr.bin/ssh/scp/Makefile index 5013d2b99cf..fa782a68649 100644 --- a/usr.bin/ssh/scp/Makefile +++ b/usr.bin/ssh/scp/Makefile @@ -8,4 +8,4 @@ MAN= scp.1 SRCS= scp.c xmalloc.c -.include<bsd.prog.mk> +.include <bsd.prog.mk> diff --git a/usr.bin/ssh/ssh-add.c b/usr.bin/ssh/ssh-add.c index 99a8ada1c9a..d2c6547badc 100644 --- a/usr.bin/ssh/ssh-add.c +++ b/usr.bin/ssh/ssh-add.c @@ -14,21 +14,22 @@ Adds an identity to the authentication server, or removes an identity. */ #include "includes.h" -RCSID("$Id: ssh-add.c,v 1.1 1999/09/26 20:53:37 deraadt Exp $"); +RCSID("$Id: ssh-add.c,v 1.2 1999/09/28 04:45:37 provos Exp $"); -#include "randoms.h" #include "rsa.h" #include "ssh.h" #include "xmalloc.h" #include "authfd.h" -void delete_file(const char *filename) +void +delete_file(const char *filename) { - RSAPublicKey key; + RSA *key; char *comment; AuthenticationConnection *ac; - if (!load_public_key(filename, &key, &comment)) + key = RSA_new(); + if (!load_public_key(filename, key, &comment)) { printf("Bad key file %s: %s\n", filename, strerror(errno)); return; @@ -40,20 +41,21 @@ void delete_file(const char *filename) { fprintf(stderr, "Could not open a connection to your authentication agent.\n"); - rsa_clear_public_key(&key); + RSA_free(key); xfree(comment); return; } - if (ssh_remove_identity(ac, &key)) + if (ssh_remove_identity(ac, key)) fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment); else fprintf(stderr, "Could not remove identity: %s\n", filename); - rsa_clear_public_key(&key); + RSA_free(key); xfree(comment); ssh_close_authentication_connection(ac); } -void delete_all() +void +delete_all() { AuthenticationConnection *ac; @@ -76,24 +78,27 @@ void delete_all() ssh_close_authentication_connection(ac); } -void add_file(const char *filename) +void +add_file(const char *filename) { - RSAPrivateKey key; - RSAPublicKey public_key; + RSA *key; + RSA *public_key; AuthenticationConnection *ac; char *saved_comment, *comment, *pass; int first; - if (!load_public_key(filename, &public_key, &saved_comment)) + key = RSA_new(); + public_key = RSA_new(); + if (!load_public_key(filename, public_key, &saved_comment)) { printf("Bad key file %s: %s\n", filename, strerror(errno)); return; } - rsa_clear_public_key(&public_key); + RSA_free(public_key); pass = xstrdup(""); first = 1; - while (!load_private_key(filename, pass, &key, &comment)) + while (!load_private_key(filename, pass, key, &comment)) { char buf[1024]; FILE *f; @@ -147,23 +152,24 @@ void add_file(const char *filename) { fprintf(stderr, "Could not open a connection to your authentication agent.\n"); - rsa_clear_private_key(&key); + RSA_free(key); xfree(comment); return; } - if (ssh_add_identity(ac, &key, comment)) + if (ssh_add_identity(ac, key, comment)) fprintf(stderr, "Identity added: %s (%s)\n", filename, comment); else fprintf(stderr, "Could not add identity: %s\n", filename); - rsa_clear_private_key(&key); + RSA_free(key); xfree(comment); ssh_close_authentication_connection(ac); } -void list_identities() +void +list_identities() { AuthenticationConnection *ac; - MP_INT e, n; + BIGNUM *e, *n; int bits, status; char *comment; int had_identities; @@ -174,29 +180,35 @@ void list_identities() fprintf(stderr, "Could not connect to authentication server.\n"); return; } - mpz_init(&e); - mpz_init(&n); + e = BN_new(); + n = BN_new(); had_identities = 0; - for (status = ssh_get_first_identity(ac, &bits, &e, &n, &comment); + for (status = ssh_get_first_identity(ac, &bits, e, n, &comment); status; - status = ssh_get_next_identity(ac, &bits, &e, &n, &comment)) + status = ssh_get_next_identity(ac, &bits, e, n, &comment)) { + char *buf; had_identities = 1; printf("%d ", bits); - mpz_out_str(stdout, 10, &e); - printf(" "); - mpz_out_str(stdout, 10, &n); - printf(" %s\n", comment); + buf = BN_bn2dec(e); + assert(buf != NULL); + printf("%s ", buf); + free (buf); + buf = BN_bn2dec(n); + assert(buf != NULL); + printf("%s %s\n", buf, comment); + free (buf); xfree(comment); } - mpz_clear(&e); - mpz_clear(&n); + BN_clear_free(e); + BN_clear_free(n); if (!had_identities) printf("The agent has no identities.\n"); ssh_close_authentication_connection(ac); } -int main(int ac, char **av) +int +main(int ac, char **av) { struct passwd *pw; char buf[1024]; diff --git a/usr.bin/ssh/ssh-add/Makefile b/usr.bin/ssh/ssh-add/Makefile index 9689c853003..5a751c80f84 100644 --- a/usr.bin/ssh/ssh-add/Makefile +++ b/usr.bin/ssh/ssh-add/Makefile @@ -4,11 +4,11 @@ PROG= ssh-add BINOWN= root BINMODE=555 BINDIR= /usr/bin -LDADD= -lkrb -lcrypto -ldes -lgmp -lutil -lz +LDADD= -lkrb -lcrypto -ldes -lutil -lz MAN= ssh-add.1 -SRCS= ssh-add.c log-client.c readpass.c rsa.c randoms.c ssh_md5.c buffer.c \ - xmalloc.c bufaux.c authfd.c authfile.c crc32.c rsaglue.c match.c \ +SRCS= ssh-add.c log-client.c readpass.c rsa.c ssh_md5.c buffer.c \ + xmalloc.c bufaux.c authfd.c authfile.c crc32.c match.c \ mpaux.c minfd.c cipher.c compress.c gen_minfd: gen_minfd.c diff --git a/usr.bin/ssh/ssh-agent.c b/usr.bin/ssh/ssh-agent.c index f038178ed5f..80f855f895c 100644 --- a/usr.bin/ssh/ssh-agent.c +++ b/usr.bin/ssh/ssh-agent.c @@ -14,11 +14,10 @@ The authentication agent program. */ #include "includes.h" -RCSID("$Id: ssh-agent.c,v 1.1 1999/09/26 20:53:37 deraadt Exp $"); +RCSID("$Id: ssh-agent.c,v 1.2 1999/09/28 04:45:37 provos Exp $"); #include "ssh.h" #include "rsa.h" -#include "randoms.h" #include "authfd.h" #include "buffer.h" #include "bufaux.h" @@ -42,7 +41,7 @@ SocketEntry *sockets = NULL; typedef struct { - RSAPrivateKey key; + RSA *key; char *comment; } Identity; @@ -51,7 +50,8 @@ Identity *identities = NULL; int max_fd = 0; -void process_request_identity(SocketEntry *e) +void +process_request_identity(SocketEntry *e) { Buffer msg; int i; @@ -61,9 +61,9 @@ void process_request_identity(SocketEntry *e) buffer_put_int(&msg, num_identities); for (i = 0; i < num_identities; i++) { - buffer_put_int(&msg, identities[i].key.bits); - buffer_put_mp_int(&msg, &identities[i].key.e); - buffer_put_mp_int(&msg, &identities[i].key.n); + buffer_put_int(&msg, BN_num_bits(identities[i].key->n)); + buffer_put_bignum(&msg, identities[i].key->e); + buffer_put_bignum(&msg, identities[i].key->n); buffer_put_string(&msg, identities[i].comment, strlen(identities[i].comment)); } @@ -72,23 +72,24 @@ void process_request_identity(SocketEntry *e) buffer_free(&msg); } -void process_authentication_challenge(SocketEntry *e) +void +process_authentication_challenge(SocketEntry *e) { - int i, pub_bits; - MP_INT pub_e, pub_n, challenge; + int i, pub_bits, len; + BIGNUM *pub_e, *pub_n, *challenge; Buffer msg; struct MD5Context md; unsigned char buf[32], mdbuf[16], session_id[16]; unsigned int response_type; buffer_init(&msg); - mpz_init(&pub_e); - mpz_init(&pub_n); - mpz_init(&challenge); + pub_e = BN_new(); + pub_n = BN_new(); + challenge = BN_new(); pub_bits = buffer_get_int(&e->input); - buffer_get_mp_int(&e->input, &pub_e); - buffer_get_mp_int(&e->input, &pub_n); - buffer_get_mp_int(&e->input, &challenge); + buffer_get_bignum(&e->input, pub_e); + buffer_get_bignum(&e->input, pub_n); + buffer_get_bignum(&e->input, challenge); if (buffer_len(&e->input) == 0) { /* Compatibility code for old servers. */ @@ -102,12 +103,12 @@ void process_authentication_challenge(SocketEntry *e) response_type = buffer_get_int(&e->input); } for (i = 0; i < num_identities; i++) - if (pub_bits == identities[i].key.bits && - mpz_cmp(&pub_e, &identities[i].key.e) == 0 && - mpz_cmp(&pub_n, &identities[i].key.n) == 0) + if (pub_bits == BN_num_bits(identities[i].key->n) && + BN_cmp(pub_e, identities[i].key->e) == 0 && + BN_cmp(pub_n, identities[i].key->n) == 0) { /* Decrypt the challenge using the private key. */ - rsa_private_decrypt(&challenge, &challenge, &identities[i].key); + rsa_private_decrypt(challenge, challenge, identities[i].key); /* Compute the desired response. */ switch (response_type) @@ -120,7 +121,10 @@ void process_authentication_challenge(SocketEntry *e) case 1: /* As of protocol 1.1 */ /* The response is MD5 of decrypted challenge plus session id. */ - mp_linearize_msb_first(buf, 32, &challenge); + len = BN_num_bytes(challenge); + assert(len <= 32 && len); + memset(buf, 0, 32); + BN_bn2bin(challenge, buf + 32 - len); MD5Init(&md); MD5Update(&md, buf, 32); MD5Update(&md, session_id, 16); @@ -147,39 +151,40 @@ void process_authentication_challenge(SocketEntry *e) buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg)); buffer_free(&msg); - mpz_clear(&pub_e); - mpz_clear(&pub_n); - mpz_clear(&challenge); + BN_clear_free(pub_e); + BN_clear_free(pub_n); + BN_clear_free(challenge); } -void process_remove_identity(SocketEntry *e) +void +process_remove_identity(SocketEntry *e) { unsigned int bits; - MP_INT dummy, n; unsigned int i; + BIGNUM *dummy, *n; - mpz_init(&dummy); - mpz_init(&n); + dummy = BN_new(); + n = BN_new(); /* Get the key from the packet. */ bits = buffer_get_int(&e->input); - buffer_get_mp_int(&e->input, &dummy); - buffer_get_mp_int(&e->input, &n); + buffer_get_bignum(&e->input, dummy); + buffer_get_bignum(&e->input, n); /* Check if we have the key. */ for (i = 0; i < num_identities; i++) - if (mpz_cmp(&identities[i].key.n, &n) == 0) + if (BN_cmp(identities[i].key->n, n) == 0) { /* We have this key. Free the old key. Since we don\'t want to leave empty slots in the middle of the array, we actually free the key there and copy data from the last entry. */ - rsa_clear_private_key(&identities[i].key); + RSA_free(identities[i].key); xfree(identities[i].comment); if (i < num_identities - 1) identities[i] = identities[num_identities - 1]; num_identities--; - mpz_clear(&dummy); - mpz_clear(&n); + BN_clear_free(dummy); + BN_clear_free(n); /* Send success. */ buffer_put_int(&e->output, 1); @@ -187,8 +192,8 @@ void process_remove_identity(SocketEntry *e) return; } /* We did not have the key. */ - mpz_clear(&dummy); - mpz_clear(&n); + BN_clear(dummy); + BN_clear(n); /* Send failure. */ buffer_put_int(&e->output, 1); @@ -197,14 +202,15 @@ void process_remove_identity(SocketEntry *e) /* Removes all identities from the agent. */ -void process_remove_all_identities(SocketEntry *e) +void +process_remove_all_identities(SocketEntry *e) { unsigned int i; /* Loop over all identities and clear the keys. */ for (i = 0; i < num_identities; i++) { - rsa_clear_private_key(&identities[i].key); + RSA_free(identities[i].key); xfree(identities[i].comment); } @@ -219,38 +225,60 @@ void process_remove_all_identities(SocketEntry *e) /* Adds an identity to the agent. */ -void process_add_identity(SocketEntry *e) +void +process_add_identity(SocketEntry *e) { - RSAPrivateKey *k; + RSA *k; int i; - + BIGNUM *aux; + BN_CTX *ctx; + if (num_identities == 0) identities = xmalloc(sizeof(Identity)); else identities = xrealloc(identities, (num_identities + 1) * sizeof(Identity)); - k = &identities[num_identities].key; - k->bits = buffer_get_int(&e->input); - mpz_init(&k->n); - buffer_get_mp_int(&e->input, &k->n); - mpz_init(&k->e); - buffer_get_mp_int(&e->input, &k->e); - mpz_init(&k->d); - buffer_get_mp_int(&e->input, &k->d); - mpz_init(&k->u); - buffer_get_mp_int(&e->input, &k->u); - mpz_init(&k->p); - buffer_get_mp_int(&e->input, &k->p); - mpz_init(&k->q); - buffer_get_mp_int(&e->input, &k->q); + + identities[num_identities].key = RSA_new(); + k = identities[num_identities].key; + buffer_get_int(&e->input); /* bits */ + k->n = BN_new(); + buffer_get_bignum(&e->input, k->n); + k->e = BN_new(); + buffer_get_bignum(&e->input, k->e); + k->d = BN_new(); + buffer_get_bignum(&e->input, k->d); + k->iqmp = BN_new(); + buffer_get_bignum(&e->input, k->iqmp); + /* SSH and SSL have p and q swapped */ + k->q = BN_new(); + buffer_get_bignum(&e->input, k->q); /* p */ + k->p = BN_new(); + buffer_get_bignum(&e->input, k->p); /* q */ + + /* Generate additional parameters */ + aux = BN_new(); + ctx = BN_CTX_new(); + + BN_sub(aux, k->q, BN_value_one()); + k->dmq1 = BN_new(); + BN_mod(k->dmq1, k->d, aux, ctx); + + BN_sub(aux, k->p, BN_value_one()); + k->dmp1 = BN_new(); + BN_mod(k->dmp1, k->d, aux, ctx); + + BN_clear_free(aux); + BN_CTX_free(ctx); + identities[num_identities].comment = buffer_get_string(&e->input, NULL); /* Check if we already have the key. */ for (i = 0; i < num_identities; i++) - if (mpz_cmp(&identities[i].key.n, &k->n) == 0) + if (BN_cmp(identities[i].key->n, k->n) == 0) { /* We already have this key. Clear and free the new data and return success. */ - rsa_clear_private_key(k); + RSA_free(k); xfree(identities[num_identities].comment); /* Send success. */ @@ -267,7 +295,8 @@ void process_add_identity(SocketEntry *e) buffer_put_char(&e->output, SSH_AGENT_SUCCESS); } -void process_message(SocketEntry *e) +void +process_message(SocketEntry *e) { unsigned int msg_len; unsigned int type; @@ -314,7 +343,8 @@ void process_message(SocketEntry *e) } } -void new_socket(int type, int fd) +void +new_socket(int type, int fd) { unsigned int i, old_alloc; #if defined(O_NONBLOCK) && !defined(O_NONBLOCK_BROKEN) @@ -351,7 +381,8 @@ void new_socket(int type, int fd) buffer_init(&sockets[old_alloc].output); } -void prepare_select(fd_set *readset, fd_set *writeset) +void +prepare_select(fd_set *readset, fd_set *writeset) { unsigned int i; for (i = 0; i < sockets_alloc; i++) @@ -483,7 +514,8 @@ void after_select(fd_set *readset, fd_set *writeset) int parent_pid = -1; char socket_name[1024]; -RETSIGTYPE check_parent_exists(int sig) +RETSIGTYPE +check_parent_exists(int sig) { if (kill(parent_pid, 0) < 0) { @@ -495,7 +527,8 @@ RETSIGTYPE check_parent_exists(int sig) alarm(10); } -int main(int ac, char **av) +int +main(int ac, char **av) { fd_set readset, writeset; char buf[1024]; diff --git a/usr.bin/ssh/ssh-agent/Makefile b/usr.bin/ssh/ssh-agent/Makefile index 0abaa966429..8639b2ecf37 100644 --- a/usr.bin/ssh/ssh-agent/Makefile +++ b/usr.bin/ssh/ssh-agent/Makefile @@ -1,14 +1,14 @@ .PATH: ${.CURDIR}/.. -PROG= ssh-keygen +PROG= ssh-agent BINOWN= root BINMODE=555 BINDIR= /usr/bin -LDADD= -lkrb -lcrypto -ldes -lgmp -lutil -lz -MAN= ssh-keygen.1 +LDADD= -lkrb -lcrypto -ldes -lutil -lz +MAN= ssh-agent.1 -SRCS= ssh-agent.c log-client.c rsa.c randoms.c ssh_md5.c buffer.c \ - xmalloc.c bufaux.c authfd.c authfile.c rsaglue.c \ +SRCS= ssh-agent.c log-client.c rsa.c ssh_md5.c buffer.c \ + xmalloc.c bufaux.c authfd.c authfile.c \ mpaux.c crc32.c match.c minfd.c cipher.c compress.c gen_minfd: gen_minfd.c @@ -16,4 +16,4 @@ minfd.o: minfd.h minfd.h: gen_minfd ./gen_minfd $(USER_SHELLS) > minfd.h -.include<bsd.prog.mk> +.include <bsd.prog.mk> diff --git a/usr.bin/ssh/ssh-askpass.wish b/usr.bin/ssh/ssh-askpass.wish deleted file mode 100644 index 5e8d3d897d3..00000000000 --- a/usr.bin/ssh/ssh-askpass.wish +++ /dev/null @@ -1,48 +0,0 @@ -# This file (ssh-askpass.wish) will be used to create ssh-askpass by-*- tcl -*- -# prepending the header line that executes wish. -# -# $Id: ssh-askpass.wish,v 1.1 1999/09/26 20:53:37 deraadt Exp $ -# - -global result - -wm title . "Authentication Password Entry" - -# Use the first argument as a prompt (if given). -if {$argv==""} { - label .header -text "Please enter your authentication password" -} { - label .header -text "[lindex $argv 0]" -} - -entry .pass -relief sunken -textvariable password -set bgcolor [lindex [.pass configure -bg] 3] -.pass configure -fg $bgcolor -selectforeground $bgcolor \ - -selectbackground $bgcolor - -bind .pass <Return> { set result ok } -frame .b -frame .b.ok_f -borderwidth 2 -relief sunken -button .b.ok -text OK -width 6 -command { set result ok } -button .b.cancel -text Cancel -width 6 -command { set result cancel } -pack .b.ok -in .b.ok_f -padx 2 -pady 2 -pack .b.ok_f -side left -padx 5m -pady 3m -pack .b.cancel -side right -padx 5m -pady 3m -pack .header .pass .b -wm protocol . WM_DELETE_WINDOW { set result cancel } - -set old_focus [focus] -grab set . -focus .pass - -set result "none" - -while {"$result" == "none"} { - tkwait variable result -} - -if {$old_focus!=""} { - focus $old_focus -} - -if {"$result" == "ok"} {puts "$password"; exit 0} {exit 1} diff --git a/usr.bin/ssh/ssh-keygen.c b/usr.bin/ssh/ssh-keygen.c index 0ff98cde1cc..2d66f2310dc 100644 --- a/usr.bin/ssh/ssh-keygen.c +++ b/usr.bin/ssh/ssh-keygen.c @@ -14,24 +14,20 @@ Identity and host key generation and maintenance. */ #include "includes.h" -RCSID("$Id: ssh-keygen.c,v 1.1 1999/09/26 20:53:37 deraadt Exp $"); +RCSID("$Id: ssh-keygen.c,v 1.2 1999/09/28 04:45:37 provos Exp $"); #ifndef HAVE_GETHOSTNAME #include <sys/utsname.h> #endif -#include "randoms.h" #include "rsa.h" #include "ssh.h" #include "xmalloc.h" /* Generated private key. */ -RSAPrivateKey private_key; +RSA *private_key; /* Generated public key. */ -RSAPublicKey public_key; - -/* Random number generator state. */ -RandomState state; +RSA *public_key; /* Number of bits in the RSA key. This value can be changed on the command line. */ @@ -45,6 +41,8 @@ int change_passphrase = 0; on the command line. */ int change_comment = 0; +int quiet = 0; + /* This is set to the identity file name if given on the command line. */ char *identity_file = NULL; @@ -60,31 +58,28 @@ char *identity_comment = NULL; /* Perform changing a passphrase. The argument is the passwd structure for the current user. */ -void do_change_passphrase(struct passwd *pw) +void +do_change_passphrase(struct passwd *pw) { char buf[1024], *comment; - RSAPrivateKey private_key; char *old_passphrase, *passphrase1, *passphrase2; struct stat st; + RSA *private_key; /* Read key file name. */ - if (identity_file != NULL) - { + if (identity_file != NULL) { strncpy(buf, identity_file, sizeof(buf)); buf[sizeof(buf) - 1] = '\0'; - } - else - { - printf("Enter file in which the key is ($HOME/%s): ", - SSH_CLIENT_IDENTITY); - fflush(stdout); - if (fgets(buf, sizeof(buf), stdin) == NULL) - exit(1); - if (strchr(buf, '\n')) - *strchr(buf, '\n') = 0; - if (strcmp(buf, "") == 0) - sprintf(buf, "%s/%s", pw->pw_dir, SSH_CLIENT_IDENTITY); - } + } else { + printf("Enter file in which the key is ($HOME/%s): ", SSH_CLIENT_IDENTITY); + fflush(stdout); + if (fgets(buf, sizeof(buf), stdin) == NULL) + exit(1); + if (strchr(buf, '\n')) + *strchr(buf, '\n') = 0; + if (strcmp(buf, "") == 0) + sprintf(buf, "%s/%s", pw->pw_dir, SSH_CLIENT_IDENTITY); + } /* Check if the file exists. */ if (stat(buf, &st) < 0) @@ -95,34 +90,35 @@ void do_change_passphrase(struct passwd *pw) /* Try to load the public key from the file the verify that it is readable and of the proper format. */ - if (!load_public_key(buf, &public_key, NULL)) + public_key = RSA_new(); + if (!load_public_key(buf, public_key, NULL)) { printf("%s is not a valid key file.\n", buf); exit(1); } /* Clear the public key since we are just about to load the whole file. */ - rsa_clear_public_key(&public_key); + RSA_free(public_key); /* Try to load the file with empty passphrase. */ - if (!load_private_key(buf, "", &private_key, &comment)) - { - /* Read passphrase from the user. */ - if (identity_passphrase) - old_passphrase = xstrdup(identity_passphrase); - else - old_passphrase = read_passphrase("Enter old passphrase: ", 1); - /* Try to load using the passphrase. */ - if (!load_private_key(buf, old_passphrase, &private_key, &comment)) - { - memset(old_passphrase, 0, strlen(old_passphrase)); - xfree(old_passphrase); - printf("Bad passphrase.\n"); - exit(1); - } - /* Destroy the passphrase. */ - memset(old_passphrase, 0, strlen(old_passphrase)); - xfree(old_passphrase); - } + private_key = RSA_new(); + if (!load_private_key(buf, "", private_key, &comment)) { + /* Read passphrase from the user. */ + if (identity_passphrase) + old_passphrase = xstrdup(identity_passphrase); + else + old_passphrase = read_passphrase("Enter old passphrase: ", 1); + /* Try to load using the passphrase. */ + if (!load_private_key(buf, old_passphrase, private_key, &comment)) + { + memset(old_passphrase, 0, strlen(old_passphrase)); + xfree(old_passphrase); + printf("Bad passphrase.\n"); + exit(1); + } + /* Destroy the passphrase. */ + memset(old_passphrase, 0, strlen(old_passphrase)); + xfree(old_passphrase); + } printf("Key has comment '%s'\n", comment); /* Ask the new passphrase (twice). */ @@ -153,20 +149,20 @@ void do_change_passphrase(struct passwd *pw) } /* Save the file using the new passphrase. */ - if (!save_private_key(buf, passphrase1, &private_key, comment, &state)) + if (!save_private_key(buf, passphrase1, private_key, comment)) { printf("Saving the key failed: %s: %s.\n", buf, strerror(errno)); memset(passphrase1, 0, strlen(passphrase1)); xfree(passphrase1); - rsa_clear_private_key(&private_key); + RSA_free(private_key); xfree(comment); exit(1); } /* Destroy the passphrase and the copy of the key in memory. */ memset(passphrase1, 0, strlen(passphrase1)); xfree(passphrase1); - rsa_clear_private_key(&private_key); + RSA_free(private_key); /* Destroys contents */ xfree(comment); printf("Your identification has been saved with the new passphrase.\n"); @@ -175,13 +171,15 @@ void do_change_passphrase(struct passwd *pw) /* Change the comment of a private key file. */ -void do_change_comment(struct passwd *pw) +void +do_change_comment(struct passwd *pw) { char buf[1024], new_comment[1024], *comment; - RSAPrivateKey private_key; + RSA *private_key; char *passphrase; struct stat st; FILE *f; + char *tmpbuf; /* Read key file name. */ if (identity_file) @@ -211,14 +209,16 @@ void do_change_comment(struct passwd *pw) /* Try to load the public key from the file the verify that it is readable and of the proper format. */ - if (!load_public_key(buf, &public_key, NULL)) + public_key = RSA_new(); + if (!load_public_key(buf, public_key, NULL)) { printf("%s is not a valid key file.\n", buf); exit(1); } + private_key = RSA_new(); /* Try to load the file with empty passphrase. */ - if (load_private_key(buf, "", &private_key, &comment)) + if (load_private_key(buf, "", private_key, &comment)) passphrase = xstrdup(""); else { @@ -231,7 +231,7 @@ void do_change_comment(struct passwd *pw) else passphrase = read_passphrase("Enter passphrase: ", 1); /* Try to load using the passphrase. */ - if (!load_private_key(buf, passphrase, &private_key, &comment)) + if (!load_private_key(buf, passphrase, private_key, &comment)) { memset(passphrase, 0, strlen(passphrase)); xfree(passphrase); @@ -253,7 +253,7 @@ void do_change_comment(struct passwd *pw) if (!fgets(new_comment, sizeof(new_comment), stdin)) { memset(passphrase, 0, strlen(passphrase)); - rsa_clear_private_key(&private_key); + RSA_free(private_key); exit(1); } @@ -263,14 +263,13 @@ void do_change_comment(struct passwd *pw) } /* Save the file using the new passphrase. */ - if (!save_private_key(buf, passphrase, &private_key, new_comment, - &state)) + if (!save_private_key(buf, passphrase, private_key, new_comment)) { printf("Saving the key failed: %s: %s.\n", buf, strerror(errno)); memset(passphrase, 0, strlen(passphrase)); xfree(passphrase); - rsa_clear_private_key(&private_key); + RSA_free(private_key); xfree(comment); exit(1); } @@ -278,7 +277,7 @@ void do_change_comment(struct passwd *pw) /* Destroy the passphrase and the private key in memory. */ memset(passphrase, 0, strlen(passphrase)); xfree(passphrase); - rsa_clear_private_key(&private_key); + RSA_free(private_key); /* Save the public key in text format in a file with the same name but .pub appended. */ @@ -289,11 +288,13 @@ void do_change_comment(struct passwd *pw) printf("Could not save your public key in %s\n", buf); exit(1); } - fprintf(f, "%d ", public_key.bits); - mpz_out_str(f, 10, &public_key.e); - fprintf(f, " "); - mpz_out_str(f, 10, &public_key.n); - fprintf(f, " %s\n", new_comment); + fprintf(f, "%d ", BN_num_bits(public_key->n)); + tmpbuf = BN_bn2dec(public_key->e); + fprintf(f, "%s ", tmpbuf); + free (tmpbuf); + tmpbuf = BN_bn2dec(public_key->n); + fprintf(f, "%s %s\n", tmpbuf, new_comment); + free (tmpbuf); fclose(f); xfree(comment); @@ -304,10 +305,12 @@ void do_change_comment(struct passwd *pw) /* Main program for key management. */ -int main(int ac, char **av) +int +main(int ac, char **av) { char buf[16384], buf2[1024], *passphrase1, *passphrase2; struct passwd *pw; + char *tmpbuf; int opt; struct stat st; FILE *f; @@ -371,6 +374,10 @@ int main(int ac, char **av) identity_comment = optarg; break; + case 'q': + quiet = 1; + break; + case '?': default: printf("ssh-keygen version %s\n", SSH_VERSION); @@ -401,21 +408,17 @@ int main(int ac, char **av) /* Initialize random number generator. This may take a while if the user has no seed file, so display a message to the user. */ - printf("Initializing random number generator...\n"); - sprintf(buf, "%s/%s", pw->pw_dir, SSH_CLIENT_SEEDFILE); - random_initialize(&state, buf); + if (!quiet) + printf("Initializing random number generator...\n"); + arc4random_stir(); - /* Save random seed so we don\'t need to do all that time-consuming - environmental noise collection the next time. */ - random_save(&state, buf); + if (quiet) + rsa_set_verbose(0); /* Generate the rsa key pair. */ - rsa_generate_key(&private_key, &public_key, &state, bits); - - /* Save the state again, just to remove any fear that the previous state - could be used to recreate the key. (That should not be possible anyway - since the pool is stirred after save and some noise is added.) */ - random_save(&state, buf); + private_key = RSA_new(); + public_key = RSA_new(); + rsa_generate_key(private_key, public_key, bits); ask_file_again: @@ -504,7 +507,7 @@ int main(int ac, char **av) } /* Save the key with the given passphrase and comment. */ - if (!save_private_key(buf, passphrase1, &private_key, buf2, &state)) + if (!save_private_key(buf, passphrase1, private_key, buf2)) { printf("Saving the key failed: %s: %s.\n", buf, strerror(errno)); @@ -517,18 +520,23 @@ int main(int ac, char **av) xfree(passphrase1); /* Clear the private key and the random number generator. */ - rsa_clear_private_key(&private_key); - random_clear(&state); + RSA_free(private_key); + arc4random_stir(); - printf("Your identification has been saved in %s.\n", buf); + if (!quiet) + printf("Your identification has been saved in %s.\n", buf); /* Display the public key on the screen. */ - printf("Your public key is:\n"); - printf("%d ", public_key.bits); - mpz_out_str(stdout, 10, &public_key.e); - printf(" "); - mpz_out_str(stdout, 10, &public_key.n); - printf(" %s\n", buf2); + if (!quiet) { + printf("Your public key is:\n"); + printf("%d ", BN_num_bits(public_key->n)); + tmpbuf = BN_bn2dec(public_key->e); + printf("%s ", tmpbuf); + free(tmpbuf); + tmpbuf = BN_bn2dec(public_key->n); + printf("%s %s\n", tmpbuf, buf2); + free(tmpbuf); + } /* Save the public key in text format in a file with the same name but .pub appended. */ @@ -539,14 +547,17 @@ int main(int ac, char **av) printf("Could not save your public key in %s\n", buf); exit(1); } - fprintf(f, "%d ", public_key.bits); - mpz_out_str(f, 10, &public_key.e); - fprintf(f, " "); - mpz_out_str(f, 10, &public_key.n); - fprintf(f, " %s\n", buf2); + fprintf(f, "%d ", BN_num_bits(public_key->n)); + tmpbuf = BN_bn2dec(public_key->e); + fprintf(f, "%s ", tmpbuf); + free(tmpbuf); + tmpbuf = BN_bn2dec(public_key->n); + fprintf(f, "%s %s\n", tmpbuf, buf2); + free(tmpbuf); fclose(f); - printf("Your public key has been saved in %s\n", buf); + if (!quiet) + printf("Your public key has been saved in %s\n", buf); exit(0); } diff --git a/usr.bin/ssh/ssh-keygen/Makefile b/usr.bin/ssh/ssh-keygen/Makefile index 9373a670545..c2fcf2451ae 100644 --- a/usr.bin/ssh/ssh-keygen/Makefile +++ b/usr.bin/ssh/ssh-keygen/Makefile @@ -4,16 +4,16 @@ PROG= ssh-keygen BINOWN= root BINMODE=555 BINDIR= /usr/bin -LDADD= -lkrb -lcrypto -ldes -lgmp -lutil -lz +LDADD= -lkrb -lcrypto -ldes -lutil -lz MAN= ssh-keygen.1 -SRCS= ssh-keygen.c log-client.c readpass.c rsa.c randoms.c ssh_md5.c \ +SRCS= ssh-keygen.c log-client.c readpass.c rsa.c ssh_md5.c \ buffer.c xmalloc.c authfile.c mpaux.c bufaux.c \ - crc32.c rsaglue.c match.c minfd.c cipher.c compress.c + crc32.c match.c minfd.c cipher.c compress.c gen_minfd: gen_minfd.c minfd.o: minfd.h minfd.h: gen_minfd ./gen_minfd $(USER_SHELLS) > minfd.h -.include<bsd.prog.mk> +.include <bsd.prog.mk> diff --git a/usr.bin/ssh/ssh.c b/usr.bin/ssh/ssh.c index f67a4f74197..039d92c08c0 100644 --- a/usr.bin/ssh/ssh.c +++ b/usr.bin/ssh/ssh.c @@ -13,13 +13,14 @@ Ssh client program. This program can be used to log into a remote machine. The software supports strong authentication, encryption, and forwarding of X11, TCP/IP, and authentication connections. +Modified to work with SSL by Niels Provos <provos@citi.umich.edu> in Canada. + */ #include "includes.h" -RCSID("$Id: ssh.c,v 1.1 1999/09/26 20:53:38 deraadt Exp $"); +RCSID("$Id: ssh.c,v 1.2 1999/09/28 04:45:37 provos Exp $"); #include "xmalloc.h" -#include "randoms.h" #include "ssh.h" #include "packet.h" #include "buffer.h" @@ -27,11 +28,6 @@ RCSID("$Id: ssh.c,v 1.1 1999/09/26 20:53:38 deraadt Exp $"); #include "readconf.h" #include "uidswap.h" -/* Random number generator state. This is initialized in ssh_login, and - left initialized. This is used both by the packet module and by various - other functions. */ -RandomState random_state; - /* Flag indicating whether debug mode is on. This can be set on the command line. */ int debug_flag = 0; @@ -77,12 +73,13 @@ char *av0; int host_private_key_loaded = 0; /* Host private key. */ -RSAPrivateKey host_private_key; +RSA *host_private_key = NULL; /* Prints a help message to the user. This function never returns. */ -void usage() +void +usage() { int i; @@ -127,7 +124,8 @@ void usage() /* Connects to the given host using rsh (or prints an error message and exits if rsh is not available). This function never returns. */ -void rsh_connect(char *host, char *user, Buffer *command) +void +rsh_connect(char *host, char *user, Buffer *command) { #ifdef RSH_PATH char *args[10]; @@ -169,7 +167,8 @@ void rsh_connect(char *host, char *user, Buffer *command) /* Main program for the ssh client. */ -int main(int ac, char **av) +int +main(int ac, char **av) { int i, opt, optind, type, exit_status, ok, fwd_port, fwd_host_port, authfd; char *optarg, *cp, buf[256]; @@ -223,9 +222,6 @@ int main(int ac, char **av) SOCKSinit(av0); #endif /* SOCKS */ - /* Set RSA (actually gmp) memory allocation functions. */ - rsa_set_mp_memory_allocation(); - /* Initialize option structure to indicate that no values have been set. */ initialize_options(&options); @@ -320,13 +316,7 @@ int main(int ac, char **av) debug_flag = 1; fprintf(stderr, "SSH Version %s, protocol version %d.%d.\n", SSH_VERSION, PROTOCOL_MAJOR, PROTOCOL_MINOR); -#ifdef RSAREF - fprintf(stderr, "Compiled with RSAREF.\n"); -#elif defined(DO_SSL) fprintf(stderr, "Compiled with SSL.\n"); -#else /* RSAREF */ - fprintf(stderr, "Standard version. Does not use RSAREF.\n"); -#endif /* RSAREF */ break; case 'q': @@ -538,13 +528,11 @@ int main(int ac, char **av) restore_uid(); /* Open a connection to the remote host. This needs root privileges if - rhosts_authentication is true. Note that the random_state is not - yet used by this call, although a pointer to it is stored, and thus it - need not be initialized. */ + rhosts_authentication is true. */ ok = ssh_connect(host, options.port, options.connection_attempts, !options.rhosts_authentication && !options.rhosts_rsa_authentication, - original_real_uid, options.proxy_command, &random_state); + original_real_uid, options.proxy_command); /* If we successfully made the connection, load the host private key in case we will need it later for combined rsa-rhosts authentication. @@ -552,7 +540,8 @@ int main(int ac, char **av) is only readable by root. */ if (ok) { - if (load_private_key(HOST_KEY_FILE, "", &host_private_key, NULL)) + host_private_key = RSA_new(); + if (load_private_key(HOST_KEY_FILE, "", host_private_key, NULL)) host_private_key_loaded = 1; } @@ -599,14 +588,13 @@ int main(int ac, char **av) options.user_hostfile = tilde_expand_filename(options.user_hostfile, original_real_uid); - /* Log into the remote system. This never returns if the login fails. - Note: this initializes the random state, and leaves it initialized. */ - ssh_login(&random_state, host_private_key_loaded, &host_private_key, + /* Log into the remote system. This never returns if the login fails. */ + ssh_login(host_private_key_loaded, host_private_key, host, &options, original_real_uid); /* We no longer need the host private key. Clear it now. */ if (host_private_key_loaded) - rsa_clear_private_key(&host_private_key); + RSA_free(host_private_key); /* Destroys contents safely */ /* Close connection cleanly after attack. */ cipher_attack_detected = packet_disconnect; @@ -713,15 +701,21 @@ int main(int ac, char **av) otherwise for the local connection. */ if (!got_data) { + u_int32_t rand; + strcpy(proto, "MIT-MAGIC-COOKIE-1"); - for (i = 0; i < 16; i++) - sprintf(data + 2 * i, "%02x", random_get_byte(&random_state)); + for (i = 0; i < 16; i++) { + if (i % 4 == 0) + rand = arc4random(); + sprintf(data + 2 * i, "%02x", rand & 0xff); + rand >>= 8; + } } /* Got local authentication reasonable information. Request forwarding with authentication spoofing. */ debug("Requesting X11 forwarding with authentication spoofing."); - x11_request_forwarding_with_spoofing(&random_state, proto, data); + x11_request_forwarding_with_spoofing(proto, data); /* Read response from the server. */ type = packet_read(&plen); diff --git a/usr.bin/ssh/ssh.h b/usr.bin/ssh/ssh.h index b2046f91574..8c62180e4a4 100644 --- a/usr.bin/ssh/ssh.h +++ b/usr.bin/ssh/ssh.h @@ -13,14 +13,12 @@ Generic header file for ssh. */ -/* RCSID("$Id: ssh.h,v 1.2 1999/09/26 21:47:55 deraadt Exp $"); */ +/* RCSID("$Id: ssh.h,v 1.3 1999/09/28 04:45:37 provos Exp $"); */ #ifndef SSH_H #define SSH_H -#include <gmp.h> #include "rsa.h" -#include "randoms.h" #include "cipher.h" /* The default cipher used if IDEA is not supported by the remote host. @@ -181,12 +179,12 @@ only by root, whereas ssh_config should be world-readable. */ #define SSH_MSG_NONE 0 /* no message */ #define SSH_MSG_DISCONNECT 1 /* cause (string) */ #define SSH_SMSG_PUBLIC_KEY 2 /* ck,msk,srvk,hostk */ -#define SSH_CMSG_SESSION_KEY 3 /* key (MP_INT) */ +#define SSH_CMSG_SESSION_KEY 3 /* key (BIGNUM) */ #define SSH_CMSG_USER 4 /* user (string) */ #define SSH_CMSG_AUTH_RHOSTS 5 /* user (string) */ -#define SSH_CMSG_AUTH_RSA 6 /* modulus (MP_INT) */ -#define SSH_SMSG_AUTH_RSA_CHALLENGE 7 /* int (MP_INT) */ -#define SSH_CMSG_AUTH_RSA_RESPONSE 8 /* int (MP_INT) */ +#define SSH_CMSG_AUTH_RSA 6 /* modulus (BIGNUM) */ +#define SSH_SMSG_AUTH_RSA_CHALLENGE 7 /* int (BIGNUM) */ +#define SSH_CMSG_AUTH_RSA_RESPONSE 8 /* int (BIGNUM) */ #define SSH_CMSG_AUTH_PASSWORD 9 /* pass (string) */ #define SSH_CMSG_REQUEST_PTY 10 /* TERM, tty modes */ #define SSH_CMSG_WINDOW_SIZE 11 /* row,col,xpix,ypix */ @@ -256,7 +254,7 @@ void record_logout(int pid, const char *ttyname); connection. */ int ssh_connect(const char *host, int port, int connection_attempts, int anonymous, uid_t original_real_uid, - const char *proxy_command, RandomState *random_state); + const char *proxy_command); /* Starts a dialog with the server, and authenticates the current user on the server. This does not need any extra privileges. The basic connection @@ -264,7 +262,7 @@ int ssh_connect(const char *host, int port, int connection_attempts, If login fails, this function prints an error and never returns. This initializes the random state, and leaves it initialized (it will also have references from the packet module). */ -void ssh_login(RandomState *state, int host_key_valid, RSAPrivateKey *host_key, +void ssh_login(int host_key_valid, RSA *host_key, const char *host, Options *options, uid_t original_real_uid); /*------------ Definitions for various authentication methods. -------*/ @@ -278,10 +276,9 @@ int auth_rhosts(struct passwd *pw, const char *client_user, /* 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(RandomState *state, - struct passwd *pw, const char *client_user, - unsigned int bits, MP_INT *client_host_key_e, - MP_INT *client_host_key_n, int ignore_rhosts, +int auth_rhosts_rsa(struct passwd *pw, const char *client_user, + unsigned int bits, BIGNUM *client_host_key_e, + BIGNUM *client_host_key_n, int ignore_rhosts, int strict_modes); /* Tries to authenticate the user using password. Returns true if @@ -291,11 +288,11 @@ int auth_password(const char *server_user, const char *password); /* Performs the RSA authentication dialog with the client. This returns 0 if the client could not be authenticated, and 1 if authentication was successful. This may exit if there is a serious protocol violation. */ -int auth_rsa(struct passwd *pw, MP_INT *client_n, RandomState *state); +int auth_rsa(struct passwd *pw, BIGNUM *client_n); /* 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, MP_INT *e, MP_INT *n); +int auth_rsa_read_key(char **cpp, unsigned int *bitsp, BIGNUM *e, BIGNUM *n); /* Returns the name of the machine at the other end of the socket. The returned string should be freed by the caller. */ @@ -329,18 +326,17 @@ int match_hostname(const char *host, const char *pattern, unsigned int len); typedef enum { HOST_OK, HOST_NEW, HOST_CHANGED } HostStatus; HostStatus check_host_in_hostfile(const char *filename, const char *host, unsigned int bits, - MP_INT *e, MP_INT *n); + BIGNUM *e, BIGNUM *n); /* 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, - unsigned int bits, MP_INT *e, MP_INT *n); + unsigned int bits, BIGNUM *e, BIGNUM *n); /* Performs the RSA authentication challenge-response dialog with the client, and returns true (non-zero) if the client gave the correct answer to our challenge; returns zero if the client gives a wrong answer. */ -int auth_rsa_challenge_dialog(RandomState *state, unsigned int bits, - MP_INT *e, MP_INT *n); +int auth_rsa_challenge_dialog(unsigned int bits, BIGNUM *e, BIGNUM *n); /* Reads a passphrase from /dev/tty with echo turned off. Returns the passphrase (allocated with xmalloc). Exits if EOF is encountered. @@ -352,14 +348,13 @@ char *read_passphrase(const char *prompt, int from_stdin); will precede the key to provide identification of the key without needing a passphrase. */ int save_private_key(const char *filename, const char *passphrase, - RSAPrivateKey *private_key, const char *comment, - RandomState *state); + RSA *private_key, const char *comment); /* Loads the public part of the key file (public key and comment). Returns 0 if an error occurred; zero if the public key was successfully read. The comment of the key is returned in comment_return if it is non-NULL; the caller must free the value with xfree. */ -int load_public_key(const char *filename, RSAPublicKey *pub, +int load_public_key(const char *filename, RSA *pub, char **comment_return); /* Loads the private key from the file. Returns 0 if an error is encountered @@ -368,7 +363,7 @@ int load_public_key(const char *filename, RSAPublicKey *pub, in comment_return if it is non-NULL; the caller must free the value with xfree. */ int load_private_key(const char *filename, const char *passphrase, - RSAPrivateKey *private_key, char **comment_return); + RSA *private_key, char **comment_return); /*------------ Definitions for logging. -----------------------*/ @@ -535,8 +530,7 @@ void x11_request_forwarding(void); /* Requests forwarding for X11 connections, with authentication spoofing. This should be called in the client only. */ -void x11_request_forwarding_with_spoofing(RandomState *state, - const char *proto, const char *data); +void x11_request_forwarding_with_spoofing(const char *proto, const char *data); /* Local Xauthority file (server only). */ extern char *xauthfile; diff --git a/usr.bin/ssh/ssh/Makefile b/usr.bin/ssh/ssh/Makefile index 341527c1507..2f02fa1d4d8 100644 --- a/usr.bin/ssh/ssh/Makefile +++ b/usr.bin/ssh/ssh/Makefile @@ -4,15 +4,15 @@ PROG= ssh BINOWN= root BINMODE=4555 BINDIR= /usr/bin -LDADD= -lkrb -lcrypto -ldes -lgmp -lutil -lz +LDADD= -lkrb -lcrypto -ldes -lutil -lz MAN= ssh.1 LINKS= ${BINDIR}/ssh ${BINDIR}/slogin MLINKS= ssh.1 slogin.1 SRCS= ssh.c sshconnect.c log-client.c readconf.c hostfile.c readpass.c \ - tildexpand.c uidswap.c clientloop.c canohost.c rsa.c randoms.c \ + tildexpand.c uidswap.c clientloop.c canohost.c rsa.c \ ssh_md5.c buffer.c packet.c xmalloc.c ttymodes.c channels.c bufaux.c \ - authfd.c authfile.c crc32.c rsaglue.c match.c mpaux.c minfd.c cipher.c \ + authfd.c authfile.c crc32.c match.c mpaux.c minfd.c cipher.c \ compress.c gen_minfd: gen_minfd.c @@ -20,4 +20,4 @@ minfd.o: minfd.h minfd.h: gen_minfd ./gen_minfd $(USER_SHELLS) > minfd.h -.include<bsd.prog.mk> +.include <bsd.prog.mk> diff --git a/usr.bin/ssh/ssh_md5.h b/usr.bin/ssh/ssh_md5.h index 999fea945a2..e7380ce740b 100644 --- a/usr.bin/ssh/ssh_md5.h +++ b/usr.bin/ssh/ssh_md5.h @@ -19,9 +19,4 @@ void MD5Final(unsigned char digest[16], struct MD5Context *context); #define MD5Transform ssh_MD5Transform void MD5Transform(uint32 buf[4], const unsigned char in[64]); -/* - * This is needed to make RSAREF happy on some MS-DOS compilers. - */ -typedef struct MD5Context MD5_CTX; - #endif /* !MD5_H */ diff --git a/usr.bin/ssh/sshconnect.c b/usr.bin/ssh/sshconnect.c index 2e955aad7c6..a37c8b14978 100644 --- a/usr.bin/ssh/sshconnect.c +++ b/usr.bin/ssh/sshconnect.c @@ -15,11 +15,10 @@ login (authentication) dialog. */ #include "includes.h" -RCSID("$Id: sshconnect.c,v 1.2 1999/09/26 22:01:24 deraadt Exp $"); +RCSID("$Id: sshconnect.c,v 1.3 1999/09/28 04:45:37 provos Exp $"); -#include <gmp.h> +#include <ssl/bn.h> #include "xmalloc.h" -#include "randoms.h" #include "rsa.h" #include "ssh.h" #include "packet.h" @@ -47,8 +46,9 @@ unsigned char session_id[16]; /* Connect to the given ssh server using a proxy command. */ -int ssh_proxy_connect(const char *host, int port, uid_t original_real_uid, - const char *proxy_command, RandomState *random_state) +int +ssh_proxy_connect(const char *host, int port, uid_t original_real_uid, + const char *proxy_command) { Buffer command; const char *cp; @@ -143,7 +143,7 @@ int ssh_proxy_connect(const char *host, int port, uid_t original_real_uid, buffer_free(&command); /* Set the connection file descriptors. */ - packet_set_connection(pout[0], pin[1], random_state); + packet_set_connection(pout[0], pin[1]); return 1; } @@ -190,7 +190,7 @@ int ssh_create_socket(uid_t original_real_uid, int privileged) int ssh_connect(const char *host, int port, int connection_attempts, int anonymous, uid_t original_real_uid, - const char *proxy_command, RandomState *random_state) + const char *proxy_command) { int sock = -1, attempt, i; int on = 1; @@ -216,8 +216,7 @@ int ssh_connect(const char *host, int port, int connection_attempts, /* If a proxy command is given, connect using it. */ if (proxy_command != NULL) - return ssh_proxy_connect(host, port, original_real_uid, proxy_command, - random_state); + return ssh_proxy_connect(host, port, original_real_uid, proxy_command); /* No proxy command. */ @@ -344,7 +343,7 @@ int ssh_connect(const char *host, int port, int connection_attempts, #endif /* SO_LINGER */ /* Set the connection. */ - packet_set_connection(sock, sock, random_state); + packet_set_connection(sock, sock); return 1; } @@ -352,28 +351,29 @@ int ssh_connect(const char *host, int port, int connection_attempts, /* Checks if the user has an authentication agent, and if so, tries to authenticate using the agent. */ -int try_agent_authentication() +int +try_agent_authentication() { int status, type, bits; - MP_INT e, n, challenge; char *comment; AuthenticationConnection *auth; unsigned char response[16]; unsigned int i; + BIGNUM *e, *n, *challenge; /* Get connection to the agent. */ auth = ssh_get_authentication_connection(); if (!auth) return 0; - mpz_init(&e); - mpz_init(&n); - mpz_init(&challenge); + e = BN_new(); + n = BN_new(); + challenge = BN_new(); /* Loop through identities served by the agent. */ - for (status = ssh_get_first_identity(auth, &bits, &e, &n, &comment); + for (status = ssh_get_first_identity(auth, &bits, e, n, &comment); status; - status = ssh_get_next_identity(auth, &bits, &e, &n, &comment)) + status = ssh_get_next_identity(auth, &bits, e, n, &comment)) { int plen, clen; @@ -383,7 +383,7 @@ int try_agent_authentication() /* Tell the server that we are willing to authenticate using this key. */ packet_start(SSH_CMSG_AUTH_RSA); - packet_put_mp_int(&n); + packet_put_bignum(n); packet_send(); packet_write_wait(); @@ -403,14 +403,14 @@ int try_agent_authentication() packet_disconnect("Protocol error during RSA authentication: %d", type); - packet_get_mp_int(&challenge, &clen); + packet_get_bignum(challenge, &clen); packet_integrity_check(plen, clen, type); debug("Received RSA challenge from server."); /* Ask the agent to decrypt the challenge. */ - if (!ssh_decrypt_challenge(auth, bits, &e, &n, &challenge, + if (!ssh_decrypt_challenge(auth, bits, e, n, challenge, session_id, 1, response)) { /* The agent failed to authenticate this identifier although it @@ -435,9 +435,9 @@ int try_agent_authentication() if (type == SSH_SMSG_SUCCESS) { debug("RSA authentication accepted by server."); - mpz_clear(&e); - mpz_clear(&n); - mpz_clear(&challenge); + BN_clear_free(e); + BN_clear_free(n); + BN_clear_free(challenge); return 1; } @@ -447,9 +447,9 @@ int try_agent_authentication() type); } - mpz_clear(&e); - mpz_clear(&n); - mpz_clear(&challenge); + BN_clear_free(e); + BN_clear_free(n); + BN_clear_free(challenge); debug("RSA authentication using agent refused."); return 0; @@ -458,18 +458,22 @@ int try_agent_authentication() /* Computes the proper response to a RSA challenge, and sends the response to the server. */ -void respond_to_rsa_challenge(MP_INT *challenge, RSAPrivateKey *prv) +void +respond_to_rsa_challenge(BIGNUM *challenge, RSA *prv) { unsigned char buf[32], response[16]; struct MD5Context md; - int i; + int i, len; /* Decrypt the challenge using the private key. */ rsa_private_decrypt(challenge, challenge, prv); /* Compute the response. */ /* The response is MD5 of decrypted challenge plus session id. */ - mp_linearize_msb_first(buf, 32, challenge); + len = BN_num_bytes(challenge); + assert(len <= sizeof(buf) && len); + memset(buf, 0, sizeof(buf)); + BN_bn2bin(challenge, buf + sizeof(buf) - len); MD5Init(&md); MD5Update(&md, buf, 32); MD5Update(&md, session_id, 16); @@ -492,30 +496,34 @@ void respond_to_rsa_challenge(MP_INT *challenge, RSAPrivateKey *prv) /* Checks if the user has authentication file, and if so, tries to authenticate the user using it. */ -int try_rsa_authentication(struct passwd *pw, const char *authfile, - int may_ask_passphrase) +int +try_rsa_authentication(struct passwd *pw, const char *authfile, + int may_ask_passphrase) { - MP_INT challenge; - RSAPrivateKey private_key; - RSAPublicKey public_key; + BIGNUM *challenge; + RSA *private_key; + RSA *public_key; char *passphrase, *comment; int type, i; int plen, clen; /* Try to load identification for the authentication key. */ - if (!load_public_key(authfile, &public_key, &comment)) + public_key = RSA_new(); + if (!load_public_key(authfile, public_key, &comment)) { + RSA_free(public_key); return 0; /* Could not load it. Fail. */ + } debug("Trying RSA authentication with key '%.100s'", comment); /* Tell the server that we are willing to authenticate using this key. */ packet_start(SSH_CMSG_AUTH_RSA); - packet_put_mp_int(&public_key.n); + packet_put_bignum(public_key->n); packet_send(); packet_write_wait(); /* We no longer need the public key. */ - rsa_clear_public_key(&public_key); + RSA_free(public_key); /* Wait for server's response. */ type = packet_read(&plen); @@ -534,16 +542,17 @@ int try_rsa_authentication(struct passwd *pw, const char *authfile, packet_disconnect("Protocol error during RSA authentication: %d", type); /* Get the challenge from the packet. */ - mpz_init(&challenge); - packet_get_mp_int(&challenge, &clen); + challenge = BN_new(); + packet_get_bignum(challenge, &clen); packet_integrity_check(plen, clen, type); debug("Received RSA challenge from server."); + private_key = RSA_new(); /* Load the private key. Try first with empty passphrase; if it fails, ask for a passphrase. */ - if (!load_private_key(authfile, "", &private_key, NULL)) + if (!load_private_key(authfile, "", private_key, NULL)) { char buf[300]; /* Request passphrase from the user. We read from /dev/tty to make @@ -561,7 +570,7 @@ int try_rsa_authentication(struct passwd *pw, const char *authfile, } /* Load the authentication file using the pasphrase. */ - if (!load_private_key(authfile, passphrase, &private_key, NULL)) + if (!load_private_key(authfile, passphrase, private_key, NULL)) { memset(passphrase, 0, strlen(passphrase)); xfree(passphrase); @@ -589,13 +598,13 @@ int try_rsa_authentication(struct passwd *pw, const char *authfile, xfree(comment); /* Compute and send a response to the challenge. */ - respond_to_rsa_challenge(&challenge, &private_key); + respond_to_rsa_challenge(challenge, private_key); /* Destroy the private key. */ - rsa_clear_private_key(&private_key); + RSA_free(private_key); /* We no longer need the challenge. */ - mpz_clear(&challenge); + BN_clear_free(challenge); /* Wait for response from the server. */ type = packet_read(&plen); @@ -613,11 +622,11 @@ int try_rsa_authentication(struct passwd *pw, const char *authfile, /* Tries to authenticate the user using combined rhosts or /etc/hosts.equiv authentication and RSA host authentication. */ -int try_rhosts_rsa_authentication(const char *local_user, - RSAPrivateKey *host_key) +int +try_rhosts_rsa_authentication(const char *local_user, RSA *host_key) { int type; - MP_INT challenge; + BIGNUM *challenge; int plen, clen; debug("Trying rhosts or /etc/hosts.equiv with RSA host authentication."); @@ -625,9 +634,9 @@ int try_rhosts_rsa_authentication(const char *local_user, /* Tell the server that we are willing to authenticate using this key. */ packet_start(SSH_CMSG_AUTH_RHOSTS_RSA); packet_put_string(local_user, strlen(local_user)); - packet_put_int(host_key->bits); - packet_put_mp_int(&host_key->e); - packet_put_mp_int(&host_key->n); + packet_put_int(BN_num_bits(host_key->n)); + packet_put_bignum(host_key->e); + packet_put_bignum(host_key->n); packet_send(); packet_write_wait(); @@ -647,18 +656,18 @@ int try_rhosts_rsa_authentication(const char *local_user, packet_disconnect("Protocol error during RSA authentication: %d", type); /* Get the challenge from the packet. */ - mpz_init(&challenge); - packet_get_mp_int(&challenge, &clen); + challenge = BN_new(); + packet_get_bignum(challenge, &clen); packet_integrity_check(plen, clen, type); debug("Received RSA challenge for host key from server."); /* Compute a response to the challenge. */ - respond_to_rsa_challenge(&challenge, host_key); + respond_to_rsa_challenge(challenge, host_key); /* We no longer need the challenge. */ - mpz_clear(&challenge); + BN_clear_free(challenge); /* Wait for response from the server. */ type = packet_read(&plen); @@ -1007,8 +1016,8 @@ int read_yes_or_no(const char *prompt, int defval) If login fails, this function prints an error and never returns. This function does not require super-user privileges. */ -void ssh_login(RandomState *state, int host_key_valid, - RSAPrivateKey *own_host_key, +void ssh_login(int host_key_valid, + RSA *own_host_key, const char *orighost, Options *options, uid_t original_real_uid) { @@ -1016,9 +1025,9 @@ void ssh_login(RandomState *state, int host_key_valid, char buf[1024]; char *password; struct passwd *pw; - MP_INT key; - RSAPublicKey host_key; - RSAPublicKey public_key; + BIGNUM *key; + RSA *host_key; + RSA *public_key; unsigned char session_key[SSH_SESSION_KEY_LENGTH]; const char *server_user, *local_user; char *cp, *host; @@ -1027,6 +1036,7 @@ void ssh_login(RandomState *state, int host_key_valid, unsigned int supported_ciphers, supported_authentications, protocol_flags; HostStatus host_status; int payload_len, clen, sum_len = 0; + u_int32_t rand; /* Convert the user-supplied hostname into all lowercase. */ host = xstrdup(orighost); @@ -1058,21 +1068,23 @@ void ssh_login(RandomState *state, int host_key_valid, check_bytes[i] = packet_get_char(); /* Get the public key. */ - public_key.bits = packet_get_int(); - mpz_init(&public_key.e); - packet_get_mp_int(&public_key.e, &clen); + public_key = RSA_new(); + packet_get_int(); /* bits */ + public_key->e = BN_new(); + packet_get_bignum(public_key->e, &clen); sum_len += clen; - mpz_init(&public_key.n); - packet_get_mp_int(&public_key.n, &clen); + public_key->n = BN_new(); + packet_get_bignum(public_key->n, &clen); sum_len += clen; /* Get the host key. */ - host_key.bits = packet_get_int(); - mpz_init(&host_key.e); - packet_get_mp_int(&host_key.e, &clen); + host_key = RSA_new(); + packet_get_int(); /* bits */ + host_key->e = BN_new(); + packet_get_bignum(host_key->e, &clen); sum_len += clen; - mpz_init(&host_key.n); - packet_get_mp_int(&host_key.n, &clen); + host_key->n = BN_new(); + packet_get_bignum(host_key->n, &clen); sum_len += clen; /* Get protocol flags. */ @@ -1086,25 +1098,26 @@ void ssh_login(RandomState *state, int host_key_valid, supported_authentications = packet_get_int(); debug("Received server public key (%d bits) and host key (%d bits).", - public_key.bits, host_key.bits); + BN_num_bits(public_key->n), BN_num_bits(host_key->n)); packet_integrity_check(payload_len, 8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4, SSH_SMSG_PUBLIC_KEY); /* Compute the session id. */ - compute_session_id(session_id, check_bytes, host_key.bits, &host_key.n, - public_key.bits, &public_key.n); + compute_session_id(session_id, check_bytes, + BN_num_bits(host_key->n), host_key->n, + BN_num_bits(public_key->n), public_key->n); /* Check if the host key is present in the user\'s list of known hosts or in the systemwide list. */ host_status = check_host_in_hostfile(options->user_hostfile, - host, host_key.bits, - &host_key.e, &host_key.n); + host, BN_num_bits(host_key->n), + host_key->e, host_key->n); if (host_status == HOST_NEW) host_status = check_host_in_hostfile(options->system_hostfile, host, - host_key.bits, &host_key.e, - &host_key.n); + BN_num_bits(host_key->n), + host_key->e, host_key->n); /* Force accepting of the host key for localhost and 127.0.0.1. The problem is that if the home directory is NFS-mounted to multiple @@ -1145,8 +1158,9 @@ void ssh_login(RandomState *state, int host_key_valid, } /* If not in strict mode, add the key automatically to the local known_hosts file. */ - if (!add_host_to_hostfile(options->user_hostfile, host, host_key.bits, - &host_key.e, &host_key.n)) + if (!add_host_to_hostfile(options->user_hostfile, host, + BN_num_bits(host_key->n), + host_key->e, host_key->n)) log("Failed to add the host to the list of known hosts (%.500s).", options->user_hostfile); else @@ -1181,68 +1195,63 @@ void ssh_login(RandomState *state, int host_key_valid, } /* Generate a session key. */ - - /* Initialize the random number generator. */ - sprintf(buf, "%.500s/%.200s", pw->pw_dir, SSH_CLIENT_SEEDFILE); - if (stat(buf, &st) < 0) - log("Creating random seed file ~/%.900s. This may take a while.", - SSH_CLIENT_SEEDFILE); - else - debug("Initializing random; seed file %.900s", buf); - random_initialize(state, buf); + arc4random_stir(); /* Generate an encryption key for the session. The key is a 256 bit random number, interpreted as a 32-byte key, with the least significant 8 bits being the first byte of the key. */ - for (i = 0; i < 32; i++) - session_key[i] = random_get_byte(state); - - /* Save the new random state. */ - random_save(state, buf); - random_stir(state); /* This is supposed to be irreversible. */ + for (i = 0; i < 32; i++) { + if (i % 4 == 0) + rand = arc4random(); + session_key[i] = rand & 0xff; + rand >>= 8; + } /* According to the protocol spec, the first byte of the session key is the highest byte of the integer. The session key is xored with the first 16 bytes of the session id. */ - mpz_init_set_ui(&key, 0); + key = BN_new(); + BN_set_word(key, 0); for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) { - mpz_mul_2exp(&key, &key, 8); + BN_lshift(key, key, 8); if (i < 16) - mpz_add_ui(&key, &key, session_key[i] ^ session_id[i]); + BN_add_word(key, session_key[i] ^ session_id[i]); else - mpz_add_ui(&key, &key, session_key[i]); + BN_add_word(key, session_key[i]); } /* Encrypt the integer using the public key and host key of the server (key with smaller modulus first). */ - if (mpz_cmp(&public_key.n, &host_key.n) < 0) + if (BN_cmp(public_key->n, host_key->n) < 0) { /* Public key has smaller modulus. */ - assert(host_key.bits >= public_key.bits + SSH_KEY_BITS_RESERVED); + assert(BN_num_bits(host_key->n) >= + BN_num_bits(public_key->n) + SSH_KEY_BITS_RESERVED); - rsa_public_encrypt(&key, &key, &public_key, state); - rsa_public_encrypt(&key, &key, &host_key, state); + rsa_public_encrypt(key, key, public_key); + rsa_public_encrypt(key, key, host_key); } else { /* Host key has smaller modulus (or they are equal). */ - assert(public_key.bits >= host_key.bits + SSH_KEY_BITS_RESERVED); + assert(BN_num_bits(public_key->n) >= + BN_num_bits(host_key->n) + SSH_KEY_BITS_RESERVED); - rsa_public_encrypt(&key, &key, &host_key, state); - rsa_public_encrypt(&key, &key, &public_key, state); + rsa_public_encrypt(key, key, host_key); + rsa_public_encrypt(key, key, public_key); } - if (options->cipher == SSH_CIPHER_NOT_SET) + if (options->cipher == SSH_CIPHER_NOT_SET) { if (cipher_mask() & supported_ciphers & (1 << ssh_cipher_default)) options->cipher = ssh_cipher_default; - else - { - debug("Cipher %d not supported, using %.100s instead.", - cipher_name(ssh_cipher_default), - cipher_name(SSH_FALLBACK_CIPHER)); - options->cipher = SSH_FALLBACK_CIPHER; - } + else { + debug("Cipher %d not supported, using %.100s instead.", + cipher_name(ssh_cipher_default), + cipher_name(SSH_FALLBACK_CIPHER)); + options->cipher = SSH_FALLBACK_CIPHER; + } + } /* Check that the selected cipher is supported. */ if (!(supported_ciphers & (1 << options->cipher))) @@ -1260,7 +1269,7 @@ void ssh_login(RandomState *state, int host_key_valid, packet_put_char(check_bytes[i]); /* Send the encrypted encryption key. */ - packet_put_mp_int(&key); + packet_put_bignum(key); /* Send protocol flags. */ packet_put_int(SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN); @@ -1271,9 +1280,9 @@ void ssh_login(RandomState *state, int host_key_valid, /* Destroy the session key integer and the public keys since we no longer need them. */ - mpz_clear(&key); - rsa_clear_public_key(&public_key); - rsa_clear_public_key(&host_key); + BN_clear_free(key); + RSA_free(public_key); + RSA_free(host_key); debug("Sent encrypted session key."); diff --git a/usr.bin/ssh/sshd.c b/usr.bin/ssh/sshd.c index bdf86bb0e05..326aab63d49 100644 --- a/usr.bin/ssh/sshd.c +++ b/usr.bin/ssh/sshd.c @@ -18,9 +18,8 @@ agent connections. */ #include "includes.h" -RCSID("$Id: sshd.c,v 1.1 1999/09/26 20:53:38 deraadt Exp $"); +RCSID("$Id: sshd.c,v 1.2 1999/09/28 04:45:37 provos Exp $"); -#include <gmp.h> #include "xmalloc.h" #include "rsa.h" #include "ssh.h" @@ -119,19 +118,16 @@ unsigned char session_id[16]; /* Any really sensitive data in the application is contained in this structure. The idea is that this structure could be locked into memory so that the pages do not get written into swap. However, there are some problems. - The private key contains MP_INTs, and we do not (in principle) have + The private key contains BIGNUMs, and we do not (in principle) have access to the internals of them, and locking just the structure is not very useful. Currently, memory locking is not implemented. */ struct { - /* Random number generator. */ - RandomState random_state; - /* Private part of server key. */ - RSAPrivateKey private_key; + RSA *private_key; /* Private part of host key. */ - RSAPrivateKey host_key; + RSA *host_key; } sensitive_data; /* Flag indicating whether the current session key has been used. This flag @@ -143,7 +139,7 @@ int received_sighup = 0; /* Public side of the server key. This value is regenerated regularly with the private key. */ -RSAPublicKey public_key; +RSA *public_key; /* Prototypes for various functions defined later in this file. */ void do_connection(int privileged_port); @@ -226,11 +222,18 @@ RETSIGTYPE key_regeneration_alarm(int sig) { /* This should really be done in the background. */ log("Generating new %d bit RSA key.", options.server_key_bits); - random_acquire_light_environmental_noise(&sensitive_data.random_state); - rsa_generate_key(&sensitive_data.private_key, &public_key, - &sensitive_data.random_state, options.server_key_bits); - random_stir(&sensitive_data.random_state); - random_save(&sensitive_data.random_state, options.random_seed_file); + + if (sensitive_data.private_key != NULL) + RSA_free(sensitive_data.private_key); + sensitive_data.private_key = RSA_new(); + + if (public_key != NULL) + RSA_free(public_key); + public_key = RSA_new(); + + rsa_generate_key(sensitive_data.private_key, public_key, + options.server_key_bits); + arc4random_stir(); key_used = 0; log("RSA key generation complete."); } @@ -242,7 +245,8 @@ RETSIGTYPE key_regeneration_alarm(int sig) /* Main program for the daemon. */ -int main(int ac, char **av) +int +main(int ac, char **av) { extern char *optarg; extern int optind; @@ -351,9 +355,10 @@ int main(int ac, char **av) debug("sshd version %.100s", SSH_VERSION); + sensitive_data.host_key = RSA_new(); /* Load the host key. It must have empty passphrase. */ if (!load_private_key(options.host_key_file, "", - &sensitive_data.host_key, &comment)) + sensitive_data.host_key, &comment)) { if (debug_flag) fprintf(stderr, "Could not load host key: %s: %s\n", @@ -415,29 +420,23 @@ int main(int ac, char **av) /* Check that server and host key lengths differ sufficiently. This is necessary to make double encryption work with rsaref. Oh, I hate - software patents. */ + software patents. I dont know if this can go? Niels */ if (options.server_key_bits > - sensitive_data.host_key.bits - SSH_KEY_BITS_RESERVED && + BN_num_bits(sensitive_data.host_key->n) - SSH_KEY_BITS_RESERVED && options.server_key_bits < - sensitive_data.host_key.bits + SSH_KEY_BITS_RESERVED) + BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) { options.server_key_bits = - sensitive_data.host_key.bits + SSH_KEY_BITS_RESERVED; + BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED; debug("Forcing server key to %d bits to make it differ from host key.", options.server_key_bits); } - /* Initialize memory allocation so that any freed MP_INT data will be - zeroed. */ - rsa_set_mp_memory_allocation(); - /* Do not display messages to stdout in RSA code. */ rsa_set_verbose(0); /* Initialize the random number generator. */ - debug("Initializing random number generator; seed file %.200s", - options.random_seed_file); - random_initialize(&sensitive_data.random_state, options.random_seed_file); + arc4random_stir(); /* Chdir to the root directory so that the current disk can be unmounted if desired. */ @@ -459,13 +458,13 @@ int main(int ac, char **av) be one of those. */ debug("inetd sockets after dupping: %d, %d", sock_in, sock_out); + public_key = RSA_new(); + sensitive_data.private_key = RSA_new(); /* Generate an rsa key. */ log("Generating %d bit RSA key.", options.server_key_bits); - rsa_generate_key(&sensitive_data.private_key, &public_key, - &sensitive_data.random_state, - options.server_key_bits); - random_stir(&sensitive_data.random_state); - random_save(&sensitive_data.random_state, options.random_seed_file); + rsa_generate_key(sensitive_data.private_key, public_key, + options.server_key_bits); + arc4random_stir(); log("RSA key generation complete."); } else @@ -521,13 +520,13 @@ int main(int ac, char **av) if (listen(listen_sock, 5) < 0) fatal("listen: %.100s", strerror(errno)); + public_key = RSA_new(); + sensitive_data.private_key = RSA_new(); /* Generate an rsa key. */ log("Generating %d bit RSA key.", options.server_key_bits); - rsa_generate_key(&sensitive_data.private_key, &public_key, - &sensitive_data.random_state, + rsa_generate_key(sensitive_data.private_key, public_key, options.server_key_bits); - random_stir(&sensitive_data.random_state); - random_save(&sensitive_data.random_state, options.random_seed_file); + arc4random_stir(); log("RSA key generation complete."); /* Schedule server key regeneration alarm. */ @@ -650,7 +649,7 @@ int main(int ac, char **av) /* Register our connection. This turns encryption off because we do not have a key. */ - packet_set_connection(sock_in, sock_out, &sensitive_data.random_state); + packet_set_connection(sock_in, sock_out); /* Log the connection. */ log("Connection from %.100s port %d", @@ -783,12 +782,13 @@ int main(int ac, char **av) void do_connection(int privileged_port) { int i; - MP_INT session_key_int; + BIGNUM *session_key_int; unsigned char session_key[SSH_SESSION_KEY_LENGTH]; unsigned char check_bytes[8]; char *user; unsigned int cipher_type, auth_mask, protocol_flags; int plen, slen; + u_int32_t rand; /* Generate check bytes that the client must send back in the user packet in order for it to be accepted; this is used to defy ip spoofing @@ -797,8 +797,12 @@ void do_connection(int privileged_port) outgoing packets and catch the random cookie. This only affects rhosts authentication, and this is one of the reasons why it is inherently insecure. */ - for (i = 0; i < 8; i++) - check_bytes[i] = random_get_byte(&sensitive_data.random_state); + for (i = 0; i < 8; i++) { + if (i % 4 == 0) + rand = arc4random(); + check_bytes[i] = rand & 0xff; + rand >>= 8; + } /* Send our public key. We include in the packet 64 bits of random data that must be matched in the reply in order to prevent IP spoofing. */ @@ -807,14 +811,14 @@ void do_connection(int privileged_port) packet_put_char(check_bytes[i]); /* Store our public server RSA key. */ - packet_put_int(public_key.bits); - packet_put_mp_int(&public_key.e); - packet_put_mp_int(&public_key.n); + packet_put_int(BN_num_bits(public_key->n)); + packet_put_bignum(public_key->e); + packet_put_bignum(public_key->n); /* Store our public host RSA key. */ - packet_put_int(sensitive_data.host_key.bits); - packet_put_mp_int(&sensitive_data.host_key.e); - packet_put_mp_int(&sensitive_data.host_key.n); + packet_put_int(BN_num_bits(sensitive_data.host_key->n)); + packet_put_bignum(sensitive_data.host_key->e); + packet_put_bignum(sensitive_data.host_key->n); /* Put protocol flags. */ packet_put_int(SSH_PROTOFLAG_HOST_IN_FWD_OPEN); @@ -851,7 +855,7 @@ void do_connection(int privileged_port) packet_write_wait(); debug("Sent %d bit public key and %d bit host key.", - public_key.bits, sensitive_data.host_key.bits); + BN_num_bits(public_key->n), BN_num_bits(sensitive_data.host_key->n)); /* Read clients reply (cipher type and session key). */ packet_read_expect(&plen, SSH_CMSG_SESSION_KEY); @@ -868,8 +872,8 @@ void do_connection(int privileged_port) debug("Encryption type: %.200s", cipher_name(cipher_type)); /* Get the encrypted integer. */ - mpz_init(&session_key_int); - packet_get_mp_int(&session_key_int, &slen); + session_key_int = BN_new(); + packet_get_bignum(session_key_int, &slen); /* Get protocol flags. */ protocol_flags = packet_get_int(); @@ -879,45 +883,47 @@ void do_connection(int privileged_port) /* Decrypt it using our private server key and private host key (key with larger modulus first). */ - if (mpz_cmp(&sensitive_data.private_key.n, &sensitive_data.host_key.n) > 0) + if (BN_cmp(sensitive_data.private_key->n, sensitive_data.host_key->n) > 0) { /* Private key has bigger modulus. */ - assert(sensitive_data.private_key.bits >= - sensitive_data.host_key.bits + SSH_KEY_BITS_RESERVED); - rsa_private_decrypt(&session_key_int, &session_key_int, - &sensitive_data.private_key); - rsa_private_decrypt(&session_key_int, &session_key_int, - &sensitive_data.host_key); + assert(BN_num_bits(sensitive_data.private_key->n) >= + BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED); + rsa_private_decrypt(session_key_int, session_key_int, + sensitive_data.private_key); + rsa_private_decrypt(session_key_int, session_key_int, + sensitive_data.host_key); } else { /* Host key has bigger modulus (or they are equal). */ - assert(sensitive_data.host_key.bits >= - sensitive_data.private_key.bits + SSH_KEY_BITS_RESERVED); - rsa_private_decrypt(&session_key_int, &session_key_int, - &sensitive_data.host_key); - rsa_private_decrypt(&session_key_int, &session_key_int, - &sensitive_data.private_key); + assert(BN_num_bits(sensitive_data.host_key->n) >= + BN_num_bits(sensitive_data.private_key->n) + + SSH_KEY_BITS_RESERVED); + rsa_private_decrypt(session_key_int, session_key_int, + sensitive_data.host_key); + rsa_private_decrypt(session_key_int, session_key_int, + sensitive_data.private_key); } /* Compute session id for this session. */ - compute_session_id(session_id, check_bytes, sensitive_data.host_key.bits, - &sensitive_data.host_key.n, - sensitive_data.private_key.bits, - &sensitive_data.private_key.n); + compute_session_id(session_id, check_bytes, + BN_num_bits(sensitive_data.host_key->n), + sensitive_data.host_key->n, + BN_num_bits(sensitive_data.private_key->n), + sensitive_data.private_key->n); /* Extract session key from the decrypted integer. The key is in the least significant 256 bits of the integer; the first byte of the key is in the highest bits. */ - mp_linearize_msb_first(session_key, sizeof(session_key), - &session_key_int); + assert(BN_num_bytes(session_key_int) == sizeof(session_key)); + BN_bn2bin(session_key_int, session_key); /* Xor the first 16 bytes of the session key with the session id. */ for (i = 0; i < 16; i++) session_key[i] ^= session_id[i]; /* Destroy the decrypted integer. It is no longer needed. */ - mpz_clear(&session_key_int); + BN_clear_free(session_key_int); /* Set the session key. From this on all communications will be encrypted. */ @@ -946,9 +952,9 @@ void do_connection(int privileged_port) } /* Destroy the private and public keys. They will no longer be needed. */ - rsa_clear_public_key(&public_key); - rsa_clear_private_key(&sensitive_data.private_key); - rsa_clear_private_key(&sensitive_data.host_key); + RSA_free(public_key); + RSA_free(sensitive_data.private_key); + RSA_free(sensitive_data.host_key); /* Do the authentication. */ do_authentication(user, privileged_port); @@ -959,7 +965,8 @@ void do_connection(int privileged_port) in as (received from the clinet). Privileged_port is true if the connection comes from a privileged port (used for .rhosts authentication).*/ -void do_authentication(char *user, int privileged_port) +void +do_authentication(char *user, int privileged_port) { int type; int authenticated = 0; @@ -967,7 +974,7 @@ void do_authentication(char *user, int privileged_port) struct passwd *pw, pwcopy; char *client_user; unsigned int client_host_key_bits; - MP_INT client_host_key_e, client_host_key_n; + BIGNUM *client_host_key_e, *client_host_key_n; #ifdef AFS /* If machine has AFS, set process authentication group. */ @@ -1185,34 +1192,33 @@ void do_authentication(char *user, int privileged_port) client_user = packet_get_string(&ulen); /* Get the client host key. */ - mpz_init(&client_host_key_e); - mpz_init(&client_host_key_n); + client_host_key_e = BN_new(); + client_host_key_n = BN_new(); client_host_key_bits = packet_get_int(); - packet_get_mp_int(&client_host_key_e, &elen); - packet_get_mp_int(&client_host_key_n, &nlen); + packet_get_bignum(client_host_key_e, &elen); + packet_get_bignum(client_host_key_n, &nlen); packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type); } /* Try to authenticate using /etc/hosts.equiv and .rhosts. */ - if (auth_rhosts_rsa(&sensitive_data.random_state, - pw, client_user, - client_host_key_bits, &client_host_key_e, - &client_host_key_n, options.ignore_rhosts, + if (auth_rhosts_rsa(pw, client_user, + client_host_key_bits, client_host_key_e, + client_host_key_n, options.ignore_rhosts, options.strict_modes)) { /* Authentication accepted. */ authenticated = 1; xfree(client_user); - mpz_clear(&client_host_key_e); - mpz_clear(&client_host_key_n); + BN_clear_free(client_host_key_e); + BN_clear_free(client_host_key_n); break; } debug("Rhosts authentication failed for %.100s, remote %.100s.", user, client_user); xfree(client_user); - mpz_clear(&client_host_key_e); - mpz_clear(&client_host_key_n); + BN_clear_free(client_host_key_e); + BN_clear_free(client_host_key_n); break; case SSH_CMSG_AUTH_RSA: @@ -1225,21 +1231,21 @@ void do_authentication(char *user, int privileged_port) /* RSA authentication requested. */ { int nlen; - MP_INT n; - mpz_init(&n); - packet_get_mp_int(&n, &nlen); + BIGNUM *n; + n = BN_new(); + packet_get_bignum(n, &nlen); packet_integrity_check(plen, nlen, type); - if (auth_rsa(pw, &n, &sensitive_data.random_state)) + if (auth_rsa(pw, n)) { /* Successful authentication. */ - mpz_clear(&n); + BN_clear_free(n); log("RSA authentication for %.100s accepted.", user); authenticated = 1; break; } - mpz_clear(&n); + BN_clear_free(n); debug("RSA authentication for %.100s failed.", user); } break; diff --git a/usr.bin/ssh/sshd/Makefile b/usr.bin/ssh/sshd/Makefile index 4ca6870c930..7c2655475d3 100644 --- a/usr.bin/ssh/sshd/Makefile +++ b/usr.bin/ssh/sshd/Makefile @@ -4,14 +4,14 @@ PROG= sshd BINOWN= root BINMODE=555 BINDIR= /usr/sbin -LDADD= -lkrb -lcrypto -ldes -lgmp -lutil -lz +LDADD= -lkrb -lcrypto -ldes -lutil -lz MAN= sshd.8 SRCS= sshd.c auth-rhosts.c auth-passwd.c auth-rsa.c auth-rh-rsa.c pty.c \ log-server.c login.c hostfile.c canohost.c servconf.c tildexpand.c \ - uidswap.c serverloop.c rsa.c randoms.c \ + uidswap.c serverloop.c rsa.c \ ssh_md5.c buffer.c packet.c xmalloc.c ttymodes.c channels.c bufaux.c \ - authfd.c authfile.c crc32.c rsaglue.c match.c mpaux.c minfd.c cipher.c \ + authfd.c authfile.c crc32.c match.c mpaux.c minfd.c cipher.c \ compress.c gen_minfd: gen_minfd.c @@ -20,4 +20,4 @@ minfd.o: minfd.h minfd.h: gen_minfd ./gen_minfd $(USER_SHELLS) > minfd.h -.include<bsd.prog.mk> +.include <bsd.prog.mk> |