version 1.1, 1999/09/26 20:53:37 |
version 1.2, 1999/09/28 04:45:37 |
|
|
|
|
#include "ssh.h" |
#include "ssh.h" |
#include "rsa.h" |
#include "rsa.h" |
#include "randoms.h" |
|
#include "authfd.h" |
#include "authfd.h" |
#include "buffer.h" |
#include "buffer.h" |
#include "bufaux.h" |
#include "bufaux.h" |
|
|
|
|
typedef struct |
typedef struct |
{ |
{ |
RSAPrivateKey key; |
RSA *key; |
char *comment; |
char *comment; |
} Identity; |
} Identity; |
|
|
|
|
|
|
int max_fd = 0; |
int max_fd = 0; |
|
|
void process_request_identity(SocketEntry *e) |
void |
|
process_request_identity(SocketEntry *e) |
{ |
{ |
Buffer msg; |
Buffer msg; |
int i; |
int i; |
|
|
buffer_put_int(&msg, num_identities); |
buffer_put_int(&msg, num_identities); |
for (i = 0; i < num_identities; i++) |
for (i = 0; i < num_identities; i++) |
{ |
{ |
buffer_put_int(&msg, identities[i].key.bits); |
buffer_put_int(&msg, BN_num_bits(identities[i].key->n)); |
buffer_put_mp_int(&msg, &identities[i].key.e); |
buffer_put_bignum(&msg, identities[i].key->e); |
buffer_put_mp_int(&msg, &identities[i].key.n); |
buffer_put_bignum(&msg, identities[i].key->n); |
buffer_put_string(&msg, identities[i].comment, |
buffer_put_string(&msg, identities[i].comment, |
strlen(identities[i].comment)); |
strlen(identities[i].comment)); |
} |
} |
|
|
buffer_free(&msg); |
buffer_free(&msg); |
} |
} |
|
|
void process_authentication_challenge(SocketEntry *e) |
void |
|
process_authentication_challenge(SocketEntry *e) |
{ |
{ |
int i, pub_bits; |
int i, pub_bits, len; |
MP_INT pub_e, pub_n, challenge; |
BIGNUM *pub_e, *pub_n, *challenge; |
Buffer msg; |
Buffer msg; |
struct MD5Context md; |
struct MD5Context md; |
unsigned char buf[32], mdbuf[16], session_id[16]; |
unsigned char buf[32], mdbuf[16], session_id[16]; |
unsigned int response_type; |
unsigned int response_type; |
|
|
buffer_init(&msg); |
buffer_init(&msg); |
mpz_init(&pub_e); |
pub_e = BN_new(); |
mpz_init(&pub_n); |
pub_n = BN_new(); |
mpz_init(&challenge); |
challenge = BN_new(); |
pub_bits = buffer_get_int(&e->input); |
pub_bits = buffer_get_int(&e->input); |
buffer_get_mp_int(&e->input, &pub_e); |
buffer_get_bignum(&e->input, pub_e); |
buffer_get_mp_int(&e->input, &pub_n); |
buffer_get_bignum(&e->input, pub_n); |
buffer_get_mp_int(&e->input, &challenge); |
buffer_get_bignum(&e->input, challenge); |
if (buffer_len(&e->input) == 0) |
if (buffer_len(&e->input) == 0) |
{ |
{ |
/* Compatibility code for old servers. */ |
/* Compatibility code for old servers. */ |
|
|
response_type = buffer_get_int(&e->input); |
response_type = buffer_get_int(&e->input); |
} |
} |
for (i = 0; i < num_identities; i++) |
for (i = 0; i < num_identities; i++) |
if (pub_bits == identities[i].key.bits && |
if (pub_bits == BN_num_bits(identities[i].key->n) && |
mpz_cmp(&pub_e, &identities[i].key.e) == 0 && |
BN_cmp(pub_e, identities[i].key->e) == 0 && |
mpz_cmp(&pub_n, &identities[i].key.n) == 0) |
BN_cmp(pub_n, identities[i].key->n) == 0) |
{ |
{ |
/* Decrypt the challenge using the private key. */ |
/* 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. */ |
/* Compute the desired response. */ |
switch (response_type) |
switch (response_type) |
|
|
|
|
case 1: /* As of protocol 1.1 */ |
case 1: /* As of protocol 1.1 */ |
/* The response is MD5 of decrypted challenge plus session id. */ |
/* 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); |
MD5Init(&md); |
MD5Update(&md, buf, 32); |
MD5Update(&md, buf, 32); |
MD5Update(&md, session_id, 16); |
MD5Update(&md, session_id, 16); |
|
|
buffer_append(&e->output, buffer_ptr(&msg), |
buffer_append(&e->output, buffer_ptr(&msg), |
buffer_len(&msg)); |
buffer_len(&msg)); |
buffer_free(&msg); |
buffer_free(&msg); |
mpz_clear(&pub_e); |
BN_clear_free(pub_e); |
mpz_clear(&pub_n); |
BN_clear_free(pub_n); |
mpz_clear(&challenge); |
BN_clear_free(challenge); |
} |
} |
|
|
void process_remove_identity(SocketEntry *e) |
void |
|
process_remove_identity(SocketEntry *e) |
{ |
{ |
unsigned int bits; |
unsigned int bits; |
MP_INT dummy, n; |
|
unsigned int i; |
unsigned int i; |
|
BIGNUM *dummy, *n; |
|
|
mpz_init(&dummy); |
dummy = BN_new(); |
mpz_init(&n); |
n = BN_new(); |
|
|
/* Get the key from the packet. */ |
/* Get the key from the packet. */ |
bits = buffer_get_int(&e->input); |
bits = buffer_get_int(&e->input); |
buffer_get_mp_int(&e->input, &dummy); |
buffer_get_bignum(&e->input, dummy); |
buffer_get_mp_int(&e->input, &n); |
buffer_get_bignum(&e->input, n); |
|
|
/* Check if we have the key. */ |
/* Check if we have the key. */ |
for (i = 0; i < num_identities; i++) |
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 |
/* 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 |
empty slots in the middle of the array, we actually free the |
key there and copy data from the last entry. */ |
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); |
xfree(identities[i].comment); |
if (i < num_identities - 1) |
if (i < num_identities - 1) |
identities[i] = identities[num_identities - 1]; |
identities[i] = identities[num_identities - 1]; |
num_identities--; |
num_identities--; |
mpz_clear(&dummy); |
BN_clear_free(dummy); |
mpz_clear(&n); |
BN_clear_free(n); |
|
|
/* Send success. */ |
/* Send success. */ |
buffer_put_int(&e->output, 1); |
buffer_put_int(&e->output, 1); |
|
|
return; |
return; |
} |
} |
/* We did not have the key. */ |
/* We did not have the key. */ |
mpz_clear(&dummy); |
BN_clear(dummy); |
mpz_clear(&n); |
BN_clear(n); |
|
|
/* Send failure. */ |
/* Send failure. */ |
buffer_put_int(&e->output, 1); |
buffer_put_int(&e->output, 1); |
|
|
|
|
/* Removes all identities from the agent. */ |
/* Removes all identities from the agent. */ |
|
|
void process_remove_all_identities(SocketEntry *e) |
void |
|
process_remove_all_identities(SocketEntry *e) |
{ |
{ |
unsigned int i; |
unsigned int i; |
|
|
/* Loop over all identities and clear the keys. */ |
/* Loop over all identities and clear the keys. */ |
for (i = 0; i < num_identities; i++) |
for (i = 0; i < num_identities; i++) |
{ |
{ |
rsa_clear_private_key(&identities[i].key); |
RSA_free(identities[i].key); |
xfree(identities[i].comment); |
xfree(identities[i].comment); |
} |
} |
|
|
|
|
|
|
/* Adds an identity to the agent. */ |
/* Adds an identity to the agent. */ |
|
|
void process_add_identity(SocketEntry *e) |
void |
|
process_add_identity(SocketEntry *e) |
{ |
{ |
RSAPrivateKey *k; |
RSA *k; |
int i; |
int i; |
|
BIGNUM *aux; |
|
BN_CTX *ctx; |
|
|
if (num_identities == 0) |
if (num_identities == 0) |
identities = xmalloc(sizeof(Identity)); |
identities = xmalloc(sizeof(Identity)); |
else |
else |
identities = xrealloc(identities, (num_identities + 1) * sizeof(Identity)); |
identities = xrealloc(identities, (num_identities + 1) * sizeof(Identity)); |
k = &identities[num_identities].key; |
|
k->bits = buffer_get_int(&e->input); |
identities[num_identities].key = RSA_new(); |
mpz_init(&k->n); |
k = identities[num_identities].key; |
buffer_get_mp_int(&e->input, &k->n); |
buffer_get_int(&e->input); /* bits */ |
mpz_init(&k->e); |
k->n = BN_new(); |
buffer_get_mp_int(&e->input, &k->e); |
buffer_get_bignum(&e->input, k->n); |
mpz_init(&k->d); |
k->e = BN_new(); |
buffer_get_mp_int(&e->input, &k->d); |
buffer_get_bignum(&e->input, k->e); |
mpz_init(&k->u); |
k->d = BN_new(); |
buffer_get_mp_int(&e->input, &k->u); |
buffer_get_bignum(&e->input, k->d); |
mpz_init(&k->p); |
k->iqmp = BN_new(); |
buffer_get_mp_int(&e->input, &k->p); |
buffer_get_bignum(&e->input, k->iqmp); |
mpz_init(&k->q); |
/* SSH and SSL have p and q swapped */ |
buffer_get_mp_int(&e->input, &k->q); |
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); |
identities[num_identities].comment = buffer_get_string(&e->input, NULL); |
|
|
/* Check if we already have the key. */ |
/* Check if we already have the key. */ |
for (i = 0; i < num_identities; i++) |
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 |
/* We already have this key. Clear and free the new data and |
return success. */ |
return success. */ |
rsa_clear_private_key(k); |
RSA_free(k); |
xfree(identities[num_identities].comment); |
xfree(identities[num_identities].comment); |
|
|
/* Send success. */ |
/* Send success. */ |
|
|
buffer_put_char(&e->output, SSH_AGENT_SUCCESS); |
buffer_put_char(&e->output, SSH_AGENT_SUCCESS); |
} |
} |
|
|
void process_message(SocketEntry *e) |
void |
|
process_message(SocketEntry *e) |
{ |
{ |
unsigned int msg_len; |
unsigned int msg_len; |
unsigned int type; |
unsigned int type; |
|
|
} |
} |
} |
} |
|
|
void new_socket(int type, int fd) |
void |
|
new_socket(int type, int fd) |
{ |
{ |
unsigned int i, old_alloc; |
unsigned int i, old_alloc; |
#if defined(O_NONBLOCK) && !defined(O_NONBLOCK_BROKEN) |
#if defined(O_NONBLOCK) && !defined(O_NONBLOCK_BROKEN) |
|
|
buffer_init(&sockets[old_alloc].output); |
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; |
unsigned int i; |
for (i = 0; i < sockets_alloc; i++) |
for (i = 0; i < sockets_alloc; i++) |
|
|
int parent_pid = -1; |
int parent_pid = -1; |
char socket_name[1024]; |
char socket_name[1024]; |
|
|
RETSIGTYPE check_parent_exists(int sig) |
RETSIGTYPE |
|
check_parent_exists(int sig) |
{ |
{ |
if (kill(parent_pid, 0) < 0) |
if (kill(parent_pid, 0) < 0) |
{ |
{ |
|
|
alarm(10); |
alarm(10); |
} |
} |
|
|
int main(int ac, char **av) |
int |
|
main(int ac, char **av) |
{ |
{ |
fd_set readset, writeset; |
fd_set readset, writeset; |
char buf[1024]; |
char buf[1024]; |