Implement key re-exchange
Этот коммит содержится в:
родитель
e934ab0816
Коммит
63c3f0e736
@ -65,6 +65,7 @@ struct ssh_crypto_struct {
|
||||
ssh_string dh_server_signature; /* information used by dh_handshake. */
|
||||
size_t digest_len; /* len of all the fields below */
|
||||
unsigned char *session_id;
|
||||
unsigned char *secret_hash; /* Secret hash is same as session id until re-kex */
|
||||
unsigned char *encryptIV;
|
||||
unsigned char *decryptIV;
|
||||
unsigned char *decryptkey;
|
||||
|
@ -66,6 +66,9 @@ enum ssh_pending_call_e {
|
||||
/* libssh calls may block an undefined amount of time */
|
||||
#define SSH_SESSION_FLAG_BLOCKING 1
|
||||
|
||||
/* Client successfully authenticated */
|
||||
#define SSH_SESSION_FLAG_AUTHENTICATED 2
|
||||
|
||||
/* codes to use with ssh_handle_packets*() */
|
||||
#define SSH_TIMEOUT_INFINITE -1
|
||||
#define SSH_TIMEOUT_USER -2
|
||||
|
@ -252,6 +252,8 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_success){
|
||||
|
||||
session->auth_state=SSH_AUTH_STATE_SUCCESS;
|
||||
session->session_state=SSH_SESSION_STATE_AUTHENTICATED;
|
||||
session->flags |= SSH_SESSION_FLAG_AUTHENTICATED;
|
||||
|
||||
if(session->current_crypto && session->current_crypto->delayed_compress_out){
|
||||
SSH_LOG(session, SSH_LOG_DEBUG, "Enabling delayed compression OUT");
|
||||
session->current_crypto->do_compress_out=1;
|
||||
|
@ -409,7 +409,10 @@ static void ssh_client_connection_callback(ssh_session session){
|
||||
if(session->dh_handshake_state==DH_STATE_FINISHED){
|
||||
set_status(session,1.0f);
|
||||
session->connected = 1;
|
||||
session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
|
||||
if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED)
|
||||
session->session_state = SSH_SESSION_STATE_AUTHENTICATED;
|
||||
else
|
||||
session->session_state=SSH_SESSION_STATE_AUTHENTICATING;
|
||||
}
|
||||
break;
|
||||
case SSH_SESSION_STATE_AUTHENTICATING:
|
||||
|
32
src/dh.c
32
src/dh.c
@ -788,31 +788,43 @@ int make_sessionid(ssh_session session) {
|
||||
case SSH_KEX_DH_GROUP14_SHA1:
|
||||
session->next_crypto->digest_len = SHA_DIGEST_LENGTH;
|
||||
session->next_crypto->mac_type = SSH_MAC_SHA1;
|
||||
session->next_crypto->session_id = malloc(session->next_crypto->digest_len);
|
||||
if(session->next_crypto->session_id == NULL){
|
||||
session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
|
||||
if(session->next_crypto->secret_hash == NULL){
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
sha1(buffer_get_rest(buf), buffer_get_rest_len(buf),
|
||||
session->next_crypto->session_id);
|
||||
session->next_crypto->secret_hash);
|
||||
break;
|
||||
case SSH_KEX_ECDH_SHA2_NISTP256:
|
||||
session->next_crypto->digest_len = SHA256_DIGEST_LENGTH;
|
||||
session->next_crypto->mac_type = SSH_MAC_SHA256;
|
||||
session->next_crypto->session_id = malloc(session->next_crypto->digest_len);
|
||||
if(session->next_crypto->session_id == NULL){
|
||||
session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
|
||||
if(session->next_crypto->secret_hash == NULL){
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
sha256(buffer_get_rest(buf), buffer_get_rest_len(buf),
|
||||
session->next_crypto->session_id);
|
||||
session->next_crypto->secret_hash);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* During the first kex, secret hash and session ID are equal. However, after
|
||||
* a key re-exchange, a new secret hash is calculated. This hash will not replace
|
||||
* but complement existing session id.
|
||||
*/
|
||||
if (!session->next_crypto->session_id){
|
||||
session->next_crypto->session_id = malloc(session->next_crypto->digest_len);
|
||||
if (session->next_crypto->session_id == NULL){
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
memcpy(session->next_crypto->session_id, session->next_crypto->secret_hash,
|
||||
session->next_crypto->digest_len);
|
||||
}
|
||||
#ifdef DEBUG_CRYPTO
|
||||
printf("Session hash: ");
|
||||
ssh_print_hexa("session id", session->next_crypto->session_id, SHA_DIGEST_LEN);
|
||||
ssh_print_hexa("secret hash", session->next_crypto->secret_hash, session->next_crypto->digest_len);
|
||||
ssh_print_hexa("session id", session->next_crypto->session_id, session->next_crypto->digest_len);
|
||||
#endif
|
||||
|
||||
rc = SSH_OK;
|
||||
@ -888,7 +900,7 @@ static int generate_one_key(ssh_string k,
|
||||
}
|
||||
|
||||
ssh_mac_update(ctx, k, ssh_string_len(k) + 4);
|
||||
ssh_mac_update(ctx, crypto->session_id, crypto->digest_len);
|
||||
ssh_mac_update(ctx, crypto->secret_hash, crypto->digest_len);
|
||||
ssh_mac_update(ctx, &letter, 1);
|
||||
ssh_mac_update(ctx, crypto->session_id, crypto->digest_len);
|
||||
ssh_mac_final(output, ctx);
|
||||
|
@ -276,7 +276,9 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit){
|
||||
(void)type;
|
||||
(void)user;
|
||||
memset(strings, 0, sizeof(strings));
|
||||
if(session->session_state != SSH_SESSION_STATE_INITIAL_KEX){
|
||||
if (session->session_state == SSH_SESSION_STATE_AUTHENTICATED){
|
||||
ssh_log(session,SSH_LOG_WARNING, "Other side initiating key re-exchange");
|
||||
} else if(session->session_state != SSH_SESSION_STATE_INITIAL_KEX){
|
||||
ssh_set_error(session,SSH_FATAL,"SSH_KEXINIT received in wrong state");
|
||||
goto error;
|
||||
}
|
||||
@ -335,6 +337,7 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit){
|
||||
|
||||
leave_function();
|
||||
session->session_state=SSH_SESSION_STATE_KEXINIT_RECEIVED;
|
||||
session->dh_handshake_state=DH_STATE_INIT;
|
||||
session->ssh_connection_callback(session);
|
||||
return SSH_PACKET_USED;
|
||||
error:
|
||||
|
@ -179,7 +179,7 @@ SSH_PACKET_CALLBACK(ssh_packet_newkeys){
|
||||
rc = ssh_pki_signature_verify_blob(session,
|
||||
sig_blob,
|
||||
key,
|
||||
session->next_crypto->session_id,
|
||||
session->next_crypto->secret_hash,
|
||||
session->next_crypto->digest_len);
|
||||
/* Set the server public key type for known host checking */
|
||||
session->next_crypto->server_pubkey_type = key->type_c;
|
||||
@ -210,6 +210,13 @@ SSH_PACKET_CALLBACK(ssh_packet_newkeys){
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
session->next_crypto->session_id = malloc(session->current_crypto->digest_len);
|
||||
if (session->next_crypto->session_id == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto error;
|
||||
}
|
||||
memcpy(session->next_crypto->session_id, session->current_crypto->session_id,
|
||||
session->current_crypto->digest_len);
|
||||
}
|
||||
session->dh_handshake_state = DH_STATE_FINISHED;
|
||||
session->ssh_connection_callback(session);
|
||||
|
@ -121,7 +121,10 @@ void crypto_free(struct ssh_crypto_struct *crypto){
|
||||
memset(crypto->session_id, '\0', crypto->digest_len);
|
||||
SAFE_FREE(crypto->session_id);
|
||||
}
|
||||
|
||||
if(crypto->secret_hash != NULL){
|
||||
memset(crypto->secret_hash, '\0', crypto->digest_len);
|
||||
SAFE_FREE(crypto->secret_hash);
|
||||
}
|
||||
#ifdef WITH_ZLIB
|
||||
if (crypto->compress_out_ctx &&
|
||||
(deflateEnd(crypto->compress_out_ctx) != 0)) {
|
||||
|
Загрузка…
Ссылка в новой задаче
Block a user