1
0
mirror of https://git.libssh.org/projects/libssh.git synced 2025-11-30 13:01:23 +03:00

Clean up code that generates session keys

This patch simply reworks the code to make it more understandable and
reduce if() branches.
It also avoids reallocs, and instead uses a support buffer to hold
intermediate results of the hmac function so that no buffer overrides
happen when the requested size is not an exact mutiple of the digest_len.

Signed-off-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
This commit is contained in:
Simo Sorce
2018-10-01 12:56:32 -04:00
committed by Andreas Schneider
parent c235841436
commit c180211c6b

257
src/kex.c
View File

@@ -1346,17 +1346,15 @@ int ssh_hashbufin_add_cookie(ssh_session session, unsigned char *cookie)
return 0; return 0;
} }
static int generate_one_key(ssh_string k, static int generate_one_key(ssh_string k, struct ssh_crypto_struct *crypto,
struct ssh_crypto_struct *crypto, unsigned char *output, char letter,
unsigned char **output,
char letter,
size_t requested_size) size_t requested_size)
{ {
ssh_mac_ctx ctx; ssh_mac_ctx ctx;
unsigned char *tmp;
size_t size = crypto->digest_len; size_t size = crypto->digest_len;
ctx = ssh_mac_ctx_init(crypto->mac_type); unsigned char digest[size];
ctx = ssh_mac_ctx_init(crypto->mac_type);
if (ctx == NULL) { if (ctx == NULL) {
return -1; return -1;
} }
@@ -1365,25 +1363,27 @@ static int generate_one_key(ssh_string k,
ssh_mac_update(ctx, crypto->secret_hash, crypto->digest_len); ssh_mac_update(ctx, crypto->secret_hash, crypto->digest_len);
ssh_mac_update(ctx, &letter, 1); ssh_mac_update(ctx, &letter, 1);
ssh_mac_update(ctx, crypto->session_id, crypto->digest_len); ssh_mac_update(ctx, crypto->session_id, crypto->digest_len);
ssh_mac_final(*output, ctx); ssh_mac_final(digest, ctx);
while(requested_size > size) { if (requested_size < size) {
tmp = realloc(*output, size + crypto->digest_len); size = requested_size;
if (tmp == NULL) { }
return -1; memcpy(output, digest, size);
}
*output = tmp;
while (requested_size > size) {
ctx = ssh_mac_ctx_init(crypto->mac_type); ctx = ssh_mac_ctx_init(crypto->mac_type);
if (ctx == NULL) { if (ctx == NULL) {
return -1; return -1;
} }
ssh_mac_update(ctx, k, ssh_string_len(k) + 4); ssh_mac_update(ctx, k, ssh_string_len(k) + 4);
ssh_mac_update(ctx, ssh_mac_update(ctx, crypto->secret_hash, crypto->digest_len);
crypto->secret_hash, ssh_mac_update(ctx, output, size);
crypto->digest_len); ssh_mac_final(digest, ctx);
ssh_mac_update(ctx, tmp, size); if (requested_size < size + crypto->digest_len) {
ssh_mac_final(tmp + size, ctx); memcpy(output+size, digest, requested_size - size);
} else {
memcpy(output+size, digest, crypto->digest_len);
}
size += crypto->digest_len; size += crypto->digest_len;
} }
@@ -1394,6 +1394,17 @@ int ssh_generate_session_keys(ssh_session session)
{ {
ssh_string k_string = NULL; ssh_string k_string = NULL;
struct ssh_crypto_struct *crypto = session->next_crypto; struct ssh_crypto_struct *crypto = session->next_crypto;
unsigned char *IV_cli_to_srv = NULL;
unsigned char *IV_srv_to_cli = NULL;
unsigned char *enckey_cli_to_srv = NULL;
unsigned char *enckey_srv_to_cli = NULL;
unsigned char *intkey_cli_to_srv = NULL;
unsigned char *intkey_srv_to_cli = NULL;
size_t IV_len = 0;
size_t enckey_cli_to_srv_len = 0;
size_t enckey_srv_to_cli_len = 0;
size_t intkey_cli_to_srv_len = 0;
size_t intkey_srv_to_cli_len = 0;
int rc = -1; int rc = -1;
k_string = ssh_make_bignum_string(crypto->k); k_string = ssh_make_bignum_string(crypto->k);
@@ -1402,153 +1413,105 @@ int ssh_generate_session_keys(ssh_session session)
goto error; goto error;
} }
crypto->encryptIV = malloc(crypto->digest_len); IV_len = crypto->digest_len;
crypto->decryptIV = malloc(crypto->digest_len); if (session->client) {
crypto->encryptkey = malloc(crypto->digest_len); enckey_cli_to_srv_len = crypto->out_cipher->keysize / 8;
crypto->decryptkey = malloc(crypto->digest_len); enckey_srv_to_cli_len = crypto->in_cipher->keysize / 8;
crypto->encryptMAC = malloc(crypto->digest_len); intkey_cli_to_srv_len = hmac_digest_len(crypto->out_hmac);
crypto->decryptMAC = malloc(crypto->digest_len); intkey_srv_to_cli_len = hmac_digest_len(crypto->in_hmac);
if (crypto->encryptIV == NULL || } else {
crypto->decryptIV == NULL || enckey_cli_to_srv_len = crypto->in_cipher->keysize / 8;
crypto->encryptkey == NULL || crypto->decryptkey == NULL || enckey_srv_to_cli_len = crypto->out_cipher->keysize / 8;
crypto->encryptMAC == NULL || crypto->decryptMAC == NULL){ intkey_cli_to_srv_len = hmac_digest_len(crypto->in_hmac);
intkey_srv_to_cli_len = hmac_digest_len(crypto->out_hmac);
}
IV_cli_to_srv = malloc(IV_len);
IV_srv_to_cli = malloc(IV_len);
enckey_cli_to_srv = malloc(enckey_cli_to_srv_len);
enckey_srv_to_cli = malloc(enckey_srv_to_cli_len);
intkey_cli_to_srv = malloc(intkey_cli_to_srv_len);
intkey_srv_to_cli = malloc(intkey_srv_to_cli_len);
if (IV_cli_to_srv == NULL || IV_srv_to_cli == NULL ||
enckey_cli_to_srv == NULL || enckey_srv_to_cli == NULL ||
intkey_cli_to_srv == NULL || intkey_srv_to_cli == NULL) {
ssh_set_error_oom(session); ssh_set_error_oom(session);
goto error; goto error;
} }
/* IV */ /* IV */
if (session->client) { rc = generate_one_key(k_string, crypto, IV_cli_to_srv, 'A', IV_len);
rc = generate_one_key(k_string, if (rc < 0) {
crypto, goto error;
&crypto->encryptIV,
'A',
crypto->digest_len);
if (rc < 0) {
goto error;
}
rc = generate_one_key(k_string,
crypto,
&crypto->decryptIV,
'B',
crypto->digest_len);
if (rc < 0) {
goto error;
}
} else {
rc = generate_one_key(k_string,
crypto,
&crypto->decryptIV,
'A',
crypto->digest_len);
if (rc < 0) {
goto error;
}
rc = generate_one_key(k_string,
crypto,
&crypto->encryptIV,
'B',
crypto->digest_len);
if (rc < 0) {
goto error;
}
} }
if (session->client) { rc = generate_one_key(k_string, crypto, IV_srv_to_cli, 'B', IV_len);
rc = generate_one_key(k_string, if (rc < 0) {
crypto, goto error;
&crypto->encryptkey, }
'C', /* Encryption Key */
crypto->out_cipher->keysize / 8); rc = generate_one_key(k_string, crypto, enckey_cli_to_srv, 'C',
if (rc < 0) { enckey_cli_to_srv_len);
goto error; if (rc < 0) {
} goto error;
rc = generate_one_key(k_string, }
crypto, rc = generate_one_key(k_string, crypto, enckey_srv_to_cli, 'D',
&crypto->decryptkey, enckey_srv_to_cli_len);
'D', if (rc < 0) {
crypto->in_cipher->keysize / 8); goto error;
if (rc < 0) { }
goto error; /* Integrity Key */
} rc = generate_one_key(k_string, crypto, intkey_cli_to_srv, 'E',
} else { intkey_cli_to_srv_len);
rc = generate_one_key(k_string, if (rc < 0) {
crypto, goto error;
&crypto->decryptkey, }
'C', rc = generate_one_key(k_string, crypto, intkey_srv_to_cli, 'F',
crypto->in_cipher->keysize / 8); intkey_srv_to_cli_len);
if (rc < 0) { if (rc < 0) {
goto error; goto error;
}
rc = generate_one_key(k_string,
crypto,
&crypto->encryptkey,
'D',
crypto->out_cipher->keysize / 8);
if (rc < 0) {
goto error;
}
} }
if(session->client) { if (session->client) {
rc = generate_one_key(k_string, crypto->encryptIV = IV_cli_to_srv;
crypto, crypto->decryptIV = IV_srv_to_cli;
&crypto->encryptMAC, crypto->encryptkey = enckey_cli_to_srv;
'E', crypto->decryptkey = enckey_srv_to_cli;
hmac_digest_len(crypto->out_hmac)); crypto->encryptMAC = intkey_cli_to_srv;
if (rc < 0) { crypto->decryptMAC = intkey_srv_to_cli;
goto error;
}
rc = generate_one_key(k_string,
crypto,
&crypto->decryptMAC,
'F',
hmac_digest_len(crypto->in_hmac));
if (rc < 0) {
goto error;
}
} else { } else {
rc = generate_one_key(k_string, crypto->encryptIV = IV_srv_to_cli;
crypto, crypto->decryptIV = IV_cli_to_srv;
&crypto->decryptMAC, crypto->encryptkey = enckey_srv_to_cli;
'E', crypto->decryptkey = enckey_cli_to_srv;
hmac_digest_len(crypto->in_hmac)); crypto->encryptMAC = intkey_srv_to_cli;
if (rc < 0) { crypto->decryptMAC = intkey_cli_to_srv;
goto error;
}
rc = generate_one_key(k_string,
crypto,
&crypto->encryptMAC,
'F',
hmac_digest_len(crypto->out_hmac));
if (rc < 0) {
goto error;
}
} }
#ifdef DEBUG_CRYPTO #ifdef DEBUG_CRYPTO
ssh_print_hexa("Encrypt IV", ssh_print_hexa("Client to Server IV", IV_cli_to_srv, IV_len);
crypto->encryptIV, ssh_print_hexa("Server to Client IV", IV_srv_to_cli, IV_len);
crypto->digest_len); ssh_print_hexa("Client to Server Encryption Key", enckey_cli_to_srv,
ssh_print_hexa("Decrypt IV", enckey_cli_to_srv_len);
crypto->decryptIV, ssh_print_hexa("Server to Client Encryption Key", enckey_srv_to_cli,
crypto->digest_len); enckey_srv_to_cli_len);
ssh_print_hexa("Encryption key", ssh_print_hexa("Client to Server Integrity Key", intkey_cli_to_srv,
crypto->encryptkey, intkey_cli_to_srv_len);
crypto->out_cipher->keysize / 8); ssh_print_hexa("Server to Client Integrity Key", intkey_srv_to_cli,
ssh_print_hexa("Decryption key", intkey_srv_to_cli_len);
crypto->decryptkey,
crypto->in_cipher->keysize / 8);
ssh_print_hexa("Encryption MAC",
crypto->encryptMAC,
hmac_digest_len(crypto->out_hmac));
ssh_print_hexa("Decryption MAC",
crypto->decryptMAC,
hmac_digest_len(crypto->in_hmac));
#endif #endif
rc = 0; rc = 0;
error: error:
ssh_string_burn(k_string); ssh_string_burn(k_string);
ssh_string_free(k_string); ssh_string_free(k_string);
if (rc != 0) {
free(IV_cli_to_srv);
free(IV_srv_to_cli);
free(enckey_cli_to_srv);
free(enckey_srv_to_cli);
free(intkey_cli_to_srv);
free(intkey_srv_to_cli);
}
return rc; return rc;
} }