aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Schneider <asn@cryptomilk.org>2011-09-10 11:03:46 +0200
committerAndreas Schneider <asn@cryptomilk.org>2011-09-10 11:03:46 +0200
commitbf72440effe7cceb2fa3db90cdaa85ebd7f6d3a4 (patch)
treec8687e80d85fc7890d26254ce6e8e6042a70068c
parent77e71ae3b5568ba43c0017a878dc780b3fe0c169 (diff)
downloadlibssh-bf72440effe7cceb2fa3db90cdaa85ebd7f6d3a4.tar.gz
libssh-bf72440effe7cceb2fa3db90cdaa85ebd7f6d3a4.tar.xz
libssh-bf72440effe7cceb2fa3db90cdaa85ebd7f6d3a4.zip
kex: Split out SSHv1 functions to kex1.c.
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/kex.c438
-rw-r--r--src/kex1.c459
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)
diff --git a/src/kex.c b/src/kex.c
index ee0d5824..e3a7857a 100644
--- a/src/kex.c
+++ b/src/kex.c
@@ -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;
+}