diff options
author | Andreas Schneider <asn@cryptomilk.org> | 2011-09-10 11:03:46 +0200 |
---|---|---|
committer | Andreas Schneider <asn@cryptomilk.org> | 2011-09-10 11:03:46 +0200 |
commit | bf72440effe7cceb2fa3db90cdaa85ebd7f6d3a4 (patch) | |
tree | c8687e80d85fc7890d26254ce6e8e6042a70068c | |
parent | 77e71ae3b5568ba43c0017a878dc780b3fe0c169 (diff) | |
download | libssh-bf72440effe7cceb2fa3db90cdaa85ebd7f6d3a4.tar.gz libssh-bf72440effe7cceb2fa3db90cdaa85ebd7f6d3a4.tar.xz libssh-bf72440effe7cceb2fa3db90cdaa85ebd7f6d3a4.zip |
kex: Split out SSHv1 functions to kex1.c.
-rw-r--r-- | src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/kex.c | 438 | ||||
-rw-r--r-- | src/kex1.c | 459 |
3 files changed, 462 insertions, 436 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7b776311..11e81d66 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -144,6 +144,7 @@ if (WITH_SSH1) ${libssh_SRCS} auth1.c channels1.c + kex1.c packet1.c ) endif (WITH_SSH1) @@ -32,17 +32,12 @@ #endif #include "libssh/priv.h" -#include "libssh/ssh2.h" -#include "libssh/ssh1.h" #include "libssh/buffer.h" -#include "libssh/packet.h" -#include "libssh/session.h" -#include "libssh/wrapper.h" -#include "libssh/keys.h" #include "libssh/dh.h" #include "libssh/kex.h" +#include "libssh/session.h" +#include "libssh/ssh2.h" #include "libssh/string.h" -#include "libssh/ecdh.h" #ifdef HAVE_LIBGCRYPT #define BLOWFISH "blowfish-cbc," @@ -482,433 +477,4 @@ int verify_existing_algo(int algo, const char *name){ return 0; } -#ifdef WITH_SSH1 - -/* makes a STRING contating 3 strings : ssh-rsa1,e and n */ -/* this is a public key in openssh's format */ -static ssh_string make_rsa1_string(ssh_string e, ssh_string n){ - ssh_buffer buffer = NULL; - ssh_string rsa = NULL; - ssh_string ret = NULL; - - buffer = ssh_buffer_new(); - rsa = ssh_string_from_char("ssh-rsa1"); - - if (buffer_add_ssh_string(buffer, rsa) < 0) { - goto error; - } - if (buffer_add_ssh_string(buffer, e) < 0) { - goto error; - } - if (buffer_add_ssh_string(buffer, n) < 0) { - goto error; - } - - ret = ssh_string_new(ssh_buffer_get_len(buffer)); - if (ret == NULL) { - goto error; - } - - ssh_string_fill(ret, ssh_buffer_get_begin(buffer), ssh_buffer_get_len(buffer)); -error: - ssh_buffer_free(buffer); - ssh_string_free(rsa); - - return ret; -} - -static int build_session_id1(ssh_session session, ssh_string servern, - ssh_string hostn) { - MD5CTX md5 = NULL; - - md5 = md5_init(); - if (md5 == NULL) { - return -1; - } - -#ifdef DEBUG_CRYPTO - ssh_print_hexa("host modulus",ssh_string_data(hostn),ssh_string_len(hostn)); - ssh_print_hexa("server modulus",ssh_string_data(servern),ssh_string_len(servern)); -#endif - md5_update(md5,ssh_string_data(hostn),ssh_string_len(hostn)); - md5_update(md5,ssh_string_data(servern),ssh_string_len(servern)); - md5_update(md5,session->server_kex.cookie,8); - md5_final(session->next_crypto->session_id,md5); -#ifdef DEBUG_CRYPTO - ssh_print_hexa("session_id",session->next_crypto->session_id,MD5_DIGEST_LEN); -#endif - - return 0; -} - -/* returns 1 if the modulus of k1 is < than the one of k2 */ -static int modulus_smaller(ssh_public_key k1, ssh_public_key k2){ - bignum n1; - bignum n2; - int res; -#ifdef HAVE_LIBGCRYPT - gcry_sexp_t sexp; - sexp=gcry_sexp_find_token(k1->rsa_pub,"n",0); - n1=gcry_sexp_nth_mpi(sexp,1,GCRYMPI_FMT_USG); - gcry_sexp_release(sexp); - sexp=gcry_sexp_find_token(k2->rsa_pub,"n",0); - n2=gcry_sexp_nth_mpi(sexp,1,GCRYMPI_FMT_USG); - gcry_sexp_release(sexp); -#elif defined HAVE_LIBCRYPTO - n1=k1->rsa_pub->n; - n2=k2->rsa_pub->n; -#endif - if(bignum_cmp(n1,n2)<0) - res=1; - else - res=0; -#ifdef HAVE_LIBGCRYPT - bignum_free(n1); - bignum_free(n2); -#endif - return res; - -} - -static ssh_string ssh_encrypt_rsa1(ssh_session session, - ssh_string data, - ssh_public_key key) { - ssh_string str = NULL; - size_t len = ssh_string_len(data); - size_t size = 0; -#ifdef HAVE_LIBGCRYPT - const char *tmp = NULL; - gcry_sexp_t ret_sexp; - gcry_sexp_t data_sexp; - - if (gcry_sexp_build(&data_sexp, NULL, "(data(flags pkcs1)(value %b))", - len, ssh_string_data(data))) { - ssh_set_error(session, SSH_FATAL, "RSA1 encrypt: libgcrypt error"); - return NULL; - } - if (gcry_pk_encrypt(&ret_sexp, data_sexp, key->rsa_pub)) { - gcry_sexp_release(data_sexp); - ssh_set_error(session, SSH_FATAL, "RSA1 encrypt: libgcrypt error"); - return NULL; - } - - gcry_sexp_release(data_sexp); - - data_sexp = gcry_sexp_find_token(ret_sexp, "a", 0); - if (data_sexp == NULL) { - ssh_set_error(session, SSH_FATAL, "RSA1 encrypt: libgcrypt error"); - gcry_sexp_release(ret_sexp); - return NULL; - } - tmp = gcry_sexp_nth_data(data_sexp, 1, &size); - if (*tmp == 0) { - size--; - tmp++; - } - - str = ssh_string_new(size); - if (str == NULL) { - ssh_set_error(session, SSH_FATAL, "Not enough space"); - gcry_sexp_release(data_sexp); - gcry_sexp_release(ret_sexp); - return NULL; - } - ssh_string_fill(str, tmp, size); - - gcry_sexp_release(data_sexp); - gcry_sexp_release(ret_sexp); -#elif defined HAVE_LIBCRYPTO - size = RSA_size(key->rsa_pub); - - str = ssh_string_new(size); - if (str == NULL) { - ssh_set_error(session, SSH_FATAL, "Not enough space"); - return NULL; - } - - if (RSA_public_encrypt(len, ssh_string_data(data), ssh_string_data(str), key->rsa_pub, - RSA_PKCS1_PADDING) < 0) { - ssh_string_free(str); - return NULL; - } -#endif - - return str; -} - -#define ABS(A) ( (A)<0 ? -(A):(A) ) -static ssh_string encrypt_session_key(ssh_session session, ssh_public_key srvkey, - ssh_public_key hostkey, int slen, int hlen) { - unsigned char buffer[32] = {0}; - int i; - ssh_string data1 = NULL; - ssh_string data2 = NULL; - - /* first, generate a session key */ - ssh_get_random(session->next_crypto->encryptkey, 32, 1); - memcpy(buffer, session->next_crypto->encryptkey, 32); - memcpy(session->next_crypto->decryptkey, session->next_crypto->encryptkey, 32); - -#ifdef DEBUG_CRYPTO - ssh_print_hexa("session key",buffer,32); -#endif - - /* xor session key with session_id */ - for (i = 0; i < 16; i++) { - buffer[i] ^= session->next_crypto->session_id[i]; - } - data1 = ssh_string_new(32); - if (data1 == NULL) { - return NULL; - } - ssh_string_fill(data1, buffer, 32); - if (ABS(hlen - slen) < 128){ - ssh_log(session, SSH_LOG_FUNCTIONS, - "Difference between server modulus and host modulus is only %d. " - "It's illegal and may not work", - ABS(hlen - slen)); - } - - if (modulus_smaller(srvkey, hostkey)) { - data2 = ssh_encrypt_rsa1(session, data1, srvkey); - ssh_string_free(data1); - data1 = NULL; - if (data2 == NULL) { - return NULL; - } - data1 = ssh_encrypt_rsa1(session, data2, hostkey); - ssh_string_free(data2); - if (data1 == NULL) { - return NULL; - } - } else { - data2 = ssh_encrypt_rsa1(session, data1, hostkey); - ssh_string_free(data1); - data1 = NULL; - if (data2 == NULL) { - return NULL; - } - data1 = ssh_encrypt_rsa1(session, data2, srvkey); - ssh_string_free(data2); - if (data1 == NULL) { - return NULL; - } - } - - return data1; -} - -/* SSH-1 functions */ -/* 2 SSH_SMSG_PUBLIC_KEY - * - * 8 bytes anti_spoofing_cookie - * 32-bit int server_key_bits - * mp-int server_key_public_exponent - * mp-int server_key_public_modulus - * 32-bit int host_key_bits - * mp-int host_key_public_exponent - * mp-int host_key_public_modulus - * 32-bit int protocol_flags - * 32-bit int supported_ciphers_mask - * 32-bit int supported_authentications_mask - */ -/** - * @brief Wait for a SSH_SMSG_PUBLIC_KEY and does the key exchange - */ -SSH_PACKET_CALLBACK(ssh_packet_publickey1){ - ssh_string server_exp = NULL; - ssh_string server_mod = NULL; - ssh_string host_exp = NULL; - ssh_string host_mod = NULL; - ssh_string serverkey = NULL; - ssh_string hostkey = NULL; - ssh_public_key srv = NULL; - ssh_public_key host = NULL; - uint32_t server_bits; - uint32_t host_bits; - uint32_t protocol_flags; - uint32_t supported_ciphers_mask; - uint32_t supported_authentications_mask; - ssh_string enc_session = NULL; - uint16_t bits; - int ko; - enter_function(); - (void)type; - (void)user; - ssh_log(session, SSH_LOG_PROTOCOL, "Got a SSH_SMSG_PUBLIC_KEY"); - if(session->session_state != SSH_SESSION_STATE_INITIAL_KEX){ - ssh_set_error(session,SSH_FATAL,"SSH_KEXINIT received in wrong state"); - goto error; - } - if (buffer_get_data(packet, session->server_kex.cookie, 8) != 8) { - ssh_set_error(session, SSH_FATAL, "Can't get cookie in buffer"); - goto error; - } - - buffer_get_u32(packet, &server_bits); - server_exp = buffer_get_mpint(packet); - if (server_exp == NULL) { - goto error; - } - server_mod = buffer_get_mpint(packet); - if (server_mod == NULL) { - goto error; - } - buffer_get_u32(packet, &host_bits); - host_exp = buffer_get_mpint(packet); - if (host_exp == NULL) { - goto error; - } - host_mod = buffer_get_mpint(packet); - if (host_mod == NULL) { - goto error; - } - buffer_get_u32(packet, &protocol_flags); - buffer_get_u32(packet, &supported_ciphers_mask); - ko = buffer_get_u32(packet, &supported_authentications_mask); - - if ((ko != sizeof(uint32_t)) || !host_mod || !host_exp - || !server_mod || !server_exp) { - ssh_log(session, SSH_LOG_RARE, "Invalid SSH_SMSG_PUBLIC_KEY packet"); - ssh_set_error(session, SSH_FATAL, "Invalid SSH_SMSG_PUBLIC_KEY packet"); - goto error; - } - - server_bits = ntohl(server_bits); - host_bits = ntohl(host_bits); - protocol_flags = ntohl(protocol_flags); - supported_ciphers_mask = ntohl(supported_ciphers_mask); - supported_authentications_mask = ntohl(supported_authentications_mask); - ssh_log(session, SSH_LOG_PROTOCOL, - "Server bits: %d; Host bits: %d; Protocol flags: %.8lx; " - "Cipher mask: %.8lx; Auth mask: %.8lx", - server_bits, - host_bits, - (unsigned long int) protocol_flags, - (unsigned long int) supported_ciphers_mask, - (unsigned long int) supported_authentications_mask); - - serverkey = make_rsa1_string(server_exp, server_mod); - if (serverkey == NULL) { - goto error; - } - hostkey = make_rsa1_string(host_exp,host_mod); - if (serverkey == NULL) { - goto error; - } - if (build_session_id1(session, server_mod, host_mod) < 0) { - goto error; - } - - srv = publickey_from_string(session, serverkey); - if (srv == NULL) { - goto error; - } - host = publickey_from_string(session, hostkey); - if (host == NULL) { - goto error; - } - - session->next_crypto->server_pubkey = ssh_string_copy(hostkey); - if (session->next_crypto->server_pubkey == NULL) { - goto error; - } - session->next_crypto->server_pubkey_type = "ssh-rsa1"; - - /* now, we must choose an encryption algo */ - /* hardcode 3des */ - if (!(supported_ciphers_mask & (1 << SSH_CIPHER_3DES))) { - ssh_set_error(session, SSH_FATAL, "Remote server doesn't accept 3DES"); - goto error; - } - ssh_log(session, SSH_LOG_PROTOCOL, "Sending SSH_CMSG_SESSION_KEY"); - - if (buffer_add_u8(session->out_buffer, SSH_CMSG_SESSION_KEY) < 0) { - goto error; - } - if (buffer_add_u8(session->out_buffer, SSH_CIPHER_3DES) < 0) { - goto error; - } - if (buffer_add_data(session->out_buffer, session->server_kex.cookie, 8) < 0) { - goto error; - } - - enc_session = encrypt_session_key(session, srv, host, server_bits, host_bits); - if (enc_session == NULL) { - goto error; - } - - bits = ssh_string_len(enc_session) * 8 - 7; - ssh_log(session, SSH_LOG_PROTOCOL, "%d bits, %" PRIdS " bytes encrypted session", - bits, ssh_string_len(enc_session)); - bits = htons(bits); - /* the encrypted mpint */ - if (buffer_add_data(session->out_buffer, &bits, sizeof(uint16_t)) < 0) { - goto error; - } - if (buffer_add_data(session->out_buffer, ssh_string_data(enc_session), - ssh_string_len(enc_session)) < 0) { - goto error; - } - /* the protocol flags */ - if (buffer_add_u32(session->out_buffer, 0) < 0) { - goto error; - } - session->session_state=SSH_SESSION_STATE_KEXINIT_RECEIVED; - if (packet_send(session) == SSH_ERROR) { - goto error; - } - - /* we can set encryption */ - if (crypt_set_algorithms(session)) { - goto error; - } - - session->current_crypto = session->next_crypto; - session->next_crypto = NULL; - goto end; -error: - session->session_state=SSH_SESSION_STATE_ERROR; -end: - - ssh_string_free(host_mod); - ssh_string_free(host_exp); - ssh_string_free(server_mod); - ssh_string_free(server_exp); - ssh_string_free(serverkey); - ssh_string_free(hostkey); - ssh_string_free(enc_session); - - publickey_free(srv); - publickey_free(host); - - leave_function(); - return SSH_PACKET_USED; -} - -int ssh_get_kex1(ssh_session session) { - int ret=SSH_ERROR; - enter_function(); - ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_PUBLIC_KEY"); - /* Here the callback is called */ - while(session->session_state==SSH_SESSION_STATE_INITIAL_KEX){ - ssh_handle_packets(session, -2); - } - if(session->session_state==SSH_SESSION_STATE_ERROR) - goto error; - ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_SUCCESS"); - /* Waiting for SSH_SMSG_SUCCESS */ - while(session->session_state==SSH_SESSION_STATE_KEXINIT_RECEIVED){ - ssh_handle_packets(session, -2); - } - if(session->session_state==SSH_SESSION_STATE_ERROR) - goto error; - ssh_log(session, SSH_LOG_PROTOCOL, "received SSH_SMSG_SUCCESS\n"); - ret=SSH_OK; -error: - leave_function(); - return ret; -} - -#endif /* WITH_SSH1 */ /* vim: set ts=2 sw=2 et cindent: */ diff --git a/src/kex1.c b/src/kex1.c new file mode 100644 index 00000000..9daf5c33 --- /dev/null +++ b/src/kex1.c @@ -0,0 +1,459 @@ +/* + * kex.c - key exchange + * + * This file is part of the SSH Library + * + * Copyright (c) 2003-2008 by Aris Adamantiadis + * + * The SSH Library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The SSH Library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the SSH Library; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#include "config.h" + +#include "libssh/priv.h" +#include "libssh/buffer.h" +#include "libssh/kex.h" +#include "libssh/keys.h" +#include "libssh/session.h" +#include "libssh/ssh1.h" +#include "libssh/wrapper.h" + +/* SSHv1 functions */ + +/* makes a STRING contating 3 strings : ssh-rsa1,e and n */ +/* this is a public key in openssh's format */ +static ssh_string make_rsa1_string(ssh_string e, ssh_string n){ + ssh_buffer buffer = NULL; + ssh_string rsa = NULL; + ssh_string ret = NULL; + + buffer = ssh_buffer_new(); + rsa = ssh_string_from_char("ssh-rsa1"); + + if (buffer_add_ssh_string(buffer, rsa) < 0) { + goto error; + } + if (buffer_add_ssh_string(buffer, e) < 0) { + goto error; + } + if (buffer_add_ssh_string(buffer, n) < 0) { + goto error; + } + + ret = ssh_string_new(ssh_buffer_get_len(buffer)); + if (ret == NULL) { + goto error; + } + + ssh_string_fill(ret, ssh_buffer_get_begin(buffer), ssh_buffer_get_len(buffer)); +error: + ssh_buffer_free(buffer); + ssh_string_free(rsa); + + return ret; +} + +static int build_session_id1(ssh_session session, ssh_string servern, + ssh_string hostn) { + MD5CTX md5 = NULL; + + md5 = md5_init(); + if (md5 == NULL) { + return -1; + } + +#ifdef DEBUG_CRYPTO + ssh_print_hexa("host modulus",ssh_string_data(hostn),ssh_string_len(hostn)); + ssh_print_hexa("server modulus",ssh_string_data(servern),ssh_string_len(servern)); +#endif + md5_update(md5,ssh_string_data(hostn),ssh_string_len(hostn)); + md5_update(md5,ssh_string_data(servern),ssh_string_len(servern)); + md5_update(md5,session->server_kex.cookie,8); + md5_final(session->next_crypto->session_id,md5); +#ifdef DEBUG_CRYPTO + ssh_print_hexa("session_id",session->next_crypto->session_id,MD5_DIGEST_LEN); +#endif + + return 0; +} + +/* returns 1 if the modulus of k1 is < than the one of k2 */ +static int modulus_smaller(ssh_public_key k1, ssh_public_key k2){ + bignum n1; + bignum n2; + int res; +#ifdef HAVE_LIBGCRYPT + gcry_sexp_t sexp; + sexp=gcry_sexp_find_token(k1->rsa_pub,"n",0); + n1=gcry_sexp_nth_mpi(sexp,1,GCRYMPI_FMT_USG); + gcry_sexp_release(sexp); + sexp=gcry_sexp_find_token(k2->rsa_pub,"n",0); + n2=gcry_sexp_nth_mpi(sexp,1,GCRYMPI_FMT_USG); + gcry_sexp_release(sexp); +#elif defined HAVE_LIBCRYPTO + n1=k1->rsa_pub->n; + n2=k2->rsa_pub->n; +#endif + if(bignum_cmp(n1,n2)<0) + res=1; + else + res=0; +#ifdef HAVE_LIBGCRYPT + bignum_free(n1); + bignum_free(n2); +#endif + return res; + +} + +static ssh_string ssh_encrypt_rsa1(ssh_session session, + ssh_string data, + ssh_public_key key) { + ssh_string str = NULL; + size_t len = ssh_string_len(data); + size_t size = 0; +#ifdef HAVE_LIBGCRYPT + const char *tmp = NULL; + gcry_sexp_t ret_sexp; + gcry_sexp_t data_sexp; + + if (gcry_sexp_build(&data_sexp, NULL, "(data(flags pkcs1)(value %b))", + len, ssh_string_data(data))) { + ssh_set_error(session, SSH_FATAL, "RSA1 encrypt: libgcrypt error"); + return NULL; + } + if (gcry_pk_encrypt(&ret_sexp, data_sexp, key->rsa_pub)) { + gcry_sexp_release(data_sexp); + ssh_set_error(session, SSH_FATAL, "RSA1 encrypt: libgcrypt error"); + return NULL; + } + + gcry_sexp_release(data_sexp); + + data_sexp = gcry_sexp_find_token(ret_sexp, "a", 0); + if (data_sexp == NULL) { + ssh_set_error(session, SSH_FATAL, "RSA1 encrypt: libgcrypt error"); + gcry_sexp_release(ret_sexp); + return NULL; + } + tmp = gcry_sexp_nth_data(data_sexp, 1, &size); + if (*tmp == 0) { + size--; + tmp++; + } + + str = ssh_string_new(size); + if (str == NULL) { + ssh_set_error(session, SSH_FATAL, "Not enough space"); + gcry_sexp_release(data_sexp); + gcry_sexp_release(ret_sexp); + return NULL; + } + ssh_string_fill(str, tmp, size); + + gcry_sexp_release(data_sexp); + gcry_sexp_release(ret_sexp); +#elif defined HAVE_LIBCRYPTO + size = RSA_size(key->rsa_pub); + + str = ssh_string_new(size); + if (str == NULL) { + ssh_set_error(session, SSH_FATAL, "Not enough space"); + return NULL; + } + + if (RSA_public_encrypt(len, ssh_string_data(data), ssh_string_data(str), key->rsa_pub, + RSA_PKCS1_PADDING) < 0) { + ssh_string_free(str); + return NULL; + } +#endif + + return str; +} + +#define ABS(A) ( (A)<0 ? -(A):(A) ) +static ssh_string encrypt_session_key(ssh_session session, ssh_public_key srvkey, + ssh_public_key hostkey, int slen, int hlen) { + unsigned char buffer[32] = {0}; + int i; + ssh_string data1 = NULL; + ssh_string data2 = NULL; + + /* first, generate a session key */ + ssh_get_random(session->next_crypto->encryptkey, 32, 1); + memcpy(buffer, session->next_crypto->encryptkey, 32); + memcpy(session->next_crypto->decryptkey, session->next_crypto->encryptkey, 32); + +#ifdef DEBUG_CRYPTO + ssh_print_hexa("session key",buffer,32); +#endif + + /* xor session key with session_id */ + for (i = 0; i < 16; i++) { + buffer[i] ^= session->next_crypto->session_id[i]; + } + data1 = ssh_string_new(32); + if (data1 == NULL) { + return NULL; + } + ssh_string_fill(data1, buffer, 32); + if (ABS(hlen - slen) < 128){ + ssh_log(session, SSH_LOG_FUNCTIONS, + "Difference between server modulus and host modulus is only %d. " + "It's illegal and may not work", + ABS(hlen - slen)); + } + + if (modulus_smaller(srvkey, hostkey)) { + data2 = ssh_encrypt_rsa1(session, data1, srvkey); + ssh_string_free(data1); + data1 = NULL; + if (data2 == NULL) { + return NULL; + } + data1 = ssh_encrypt_rsa1(session, data2, hostkey); + ssh_string_free(data2); + if (data1 == NULL) { + return NULL; + } + } else { + data2 = ssh_encrypt_rsa1(session, data1, hostkey); + ssh_string_free(data1); + data1 = NULL; + if (data2 == NULL) { + return NULL; + } + data1 = ssh_encrypt_rsa1(session, data2, srvkey); + ssh_string_free(data2); + if (data1 == NULL) { + return NULL; + } + } + + return data1; +} + +/* 2 SSH_SMSG_PUBLIC_KEY + * + * 8 bytes anti_spoofing_cookie + * 32-bit int server_key_bits + * mp-int server_key_public_exponent + * mp-int server_key_public_modulus + * 32-bit int host_key_bits + * mp-int host_key_public_exponent + * mp-int host_key_public_modulus + * 32-bit int protocol_flags + * 32-bit int supported_ciphers_mask + * 32-bit int supported_authentications_mask + */ +/** + * @brief Wait for a SSH_SMSG_PUBLIC_KEY and does the key exchange + */ +SSH_PACKET_CALLBACK(ssh_packet_publickey1){ + ssh_string server_exp = NULL; + ssh_string server_mod = NULL; + ssh_string host_exp = NULL; + ssh_string host_mod = NULL; + ssh_string serverkey = NULL; + ssh_string hostkey = NULL; + ssh_public_key srv = NULL; + ssh_public_key host = NULL; + uint32_t server_bits; + uint32_t host_bits; + uint32_t protocol_flags; + uint32_t supported_ciphers_mask; + uint32_t supported_authentications_mask; + ssh_string enc_session = NULL; + uint16_t bits; + int ko; + enter_function(); + (void)type; + (void)user; + ssh_log(session, SSH_LOG_PROTOCOL, "Got a SSH_SMSG_PUBLIC_KEY"); + if(session->session_state != SSH_SESSION_STATE_INITIAL_KEX){ + ssh_set_error(session,SSH_FATAL,"SSH_KEXINIT received in wrong state"); + goto error; + } + if (buffer_get_data(packet, session->server_kex.cookie, 8) != 8) { + ssh_set_error(session, SSH_FATAL, "Can't get cookie in buffer"); + goto error; + } + + buffer_get_u32(packet, &server_bits); + server_exp = buffer_get_mpint(packet); + if (server_exp == NULL) { + goto error; + } + server_mod = buffer_get_mpint(packet); + if (server_mod == NULL) { + goto error; + } + buffer_get_u32(packet, &host_bits); + host_exp = buffer_get_mpint(packet); + if (host_exp == NULL) { + goto error; + } + host_mod = buffer_get_mpint(packet); + if (host_mod == NULL) { + goto error; + } + buffer_get_u32(packet, &protocol_flags); + buffer_get_u32(packet, &supported_ciphers_mask); + ko = buffer_get_u32(packet, &supported_authentications_mask); + + if ((ko != sizeof(uint32_t)) || !host_mod || !host_exp + || !server_mod || !server_exp) { + ssh_log(session, SSH_LOG_RARE, "Invalid SSH_SMSG_PUBLIC_KEY packet"); + ssh_set_error(session, SSH_FATAL, "Invalid SSH_SMSG_PUBLIC_KEY packet"); + goto error; + } + + server_bits = ntohl(server_bits); + host_bits = ntohl(host_bits); + protocol_flags = ntohl(protocol_flags); + supported_ciphers_mask = ntohl(supported_ciphers_mask); + supported_authentications_mask = ntohl(supported_authentications_mask); + ssh_log(session, SSH_LOG_PROTOCOL, + "Server bits: %d; Host bits: %d; Protocol flags: %.8lx; " + "Cipher mask: %.8lx; Auth mask: %.8lx", + server_bits, + host_bits, + (unsigned long int) protocol_flags, + (unsigned long int) supported_ciphers_mask, + (unsigned long int) supported_authentications_mask); + + serverkey = make_rsa1_string(server_exp, server_mod); + if (serverkey == NULL) { + goto error; + } + hostkey = make_rsa1_string(host_exp,host_mod); + if (serverkey == NULL) { + goto error; + } + if (build_session_id1(session, server_mod, host_mod) < 0) { + goto error; + } + + srv = publickey_from_string(session, serverkey); + if (srv == NULL) { + goto error; + } + host = publickey_from_string(session, hostkey); + if (host == NULL) { + goto error; + } + + session->next_crypto->server_pubkey = ssh_string_copy(hostkey); + if (session->next_crypto->server_pubkey == NULL) { + goto error; + } + session->next_crypto->server_pubkey_type = "ssh-rsa1"; + + /* now, we must choose an encryption algo */ + /* hardcode 3des */ + if (!(supported_ciphers_mask & (1 << SSH_CIPHER_3DES))) { + ssh_set_error(session, SSH_FATAL, "Remote server doesn't accept 3DES"); + goto error; + } + ssh_log(session, SSH_LOG_PROTOCOL, "Sending SSH_CMSG_SESSION_KEY"); + + if (buffer_add_u8(session->out_buffer, SSH_CMSG_SESSION_KEY) < 0) { + goto error; + } + if (buffer_add_u8(session->out_buffer, SSH_CIPHER_3DES) < 0) { + goto error; + } + if (buffer_add_data(session->out_buffer, session->server_kex.cookie, 8) < 0) { + goto error; + } + + enc_session = encrypt_session_key(session, srv, host, server_bits, host_bits); + if (enc_session == NULL) { + goto error; + } + + bits = ssh_string_len(enc_session) * 8 - 7; + ssh_log(session, SSH_LOG_PROTOCOL, "%d bits, %" PRIdS " bytes encrypted session", + bits, ssh_string_len(enc_session)); + bits = htons(bits); + /* the encrypted mpint */ + if (buffer_add_data(session->out_buffer, &bits, sizeof(uint16_t)) < 0) { + goto error; + } + if (buffer_add_data(session->out_buffer, ssh_string_data(enc_session), + ssh_string_len(enc_session)) < 0) { + goto error; + } + /* the protocol flags */ + if (buffer_add_u32(session->out_buffer, 0) < 0) { + goto error; + } + session->session_state=SSH_SESSION_STATE_KEXINIT_RECEIVED; + if (packet_send(session) == SSH_ERROR) { + goto error; + } + + /* we can set encryption */ + if (crypt_set_algorithms(session)) { + goto error; + } + + session->current_crypto = session->next_crypto; + session->next_crypto = NULL; + goto end; +error: + session->session_state=SSH_SESSION_STATE_ERROR; +end: + + ssh_string_free(host_mod); + ssh_string_free(host_exp); + ssh_string_free(server_mod); + ssh_string_free(server_exp); + ssh_string_free(serverkey); + ssh_string_free(hostkey); + ssh_string_free(enc_session); + + publickey_free(srv); + publickey_free(host); + + leave_function(); + return SSH_PACKET_USED; +} + +int ssh_get_kex1(ssh_session session) { + int ret=SSH_ERROR; + enter_function(); + ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_PUBLIC_KEY"); + /* Here the callback is called */ + while(session->session_state==SSH_SESSION_STATE_INITIAL_KEX){ + ssh_handle_packets(session, -2); + } + if(session->session_state==SSH_SESSION_STATE_ERROR) + goto error; + ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_SUCCESS"); + /* Waiting for SSH_SMSG_SUCCESS */ + while(session->session_state==SSH_SESSION_STATE_KEXINIT_RECEIVED){ + ssh_handle_packets(session, -2); + } + if(session->session_state==SSH_SESSION_STATE_ERROR) + goto error; + ssh_log(session, SSH_LOG_PROTOCOL, "received SSH_SMSG_SUCCESS\n"); + ret=SSH_OK; +error: + leave_function(); + return ret; +} |