kex.c | kex.c | |||
---|---|---|---|---|
skipping to change at line 24 | skipping to change at line 24 | |||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILI TY | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILI TY | |||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | |||
* License for more details. | * License for more details. | |||
* | * | |||
* You should have received a copy of the GNU Lesser General Public License | * 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 | * along with the SSH Library; see the file COPYING. If not, write to | |||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | |||
* MA 02111-1307, USA. | * MA 02111-1307, USA. | |||
*/ | */ | |||
#include "config.h" | ||||
#include <string.h> | #include <string.h> | |||
#include <stdlib.h> | #include <stdlib.h> | |||
#include <stdio.h> | #include <stdio.h> | |||
#ifndef _WIN32 | #ifndef _WIN32 | |||
#include <arpa/inet.h> | #include <arpa/inet.h> | |||
#endif | #endif | |||
#include "config.h" | ||||
#include "libssh/priv.h" | #include "libssh/priv.h" | |||
#include "libssh/ssh2.h" | #include "libssh/ssh2.h" | |||
#include "libssh/ssh1.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" | ||||
#ifdef HAVE_LIBGCRYPT | #ifdef HAVE_LIBGCRYPT | |||
#define BLOWFISH "blowfish-cbc," | #define BLOWFISH "blowfish-cbc," | |||
#define AES "aes256-cbc,aes192-cbc,aes128-cbc," | #define AES "aes256-cbc,aes192-cbc,aes128-cbc," | |||
#define DES "3des-cbc" | #define DES "3des-cbc" | |||
#elif defined HAVE_LIBCRYPTO | #elif defined HAVE_LIBCRYPTO | |||
#ifdef HAVE_OPENSSL_BLOWFISH_H | #ifdef HAVE_OPENSSL_BLOWFISH_H | |||
#define BLOWFISH "blowfish-cbc," | #define BLOWFISH "blowfish-cbc," | |||
#else | #else | |||
#define BLOWFISH "" | #define BLOWFISH "" | |||
skipping to change at line 235 | skipping to change at line 242 | |||
} | } | |||
} | } | |||
} | } | |||
free(tok_in[0]); | free(tok_in[0]); | |||
free(tok_what[0]); | free(tok_what[0]); | |||
free(tok_in); | free(tok_in); | |||
free(tok_what); | free(tok_what); | |||
return NULL; | return NULL; | |||
} | } | |||
int ssh_get_kex(SSH_SESSION *session, int server_kex) { | int ssh_get_kex(ssh_session session, int server_kex) { | |||
STRING *str = NULL; | ssh_string str = NULL; | |||
char *strings[10]; | char *strings[10]; | |||
int i; | int i; | |||
enter_function(); | enter_function(); | |||
if (packet_wait(session, SSH2_MSG_KEXINIT, 1) != SSH_OK) { | if (packet_wait(session, SSH2_MSG_KEXINIT, 1) != SSH_OK) { | |||
leave_function(); | leave_function(); | |||
return -1; | return -1; | |||
} | } | |||
skipping to change at line 314 | skipping to change at line 321 | |||
error: | error: | |||
string_free(str); | string_free(str); | |||
for (i = 0; i < 10; i++) { | for (i = 0; i < 10; i++) { | |||
SAFE_FREE(strings[i]); | SAFE_FREE(strings[i]); | |||
} | } | |||
leave_function(); | leave_function(); | |||
return -1; | return -1; | |||
} | } | |||
void ssh_list_kex(struct ssh_session *session, KEX *kex) { | void ssh_list_kex(ssh_session session, KEX *kex) { | |||
int i = 0; | int i = 0; | |||
#ifdef DEBUG_CRYPTO | #ifdef DEBUG_CRYPTO | |||
ssh_print_hexa("session cookie", kex->cookie, 16); | ssh_print_hexa("session cookie", kex->cookie, 16); | |||
#endif | #endif | |||
for(i = 0; i < 10; i++) { | for(i = 0; i < 10; i++) { | |||
ssh_log(session, SSH_LOG_FUNCTIONS, "%s: %s", | ssh_log(session, SSH_LOG_FUNCTIONS, "%s: %s", | |||
ssh_kex_nums[i], kex->methods[i]); | ssh_kex_nums[i], kex->methods[i]); | |||
} | } | |||
} | } | |||
/* set_kex basicaly look at the option structure of the session and set the output kex message */ | /* set_kex basicaly look at the option structure of the session and set the output kex message */ | |||
/* it must be aware of the server kex message */ | /* it must be aware of the server kex message */ | |||
/* it can fail if option is null, not any user specified kex method matches the server one, if not any default kex matches */ | /* it can fail if option is null, not any user specified kex method matches the server one, if not any default kex matches */ | |||
int set_kex(SSH_SESSION *session){ | int set_kex(ssh_session session){ | |||
KEX *server = &session->server_kex; | KEX *server = &session->server_kex; | |||
KEX *client=&session->client_kex; | KEX *client=&session->client_kex; | |||
SSH_OPTIONS *options=session->options; | ||||
int i; | int i; | |||
const char *wanted; | const char *wanted; | |||
enter_function(); | enter_function(); | |||
/* the client might ask for a specific cookie to be sent. useful for se | ssh_get_random(client->cookie,16,0); | |||
rver debugging */ | ||||
if(options->wanted_cookie) | ||||
memcpy(client->cookie,options->wanted_cookie,16); | ||||
else | ||||
ssh_get_random(client->cookie,16,0); | ||||
client->methods=malloc(10 * sizeof(char **)); | client->methods=malloc(10 * sizeof(char **)); | |||
if (client->methods == NULL) { | if (client->methods == NULL) { | |||
ssh_set_error(session, SSH_FATAL, "No space left"); | ssh_set_error(session, SSH_FATAL, "No space left"); | |||
leave_function(); | leave_function(); | |||
return -1; | return -1; | |||
} | } | |||
memset(client->methods,0,10*sizeof(char **)); | memset(client->methods,0,10*sizeof(char **)); | |||
for (i=0;i<10;i++){ | for (i=0;i<10;i++){ | |||
if(!(wanted=options->wanted_methods[i])) | if(!(wanted=session->wanted_methods[i])) | |||
wanted=default_methods[i]; | wanted=default_methods[i]; | |||
client->methods[i]=ssh_find_matching(server->methods[i],wanted); | client->methods[i]=ssh_find_matching(server->methods[i],wanted); | |||
if(!client->methods[i] && i < SSH_LANG_C_S){ | if(!client->methods[i] && i < SSH_LANG_C_S){ | |||
ssh_set_error(session,SSH_FATAL,"kex error : did not find one o f algos %s in list %s for %s", | ssh_set_error(session,SSH_FATAL,"kex error : did not find one o f algos %s in list %s for %s", | |||
wanted,server->methods[i],ssh_kex_nums[i]); | wanted,server->methods[i],ssh_kex_nums[i]); | |||
leave_function(); | leave_function(); | |||
return -1; | return -1; | |||
} else { | } else { | |||
if ((i >= SSH_LANG_C_S) && (client->methods[i] == NULL)) { | if ((i >= SSH_LANG_C_S) && (client->methods[i] == NULL)) { | |||
/* we can safely do that for languages */ | /* we can safely do that for languages */ | |||
skipping to change at line 374 | skipping to change at line 376 | |||
return -1; | return -1; | |||
} | } | |||
} | } | |||
} | } | |||
} | } | |||
leave_function(); | leave_function(); | |||
return 0; | return 0; | |||
} | } | |||
/* this function only sends the predefined set of kex methods */ | /* this function only sends the predefined set of kex methods */ | |||
int ssh_send_kex(SSH_SESSION *session, int server_kex) { | int ssh_send_kex(ssh_session session, int server_kex) { | |||
KEX *kex = (server_kex ? &session->server_kex : &session->client_kex); | KEX *kex = (server_kex ? &session->server_kex : &session->client_kex); | |||
STRING *str = NULL; | ssh_string str = NULL; | |||
int i; | int i; | |||
enter_function(); | enter_function(); | |||
if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXINIT) < 0) { | if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXINIT) < 0) { | |||
goto error; | goto error; | |||
} | } | |||
if (buffer_add_data(session->out_buffer, kex->cookie, 16) < 0) { | if (buffer_add_data(session->out_buffer, kex->cookie, 16) < 0) { | |||
goto error; | goto error; | |||
} | } | |||
skipping to change at line 447 | skipping to change at line 449 | |||
ptr=ssh_find_matching(supported_methods[algo],name); | ptr=ssh_find_matching(supported_methods[algo],name); | |||
if(ptr){ | if(ptr){ | |||
free(ptr); | free(ptr); | |||
return 1; | return 1; | |||
} | } | |||
return 0; | return 0; | |||
} | } | |||
/* makes a STRING contating 3 strings : ssh-rsa1,e and n */ | /* makes a STRING contating 3 strings : ssh-rsa1,e and n */ | |||
/* this is a public key in openssh's format */ | /* this is a public key in openssh's format */ | |||
static STRING *make_rsa1_string(STRING *e, STRING *n){ | static ssh_string make_rsa1_string(ssh_string e, ssh_string n){ | |||
BUFFER *buffer = NULL; | ssh_buffer buffer = NULL; | |||
STRING *rsa = NULL; | ssh_string rsa = NULL; | |||
STRING *ret = NULL; | ssh_string ret = NULL; | |||
buffer = buffer_new(); | buffer = buffer_new(); | |||
rsa = string_from_char("ssh-rsa1"); | rsa = string_from_char("ssh-rsa1"); | |||
if (buffer_add_ssh_string(buffer, rsa) < 0) { | if (buffer_add_ssh_string(buffer, rsa) < 0) { | |||
goto error; | goto error; | |||
} | } | |||
if (buffer_add_ssh_string(buffer, e) < 0) { | if (buffer_add_ssh_string(buffer, e) < 0) { | |||
goto error; | goto error; | |||
} | } | |||
skipping to change at line 478 | skipping to change at line 480 | |||
} | } | |||
string_fill(ret, buffer_get(buffer), buffer_get_len(buffer)); | string_fill(ret, buffer_get(buffer), buffer_get_len(buffer)); | |||
error: | error: | |||
buffer_free(buffer); | buffer_free(buffer); | |||
string_free(rsa); | string_free(rsa); | |||
return ret; | return ret; | |||
} | } | |||
static int build_session_id1(SSH_SESSION *session, STRING *servern, | static int build_session_id1(ssh_session session, ssh_string servern, | |||
STRING *hostn) { | ssh_string hostn) { | |||
MD5CTX md5 = NULL; | MD5CTX md5 = NULL; | |||
md5 = md5_init(); | md5 = md5_init(); | |||
if (md5 == NULL) { | if (md5 == NULL) { | |||
return -1; | return -1; | |||
} | } | |||
#ifdef DEBUG_CRYPTO | #ifdef DEBUG_CRYPTO | |||
ssh_print_hexa("host modulus",hostn->string,string_len(hostn)); | ssh_print_hexa("host modulus",hostn->string,string_len(hostn)); | |||
ssh_print_hexa("server modulus",servern->string,string_len(servern)); | ssh_print_hexa("server modulus",servern->string,string_len(servern)); | |||
#endif | #endif | |||
md5_update(md5,hostn->string,string_len(hostn)); | md5_update(md5,string_data(hostn),string_len(hostn)); | |||
md5_update(md5,servern->string,string_len(servern)); | md5_update(md5,string_data(servern),string_len(servern)); | |||
md5_update(md5,session->server_kex.cookie,8); | md5_update(md5,session->server_kex.cookie,8); | |||
md5_final(session->next_crypto->session_id,md5); | md5_final(session->next_crypto->session_id,md5); | |||
#ifdef DEBUG_CRYPTO | #ifdef DEBUG_CRYPTO | |||
ssh_print_hexa("session_id",session->next_crypto->session_id,MD5_DIGEST_L EN); | ssh_print_hexa("session_id",session->next_crypto->session_id,MD5_DIGEST_L EN); | |||
#endif | #endif | |||
return 0; | return 0; | |||
} | } | |||
/* returns 1 if the modulus of k1 is < than the one of k2 */ | /* returns 1 if the modulus of k1 is < than the one of k2 */ | |||
static int modulus_smaller(PUBLIC_KEY *k1, PUBLIC_KEY *k2){ | static int modulus_smaller(ssh_public_key k1, ssh_public_key k2){ | |||
bignum n1; | bignum n1; | |||
bignum n2; | bignum n2; | |||
int res; | int res; | |||
#ifdef HAVE_LIBGCRYPT | #ifdef HAVE_LIBGCRYPT | |||
gcry_sexp_t sexp; | gcry_sexp_t sexp; | |||
sexp=gcry_sexp_find_token(k1->rsa_pub,"n",0); | sexp=gcry_sexp_find_token(k1->rsa_pub,"n",0); | |||
n1=gcry_sexp_nth_mpi(sexp,1,GCRYMPI_FMT_USG); | n1=gcry_sexp_nth_mpi(sexp,1,GCRYMPI_FMT_USG); | |||
gcry_sexp_release(sexp); | gcry_sexp_release(sexp); | |||
sexp=gcry_sexp_find_token(k2->rsa_pub,"n",0); | sexp=gcry_sexp_find_token(k2->rsa_pub,"n",0); | |||
n2=gcry_sexp_nth_mpi(sexp,1,GCRYMPI_FMT_USG); | n2=gcry_sexp_nth_mpi(sexp,1,GCRYMPI_FMT_USG); | |||
skipping to change at line 532 | skipping to change at line 534 | |||
res=0; | res=0; | |||
#ifdef HAVE_LIBGCRYPT | #ifdef HAVE_LIBGCRYPT | |||
bignum_free(n1); | bignum_free(n1); | |||
bignum_free(n2); | bignum_free(n2); | |||
#endif | #endif | |||
return res; | return res; | |||
} | } | |||
#define ABS(A) ( (A)<0 ? -(A):(A) ) | #define ABS(A) ( (A)<0 ? -(A):(A) ) | |||
static STRING *encrypt_session_key(SSH_SESSION *session, PUBLIC_KEY *srvkey | static ssh_string encrypt_session_key(ssh_session session, ssh_public_key s | |||
, | rvkey, | |||
PUBLIC_KEY *hostkey, int slen, int hlen) { | ssh_public_key hostkey, int slen, int hlen) { | |||
unsigned char buffer[32] = {0}; | unsigned char buffer[32] = {0}; | |||
int i; | int i; | |||
STRING *data1 = NULL; | ssh_string data1 = NULL; | |||
STRING *data2 = NULL; | ssh_string data2 = NULL; | |||
/* first, generate a session key */ | /* first, generate a session key */ | |||
ssh_get_random(session->next_crypto->encryptkey, 32, 1); | ssh_get_random(session->next_crypto->encryptkey, 32, 1); | |||
memcpy(buffer, session->next_crypto->encryptkey, 32); | memcpy(buffer, session->next_crypto->encryptkey, 32); | |||
memcpy(session->next_crypto->decryptkey, session->next_crypto->encryptkey , 32); | memcpy(session->next_crypto->decryptkey, session->next_crypto->encryptkey , 32); | |||
#ifdef DEBUG_CRYPTO | #ifdef DEBUG_CRYPTO | |||
ssh_print_hexa("session key",buffer,32); | ssh_print_hexa("session key",buffer,32); | |||
#endif | #endif | |||
skipping to change at line 608 | skipping to change at line 610 | |||
* mp-int server_key_public_exponent | * mp-int server_key_public_exponent | |||
* mp-int server_key_public_modulus | * mp-int server_key_public_modulus | |||
* 32-bit int host_key_bits | * 32-bit int host_key_bits | |||
* mp-int host_key_public_exponent | * mp-int host_key_public_exponent | |||
* mp-int host_key_public_modulus | * mp-int host_key_public_modulus | |||
* 32-bit int protocol_flags | * 32-bit int protocol_flags | |||
* 32-bit int supported_ciphers_mask | * 32-bit int supported_ciphers_mask | |||
* 32-bit int supported_authentications_mask | * 32-bit int supported_authentications_mask | |||
*/ | */ | |||
int ssh_get_kex1(SSH_SESSION *session) { | int ssh_get_kex1(ssh_session session) { | |||
STRING *server_exp = NULL; | ssh_string server_exp = NULL; | |||
STRING *server_mod = NULL; | ssh_string server_mod = NULL; | |||
STRING *host_exp = NULL; | ssh_string host_exp = NULL; | |||
STRING *host_mod = NULL; | ssh_string host_mod = NULL; | |||
STRING *serverkey = NULL; | ssh_string serverkey = NULL; | |||
STRING *hostkey = NULL; | ssh_string hostkey = NULL; | |||
STRING *enc_session = NULL; | ssh_string enc_session = NULL; | |||
PUBLIC_KEY *srv = NULL; | ssh_public_key srv = NULL; | |||
PUBLIC_KEY *host = NULL; | ssh_public_key host = NULL; | |||
u32 server_bits; | uint32_t server_bits; | |||
u32 host_bits; | uint32_t host_bits; | |||
u32 protocol_flags; | uint32_t protocol_flags; | |||
u32 supported_ciphers_mask; | uint32_t supported_ciphers_mask; | |||
u32 supported_authentications_mask; | uint32_t supported_authentications_mask; | |||
u16 bits; | uint16_t bits; | |||
int rc = -1; | int rc = -1; | |||
int ko; | int ko; | |||
enter_function(); | enter_function(); | |||
ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_PUBLIC_KEY"); | ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_PUBLIC_KEY"); | |||
if (packet_wait(session, SSH_SMSG_PUBLIC_KEY, 1) != SSH_OK) { | if (packet_wait(session, SSH_SMSG_PUBLIC_KEY, 1) != SSH_OK) { | |||
leave_function(); | leave_function(); | |||
return -1; | return -1; | |||
} | } | |||
skipping to change at line 663 | skipping to change at line 665 | |||
goto error; | goto error; | |||
} | } | |||
host_mod = buffer_get_mpint(session->in_buffer); | host_mod = buffer_get_mpint(session->in_buffer); | |||
if (host_mod == NULL) { | if (host_mod == NULL) { | |||
goto error; | goto error; | |||
} | } | |||
buffer_get_u32(session->in_buffer, &protocol_flags); | buffer_get_u32(session->in_buffer, &protocol_flags); | |||
buffer_get_u32(session->in_buffer, &supported_ciphers_mask); | buffer_get_u32(session->in_buffer, &supported_ciphers_mask); | |||
ko = buffer_get_u32(session->in_buffer, &supported_authentications_mask); | ko = buffer_get_u32(session->in_buffer, &supported_authentications_mask); | |||
if ((ko != sizeof(u32)) || !host_mod || !host_exp | if ((ko != sizeof(uint32_t)) || !host_mod || !host_exp | |||
|| !server_mod || !server_exp) { | || !server_mod || !server_exp) { | |||
ssh_log(session, SSH_LOG_RARE, "Invalid SSH_SMSG_PUBLIC_KEY packet"); | ssh_log(session, SSH_LOG_RARE, "Invalid SSH_SMSG_PUBLIC_KEY packet"); | |||
ssh_set_error(session, SSH_FATAL, "Invalid SSH_SMSG_PUBLIC_KEY packet") ; | ssh_set_error(session, SSH_FATAL, "Invalid SSH_SMSG_PUBLIC_KEY packet") ; | |||
goto error; | goto error; | |||
} | } | |||
server_bits = ntohl(server_bits); | server_bits = ntohl(server_bits); | |||
host_bits = ntohl(host_bits); | host_bits = ntohl(host_bits); | |||
protocol_flags = ntohl(protocol_flags); | protocol_flags = ntohl(protocol_flags); | |||
supported_ciphers_mask = ntohl(supported_ciphers_mask); | supported_ciphers_mask = ntohl(supported_ciphers_mask); | |||
skipping to change at line 740 | skipping to change at line 742 | |||
enc_session = encrypt_session_key(session, srv, host, server_bits, host_b its); | enc_session = encrypt_session_key(session, srv, host, server_bits, host_b its); | |||
if (enc_session == NULL) { | if (enc_session == NULL) { | |||
goto error; | goto error; | |||
} | } | |||
bits = string_len(enc_session) * 8 - 7; | bits = string_len(enc_session) * 8 - 7; | |||
ssh_log(session, SSH_LOG_PROTOCOL, "%d bits, %zu bytes encrypted session" , | ssh_log(session, SSH_LOG_PROTOCOL, "%d bits, %zu bytes encrypted session" , | |||
bits, string_len(enc_session)); | bits, string_len(enc_session)); | |||
bits = htons(bits); | bits = htons(bits); | |||
/* the encrypted mpint */ | /* the encrypted mpint */ | |||
if (buffer_add_data(session->out_buffer, &bits, sizeof(u16)) < 0) { | if (buffer_add_data(session->out_buffer, &bits, sizeof(uint16_t)) < 0) { | |||
goto error; | goto error; | |||
} | } | |||
if (buffer_add_data(session->out_buffer, enc_session->string, | if (buffer_add_data(session->out_buffer, string_data(enc_session), | |||
string_len(enc_session)) < 0) { | string_len(enc_session)) < 0) { | |||
goto error; | goto error; | |||
} | } | |||
/* the protocol flags */ | /* the protocol flags */ | |||
if (buffer_add_u32(session->out_buffer, 0) < 0) { | if (buffer_add_u32(session->out_buffer, 0) < 0) { | |||
goto error; | goto error; | |||
} | } | |||
if (packet_send(session) != SSH_OK) { | if (packet_send(session) != SSH_OK) { | |||
goto error; | goto error; | |||
End of changes. 21 change blocks. | ||||
48 lines changed or deleted | 49 lines changed or added | |||
This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/ |