aesni_setkey_enc_128() is called twice for each connection (assuming
MBEDTLS_USE_PSA_CRYPTO is not enabled and no renegociation happens):
once for the outgoing key and once for the incoming key. This happens
before the call to mbedtls_gcm_starts(). The RNG does not call
aesni_setkey_enc_128() since it uses AES-256 by default.
In the default configuration, on x86_64 with AESNI, for mbedtls-3.3.0,
running ssl_client2
force_ciphersuite=TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256, here's the call
stack at the point where the key schedule starts (copied from gdb on Linux):
0 in aesni_setkey_enc_128 of source/library/aesni.c:277
1 in mbedtls_aesni_setkey_enc of source/library/aesni.c:453
2 in mbedtls_aes_setkey_enc of source/library/aes.c:545
3 in aes_setkey_enc_wrap of source/library/cipher_wrap.c:193
4 in mbedtls_cipher_setkey of source/library/cipher.c:328
5 in mbedtls_gcm_setkey of source/library/gcm.c:147
6 in gcm_aes_setkey_wrap of source/library/cipher_wrap.c:504
7 in mbedtls_cipher_setkey of source/library/cipher.c:328
8 in ssl_tls12_populate_transform of source/library/ssl_tls.c:8364
9 in mbedtls_ssl_derive_keys of source/library/ssl_tls.c:6337
10 in ssl_write_certificate_verify of source/library/ssl_tls12_client.c:3423
11 in mbedtls_ssl_handshake_client_step of
source/library/ssl_tls12_client.c:3725
12 in mbedtls_ssl_handshake_step of source/library/ssl_tls.c:3730
13 in mbedtls_ssl_handshake of source/library/ssl_tls.c:3795
14 in main of source/programs/ssl/ssl_client2.c:2280
Then a second call with
8 in ssl_tls12_populate_transform of source/library/ssl_tls.c:8372
for the key in the other direction.
Best regards,
--
Gilles Peskine
Mbed TLS developer
On 13/02/2023 14:01, M M via mbed-tls wrote:
> Hi, thank you for taking the time to reply.
>
> I added attribute noinline to the function generating the key schedule, aesni_setkey_enc_128() and rebuilt. However, it is still only called twice in total.
> I also added a breakpoint in aes.c:547, which looks like the non AES-NI code to generate the key schedule? That was never called.
>
> My ciphersuite is TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256, according to mbedtls_ssl_get_ciphersuite(mbedtls_ssl_context).
>
> Besides adding break points I have also stepped through the code, line by line. Please correct me if my understanding is wrong here:
>
> mbedtls_ssl_decrypt_buf() extracts the 4 byte salt, which is stored within transform->iv_dec?
> mbedtls_ssl_decrypt_buf() also sets the 8 byte explicit_nonce to variable dynamic_iv?
> The same function then passes these two variables to ssl_build_record_nonce(), which creates the 12-byte IV?
>
> Eventually we reach mbedtls_gcm_crypt_and_tag(), which calls mbedtls_gcm_starts()
>
> mbedtls_gcm_starts() copies the 12 byte IV in to a 16 byte within mbedtls_gcm_context->y and increments by 1. This is the IV value required to generate the key schedule of the first block of ciphertext.
>
> The remaining call stack to the point of decryption is:
>
> mbedtls_gcm_starts()
> mbedtls_cipher_update()
> ctx->cipher_info->base->ecb_func()
> aes_crypt_ecb_wrap()
> mbedtls_aes_crypt_ecb()
> mbedtls_aesni_crypt_ecb()
>
> mbedtls_aesni_crypt_ecb() loads the round key via (ctx->buf + ctx->rk_offset) to decrypt the first block of ciphertext.
>
> However, I could not see any of this path calling a function which generated a key schedule.
>
> I must be wrong (because it works) but if you could show where it is happening, that would be greatly appreciated.
>
> Just to repeat (in case my understanding is wrong) I am expecting 11 keys to be generated before every block of 16 bytes is decrypted.