Use a common KDF function

Cleanup the KDF function to use only one function per crypto backend.
Improve the KDF function to properly handle requested lenght and to
avoid unnecessarily reallocating buffers.

In OpenSSL use the new EVP_KDF API if available.

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 18:00:01 -04:00
committed by Andreas Schneider
parent c180211c6b
commit 104c9dca3f
11 changed files with 299 additions and 256 deletions

View File

@@ -1196,7 +1196,7 @@ int ssh_make_sessionid(ssh_session session)
case SSH_KEX_DH_GEX_SHA1:
#endif /* WITH_GEX */
session->next_crypto->digest_len = SHA_DIGEST_LENGTH;
session->next_crypto->mac_type = SSH_MAC_SHA1;
session->next_crypto->digest_type = SSH_KDF_SHA1;
session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
if (session->next_crypto->secret_hash == NULL) {
ssh_set_error_oom(session);
@@ -1212,7 +1212,7 @@ int ssh_make_sessionid(ssh_session session)
case SSH_KEX_DH_GEX_SHA256:
#endif /* WITH_GEX */
session->next_crypto->digest_len = SHA256_DIGEST_LENGTH;
session->next_crypto->mac_type = SSH_MAC_SHA256;
session->next_crypto->digest_type = SSH_KDF_SHA256;
session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
if (session->next_crypto->secret_hash == NULL) {
ssh_set_error_oom(session);
@@ -1223,7 +1223,7 @@ int ssh_make_sessionid(ssh_session session)
break;
case SSH_KEX_ECDH_SHA2_NISTP384:
session->next_crypto->digest_len = SHA384_DIGEST_LENGTH;
session->next_crypto->mac_type = SSH_MAC_SHA384;
session->next_crypto->digest_type = SSH_KDF_SHA384;
session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
if (session->next_crypto->secret_hash == NULL) {
ssh_set_error_oom(session);
@@ -1236,7 +1236,7 @@ int ssh_make_sessionid(ssh_session session)
case SSH_KEX_DH_GROUP18_SHA512:
case SSH_KEX_ECDH_SHA2_NISTP521:
session->next_crypto->digest_len = SHA512_DIGEST_LENGTH;
session->next_crypto->mac_type = SSH_MAC_SHA512;
session->next_crypto->digest_type = SSH_KDF_SHA512;
session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
if (session->next_crypto->secret_hash == NULL) {
ssh_set_error_oom(session);
@@ -1346,60 +1346,18 @@ int ssh_hashbufin_add_cookie(ssh_session session, unsigned char *cookie)
return 0;
}
static int generate_one_key(ssh_string k, struct ssh_crypto_struct *crypto,
unsigned char *output, char letter,
size_t requested_size)
{
ssh_mac_ctx ctx;
size_t size = crypto->digest_len;
unsigned char digest[size];
ctx = ssh_mac_ctx_init(crypto->mac_type);
if (ctx == NULL) {
return -1;
}
ssh_mac_update(ctx, k, ssh_string_len(k) + 4);
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(digest, ctx);
if (requested_size < size) {
size = requested_size;
}
memcpy(output, digest, size);
while (requested_size > size) {
ctx = ssh_mac_ctx_init(crypto->mac_type);
if (ctx == NULL) {
return -1;
}
ssh_mac_update(ctx, k, ssh_string_len(k) + 4);
ssh_mac_update(ctx, crypto->secret_hash, crypto->digest_len);
ssh_mac_update(ctx, output, size);
ssh_mac_final(digest, ctx);
if (requested_size < size + crypto->digest_len) {
memcpy(output+size, digest, requested_size - size);
} else {
memcpy(output+size, digest, crypto->digest_len);
}
size += crypto->digest_len;
}
return 0;
}
int ssh_generate_session_keys(ssh_session session)
{
ssh_string k_string = NULL;
struct ssh_crypto_struct *crypto = session->next_crypto;
unsigned char *key = NULL;
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 key_len = 0;
size_t IV_len = 0;
size_t enckey_cli_to_srv_len = 0;
size_t enckey_srv_to_cli_len = 0;
@@ -1412,6 +1370,10 @@ int ssh_generate_session_keys(ssh_session session)
ssh_set_error_oom(session);
goto error;
}
/* See RFC4251 Section 5 for the definition of mpint which is the
* encoding we need to use for key in the SSH KDF */
key = (unsigned char *)k_string;
key_len = ssh_string_len(k_string) + 4;
IV_len = crypto->digest_len;
if (session->client) {
@@ -1440,33 +1402,33 @@ int ssh_generate_session_keys(ssh_session session)
}
/* IV */
rc = generate_one_key(k_string, crypto, IV_cli_to_srv, 'A', IV_len);
rc = ssh_kdf(crypto, key, key_len, 'A', IV_cli_to_srv, IV_len);
if (rc < 0) {
goto error;
}
rc = generate_one_key(k_string, crypto, IV_srv_to_cli, 'B', IV_len);
rc = ssh_kdf(crypto, key, key_len, 'B', IV_srv_to_cli, IV_len);
if (rc < 0) {
goto error;
}
/* Encryption Key */
rc = generate_one_key(k_string, crypto, enckey_cli_to_srv, 'C',
enckey_cli_to_srv_len);
rc = ssh_kdf(crypto, key, key_len, 'C', enckey_cli_to_srv,
enckey_cli_to_srv_len);
if (rc < 0) {
goto error;
}
rc = generate_one_key(k_string, crypto, enckey_srv_to_cli, 'D',
enckey_srv_to_cli_len);
rc = ssh_kdf(crypto, key, key_len, 'D', enckey_srv_to_cli,
enckey_srv_to_cli_len);
if (rc < 0) {
goto error;
}
/* Integrity Key */
rc = generate_one_key(k_string, crypto, intkey_cli_to_srv, 'E',
intkey_cli_to_srv_len);
rc = ssh_kdf(crypto, key, key_len, 'E', intkey_cli_to_srv,
intkey_cli_to_srv_len);
if (rc < 0) {
goto error;
}
rc = generate_one_key(k_string, crypto, intkey_srv_to_cli, 'F',
intkey_srv_to_cli_len);
rc = ssh_kdf(crypto, key, key_len, 'F', intkey_srv_to_cli,
intkey_srv_to_cli_len);
if (rc < 0) {
goto error;
}