1
1
Signed-off-by: Aris Adamantiadis <aris@0xbadc0de.be>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Этот коммит содержится в:
Aris Adamantiadis 2018-11-06 16:12:20 +01:00 коммит произвёл Andreas Schneider
родитель a6c47099b7
Коммит 9c88769707
5 изменённых файлов: 222 добавлений и 351 удалений

Просмотреть файл

@ -93,6 +93,8 @@ enum ssh_cipher_e {
struct ssh_crypto_struct { struct ssh_crypto_struct {
bignum e,f,x,k,y; bignum e,f,x,k,y;
bignum g, p;
int dh_group_is_mutable; /* do free group parameters */
#ifdef HAVE_ECDH #ifdef HAVE_ECDH
#ifdef HAVE_OPENSSL_ECC #ifdef HAVE_OPENSSL_ECC
EC_KEY *ecdh_privkey; EC_KEY *ecdh_privkey;

Просмотреть файл

@ -25,20 +25,9 @@
#include "libssh/crypto.h" #include "libssh/crypto.h"
int ssh_dh_generate_e(ssh_session session);
int ssh_dh_generate_f(ssh_session session);
int ssh_dh_generate_x(ssh_session session);
int ssh_dh_generate_y(ssh_session session);
int ssh_dh_init(void); int ssh_dh_init(void);
void ssh_dh_finalize(void); void ssh_dh_finalize(void);
ssh_string ssh_dh_get_e(ssh_session session);
ssh_string ssh_dh_get_f(ssh_session session);
int ssh_dh_import_f(ssh_session session,ssh_string f_string);
int ssh_dh_import_e(ssh_session session, ssh_string e_string);
int ssh_dh_import_pubkey_blob(ssh_session session, ssh_string pubkey_blob);
int ssh_dh_import_next_pubkey_blob(ssh_session session, ssh_string pubkey_blob); int ssh_dh_import_next_pubkey_blob(ssh_session session, ssh_string pubkey_blob);
int ssh_dh_build_k(ssh_session session); int ssh_dh_build_k(ssh_session session);
@ -54,4 +43,9 @@ int ssh_dh_get_next_server_publickey_blob(ssh_session session,
#ifdef WITH_SERVER #ifdef WITH_SERVER
void ssh_server_dh_init(ssh_session session); void ssh_server_dh_init(ssh_session session);
#endif /* WITH_SERVER */ #endif /* WITH_SERVER */
int ssh_dh_init_common(ssh_session session);
void ssh_dh_cleanup(ssh_session session);
int ssh_dh_generate_secret(ssh_session session, bignum dest);
#endif /* DH_H_ */ #endif /* DH_H_ */

548
src/dh.c
Просмотреть файл

@ -3,7 +3,7 @@
* *
* This file is part of the SSH Library * This file is part of the SSH Library
* *
* Copyright (c) 2003-2013 by Aris Adamantiadis * Copyright (c) 2003-2018 by Aris Adamantiadis
* Copyright (c) 2009-2013 by Andreas Schneider <asn@cryptomilk.org> * Copyright (c) 2009-2013 by Andreas Schneider <asn@cryptomilk.org>
* Copyright (c) 2012 by Dmitriy Kuznetsov <dk@yandex.ru> * Copyright (c) 2012 by Dmitriy Kuznetsov <dk@yandex.ru>
* *
@ -23,34 +23,7 @@
* MA 02111-1307, USA. * MA 02111-1307, USA.
*/ */
/*
* Let us resume the dh protocol.
* Each side computes a private prime number, x at client side, y at server
* side.
* g and n are two numbers common to every ssh software.
* client's public key (e) is calculated by doing:
* e = g^x mod p
* client sends e to the server.
* the server computes his own public key, f
* f = g^y mod p
* it sends it to the client
* the common key K is calculated by the client by doing
* k = f^x mod p
* the server does the same with the client public key e
* k' = e^y mod p
* if everything went correctly, k and k' are equal
*/
#include "config.h" #include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#ifndef _WIN32
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#include "libssh/priv.h" #include "libssh/priv.h"
#include "libssh/crypto.h" #include "libssh/crypto.h"
@ -62,15 +35,6 @@
#include "libssh/pki.h" #include "libssh/pki.h"
#include "libssh/bignum.h" #include "libssh/bignum.h"
/* todo: remove it */
#include "libssh/string.h"
#ifdef HAVE_LIBCRYPTO
#include <openssl/rand.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include "libssh/libcrypto.h"
#endif
static unsigned char p_group1_value[] = { static unsigned char p_group1_value[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
@ -248,6 +212,11 @@ static unsigned char p_group18_value[] = {
0xFF, 0xFF, 0xFF, 0xFF}; 0xFF, 0xFF, 0xFF, 0xFF};
#define P_GROUP18_LEN 1024 /* Size in bytes of the p number for group 18 */ #define P_GROUP18_LEN 1024 /* Size in bytes of the p number for group 18 */
/*
* How many bits of security we want for fast DH. DH private key size must be
* twice that size.
*/
#define DH_SECURITY_BITS 512
static unsigned long g_int = 2 ; /* G is defined as 2 by the ssh2 standards */ static unsigned long g_int = 2 ; /* G is defined as 2 by the ssh2 standards */
static bignum g; static bignum g;
@ -257,21 +226,6 @@ static bignum p_group16;
static bignum p_group18; static bignum p_group18;
static int dh_crypto_initialized; static int dh_crypto_initialized;
static bignum select_p(enum ssh_key_exchange_e type) {
switch(type) {
case SSH_KEX_DH_GROUP1_SHA1:
return p_group1;
case SSH_KEX_DH_GROUP14_SHA1:
return p_group14;
case SSH_KEX_DH_GROUP16_SHA512:
return p_group16;
case SSH_KEX_DH_GROUP18_SHA512:
return p_group18;
default:
return NULL;
}
}
/** /**
* @internal * @internal
* @brief Initialize global constants used in DH key agreement * @brief Initialize global constants used in DH key agreement
@ -356,140 +310,63 @@ void ssh_dh_finalize(void)
dh_crypto_initialized = 0; dh_crypto_initialized = 0;
} }
int ssh_dh_generate_x(ssh_session session) /**
{ * @internal
size_t keysize; * @brief allocate and initialize ephemeral values used in dh kex
*/
int ssh_dh_init_common(ssh_session session){
struct ssh_crypto_struct *crypto=session->next_crypto;
crypto->x = bignum_new();
crypto->y = bignum_new();
crypto->e = NULL;
crypto->f = NULL;
crypto->k = bignum_new();
crypto->g = NULL;
crypto->p = NULL;
crypto->dh_group_is_mutable = 0;
switch(session->next_crypto->kex_type) { switch(session->next_crypto->kex_type) {
case SSH_KEX_DH_GROUP1_SHA1: case SSH_KEX_DH_GROUP1_SHA1:
keysize = 1023; session->next_crypto->p = p_group1;
session->next_crypto->g = g;
session->next_crypto->dh_group_is_mutable = 0;
break; break;
case SSH_KEX_DH_GROUP14_SHA1: case SSH_KEX_DH_GROUP14_SHA1:
keysize = 2047; session->next_crypto->p = p_group14;
session->next_crypto->g = g;
session->next_crypto->dh_group_is_mutable = 0;
break; break;
case SSH_KEX_DH_GROUP16_SHA512: case SSH_KEX_DH_GROUP16_SHA512:
keysize = 4095; session->next_crypto->p = p_group16;
session->next_crypto->g = g;
session->next_crypto->dh_group_is_mutable = 0;
break; break;
case SSH_KEX_DH_GROUP18_SHA512: case SSH_KEX_DH_GROUP18_SHA512:
keysize = 8191; session->next_crypto->p = p_group18;
session->next_crypto->g = g;
session->next_crypto->dh_group_is_mutable = 0;
break;
default:
/* fall through */
break; break;
default:
return -1;
} }
if (crypto->x == NULL || crypto->y == NULL || crypto->k == NULL){
session->next_crypto->x = bignum_new(); ssh_set_error_oom(session);
if (session->next_crypto->x == NULL) { return SSH_ERROR;
return -1; } else {
return SSH_OK;
} }
bignum_rand(session->next_crypto->x, keysize);
/* not harder than this */
#ifdef DEBUG_CRYPTO
ssh_print_bignum("x", session->next_crypto->x);
#endif
return 0;
} }
/* used by server */ void ssh_dh_cleanup(ssh_session session){
int ssh_dh_generate_y(ssh_session session) struct ssh_crypto_struct *crypto=session->next_crypto;
{ bignum_safe_free(crypto->x);
size_t keysize; bignum_safe_free(crypto->y);
bignum_safe_free(crypto->e);
switch(session->next_crypto->kex_type) { bignum_safe_free(crypto->f);
case SSH_KEX_DH_GROUP1_SHA1: if (crypto->dh_group_is_mutable){
keysize = 1023; bignum_safe_free(crypto->p);
break; bignum_safe_free(crypto->g);
case SSH_KEX_DH_GROUP14_SHA1:
keysize = 2047;
break;
case SSH_KEX_DH_GROUP16_SHA512:
keysize = 4095;
break;
case SSH_KEX_DH_GROUP18_SHA512:
keysize = 8191;
break;
default:
return -1;
} }
session->next_crypto->y = bignum_new();
if (session->next_crypto->y == NULL) {
return -1;
}
bignum_rand(session->next_crypto->y, keysize);
/* not harder than this */
#ifdef DEBUG_CRYPTO
ssh_print_bignum("y", session->next_crypto->y);
#endif
return 0;
}
/* used by server */
int ssh_dh_generate_e(ssh_session session) {
bignum_CTX ctx = bignum_ctx_new();
if (bignum_ctx_invalid(ctx)) {
return -1;
}
session->next_crypto->e = bignum_new();
if (session->next_crypto->e == NULL) {
bignum_ctx_free(ctx);
return -1;
}
bignum_mod_exp(session->next_crypto->e, g, session->next_crypto->x,
select_p(session->next_crypto->kex_type), ctx);
#ifdef DEBUG_CRYPTO
ssh_print_bignum("e", session->next_crypto->e);
#endif
bignum_ctx_free(ctx);
return 0;
}
int ssh_dh_generate_f(ssh_session session) {
bignum_CTX ctx = bignum_ctx_new();
if (bignum_ctx_invalid(ctx)) {
return -1;
}
session->next_crypto->f = bignum_new();
if (session->next_crypto->f == NULL) {
bignum_ctx_free(ctx);
return -1;
}
bignum_mod_exp(session->next_crypto->f, g, session->next_crypto->y,
select_p(session->next_crypto->kex_type), ctx);
#ifdef DEBUG_CRYPTO
ssh_print_bignum("f", session->next_crypto->f);
#endif
bignum_ctx_free(ctx);
return 0;
}
ssh_string ssh_dh_get_e(ssh_session session) {
return ssh_make_bignum_string(session->next_crypto->e);
}
/* used by server */
ssh_string ssh_dh_get_f(ssh_session session) {
return ssh_make_bignum_string(session->next_crypto->f);
}
int ssh_dh_import_pubkey_blob(ssh_session session, ssh_string pubkey_blob)
{
return ssh_pki_import_pubkey_blob(pubkey_blob,
&session->current_crypto->server_pubkey);
} }
int ssh_dh_import_next_pubkey_blob(ssh_session session, ssh_string pubkey_blob) int ssh_dh_import_next_pubkey_blob(ssh_session session, ssh_string pubkey_blob)
@ -499,31 +376,70 @@ int ssh_dh_import_next_pubkey_blob(ssh_session session, ssh_string pubkey_blob)
} }
int ssh_dh_import_f(ssh_session session, ssh_string f_string) {
session->next_crypto->f = ssh_make_string_bn(f_string);
if (session->next_crypto->f == NULL) {
return -1;
}
#ifdef DEBUG_CRYPTO #ifdef DEBUG_CRYPTO
ssh_print_bignum("f",session->next_crypto->f); static void ssh_dh_debug(ssh_session session){
#endif ssh_print_bignum("p", session->next_crypto->p);
ssh_print_bignum("g", session->next_crypto->g);
return 0; ssh_print_bignum("x", session->next_crypto->x);
ssh_print_bignum("y", session->next_crypto->y);
ssh_print_bignum("e", session->next_crypto->e);
ssh_print_bignum("f", session->next_crypto->f);
ssh_print_hexa("Session server cookie",
session->next_crypto->server_kex.cookie, 16);
ssh_print_hexa("Session client cookie",
session->next_crypto->client_kex.cookie, 16);
ssh_print_bignum("k", session->next_crypto->k);
} }
#else
/* used by the server implementation */ #define ssh_dh_debug(session)
int ssh_dh_import_e(ssh_session session, ssh_string e_string) {
session->next_crypto->e = ssh_make_string_bn(e_string);
if (session->next_crypto->e == NULL) {
return -1;
}
#ifdef DEBUG_CRYPTO
ssh_print_bignum("e",session->next_crypto->e);
#endif #endif
return 0; /** @internal
* @brief generates a secret DH parameter of at least DH_SECURITY_BITS
* security.
* @param[out] dest preallocated bignum where to store the parameter
* @return SSH_OK on success, SSH_ERROR on error
*/
int ssh_dh_generate_secret(ssh_session session, bignum dest)
{
bignum tmp = NULL;
bignum_CTX ctx = NULL;
int rc = 0;
int bits = 0;
int p_bits = 0;
ctx = bignum_ctx_new();
if (bignum_ctx_invalid(ctx)){
goto error;
}
tmp = bignum_new();
if (tmp == NULL) {
goto error;
}
p_bits = bignum_num_bits(session->next_crypto->p);
/* we need at most DH_SECURITY_BITS */
bits = MIN(DH_SECURITY_BITS * 2, p_bits);
/* ensure we're not too close of p so rnd()%p stays uniform */
if (bits <= p_bits && bits + 64 > p_bits) {
bits += 64;
}
rc = bignum_rand(tmp, bits);
if (rc != 1) {
goto error;
}
rc = bignum_mod(dest, tmp, session->next_crypto->p, ctx);
if (rc != 1) {
goto error;
}
bignum_safe_free(tmp);
bignum_ctx_free(ctx);
return SSH_OK;
error:
ssh_set_error_oom(session);
bignum_safe_free(tmp);
bignum_ctx_free(ctx);
return SSH_ERROR;
} }
int ssh_dh_build_k(ssh_session session) { int ssh_dh_build_k(ssh_session session) {
@ -533,30 +449,17 @@ int ssh_dh_build_k(ssh_session session) {
return -1; return -1;
} }
session->next_crypto->k = bignum_new();
if (session->next_crypto->k == NULL) {
bignum_ctx_free(ctx);
return -1;
}
/* the server and clients don't use the same numbers */ /* the server and clients don't use the same numbers */
if (session->client) { if (session->client) {
rc = bignum_mod_exp(session->next_crypto->k, session->next_crypto->f, rc = bignum_mod_exp(session->next_crypto->k, session->next_crypto->f,
session->next_crypto->x, select_p(session->next_crypto->kex_type), ctx); session->next_crypto->x, session->next_crypto->p, ctx);
} else { } else {
rc = bignum_mod_exp(session->next_crypto->k, session->next_crypto->e, rc = bignum_mod_exp(session->next_crypto->k, session->next_crypto->e,
session->next_crypto->y, select_p(session->next_crypto->kex_type), ctx); session->next_crypto->y, session->next_crypto->p, ctx);
} }
#ifdef DEBUG_CRYPTO
ssh_print_hexa("Session server cookie",
session->next_crypto->server_kex.cookie, 16);
ssh_print_hexa("Session client cookie",
session->next_crypto->client_kex.cookie, 16);
ssh_print_bignum("Shared secret key", session->next_crypto->k);
#endif
bignum_ctx_free(ctx); bignum_ctx_free(ctx);
ssh_dh_debug();
if (rc != 1) { if (rc != 1) {
return SSH_ERROR; return SSH_ERROR;
} }
@ -580,88 +483,71 @@ static struct ssh_packet_callbacks_struct ssh_dh_client_callbacks = {
* @brief Starts diffie-hellman-group1 key exchange * @brief Starts diffie-hellman-group1 key exchange
*/ */
int ssh_client_dh_init(ssh_session session){ int ssh_client_dh_init(ssh_session session){
ssh_string e = NULL; bignum_CTX ctx = bignum_ctx_new();
int rc; int rc;
if (ssh_dh_generate_x(session) < 0) { if (bignum_ctx_invalid(ctx)) {
goto error; goto error;
} }
if (ssh_dh_generate_e(session) < 0) { rc = ssh_dh_init_common(session);
if (rc == SSH_ERROR) {
goto error; goto error;
} }
e = ssh_dh_get_e(session); rc = ssh_dh_generate_secret(session, session->next_crypto->x);
if (e == NULL) { if (rc == SSH_ERROR){
goto error;
}
session->next_crypto->e = bignum_new();
if (session->next_crypto->e == NULL){
goto error;
}
rc = bignum_mod_exp(session->next_crypto->e, session->next_crypto->g, session->next_crypto->x,
session->next_crypto->p, ctx);
bignum_ctx_free(ctx);
if (rc != 1) {
goto error; goto error;
} }
rc = ssh_buffer_pack(session->out_buffer, "bB", SSH2_MSG_KEXDH_INIT, session->next_crypto->e);
rc = ssh_buffer_pack(session->out_buffer, "bS", SSH2_MSG_KEXDH_INIT, e);
if (rc != SSH_OK) { if (rc != SSH_OK) {
goto error; goto error;
} }
ssh_string_burn(e);
ssh_string_free(e);
e=NULL;
/* register the packet callbacks */ /* register the packet callbacks */
ssh_packet_set_callbacks(session, &ssh_dh_client_callbacks); ssh_packet_set_callbacks(session, &ssh_dh_client_callbacks);
rc = ssh_packet_send(session); rc = ssh_packet_send(session);
return rc; return rc;
error: error:
if(e != NULL){ ssh_dh_cleanup(session);
ssh_string_burn(e);
ssh_string_free(e);
}
return SSH_ERROR; return SSH_ERROR;
} }
SSH_PACKET_CALLBACK(ssh_packet_client_dh_reply){ SSH_PACKET_CALLBACK(ssh_packet_client_dh_reply){
ssh_string f; struct ssh_crypto_struct *crypto=session->next_crypto;
ssh_string pubkey_blob = NULL; ssh_string pubkey_blob = NULL;
ssh_string signature = NULL;
int rc; int rc;
(void)type; (void)type;
(void)user; (void)user;
ssh_packet_remove_callbacks(session, &ssh_dh_client_callbacks); ssh_packet_remove_callbacks(session, &ssh_dh_client_callbacks);
pubkey_blob = ssh_buffer_get_ssh_string(packet); rc = ssh_buffer_unpack(packet, "SBS", &pubkey_blob, &crypto->f,
if (pubkey_blob == NULL){ &crypto->dh_server_signature);
ssh_set_error(session,SSH_FATAL, "No public key in packet"); if (rc == SSH_ERROR) {
goto error; goto error;
} }
rc = ssh_dh_import_next_pubkey_blob(session, pubkey_blob); rc = ssh_dh_import_next_pubkey_blob(session, pubkey_blob);
ssh_string_free(pubkey_blob); ssh_string_free(pubkey_blob);
if (rc != 0) { if (rc != 0) {
goto error; goto error;
} }
f = ssh_buffer_get_ssh_string(packet); rc = ssh_dh_build_k(session);
if (f == NULL) { if (rc == SSH_ERROR){
ssh_set_error(session,SSH_FATAL, "No F number in packet"); ssh_set_error(session, SSH_FATAL, "Could not generate shared secret");
goto error;
}
rc = ssh_dh_import_f(session, f);
ssh_string_burn(f);
ssh_string_free(f);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL, "Cannot import f number");
goto error;
}
signature = ssh_buffer_get_ssh_string(packet);
if (signature == NULL) {
ssh_set_error(session, SSH_FATAL, "No signature in packet");
goto error;
}
session->next_crypto->dh_server_signature = signature;
signature=NULL; /* ownership changed */
if (ssh_dh_build_k(session) < 0) {
ssh_set_error(session, SSH_FATAL, "Cannot build k number");
goto error; goto error;
} }
@ -679,6 +565,7 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dh_reply){
session->dh_handshake_state = DH_STATE_NEWKEYS_SENT; session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
return SSH_PACKET_USED; return SSH_PACKET_USED;
error: error:
ssh_dh_cleanup(session);
session->session_state=SSH_SESSION_STATE_ERROR; session->session_state=SSH_SESSION_STATE_ERROR;
return SSH_PACKET_USED; return SSH_PACKET_USED;
} }
@ -704,128 +591,111 @@ static struct ssh_packet_callbacks_struct ssh_dh_server_callbacks = {
void ssh_server_dh_init(ssh_session session){ void ssh_server_dh_init(ssh_session session){
/* register the packet callbacks */ /* register the packet callbacks */
ssh_packet_set_callbacks(session, &ssh_dh_server_callbacks); ssh_packet_set_callbacks(session, &ssh_dh_server_callbacks);
ssh_dh_init_common(session);
} }
static int dh_handshake_server(ssh_session session) /** @internal
* @brief processes a SSH_MSG_KEXDH_INIT or SSH_MSG_KEX_DH_GEX_INIT packet and send
* the appropriate SSH_MSG_KEXDH_REPLY or SSH_MSG_KEX_DH_GEX_REPLY
*/
static SSH_PACKET_CALLBACK(ssh_packet_server_dh_init)
{ {
ssh_key privkey = NULL; ssh_key privkey = NULL;
ssh_string sig_blob = NULL; ssh_string sig_blob = NULL;
ssh_string f = NULL;
ssh_string pubkey_blob = NULL; ssh_string pubkey_blob = NULL;
bignum_CTX ctx = bignum_ctx_new();
int rc; int rc;
(void)type;
(void)user;
rc = ssh_dh_generate_y(session); if (bignum_ctx_invalid(ctx)) {
if (rc < 0) { goto error;
ssh_set_error(session, SSH_FATAL, "Could not create y number");
return -1;
} }
rc = ssh_dh_generate_f(session); ssh_packet_remove_callbacks(session, &ssh_dh_server_callbacks);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL, "Could not create f number"); rc = ssh_buffer_unpack(packet, "B", &session->next_crypto->e);
return -1; if (rc == SSH_ERROR) {
ssh_set_error(session, SSH_FATAL, "No e number in client request");
goto error;
} }
f = ssh_dh_get_f(session); rc = ssh_dh_generate_secret(session, session->next_crypto->y);
if (f == NULL) { if (rc == SSH_ERROR){
ssh_set_error(session, SSH_FATAL, "Could not get the f number"); goto error;
return -1;
} }
if (ssh_get_key_params(session,&privkey) != SSH_OK){ session->next_crypto->f = bignum_new();
ssh_string_free(f); if (session->next_crypto->f == NULL){
return -1; goto error;
}
rc = bignum_mod_exp(session->next_crypto->f,
session->next_crypto->g,
session->next_crypto->y,
session->next_crypto->p, ctx);
bignum_ctx_free(ctx);
ctx = NULL;
if (rc != 1) {
goto error;
} }
rc = ssh_get_key_params(session, &privkey);
if (rc != SSH_OK) {
goto error;
}
rc = ssh_dh_build_k(session); rc = ssh_dh_build_k(session);
if (rc < 0) { if (rc == SSH_ERROR) {
ssh_set_error(session, SSH_FATAL, "Could not import the public key"); ssh_set_error(session, SSH_FATAL, "Could not generate shared secret");
ssh_string_free(f); goto error;
return -1;
} }
rc = ssh_make_sessionid(session); rc = ssh_make_sessionid(session);
if (rc != SSH_OK) { if (rc != SSH_OK) {
ssh_set_error(session, SSH_FATAL, "Could not create a session id"); ssh_set_error(session, SSH_FATAL, "Could not create a session id");
ssh_string_free(f); goto error;
return -1;
} }
sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey); sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey);
if (sig_blob == NULL) { if (sig_blob == NULL) {
ssh_set_error(session, SSH_FATAL, "Could not sign the session id"); ssh_set_error(session, SSH_FATAL, "Could not sign the session id");
ssh_string_free(f); goto error;
return -1;
} }
rc = ssh_dh_get_next_server_publickey_blob(session, &pubkey_blob); rc = ssh_dh_get_next_server_publickey_blob(session, &pubkey_blob);
if (rc != SSH_OK){ if (rc != SSH_OK){
ssh_set_error_oom(session); ssh_set_error_oom(session);
ssh_string_free(f); goto error;
ssh_string_free(sig_blob);
return -1;
} }
rc = ssh_buffer_pack(session->out_buffer, rc = ssh_buffer_pack(session->out_buffer,
"bSSS", "bSBS",
SSH2_MSG_KEXDH_REPLY, SSH2_MSG_KEXDH_REPLY,
pubkey_blob, pubkey_blob,
f, session->next_crypto->f,
sig_blob); sig_blob);
ssh_string_free(f);
ssh_string_free(sig_blob); ssh_string_free(sig_blob);
if (rc != SSH_OK) { if(rc != SSH_OK) {
ssh_set_error_oom(session); ssh_set_error_oom(session);
ssh_buffer_reinit(session->out_buffer); ssh_buffer_reinit(session->out_buffer);
return -1; goto error;
} }
rc = ssh_packet_send(session); rc = ssh_packet_send(session);
if (rc == SSH_ERROR) { if (rc == SSH_ERROR) {
return -1; goto error;
} }
if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS);
if (rc < 0) {
ssh_buffer_reinit(session->out_buffer); ssh_buffer_reinit(session->out_buffer);
return -1; goto error;
} }
if (ssh_packet_send(session) == SSH_ERROR) {
rc = ssh_packet_send(session); goto error;
if (rc == SSH_ERROR) {
return -1;
} }
SSH_LOG(SSH_LOG_PACKET, "SSH_MSG_NEWKEYS sent"); SSH_LOG(SSH_LOG_PACKET, "SSH_MSG_NEWKEYS sent");
session->dh_handshake_state=DH_STATE_NEWKEYS_SENT; session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
ssh_dh_cleanup(session);
return 0;
}
/** @internal
* @brief parse an incoming SSH_MSG_KEXDH_INIT packet and complete
* Diffie-Hellman key exchange
**/
static SSH_PACKET_CALLBACK(ssh_packet_server_dh_init)
{
ssh_string e = NULL;
int rc;
(void)type;
(void)user;
ssh_packet_remove_callbacks(session, &ssh_dh_server_callbacks);
e = ssh_buffer_get_ssh_string(packet);
if (e == NULL) {
ssh_set_error(session, SSH_FATAL, "No e number in client request");
return -1;
}
rc = ssh_dh_import_e(session, e);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL, "Cannot import e number");
goto error;
}
session->dh_handshake_state = DH_STATE_INIT_SENT;
dh_handshake_server(session);
ssh_string_free(e);
return SSH_PACKET_USED; return SSH_PACKET_USED;
error: error:
ssh_dh_cleanup(session);
if (!bignum_ctx_invalid(ctx)) {
bignum_ctx_free(ctx);
}
session->session_state = SSH_SESSION_STATE_ERROR; session->session_state = SSH_SESSION_STATE_ERROR;
return SSH_PACKET_USED; return SSH_PACKET_USED;
} }

Просмотреть файл

@ -106,13 +106,17 @@ int ssh_gcry_rand_range(bignum dest, bignum max)
{ {
size_t bits; size_t bits;
bignum rnd; bignum rnd;
int rc;
bits = bignum_num_bits(max) + 64; bits = bignum_num_bits(max) + 64;
rnd = bignum_new(); rnd = bignum_new();
if (rnd == NULL) { if (rnd == NULL) {
return 0; return 0;
} }
bignum_rand(rnd, bits); rc = bignum_rand(rnd, bits);
if (rc != 1) {
return rc;
}
gcry_mpi_mod(dest, rnd, max); gcry_mpi_mod(dest, rnd, max);
bignum_safe_free(rnd); bignum_safe_free(rnd);
return 1; return 1;

Просмотреть файл

@ -1475,6 +1475,7 @@ int ssh_generate_session_keys(ssh_session session)
rc = 0; rc = 0;
error: error:
ssh_string_burn(k_string);
ssh_string_free(k_string); ssh_string_free(k_string);
return rc; return rc;