From 71ee919dbeb550fdeab71af51c514033b85d73ce Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 25 Jul 2025 20:00:39 +0200 Subject: [PATCH 01/16] More meaningful test case names Signed-off-by: Gilles Peskine --- tests/suites/test_suite_cipher.aes.data | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/suites/test_suite_cipher.aes.data b/tests/suites/test_suite_cipher.aes.data index 99a662b83f..6e9481b704 100644 --- a/tests/suites/test_suite_cipher.aes.data +++ b/tests/suites/test_suite_cipher.aes.data @@ -1482,43 +1482,43 @@ AES-256 CBC - Encrypt and decrypt 32 bytes in multiple parts with PKCS7 padding depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH enc_dec_buf_multipart:MBEDTLS_CIPHER_AES_256_CBC:256:16:16:MBEDTLS_PADDING_PKCS7:16:16:0:32 -AES Decrypt test vector #0 +AES-128-CBC Decrypt test vector, invalid PKCS7 padding depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_PADDING_PKCS7:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7 decrypt_test_vec:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"23f710842b9bb9c32f26648c786807ca":"00000000000000000000000000000000":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 -AES Decrypt test vector #1 +AES-128-CBC Decrypt test vector, no padding depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7 decrypt_test_vec:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_NONE:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"23f710842b9bb9c32f26648c786807ca":"00000000000000000000000000000000":"":"":0:0 -AES Decrypt test vector #2 +AES-192-CBC Decrypt test vector, no padding depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH decrypt_test_vec:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_NONE:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"707b1dbb0ffa40ef7d95def421233fae":"fffffffff80000000000000000000000":"":"":0:0 -AES Decrypt test vector #3 +AES-256-CBC Decrypt test vector, no padding depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH decrypt_test_vec:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_NONE:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"49af6b372135acef10132e548f217b17":"ff000000000000000000000000000000":"":"":0:0 -AES Decrypt test vector #4 +AES-128-CFB Decrypt test vector depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CFB decrypt_test_vec:MBEDTLS_CIPHER_AES_128_CFB128:-1:"fffffffe000000000000000000000000":"00000000000000000000000000000000":"1114bc2028009b923f0b01915ce5e7c4":"00000000000000000000000000000000":"":"":0:0: -AES Decrypt test vector #5 +AES-192-CFB Decrypt test vector depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CFB:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH decrypt_test_vec:MBEDTLS_CIPHER_AES_192_CFB128:-1:"ffffffffffffffffffffffffffffffffffffffffffe00000":"00000000000000000000000000000000":"60136703374f64e860b48ce31f930716":"00000000000000000000000000000000":"":"":0:0 -AES Decrypt test vector #6 +AES-256-CFB Decrypt test vector depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CFB:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH decrypt_test_vec:MBEDTLS_CIPHER_AES_256_CFB128:-1:"ffffffffff800000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"be66cfea2fecd6bf0ec7b4352c99bcaa":"00000000000000000000000000000000":"":"":0:0 -AES Decrypt test vector #7 +AES-128-OFB Decrypt test vector depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_OFB decrypt_test_vec:MBEDTLS_CIPHER_AES_128_OFB:-1:"2B7E151628AED2A6ABF7158809CF4F3C":"000102030405060708090A0B0C0D0E0F":"3B3FD92EB72DAD20333449F8E83CFB4A7789508d16918f03f53c52dac54ed8259740051e9c5fecf64344f7a82260edcc304c6528f659c77866a510d9c1d6ae5e":"6BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710":"":"":0:0: -AES Decrypt test vector #8 +AES-192-OFB Decrypt test vector depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_OFB:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH decrypt_test_vec:MBEDTLS_CIPHER_AES_192_OFB:-1:"8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B":"000102030405060708090A0B0C0D0E0F":"CDC80D6FDDF18CAB34C25909C99A4174fcc28b8d4c63837c09e81700c11004018d9a9aeac0f6596f559c6d4daf59a5f26d9f200857ca6c3e9cac524bd9acc92a":"6BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710":"":"":0:0: -AES Decrypt test vector #9 +AES-256-OFB Decrypt test vector depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_OFB:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH decrypt_test_vec:MBEDTLS_CIPHER_AES_256_OFB:-1:"603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4":"000102030405060708090A0B0C0D0E0F":"DC7E84BFDA79164B7ECD8486985D38604febdc6740d20b3ac88f6ad82a4fb08d71ab47a086e86eedf39d1c5bba97c4080126141d67f37be8538f5a8be740e484":"6BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710":"":"":0:0: From 5ee94d52a6df43cc2ac5c647e87d079165419ac4 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sun, 27 Jul 2025 18:02:21 +0200 Subject: [PATCH 02/16] More variety of CBC decrypt tests Have tests without padding, with valid PKCS7 padding and with several kinds of invalid PKCS7 padding. #!/usr/bin/env python3 from Crypto.Cipher import AES KEYS = { 128: bytes.fromhex("ffffffffe00000000000000000000000"), 192: bytes.fromhex("000000000000000000000000000000000000000000000000"), 256: bytes.fromhex("0000000000000000000000000000000000000000000000000000000000000000"), } IV = bytes.fromhex("00000000000000000000000000000000") def decrypt_test_vec(cf, bits, mode, padded_hex, padding_length, note=''): depends = ['MBEDTLS_AES_C', 'MBEDTLS_CIPHER_MODE_CBC'] plaintext = bytes.fromhex(padded_hex) plaintext_length = len(plaintext) if bits != 128: depends.append('!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH') key = KEYS[bits] iv = IV result = '0' if mode == 'NONE': padding_description = 'no padding' assert padding_length == 0 else: depends.append('MBEDTLS_CIPHER_PADDING_' + mode) padding_description = mode if padding_length is None: result = 'MBEDTLS_ERR_CIPHER_INVALID_PADDING' plaintext_length = 0 else: plaintext_length -= padding_length cipher = AES.new(key, AES.MODE_CBC, iv=iv) ciphertext = cipher.encrypt(plaintext) function = 'decrypt_test_vec' cf_maybe = '' if cf: function += '_cf' cf_maybe = 'CF ' depends.append('HAVE_CONSTANT_TIME_AES') if note: note = f' ({note})' print(f'''\ {cf_maybe}AES-{bits}-CBC Decrypt test vector, {padding_description}{note} depends_on:{':'.join(depends)} {function}:MBEDTLS_CIPHER_AES_{bits}_CBC:MBEDTLS_PADDING_{mode}:"{key.hex()}":"{iv.hex()}":"{ciphertext.hex()}":"{plaintext[:plaintext_length].hex()}":"":"":{result}:0 ''') def emit_tests(cf): # Already existing tests decrypt_test_vec(cf, 128, 'NONE', "00000000000000000000000000000000", 0) decrypt_test_vec(cf, 192, 'NONE', "fffffffff80000000000000000000000", 0) decrypt_test_vec(cf, 256, 'NONE', "ff000000000000000000000000000000", 0) # New tests decrypt_test_vec(cf, 128, 'PKCS7', "00000000000000000000000000000001", 1, 'good pad 1') decrypt_test_vec(cf, 192, 'PKCS7', "fffffffff80000000000000000000001", 1, 'good pad 1') decrypt_test_vec(cf, 256, 'PKCS7', "ff000000000000000000000000000001", 1, 'good pad 1') decrypt_test_vec(cf, 128, 'PKCS7', "00000000000000000000000000000202", 2, 'good pad 2') decrypt_test_vec(cf, 192, 'PKCS7', "fffffffff80000000000000000000202", 2, 'good pad 2') decrypt_test_vec(cf, 256, 'PKCS7', "ff000000000000000000000000000202", 2, 'good pad 2') decrypt_test_vec(cf, 128, 'PKCS7', "2a0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f", 15, 'good pad 15') decrypt_test_vec(cf, 192, 'PKCS7', "2a0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f", 15, 'good pad 15') decrypt_test_vec(cf, 256, 'PKCS7', "2a0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f", 15, 'good pad 15') decrypt_test_vec(cf, 128, 'PKCS7', "10101010101010101010101010101010", 16, 'good pad 16') decrypt_test_vec(cf, 192, 'PKCS7', "10101010101010101010101010101010", 16, 'good pad 16') decrypt_test_vec(cf, 256, 'PKCS7', "10101010101010101010101010101010", 16, 'good pad 16') decrypt_test_vec(cf, 128, 'PKCS7', "00000000000000000000000000000000", None, 'bad pad 0') decrypt_test_vec(cf, 192, 'PKCS7', "fffffffff80000000000000000000000", None, 'bad pad 0') decrypt_test_vec(cf, 256, 'PKCS7', "ff000000000000000000000000000000", None, 'bad pad 0') decrypt_test_vec(cf, 128, 'PKCS7', "00000000000000000000000000000102", None, 'bad pad 0102') decrypt_test_vec(cf, 192, 'PKCS7', "fffffffff80000000000000000000102", None, 'bad pad 0102') decrypt_test_vec(cf, 256, 'PKCS7', "ff000000000000000000000000000102", None, 'bad pad 0102') decrypt_test_vec(cf, 128, 'PKCS7', "1111111111111111111111111111111111111111111111111111111111111111", None, 'long, bad pad 17') decrypt_test_vec(cf, 192, 'PKCS7', "1111111111111111111111111111111111111111111111111111111111111111", None, 'long, bad pad 17') decrypt_test_vec(cf, 256, 'PKCS7', "1111111111111111111111111111111111111111111111111111111111111111", None, 'long, bad pad 17') decrypt_test_vec(cf, 128, 'PKCS7', "11111111111111111111111111111111", None, 'short, bad pad 17') decrypt_test_vec(cf, 192, 'PKCS7', "11111111111111111111111111111111", None, 'short, bad pad 17') decrypt_test_vec(cf, 256, 'PKCS7', "11111111111111111111111111111111", None, 'short, bad pad 17') emit_tests(False) Signed-off-by: Gilles Peskine --- tests/suites/test_suite_cipher.aes.data | 106 ++++++++++++++++++++++-- 1 file changed, 99 insertions(+), 7 deletions(-) diff --git a/tests/suites/test_suite_cipher.aes.data b/tests/suites/test_suite_cipher.aes.data index 6e9481b704..dd8bf719e0 100644 --- a/tests/suites/test_suite_cipher.aes.data +++ b/tests/suites/test_suite_cipher.aes.data @@ -1482,22 +1482,114 @@ AES-256 CBC - Encrypt and decrypt 32 bytes in multiple parts with PKCS7 padding depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH enc_dec_buf_multipart:MBEDTLS_CIPHER_AES_256_CBC:256:16:16:MBEDTLS_PADDING_PKCS7:16:16:0:32 -AES-128-CBC Decrypt test vector, invalid PKCS7 padding -depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_PADDING_PKCS7:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7 -decrypt_test_vec:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"23f710842b9bb9c32f26648c786807ca":"00000000000000000000000000000000":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 - AES-128-CBC Decrypt test vector, no padding -depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7 +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC decrypt_test_vec:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_NONE:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"23f710842b9bb9c32f26648c786807ca":"00000000000000000000000000000000":"":"":0:0 AES-192-CBC Decrypt test vector, no padding -depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH decrypt_test_vec:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_NONE:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"707b1dbb0ffa40ef7d95def421233fae":"fffffffff80000000000000000000000":"":"":0:0 AES-256-CBC Decrypt test vector, no padding -depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH decrypt_test_vec:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_NONE:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"49af6b372135acef10132e548f217b17":"ff000000000000000000000000000000":"":"":0:0 +AES-128-CBC Decrypt test vector, PKCS7 (good pad 1) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_test_vec:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"6dbd04d1579f6a7bee0842b9ae491588":"000000000000000000000000000000":"":"":0:0 + +AES-192-CBC Decrypt test vector, PKCS7 (good pad 1) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_test_vec:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"593ebdf9a785f414cbed5d8a9eee1e4d":"fffffffff800000000000000000000":"":"":0:0 + +AES-256-CBC Decrypt test vector, PKCS7 (good pad 1) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_test_vec:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"f1b27ac78b93f6b0ab9787d8827176e6":"ff0000000000000000000000000000":"":"":0:0 + +AES-128-CBC Decrypt test vector, PKCS7 (good pad 2) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_test_vec:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"175334ced3166a22437861f4bcced178":"0000000000000000000000000000":"":"":0:0 + +AES-192-CBC Decrypt test vector, PKCS7 (good pad 2) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_test_vec:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"5d9ee7bc7066e438582c86c165604f2e":"fffffffff8000000000000000000":"":"":0:0 + +AES-256-CBC Decrypt test vector, PKCS7 (good pad 2) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_test_vec:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"cc71abea78b8e82c3791b52d3dba55e2":"ff00000000000000000000000000":"":"":0:0 + +AES-128-CBC Decrypt test vector, PKCS7 (good pad 15) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_test_vec:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"7d340c60b9067883962c69766cf9ec35":"2a":"":"":0:0 + +AES-192-CBC Decrypt test vector, PKCS7 (good pad 15) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_test_vec:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"48fef8aaa78c4a148f241aaf14866772":"2a":"":"":0:0 + +AES-256-CBC Decrypt test vector, PKCS7 (good pad 15) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_test_vec:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"6ad50ca266a3e32024818f11839afb2f":"2a":"":"":0:0 + +AES-128-CBC Decrypt test vector, PKCS7 (good pad 16) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_test_vec:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"e9844992c4b55bcaf8199d5df842adad":"":"":"":0:0 + +AES-192-CBC Decrypt test vector, PKCS7 (good pad 16) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_test_vec:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"02bb292527e726fd51eb29894d6f0aad":"":"":"":0:0 + +AES-256-CBC Decrypt test vector, PKCS7 (good pad 16) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_test_vec:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"1f788fe6d86c317549697fbf0c07fa43":"":"":"":0:0 + +AES-128-CBC Decrypt test vector, PKCS7 (bad pad 0) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_test_vec:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"23f710842b9bb9c32f26648c786807ca":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +AES-192-CBC Decrypt test vector, PKCS7 (bad pad 0) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_test_vec:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"707b1dbb0ffa40ef7d95def421233fae":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +AES-256-CBC Decrypt test vector, PKCS7 (bad pad 0) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_test_vec:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"49af6b372135acef10132e548f217b17":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +AES-128-CBC Decrypt test vector, PKCS7 (bad pad 0102) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_test_vec:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"e651289760d35177eade56eae724f8fd":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +AES-192-CBC Decrypt test vector, PKCS7 (bad pad 0102) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_test_vec:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"f5b599490354e71a3b3fb5f1419fb971":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +AES-256-CBC Decrypt test vector, PKCS7 (bad pad 0102) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_test_vec:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"6852d318a0884a289a725c558e761e25":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +AES-128-CBC Decrypt test vector, PKCS7 (long, bad pad 17) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_test_vec:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"9c336551cc31074ffcefc161bac686b7afa572c3b53bd14a1b98d201229ddd03":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +AES-192-CBC Decrypt test vector, PKCS7 (long, bad pad 17) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_test_vec:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"33a31ec7605c85893872a467777f3ddb5c4271870e51a0c618f20a0efccc2bfc":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +AES-256-CBC Decrypt test vector, PKCS7 (long, bad pad 17) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_test_vec:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"3e536c7917a695485ef046bda7c6a3e64f439d87aa0deb338029253bea0ba54f":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +AES-128-CBC Decrypt test vector, PKCS7 (short, bad pad 17) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_test_vec:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"9c336551cc31074ffcefc161bac686b7":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +AES-192-CBC Decrypt test vector, PKCS7 (short, bad pad 17) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_test_vec:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"33a31ec7605c85893872a467777f3ddb":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +AES-256-CBC Decrypt test vector, PKCS7 (short, bad pad 17) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_test_vec:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"3e536c7917a695485ef046bda7c6a3e6":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + AES-128-CFB Decrypt test vector depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CFB decrypt_test_vec:MBEDTLS_CIPHER_AES_128_CFB128:-1:"fffffffe000000000000000000000000":"00000000000000000000000000000000":"1114bc2028009b923f0b01915ce5e7c4":"00000000000000000000000000000000":"":"":0:0: From 54131a3dc6c639abf775073cca6d114e2c46d00c Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 7 Aug 2025 22:55:56 +0200 Subject: [PATCH 03/16] Move constant-time padding tests to a separate suite Make it easier to run just the tests that matter under constant-flow testing instrumentation. Signed-off-by: Gilles Peskine --- tests/suites/test_suite_cipher.constant_time.data | 14 ++++++++++++++ tests/suites/test_suite_cipher.padding.data | 15 --------------- 2 files changed, 14 insertions(+), 15 deletions(-) create mode 100644 tests/suites/test_suite_cipher.constant_time.data diff --git a/tests/suites/test_suite_cipher.constant_time.data b/tests/suites/test_suite_cipher.constant_time.data new file mode 100644 index 0000000000..c2af62e006 --- /dev/null +++ b/tests/suites/test_suite_cipher.constant_time.data @@ -0,0 +1,14 @@ +Constant-time PKCS7 padding, valid #1 +get_pkcs_padding:"00112233445566778899AABBCCDDEE01":0:15 + +Constant-time PKCS7 padding, valid #2 +get_pkcs_padding:"00112233445566778899AA0505050505":0:11 + +Constant-time PKCS7 padding, valid #3 +get_pkcs_padding:"10101010101010101010101010101010":0:0 + +Constant-time PKCS7 padding, invalid zero +get_pkcs_padding:"00112233445566778899AABBCCDDEE00":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +Constant-time PKCS7 padding, invalid > 16 +get_pkcs_padding:"00112233445566778899AABBCCDDEE11":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 diff --git a/tests/suites/test_suite_cipher.padding.data b/tests/suites/test_suite_cipher.padding.data index 85b14c1f2f..0370fb3d28 100644 --- a/tests/suites/test_suite_cipher.padding.data +++ b/tests/suites/test_suite_cipher.padding.data @@ -217,18 +217,3 @@ check_padding:MBEDTLS_PADDING_NONE:"DABBAD0001":0:5 Check no padding #3 (correct by definition) check_padding:MBEDTLS_PADDING_NONE:"":0:0 - -Constant-time PKCS7 padding, valid #1 -get_pkcs_padding:"00112233445566778899AABBCCDDEE01":0:15 - -Constant-time PKCS7 padding, valid #2 -get_pkcs_padding:"00112233445566778899AA0505050505":0:11 - -Constant-time PKCS7 padding, valid #3 -get_pkcs_padding:"10101010101010101010101010101010":0:0 - -Constant-time PKCS7 padding, invalid zero -get_pkcs_padding:"00112233445566778899AABBCCDDEE00":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 - -Constant-time PKCS7 padding, invalid > 16 -get_pkcs_padding:"00112233445566778899AABBCCDDEE11":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 From 580d1f49544003972d2786c1ed1217bdf59baf42 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 8 Aug 2025 00:06:06 +0200 Subject: [PATCH 04/16] Do dedicated constant-time testing in a few more configurations Do constant-time testing in a couple of configurations that give some interesting coverage; * In a configuration that's close to the default: `test_aes_only_128_bit_keys`. Having only 128-bit AES keys doesn't reduce the interesting scope much (except that it doesn't test 192-bit and 256-bit AES, but since that configuration uses hardware AES, we don't care about that part). * when PSA buffer copying is not done, i.e. when `MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS` is enabled. This will be very relevant for the upcoming PSA constant-time tests. Use Valgrind, since some of the interesting tests require constant-time AES, which for us means AESNI or AESCE, which MSan doesn't support. Signed-off-by: Gilles Peskine --- .../components-configuration-crypto.sh | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/scripts/components-configuration-crypto.sh b/tests/scripts/components-configuration-crypto.sh index 04c38f6c36..6b12bb9af5 100644 --- a/tests/scripts/components-configuration-crypto.sh +++ b/tests/scripts/components-configuration-crypto.sh @@ -5,6 +5,28 @@ # This file contains test components that are executed by all.sh +## test_with_valgrind tests/suites/SUITE.data [...] +## Run the specified test suite(s) with Valgrind. +test_with_valgrind () { + for data_file in "$@"; do + suite="${data_file##*/}"; suite="${suite%.data}" + exe="tests/$suite" + log_file="tests/MemoryChecker.$suite.log" + make -C tests "$suite" + valgrind -q --tool=memcheck --track-origins=yes --log-file="$log_file" "$exe" + not grep . -- "$log_file" + done +} + +## Run a small set of dedicated constant-time tests with Valgrind. +## Exclude very slow suites. +## Exclude suites that contain some constant-time tests, but whose focus +## isn't on constant-time tests. +test_with_valgrind_constant_time () { + declare GLOBIGNORE="tests/suites/test_suite_constant_time_hmac.data" + test_with_valgrind tests/suites/*constant_time*.data +} + ################################################################ #### Configuration Testing - Crypto ################################################################ @@ -31,6 +53,17 @@ component_test_psa_assume_exclusive_buffers () { make test } +component_test_psa_assume_exclusive_buffers_valgrind_cf () { + msg "build: full config + MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS, constant flow with Valgrind" + scripts/config.py full + scripts/config.py set MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS + scripts/config.py set MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND + make lib + + msg "test: full config + MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS, constant flow with Valgrind, selected suites" + test_with_valgrind_constant_time tests/suites/*constant_time*.data +} + component_test_crypto_with_static_key_slots() { msg "build: crypto full + MBEDTLS_PSA_STATIC_KEY_SLOTS" scripts/config.py crypto_full @@ -2969,11 +3002,15 @@ component_test_aes_only_128_bit_keys () { msg "build: default config + AES_ONLY_128_BIT_KEY_LENGTH" scripts/config.py set MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH scripts/config.py unset MBEDTLS_PADLOCK_C + scripts/config.py set MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND make CFLAGS='-O2 -Werror -Wall -Wextra' msg "test: default config + AES_ONLY_128_BIT_KEY_LENGTH" make test + + msg "test: default config + AES_ONLY_128_BIT_KEY_LENGTH constant flow with Valgrind, selected suites" + test_with_valgrind_constant_time } component_test_no_ctr_drbg_aes_only_128_bit_keys () { From df00d458a2a2266b3ac9ab4ced85028cf59d68ae Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sun, 27 Jul 2025 18:03:26 +0200 Subject: [PATCH 05/16] Constant-flow AES-CBC multipart decrypt tests The main goal is to validate that unpadding is constant-time, including error reporting. Use a separate test function, not annotations in the existing function, so that the functional tests can run on any platform, and we know from test outcomes where we have run the constant-time tests. The tests can only be actually constant-time if AES is constant time, since AES computations are part of what is checked. Thus this requires hardware-accelerated AES. We can't run our AESNI (or AESCE?) code under Msan (it doesn't detect when memory is written from assembly code), so these tests can only be run with Valgrind. Same test data as the newly introduced functional tests. #!/usr/bin/env python3 from Crypto.Cipher import AES KEYS = { 128: bytes.fromhex("ffffffffe00000000000000000000000"), 192: bytes.fromhex("000000000000000000000000000000000000000000000000"), 256: bytes.fromhex("0000000000000000000000000000000000000000000000000000000000000000"), } IV = bytes.fromhex("00000000000000000000000000000000") def decrypt_test_vec(cf, bits, mode, padded_hex, padding_length, note=''): depends = ['MBEDTLS_AES_C', 'MBEDTLS_CIPHER_MODE_CBC'] plaintext = bytes.fromhex(padded_hex) plaintext_length = len(plaintext) if bits != 128: depends.append('!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH') key = KEYS[bits] iv = IV result = '0' if mode == 'NONE': padding_description = 'no padding' assert padding_length == 0 else: depends.append('MBEDTLS_CIPHER_PADDING_' + mode) padding_description = mode if padding_length is None: result = 'MBEDTLS_ERR_CIPHER_INVALID_PADDING' plaintext_length = 0 else: plaintext_length -= padding_length cipher = AES.new(key, AES.MODE_CBC, iv=iv) ciphertext = cipher.encrypt(plaintext) function = 'decrypt_test_vec' cf_maybe = '' if cf: function += '_cf' cf_maybe = 'CF ' depends.append('HAVE_CONSTANT_TIME_AES') if note: note = f' ({note})' print(f'''\ {cf_maybe}AES-{bits}-CBC Decrypt test vector, {padding_description}{note} depends_on:{':'.join(depends)} {function}:MBEDTLS_CIPHER_AES_{bits}_CBC:MBEDTLS_PADDING_{mode}:"{key.hex()}":"{iv.hex()}":"{ciphertext.hex()}":"{plaintext[:plaintext_length].hex()}":"":"":{result}:0 ''') def emit_tests(cf): # Already existing tests decrypt_test_vec(cf, 128, 'NONE', "00000000000000000000000000000000", 0) decrypt_test_vec(cf, 192, 'NONE', "fffffffff80000000000000000000000", 0) decrypt_test_vec(cf, 256, 'NONE', "ff000000000000000000000000000000", 0) # New tests decrypt_test_vec(cf, 128, 'PKCS7', "00000000000000000000000000000001", 1, 'good pad 1') decrypt_test_vec(cf, 192, 'PKCS7', "fffffffff80000000000000000000001", 1, 'good pad 1') decrypt_test_vec(cf, 256, 'PKCS7', "ff000000000000000000000000000001", 1, 'good pad 1') decrypt_test_vec(cf, 128, 'PKCS7', "00000000000000000000000000000202", 2, 'good pad 2') decrypt_test_vec(cf, 192, 'PKCS7', "fffffffff80000000000000000000202", 2, 'good pad 2') decrypt_test_vec(cf, 256, 'PKCS7', "ff000000000000000000000000000202", 2, 'good pad 2') decrypt_test_vec(cf, 128, 'PKCS7', "2a0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f", 15, 'good pad 15') decrypt_test_vec(cf, 192, 'PKCS7', "2a0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f", 15, 'good pad 15') decrypt_test_vec(cf, 256, 'PKCS7', "2a0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f", 15, 'good pad 15') decrypt_test_vec(cf, 128, 'PKCS7', "10101010101010101010101010101010", 16, 'good pad 16') decrypt_test_vec(cf, 192, 'PKCS7', "10101010101010101010101010101010", 16, 'good pad 16') decrypt_test_vec(cf, 256, 'PKCS7', "10101010101010101010101010101010", 16, 'good pad 16') decrypt_test_vec(cf, 128, 'PKCS7', "00000000000000000000000000000000", None, 'bad pad 0') decrypt_test_vec(cf, 192, 'PKCS7', "fffffffff80000000000000000000000", None, 'bad pad 0') decrypt_test_vec(cf, 256, 'PKCS7', "ff000000000000000000000000000000", None, 'bad pad 0') decrypt_test_vec(cf, 128, 'PKCS7', "00000000000000000000000000000102", None, 'bad pad 0102') decrypt_test_vec(cf, 192, 'PKCS7', "fffffffff80000000000000000000102", None, 'bad pad 0102') decrypt_test_vec(cf, 256, 'PKCS7', "ff000000000000000000000000000102", None, 'bad pad 0102') decrypt_test_vec(cf, 128, 'PKCS7', "1111111111111111111111111111111111111111111111111111111111111111", None, 'long, bad pad 17') decrypt_test_vec(cf, 192, 'PKCS7', "1111111111111111111111111111111111111111111111111111111111111111", None, 'long, bad pad 17') decrypt_test_vec(cf, 256, 'PKCS7', "1111111111111111111111111111111111111111111111111111111111111111", None, 'long, bad pad 17') decrypt_test_vec(cf, 128, 'PKCS7', "11111111111111111111111111111111", None, 'short, bad pad 17') decrypt_test_vec(cf, 192, 'PKCS7', "11111111111111111111111111111111", None, 'short, bad pad 17') decrypt_test_vec(cf, 256, 'PKCS7', "11111111111111111111111111111111", None, 'short, bad pad 17') emit_tests(True) Signed-off-by: Gilles Peskine --- .../test_suite_cipher.constant_time.data | 108 ++++++++++++++++++ tests/suites/test_suite_cipher.function | 88 ++++++++++++++ 2 files changed, 196 insertions(+) diff --git a/tests/suites/test_suite_cipher.constant_time.data b/tests/suites/test_suite_cipher.constant_time.data index c2af62e006..af608044bb 100644 --- a/tests/suites/test_suite_cipher.constant_time.data +++ b/tests/suites/test_suite_cipher.constant_time.data @@ -12,3 +12,111 @@ get_pkcs_padding:"00112233445566778899AABBCCDDEE00":MBEDTLS_ERR_CIPHER_INVALID_P Constant-time PKCS7 padding, invalid > 16 get_pkcs_padding:"00112233445566778899AABBCCDDEE11":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-128-CBC Decrypt test vector, no padding +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_NONE:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"23f710842b9bb9c32f26648c786807ca":"00000000000000000000000000000000":"":"":0:0 + +CF AES-192-CBC Decrypt test vector, no padding +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_NONE:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"707b1dbb0ffa40ef7d95def421233fae":"fffffffff80000000000000000000000":"":"":0:0 + +CF AES-256-CBC Decrypt test vector, no padding +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_NONE:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"49af6b372135acef10132e548f217b17":"ff000000000000000000000000000000":"":"":0:0 + +CF AES-128-CBC Decrypt test vector, PKCS7 (good pad 1) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"6dbd04d1579f6a7bee0842b9ae491588":"000000000000000000000000000000":"":"":0:0 + +CF AES-192-CBC Decrypt test vector, PKCS7 (good pad 1) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"593ebdf9a785f414cbed5d8a9eee1e4d":"fffffffff800000000000000000000":"":"":0:0 + +CF AES-256-CBC Decrypt test vector, PKCS7 (good pad 1) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"f1b27ac78b93f6b0ab9787d8827176e6":"ff0000000000000000000000000000":"":"":0:0 + +CF AES-128-CBC Decrypt test vector, PKCS7 (good pad 2) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"175334ced3166a22437861f4bcced178":"0000000000000000000000000000":"":"":0:0 + +CF AES-192-CBC Decrypt test vector, PKCS7 (good pad 2) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"5d9ee7bc7066e438582c86c165604f2e":"fffffffff8000000000000000000":"":"":0:0 + +CF AES-256-CBC Decrypt test vector, PKCS7 (good pad 2) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"cc71abea78b8e82c3791b52d3dba55e2":"ff00000000000000000000000000":"":"":0:0 + +CF AES-128-CBC Decrypt test vector, PKCS7 (good pad 15) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"7d340c60b9067883962c69766cf9ec35":"2a":"":"":0:0 + +CF AES-192-CBC Decrypt test vector, PKCS7 (good pad 15) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"48fef8aaa78c4a148f241aaf14866772":"2a":"":"":0:0 + +CF AES-256-CBC Decrypt test vector, PKCS7 (good pad 15) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"6ad50ca266a3e32024818f11839afb2f":"2a":"":"":0:0 + +CF AES-128-CBC Decrypt test vector, PKCS7 (good pad 16) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"e9844992c4b55bcaf8199d5df842adad":"":"":"":0:0 + +CF AES-192-CBC Decrypt test vector, PKCS7 (good pad 16) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"02bb292527e726fd51eb29894d6f0aad":"":"":"":0:0 + +CF AES-256-CBC Decrypt test vector, PKCS7 (good pad 16) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"1f788fe6d86c317549697fbf0c07fa43":"":"":"":0:0 + +CF AES-128-CBC Decrypt test vector, PKCS7 (bad pad 0) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"23f710842b9bb9c32f26648c786807ca":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-192-CBC Decrypt test vector, PKCS7 (bad pad 0) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"707b1dbb0ffa40ef7d95def421233fae":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-256-CBC Decrypt test vector, PKCS7 (bad pad 0) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"49af6b372135acef10132e548f217b17":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-128-CBC Decrypt test vector, PKCS7 (bad pad 0102) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"e651289760d35177eade56eae724f8fd":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-192-CBC Decrypt test vector, PKCS7 (bad pad 0102) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"f5b599490354e71a3b3fb5f1419fb971":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-256-CBC Decrypt test vector, PKCS7 (bad pad 0102) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"6852d318a0884a289a725c558e761e25":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-128-CBC Decrypt test vector, PKCS7 (long, bad pad 17) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"9c336551cc31074ffcefc161bac686b7afa572c3b53bd14a1b98d201229ddd03":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-192-CBC Decrypt test vector, PKCS7 (long, bad pad 17) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"33a31ec7605c85893872a467777f3ddb5c4271870e51a0c618f20a0efccc2bfc":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-256-CBC Decrypt test vector, PKCS7 (long, bad pad 17) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"3e536c7917a695485ef046bda7c6a3e64f439d87aa0deb338029253bea0ba54f":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-128-CBC Decrypt test vector, PKCS7 (short, bad pad 17) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"9c336551cc31074ffcefc161bac686b7":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-192-CBC Decrypt test vector, PKCS7 (short, bad pad 17) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"33a31ec7605c85893872a467777f3ddb":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-256-CBC Decrypt test vector, PKCS7 (short, bad pad 17) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"3e536c7917a695485ef046bda7c6a3e6":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 diff --git a/tests/suites/test_suite_cipher.function b/tests/suites/test_suite_cipher.function index 2856ae5699..37a77e5687 100644 --- a/tests/suites/test_suite_cipher.function +++ b/tests/suites/test_suite_cipher.function @@ -14,6 +14,20 @@ #define MBEDTLS_CIPHER_AUTH_CRYPT #endif +/* Our software AES implementation is not constant-time. For constant-time + * testing involving AES, require a hardware-assisted AES that is + * constant-time. + * + * We assume that if the hardware-assisted version is available in the build, + * it will be available at runtime. The AES tests will fail if run on a + * processor without AESNI/AESCE. + */ +#include "aesce.h" +#include "aesni.h" +#if defined(MBEDTLS_AESCE_HAVE_CODE) || defined(MBEDTLS_AESNI_HAVE_CODE) +#define HAVE_CONSTANT_TIME_AES +#endif + /* Check the internal consistency of a cipher info structure, and * check it against mbedtls_cipher_info_from_xxx(). */ static int check_cipher_info(mbedtls_cipher_type_t type, @@ -858,6 +872,80 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void decrypt_test_vec_cf(int cipher_id, int pad_mode, data_t *key, + data_t *iv, data_t *cipher, + data_t *clear, data_t *ad, data_t *tag, + int expected_finish_result, int tag_result) +{ + unsigned char output[265]; + mbedtls_cipher_context_t ctx; + size_t outlen, total_len; + + mbedtls_cipher_init(&ctx); + + memset(output, 0x00, sizeof(output)); + +#if !defined(MBEDTLS_GCM_C) && !defined(MBEDTLS_CHACHAPOLY_C) + ((void) ad); + ((void) tag); +#endif + + TEST_CF_SECRET(key->x, key->len); + TEST_CF_SECRET(cipher->x, cipher->len); + + /* Prepare context */ + TEST_ASSERT(0 == mbedtls_cipher_setup(&ctx, + mbedtls_cipher_info_from_type(cipher_id))); + TEST_ASSERT(0 == mbedtls_cipher_setkey(&ctx, key->x, 8 * key->len, MBEDTLS_DECRYPT)); +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) + if (pad_mode != -1) { + TEST_ASSERT(0 == mbedtls_cipher_set_padding_mode(&ctx, pad_mode)); + } +#else + (void) pad_mode; +#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ + TEST_ASSERT(0 == mbedtls_cipher_set_iv(&ctx, iv->x, iv->len)); + TEST_ASSERT(0 == mbedtls_cipher_reset(&ctx)); +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) + int expected = (ctx.cipher_info->mode == MBEDTLS_MODE_GCM || + ctx.cipher_info->type == MBEDTLS_CIPHER_CHACHA20_POLY1305) ? + 0 : MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; + + TEST_EQUAL(expected, mbedtls_cipher_update_ad(&ctx, ad->x, ad->len)); +#endif + + /* decode buffer and check tag->x */ + total_len = 0; + TEST_ASSERT(0 == mbedtls_cipher_update(&ctx, cipher->x, cipher->len, output, &outlen)); + total_len += outlen; + int actual_finish_result = mbedtls_cipher_finish(&ctx, output + outlen, + &outlen); + TEST_EQUAL(actual_finish_result, expected_finish_result); + if (0 != expected_finish_result) { + /* Check output parameter is set to the least-harmful value on error */ + TEST_ASSERT(0 == outlen); + } + total_len += outlen; +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) + int tag_expected = (ctx.cipher_info->mode == MBEDTLS_MODE_GCM || + ctx.cipher_info->type == MBEDTLS_CIPHER_CHACHA20_POLY1305) ? + tag_result : MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; + + TEST_EQUAL(tag_expected, mbedtls_cipher_check_tag(&ctx, tag->x, tag->len)); +#endif + + /* check plaintext only if everything went fine */ + if (0 == expected_finish_result && 0 == tag_result) { + TEST_CF_PUBLIC(output, sizeof(output)); + TEST_MEMORY_COMPARE(output, total_len, clear->x, clear->len); + } + +exit: + mbedtls_cipher_free(&ctx); +} +/* END_CASE */ + /* BEGIN_CASE depends_on:MBEDTLS_CIPHER_MODE_AEAD */ void auth_crypt_tv(int cipher_id, data_t *key, data_t *iv, data_t *ad, data_t *cipher, data_t *tag, From 2da5328406529ebd057bcbae99c74745cffcdeb6 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sun, 27 Jul 2025 18:44:21 +0200 Subject: [PATCH 06/16] Constant-flow tests for mbedtls_cipher_crypt Add some basic constant-flow tests for `mbedtls_cipher_crypt()`. We already test auxiliary functions and functional behavior pretty thoroughly elsewhere, so here just focus on the interesting cases for constant-flow behavior with this specific function: encrypt, valid decrypt and invalid-padding decrypt. Signed-off-by: Gilles Peskine --- .../test_suite_cipher.constant_time.data | 25 +++++++++ tests/suites/test_suite_cipher.function | 54 +++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/tests/suites/test_suite_cipher.constant_time.data b/tests/suites/test_suite_cipher.constant_time.data index af608044bb..7f9f4af6ff 100644 --- a/tests/suites/test_suite_cipher.constant_time.data +++ b/tests/suites/test_suite_cipher.constant_time.data @@ -120,3 +120,28 @@ decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"0000000000 CF AES-256-CBC Decrypt test vector, PKCS7 (short, bad pad 17) depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"3e536c7917a695485ef046bda7c6a3e6":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-128-CBC crypt Encrypt NIST KAT #4 +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:HAVE_CONSTANT_TIME_AES +test_vec_crypt_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_NONE:MBEDTLS_ENCRYPT:"00000000000000000000000000000000":"00000000000000000000000000000000":"f34481ec3cc627bacd5dc3fb08f273e6":"0336763e966d92595a567cc9ce537f5e":0:0 + +CF AES-128-CBC crypt Decrypt NIST KAT #4 +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:HAVE_CONSTANT_TIME_AES +test_vec_crypt_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_NONE:MBEDTLS_DECRYPT:"00000000000000000000000000000000":"00000000000000000000000000000000":"0336763e966d92595a567cc9ce537f5e":"f34481ec3cc627bacd5dc3fb08f273e6":0:0 + +CF AES-128-CBC crypt Decrypt PKCS7 invalid padding +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +test_vec_crypt_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:MBEDTLS_DECRYPT:"00000000000000000000000000000000":"00000000000000000000000000000000":"0336763e966d92595a567cc9ce537f5e":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-128-CBC crypt Encrypt NIST KAT #4 PSA +depends_on:MBEDTLS_USE_PSA_CRYPTO:MBEDTLS_TEST_DEPRECATED:PSA_WANT_KEY_TYPE_AES:PSA_WANT_ALG_CBC_NO_PADDING:HAVE_CONSTANT_TIME_AES +test_vec_crypt_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_NONE:MBEDTLS_ENCRYPT:"00000000000000000000000000000000":"00000000000000000000000000000000":"f34481ec3cc627bacd5dc3fb08f273e6":"0336763e966d92595a567cc9ce537f5e":0:1 + +CF AES-128-CBC crypt Decrypt NIST KAT #4 PSA +depends_on:MBEDTLS_USE_PSA_CRYPTO:MBEDTLS_TEST_DEPRECATED:PSA_WANT_KEY_TYPE_AES:PSA_WANT_ALG_CBC_NO_PADDING:HAVE_CONSTANT_TIME_AES +test_vec_crypt_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_NONE:MBEDTLS_DECRYPT:"00000000000000000000000000000000":"00000000000000000000000000000000":"0336763e966d92595a567cc9ce537f5e":"f34481ec3cc627bacd5dc3fb08f273e6":0:1 + +## PSA-backed cipher contexts do not support PKCS7 padding. +#CF AES-128-CBC crypt Decrypt PKCS7 invalid padding PSA +#depends_on:MBEDTLS_USE_PSA_CRYPTO:MBEDTLS_TEST_DEPRECATED:PSA_WANT_KEY_TYPE_AES:PSA_WANT_ALG_CBC_PKCS7:HAVE_CONSTANT_TIME_AES +#test_vec_crypt_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:MBEDTLS_DECRYPT:"00000000000000000000000000000000":"00000000000000000000000000000000":"0336763e966d92595a567cc9ce537f5e":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:1 diff --git a/tests/suites/test_suite_cipher.function b/tests/suites/test_suite_cipher.function index 37a77e5687..8ae2234d4c 100644 --- a/tests/suites/test_suite_cipher.function +++ b/tests/suites/test_suite_cipher.function @@ -1228,6 +1228,60 @@ exit: } /* END_CASE */ +/* BEGIN_CASE depends_on:MBEDTLS_CIPHER_MODE_WITH_PADDING */ +void test_vec_crypt_cf(int cipher_id, int pad_mode, int operation, data_t *key, + data_t *iv, data_t *input, data_t *result, + int expected_finish_result, int use_psa) +{ + mbedtls_cipher_context_t ctx; + unsigned char output[32]; + size_t outlen; + + mbedtls_cipher_init(&ctx); + + memset(output, 0x00, sizeof(output)); + + TEST_CF_SECRET(key->x, key->len); + TEST_CF_SECRET(input->x, input->len); + + /* Prepare context */ +#if !defined(MBEDTLS_USE_PSA_CRYPTO) || !defined(MBEDTLS_TEST_DEPRECATED) + (void) use_psa; +#else + if (use_psa == 1) { + PSA_ASSERT(psa_crypto_init()); + TEST_ASSERT(0 == mbedtls_cipher_setup_psa(&ctx, + mbedtls_cipher_info_from_type(cipher_id), 0)); + } else +#endif /* !MBEDTLS_USE_PSA_CRYPTO || !MBEDTLS_TEST_DEPRECATED*/ + TEST_ASSERT(0 == mbedtls_cipher_setup(&ctx, + mbedtls_cipher_info_from_type(cipher_id))); + + TEST_ASSERT(0 == mbedtls_cipher_setkey(&ctx, key->x, 8 * key->len, operation)); + if (MBEDTLS_MODE_CBC == ctx.cipher_info->mode) { + TEST_ASSERT(0 == mbedtls_cipher_set_padding_mode(&ctx, pad_mode)); + } + + int actual_finish_result = + mbedtls_cipher_crypt(&ctx, iv->len ? iv->x : NULL, iv->len, + input->x, input->len, + output, &outlen); + TEST_EQUAL(expected_finish_result, actual_finish_result); + + /* check plaintext only if everything went fine */ + if (0 == expected_finish_result) { + TEST_CF_PUBLIC(output, sizeof(output)); + TEST_MEMORY_COMPARE(output, outlen, result->x, result->len); + } + +exit: + mbedtls_cipher_free(&ctx); +#if defined(MBEDTLS_USE_PSA_CRYPTO) && defined(MBEDTLS_TEST_DEPRECATED) + PSA_DONE(); +#endif /* MBEDTLS_USE_PSA_CRYPTO && MBEDTLS_TEST_DEPRECATED */ +} +/* END_CASE */ + /* BEGIN_CASE depends_on:MBEDTLS_CIPHER_MODE_WITH_PADDING */ void set_padding(int cipher_id, int pad_mode, int ret) { From 155de2ab775e77ab6fa81bf2b1e6e63768123bc1 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sun, 27 Jul 2025 18:53:57 +0200 Subject: [PATCH 07/16] New function mbedtls_cipher_finish_padded New function `mbedtls_cipher_finish_padded()`, similar to `mbedtls_cipher_finish()`, but reporting padding errors through a separate output parameter. This makes it easier to avoid leaking the presence of a padding error, especially through timing. Thus the new function is recommended to defend against padding oracle attacks. In this commit, implement this function naively, with timing that depends on whether an error happened. A subsequent commit will make this function constant-time. Copy the test decrypt_test_vec and decrypt_test_vec_cf test cases into variants that call `mbedtls_cipher_finish_padded()`. Signed-off-by: Gilles Peskine --- include/mbedtls/cipher.h | 66 ++++++- library/cipher.c | 17 ++ tests/suites/test_suite_cipher.aes.data | 108 +++++++++++ .../test_suite_cipher.constant_time.data | 108 +++++++++++ tests/suites/test_suite_cipher.function | 173 ++++++++++++++++++ 5 files changed, 468 insertions(+), 4 deletions(-) diff --git a/include/mbedtls/cipher.h b/include/mbedtls/cipher.h index 1dc31c9c24..6ef703ddab 100644 --- a/include/mbedtls/cipher.h +++ b/include/mbedtls/cipher.h @@ -881,7 +881,7 @@ int mbedtls_cipher_set_iv(mbedtls_cipher_context_t *ctx, * 1. mbedtls_cipher_set_iv() if the mode uses an IV/nonce. * 2. mbedtls_cipher_reset() * 3. mbedtls_cipher_update() one or more times - * 4. mbedtls_cipher_finish() + * 4. mbedtls_cipher_finish() or mbedtls_cipher_finish_padded() * . * This sequence can be repeated to encrypt or decrypt multiple * messages with the same key. @@ -892,7 +892,7 @@ int mbedtls_cipher_set_iv(mbedtls_cipher_context_t *ctx, * 2. mbedtls_cipher_reset() * 3. mbedtls_cipher_update_ad() * 4. mbedtls_cipher_update() one or more times - * 5. mbedtls_cipher_finish() + * 5. mbedtls_cipher_finish() or mbedtls_cipher_finish_padded() * 6. mbedtls_cipher_check_tag() (for decryption) or * mbedtls_cipher_write_tag() (for encryption). * . @@ -930,7 +930,8 @@ int mbedtls_cipher_update_ad(mbedtls_cipher_context_t *ctx, * many block-sized blocks of data as possible to output. * Any data that cannot be written immediately is either * added to the next block, or flushed when - * mbedtls_cipher_finish() is called. + * mbedtls_cipher_finish() or mbedtls_cipher_finish_padded() + * is called. * Exception: For MBEDTLS_MODE_ECB, expects a single block * in size. For example, 16 Bytes for AES. * @@ -964,6 +965,19 @@ int mbedtls_cipher_update(mbedtls_cipher_context_t *ctx, * contained in it is padded to the size of * the last block, and written to the \p output buffer. * + * \warning This function reports invalid padding through an error + * code. Adversaries may be able to decrypt encrypted + * data if they can submit chosen ciphertexts and + * detect whether it has valid padding or not, + * either through direct observation or through a side + * channel such as timing. This is known as a + * padding oracle attack. + * Therefore applications that call this function for + * decryption with a cipher that involves padding + * should take care around error handling. Preferably, + * such applicatios should use + * mbedtls_cipher_finish_padded() instead of this function. + * * \param ctx The generic cipher context. This must be initialized and * bound to a key. * \param output The buffer to write data to. This needs to be a writable @@ -977,12 +991,56 @@ int mbedtls_cipher_update(mbedtls_cipher_context_t *ctx, * \return #MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED on decryption * expecting a full block but not receiving one. * \return #MBEDTLS_ERR_CIPHER_INVALID_PADDING on invalid padding - * while decrypting. + * while decrypting. Note that invalid-padding errors + * should be handled carefully; see the warning above. * \return A cipher-specific error code on failure. */ int mbedtls_cipher_finish(mbedtls_cipher_context_t *ctx, unsigned char *output, size_t *olen); +/** + * \brief The generic cipher finalization function. If data still + * needs to be flushed from an incomplete block, the data + * contained in it is padded to the size of + * the last block, and written to the \p output buffer. + * + * \note This function is similar to mbedtls_cipher_finish(). + * The only difference is that it reports invalid padding + * decryption differently, through the \p invalid_padding + * parameter rather than an error code. + * For encryption, and in modes without padding (including + * all authenticated modes), this function is identical + * to mbedtls_cipher_finish(). + * + * \param[in,out] ctx The generic cipher context. This must be initialized and + * bound to a key. + * \param[out] output The buffer to write data to. This needs to be a writable + * buffer of at least block_size Bytes. + * \param[out] olen The length of the data written to the \p output buffer. + * This may not be \c NULL. + * \param[out] invalid_padding + * If this function returns \c 0 on decryption, + * \p *invalid_padding is \c 0 if the ciphertext was + * valid, and all-bits-one if the ciphertext had invalid + * padding. + * On encryption, or in a mode without padding (including + * all authenticated modes), \p *invalid_padding is \c 0 + * on success. + * The value in \p *invalid_padding is unspecified if + * this function returns a nonzero status. + * + * \return \c 0 on success. + * Also \c 0 for decryption with invalid padding. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return #MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED on decryption + * expecting a full block but not receiving one. + * \return A cipher-specific error code on failure. + */ +int mbedtls_cipher_finish_padded(mbedtls_cipher_context_t *ctx, + unsigned char *output, size_t *olen, + size_t *invalid_padding); + #if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) /** * \brief This function writes a tag for AEAD ciphers. diff --git a/library/cipher.c b/library/cipher.c index 2ae01dd84d..f3e2f91f82 100644 --- a/library/cipher.c +++ b/library/cipher.c @@ -1124,6 +1124,23 @@ int mbedtls_cipher_finish(mbedtls_cipher_context_t *ctx, return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; } +int mbedtls_cipher_finish_padded(mbedtls_cipher_context_t *ctx, + unsigned char *output, size_t *olen, + size_t *invalid_padding) +{ + *invalid_padding = 0; + int ret = mbedtls_cipher_finish(ctx, output, olen); +#if defined(MBEDTLS_CIPHER_PADDING_PKCS7) || \ + defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS) || \ + defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN) + if (ret == MBEDTLS_ERR_CIPHER_INVALID_PADDING) { + ret = 0; + *invalid_padding = SIZE_MAX; + } +#endif + return ret; +} + #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) int mbedtls_cipher_set_padding_mode(mbedtls_cipher_context_t *ctx, mbedtls_cipher_padding_t mode) diff --git a/tests/suites/test_suite_cipher.aes.data b/tests/suites/test_suite_cipher.aes.data index dd8bf719e0..4298b1d595 100644 --- a/tests/suites/test_suite_cipher.aes.data +++ b/tests/suites/test_suite_cipher.aes.data @@ -1590,6 +1590,114 @@ AES-256-CBC Decrypt test vector, PKCS7 (short, bad pad 17) depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 decrypt_test_vec:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"3e536c7917a695485ef046bda7c6a3e6":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 +AES-128-CBC Decrypt with finish_padded, no padding +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_NONE:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"23f710842b9bb9c32f26648c786807ca":"00000000000000000000000000000000":"":"":0:0 + +AES-192-CBC Decrypt with finish_padded, no padding +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_NONE:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"707b1dbb0ffa40ef7d95def421233fae":"fffffffff80000000000000000000000":"":"":0:0 + +AES-256-CBC Decrypt with finish_padded, no padding +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_NONE:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"49af6b372135acef10132e548f217b17":"ff000000000000000000000000000000":"":"":0:0 + +AES-128-CBC Decrypt with finish_padded, PKCS7 (good pad 1) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"6dbd04d1579f6a7bee0842b9ae491588":"000000000000000000000000000000":"":"":0:0 + +AES-192-CBC Decrypt with finish_padded, PKCS7 (good pad 1) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"593ebdf9a785f414cbed5d8a9eee1e4d":"fffffffff800000000000000000000":"":"":0:0 + +AES-256-CBC Decrypt with finish_padded, PKCS7 (good pad 1) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"f1b27ac78b93f6b0ab9787d8827176e6":"ff0000000000000000000000000000":"":"":0:0 + +AES-128-CBC Decrypt with finish_padded, PKCS7 (good pad 2) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"175334ced3166a22437861f4bcced178":"0000000000000000000000000000":"":"":0:0 + +AES-192-CBC Decrypt with finish_padded, PKCS7 (good pad 2) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"5d9ee7bc7066e438582c86c165604f2e":"fffffffff8000000000000000000":"":"":0:0 + +AES-256-CBC Decrypt with finish_padded, PKCS7 (good pad 2) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"cc71abea78b8e82c3791b52d3dba55e2":"ff00000000000000000000000000":"":"":0:0 + +AES-128-CBC Decrypt with finish_padded, PKCS7 (good pad 15) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"7d340c60b9067883962c69766cf9ec35":"2a":"":"":0:0 + +AES-192-CBC Decrypt with finish_padded, PKCS7 (good pad 15) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"48fef8aaa78c4a148f241aaf14866772":"2a":"":"":0:0 + +AES-256-CBC Decrypt with finish_padded, PKCS7 (good pad 15) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"6ad50ca266a3e32024818f11839afb2f":"2a":"":"":0:0 + +AES-128-CBC Decrypt with finish_padded, PKCS7 (good pad 16) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"e9844992c4b55bcaf8199d5df842adad":"":"":"":0:0 + +AES-192-CBC Decrypt with finish_padded, PKCS7 (good pad 16) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"02bb292527e726fd51eb29894d6f0aad":"":"":"":0:0 + +AES-256-CBC Decrypt with finish_padded, PKCS7 (good pad 16) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"1f788fe6d86c317549697fbf0c07fa43":"":"":"":0:0 + +AES-128-CBC Decrypt with finish_padded, PKCS7 (bad pad 0) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"23f710842b9bb9c32f26648c786807ca":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +AES-192-CBC Decrypt with finish_padded, PKCS7 (bad pad 0) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"707b1dbb0ffa40ef7d95def421233fae":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +AES-256-CBC Decrypt with finish_padded, PKCS7 (bad pad 0) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"49af6b372135acef10132e548f217b17":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +AES-128-CBC Decrypt with finish_padded, PKCS7 (bad pad 0102) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"e651289760d35177eade56eae724f8fd":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +AES-192-CBC Decrypt with finish_padded, PKCS7 (bad pad 0102) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"f5b599490354e71a3b3fb5f1419fb971":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +AES-256-CBC Decrypt with finish_padded, PKCS7 (bad pad 0102) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"6852d318a0884a289a725c558e761e25":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +AES-128-CBC Decrypt with finish_padded, PKCS7 (long, bad pad 17) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"9c336551cc31074ffcefc161bac686b7afa572c3b53bd14a1b98d201229ddd03":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +AES-192-CBC Decrypt with finish_padded, PKCS7 (long, bad pad 17) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"33a31ec7605c85893872a467777f3ddb5c4271870e51a0c618f20a0efccc2bfc":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +AES-256-CBC Decrypt with finish_padded, PKCS7 (long, bad pad 17) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"3e536c7917a695485ef046bda7c6a3e64f439d87aa0deb338029253bea0ba54f":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +AES-128-CBC Decrypt with finish_padded, PKCS7 (short, bad pad 17) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"9c336551cc31074ffcefc161bac686b7":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +AES-192-CBC Decrypt with finish_padded, PKCS7 (short, bad pad 17) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"33a31ec7605c85893872a467777f3ddb":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +AES-256-CBC Decrypt with finish_padded, PKCS7 (short, bad pad 17) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7 +decrypt_padded_test_vec:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"3e536c7917a695485ef046bda7c6a3e6":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + AES-128-CFB Decrypt test vector depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CFB decrypt_test_vec:MBEDTLS_CIPHER_AES_128_CFB128:-1:"fffffffe000000000000000000000000":"00000000000000000000000000000000":"1114bc2028009b923f0b01915ce5e7c4":"00000000000000000000000000000000":"":"":0:0: diff --git a/tests/suites/test_suite_cipher.constant_time.data b/tests/suites/test_suite_cipher.constant_time.data index 7f9f4af6ff..2de31ed15c 100644 --- a/tests/suites/test_suite_cipher.constant_time.data +++ b/tests/suites/test_suite_cipher.constant_time.data @@ -13,6 +13,114 @@ get_pkcs_padding:"00112233445566778899AABBCCDDEE00":MBEDTLS_ERR_CIPHER_INVALID_P Constant-time PKCS7 padding, invalid > 16 get_pkcs_padding:"00112233445566778899AABBCCDDEE11":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 +CF AES-128-CBC Decrypt with finish_padded, no padding +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_NONE:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"23f710842b9bb9c32f26648c786807ca":"00000000000000000000000000000000":"":"":0:0 + +CF AES-192-CBC Decrypt with finish_padded, no padding +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_NONE:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"707b1dbb0ffa40ef7d95def421233fae":"fffffffff80000000000000000000000":"":"":0:0 + +CF AES-256-CBC Decrypt with finish_padded, no padding +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_NONE:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"49af6b372135acef10132e548f217b17":"ff000000000000000000000000000000":"":"":0:0 + +CF AES-128-CBC Decrypt with finish_padded, PKCS7 (good pad 1) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"6dbd04d1579f6a7bee0842b9ae491588":"000000000000000000000000000000":"":"":0:0 + +CF AES-192-CBC Decrypt with finish_padded, PKCS7 (good pad 1) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"593ebdf9a785f414cbed5d8a9eee1e4d":"fffffffff800000000000000000000":"":"":0:0 + +CF AES-256-CBC Decrypt with finish_padded, PKCS7 (good pad 1) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"f1b27ac78b93f6b0ab9787d8827176e6":"ff0000000000000000000000000000":"":"":0:0 + +CF AES-128-CBC Decrypt with finish_padded, PKCS7 (good pad 2) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"175334ced3166a22437861f4bcced178":"0000000000000000000000000000":"":"":0:0 + +CF AES-192-CBC Decrypt with finish_padded, PKCS7 (good pad 2) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"5d9ee7bc7066e438582c86c165604f2e":"fffffffff8000000000000000000":"":"":0:0 + +CF AES-256-CBC Decrypt with finish_padded, PKCS7 (good pad 2) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"cc71abea78b8e82c3791b52d3dba55e2":"ff00000000000000000000000000":"":"":0:0 + +CF AES-128-CBC Decrypt with finish_padded, PKCS7 (good pad 15) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"7d340c60b9067883962c69766cf9ec35":"2a":"":"":0:0 + +CF AES-192-CBC Decrypt with finish_padded, PKCS7 (good pad 15) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"48fef8aaa78c4a148f241aaf14866772":"2a":"":"":0:0 + +CF AES-256-CBC Decrypt with finish_padded, PKCS7 (good pad 15) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"6ad50ca266a3e32024818f11839afb2f":"2a":"":"":0:0 + +CF AES-128-CBC Decrypt with finish_padded, PKCS7 (good pad 16) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"e9844992c4b55bcaf8199d5df842adad":"":"":"":0:0 + +CF AES-192-CBC Decrypt with finish_padded, PKCS7 (good pad 16) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"02bb292527e726fd51eb29894d6f0aad":"":"":"":0:0 + +CF AES-256-CBC Decrypt with finish_padded, PKCS7 (good pad 16) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"1f788fe6d86c317549697fbf0c07fa43":"":"":"":0:0 + +CF AES-128-CBC Decrypt with finish_padded, PKCS7 (bad pad 0) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"23f710842b9bb9c32f26648c786807ca":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-192-CBC Decrypt with finish_padded, PKCS7 (bad pad 0) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"707b1dbb0ffa40ef7d95def421233fae":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-256-CBC Decrypt with finish_padded, PKCS7 (bad pad 0) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"49af6b372135acef10132e548f217b17":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-128-CBC Decrypt with finish_padded, PKCS7 (bad pad 0102) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"e651289760d35177eade56eae724f8fd":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-192-CBC Decrypt with finish_padded, PKCS7 (bad pad 0102) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"f5b599490354e71a3b3fb5f1419fb971":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-256-CBC Decrypt with finish_padded, PKCS7 (bad pad 0102) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"6852d318a0884a289a725c558e761e25":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-128-CBC Decrypt with finish_padded, PKCS7 (long, bad pad 17) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"9c336551cc31074ffcefc161bac686b7afa572c3b53bd14a1b98d201229ddd03":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-192-CBC Decrypt with finish_padded, PKCS7 (long, bad pad 17) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"33a31ec7605c85893872a467777f3ddb5c4271870e51a0c618f20a0efccc2bfc":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-256-CBC Decrypt with finish_padded, PKCS7 (long, bad pad 17) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"3e536c7917a695485ef046bda7c6a3e64f439d87aa0deb338029253bea0ba54f":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-128-CBC Decrypt with finish_padded, PKCS7 (short, bad pad 17) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_PKCS7:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"9c336551cc31074ffcefc161bac686b7":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-192-CBC Decrypt with finish_padded, PKCS7 (short, bad pad 17) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_192_CBC:MBEDTLS_PADDING_PKCS7:"000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"33a31ec7605c85893872a467777f3ddb":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + +CF AES-256-CBC Decrypt with finish_padded, PKCS7 (short, bad pad 17) +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:MBEDTLS_CIPHER_PADDING_PKCS7:HAVE_CONSTANT_TIME_AES +decrypt_padded_test_vec_cf:MBEDTLS_CIPHER_AES_256_CBC:MBEDTLS_PADDING_PKCS7:"0000000000000000000000000000000000000000000000000000000000000000":"00000000000000000000000000000000":"3e536c7917a695485ef046bda7c6a3e6":"":"":"":MBEDTLS_ERR_CIPHER_INVALID_PADDING:0 + CF AES-128-CBC Decrypt test vector, no padding depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:HAVE_CONSTANT_TIME_AES decrypt_test_vec_cf:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_PADDING_NONE:"ffffffffe00000000000000000000000":"00000000000000000000000000000000":"23f710842b9bb9c32f26648c786807ca":"00000000000000000000000000000000":"":"":0:0 diff --git a/tests/suites/test_suite_cipher.function b/tests/suites/test_suite_cipher.function index 8ae2234d4c..fbc48b7974 100644 --- a/tests/suites/test_suite_cipher.function +++ b/tests/suites/test_suite_cipher.function @@ -946,6 +946,179 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void decrypt_padded_test_vec(int cipher_id, int pad_mode, data_t *key, + data_t *iv, data_t *cipher, + data_t *clear, data_t *ad, data_t *tag, + int expected_finish_result, int tag_result) +{ + unsigned char output[265]; + mbedtls_cipher_context_t ctx; + size_t outlen, total_len; + + mbedtls_cipher_init(&ctx); + + memset(output, 0x00, sizeof(output)); + +#if !defined(MBEDTLS_GCM_C) && !defined(MBEDTLS_CHACHAPOLY_C) + ((void) ad); + ((void) tag); +#endif + + /* Prepare context */ + TEST_ASSERT(0 == mbedtls_cipher_setup(&ctx, + mbedtls_cipher_info_from_type(cipher_id))); + TEST_ASSERT(0 == mbedtls_cipher_setkey(&ctx, key->x, 8 * key->len, MBEDTLS_DECRYPT)); +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) + if (pad_mode != -1) { + TEST_ASSERT(0 == mbedtls_cipher_set_padding_mode(&ctx, pad_mode)); + } +#else + (void) pad_mode; +#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ + TEST_ASSERT(0 == mbedtls_cipher_set_iv(&ctx, iv->x, iv->len)); + TEST_ASSERT(0 == mbedtls_cipher_reset(&ctx)); +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) + int expected = (ctx.cipher_info->mode == MBEDTLS_MODE_GCM || + ctx.cipher_info->type == MBEDTLS_CIPHER_CHACHA20_POLY1305) ? + 0 : MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; + + TEST_EQUAL(expected, mbedtls_cipher_update_ad(&ctx, ad->x, ad->len)); +#endif + + /* decode buffer and check tag->x */ + total_len = 0; + TEST_ASSERT(0 == mbedtls_cipher_update(&ctx, cipher->x, cipher->len, output, &outlen)); + total_len += outlen; + + size_t invalid_padding = 42; + int actual_finish_result = + mbedtls_cipher_finish_padded(&ctx, output + outlen, &outlen, + &invalid_padding); + switch (expected_finish_result) { + case 0: + TEST_EQUAL(actual_finish_result, 0); + TEST_EQUAL(invalid_padding, 0); + break; + case MBEDTLS_ERR_CIPHER_INVALID_PADDING: + TEST_EQUAL(actual_finish_result, 0); + TEST_EQUAL(invalid_padding, SIZE_MAX); + break; + default: + TEST_EQUAL(actual_finish_result, expected_finish_result); + /* Check output parameter is set to the least-harmful value on error */ + TEST_EQUAL(0, outlen); + break; + } + total_len += outlen; + +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) + int tag_expected = (ctx.cipher_info->mode == MBEDTLS_MODE_GCM || + ctx.cipher_info->type == MBEDTLS_CIPHER_CHACHA20_POLY1305) ? + tag_result : MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; + + TEST_EQUAL(tag_expected, mbedtls_cipher_check_tag(&ctx, tag->x, tag->len)); +#endif + + /* check plaintext only if everything went fine */ + if (0 == expected_finish_result && 0 == tag_result) { + TEST_ASSERT(total_len == clear->len); + TEST_ASSERT(0 == memcmp(output, clear->x, clear->len)); + } + +exit: + mbedtls_cipher_free(&ctx); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void decrypt_padded_test_vec_cf(int cipher_id, int pad_mode, data_t *key, + data_t *iv, data_t *cipher, + data_t *clear, data_t *ad, data_t *tag, + int expected_finish_result, int tag_result) +{ + unsigned char output[265]; + mbedtls_cipher_context_t ctx; + size_t outlen, total_len; + + mbedtls_cipher_init(&ctx); + + memset(output, 0x00, sizeof(output)); + +#if !defined(MBEDTLS_GCM_C) && !defined(MBEDTLS_CHACHAPOLY_C) + ((void) ad); + ((void) tag); +#endif + + TEST_CF_SECRET(key->x, key->len); + TEST_CF_SECRET(cipher->x, cipher->len); + + /* Prepare context */ + TEST_ASSERT(0 == mbedtls_cipher_setup(&ctx, + mbedtls_cipher_info_from_type(cipher_id))); + TEST_ASSERT(0 == mbedtls_cipher_setkey(&ctx, key->x, 8 * key->len, MBEDTLS_DECRYPT)); +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) + if (pad_mode != -1) { + TEST_ASSERT(0 == mbedtls_cipher_set_padding_mode(&ctx, pad_mode)); + } +#else + (void) pad_mode; +#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ + TEST_ASSERT(0 == mbedtls_cipher_set_iv(&ctx, iv->x, iv->len)); + TEST_ASSERT(0 == mbedtls_cipher_reset(&ctx)); +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) + int expected = (ctx.cipher_info->mode == MBEDTLS_MODE_GCM || + ctx.cipher_info->type == MBEDTLS_CIPHER_CHACHA20_POLY1305) ? + 0 : MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; + + TEST_EQUAL(expected, mbedtls_cipher_update_ad(&ctx, ad->x, ad->len)); +#endif + + /* decode buffer and check tag->x */ + total_len = 0; + TEST_ASSERT(0 == mbedtls_cipher_update(&ctx, cipher->x, cipher->len, output, &outlen)); + total_len += outlen; + + size_t invalid_padding = 42; + int actual_finish_result = + mbedtls_cipher_finish_padded(&ctx, output + outlen, &outlen, + &invalid_padding); + switch (expected_finish_result) { + case 0: + TEST_EQUAL(actual_finish_result, 0); + TEST_EQUAL(invalid_padding, 0); + break; + case MBEDTLS_ERR_CIPHER_INVALID_PADDING: + TEST_EQUAL(actual_finish_result, 0); + TEST_EQUAL(invalid_padding, SIZE_MAX); + break; + default: + TEST_EQUAL(actual_finish_result, expected_finish_result); + /* Check output parameter is set to the least-harmful value on error */ + TEST_EQUAL(0, outlen); + break; + } + total_len += outlen; + +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) + int tag_expected = (ctx.cipher_info->mode == MBEDTLS_MODE_GCM || + ctx.cipher_info->type == MBEDTLS_CIPHER_CHACHA20_POLY1305) ? + tag_result : MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; + + TEST_EQUAL(tag_expected, mbedtls_cipher_check_tag(&ctx, tag->x, tag->len)); +#endif + + /* check plaintext only if everything went fine */ + if (0 == expected_finish_result && 0 == tag_result) { + TEST_CF_PUBLIC(output, sizeof(output)); + TEST_MEMORY_COMPARE(output, total_len, clear->x, clear->len); + } + +exit: + mbedtls_cipher_free(&ctx); +} +/* END_CASE */ + /* BEGIN_CASE depends_on:MBEDTLS_CIPHER_MODE_AEAD */ void auth_crypt_tv(int cipher_id, data_t *key, data_t *iv, data_t *ad, data_t *cipher, data_t *tag, From 6cb9f35d8c84d6b3d92e2071a31fb6b183da949f Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sun, 27 Jul 2025 21:22:39 +0200 Subject: [PATCH 08/16] Switch legacy cipher to constant-time invalid padding reporting In internal `get_padding` functions, report whether the padding was invalid through a separate output parameter, rather than the return code. Take advantage of this to have `mbedtls_cipher_finish_padded()` be the easy path that just passes the `invalid_padding` through. Make `mbedtls_cipher_finish()` a wrapper around `mbedtls_cipher_finish_padded()` that converts the invalid-padding output into an error code. Signed-off-by: Gilles Peskine --- include/mbedtls/cipher.h | 11 ++++- library/cipher.c | 62 ++++++++++++++----------- library/cipher_invasive.h | 3 +- tests/suites/test_suite_cipher.function | 43 +++++++++++++---- 4 files changed, 78 insertions(+), 41 deletions(-) diff --git a/include/mbedtls/cipher.h b/include/mbedtls/cipher.h index 6ef703ddab..3778f44551 100644 --- a/include/mbedtls/cipher.h +++ b/include/mbedtls/cipher.h @@ -329,8 +329,15 @@ typedef struct mbedtls_cipher_context_t { /** Padding functions to use, if relevant for * the specific cipher mode. */ - void(*MBEDTLS_PRIVATE(add_padding))(unsigned char *output, size_t olen, size_t data_len); - int(*MBEDTLS_PRIVATE(get_padding))(unsigned char *input, size_t ilen, size_t *data_len); + void(*MBEDTLS_PRIVATE(add_padding))(unsigned char *output, size_t olen, + size_t data_len); + /* Report invalid-padding condition through the output parameter + * invalid_padding. To minimize changes in Mbed TLS 3.6, where this + * declaration is in a public header, use the public type size_t + * rather than the internal type mbedtls_ct_condition_t. */ + int(*MBEDTLS_PRIVATE(get_padding))(unsigned char *input, size_t ilen, + size_t *data_len, + size_t *invalid_padding); #endif /** Buffer for input that has not been processed yet. */ diff --git a/library/cipher.c b/library/cipher.c index f3e2f91f82..f9d46213db 100644 --- a/library/cipher.c +++ b/library/cipher.c @@ -846,7 +846,8 @@ static void add_pkcs_padding(unsigned char *output, size_t output_len, */ MBEDTLS_STATIC_TESTABLE int mbedtls_get_pkcs_padding(unsigned char *input, size_t input_len, - size_t *data_len) + size_t *data_len, + size_t *invalid_padding) { size_t i, pad_idx; unsigned char padding_len; @@ -872,7 +873,8 @@ MBEDTLS_STATIC_TESTABLE int mbedtls_get_pkcs_padding(unsigned char *input, /* If the padding is invalid, set the output length to 0 */ *data_len = mbedtls_ct_if(bad, 0, input_len - padding_len); - return mbedtls_ct_error_if_else_0(bad, MBEDTLS_ERR_CIPHER_INVALID_PADDING); + *invalid_padding = mbedtls_ct_size_if_else_0(bad, SIZE_MAX); + return 0; } #endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */ @@ -893,7 +895,7 @@ static void add_one_and_zeros_padding(unsigned char *output, } static int get_one_and_zeros_padding(unsigned char *input, size_t input_len, - size_t *data_len) + size_t *data_len, size_t *invalid_padding) { if (NULL == input || NULL == data_len) { return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; @@ -916,7 +918,8 @@ static int get_one_and_zeros_padding(unsigned char *input, size_t input_len, in_padding = mbedtls_ct_bool_and(in_padding, mbedtls_ct_bool_not(is_nonzero)); } - return mbedtls_ct_error_if_else_0(bad, MBEDTLS_ERR_CIPHER_INVALID_PADDING); + *invalid_padding = mbedtls_ct_size_if_else_0(bad, SIZE_MAX); + return 0; } #endif /* MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS */ @@ -937,7 +940,7 @@ static void add_zeros_and_len_padding(unsigned char *output, } static int get_zeros_and_len_padding(unsigned char *input, size_t input_len, - size_t *data_len) + size_t *data_len, size_t *invalid_padding) { size_t i, pad_idx; unsigned char padding_len; @@ -963,7 +966,8 @@ static int get_zeros_and_len_padding(unsigned char *input, size_t input_len, bad = mbedtls_ct_bool_or(bad, nonzero_pad_byte); } - return mbedtls_ct_error_if_else_0(bad, MBEDTLS_ERR_CIPHER_INVALID_PADDING); + *invalid_padding = mbedtls_ct_size_if_else_0(bad, SIZE_MAX); + return 0; } #endif /* MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN */ @@ -978,7 +982,7 @@ static void add_zeros_padding(unsigned char *output, } static int get_zeros_padding(unsigned char *input, size_t input_len, - size_t *data_len) + size_t *data_len, size_t *invalid_padding) { size_t i; mbedtls_ct_condition_t done = MBEDTLS_CT_FALSE, prev_done; @@ -994,6 +998,7 @@ static int get_zeros_padding(unsigned char *input, size_t input_len, *data_len = mbedtls_ct_size_if(mbedtls_ct_bool_ne(done, prev_done), i, *data_len); } + *invalid_padding = 0; return 0; } #endif /* MBEDTLS_CIPHER_PADDING_ZEROS */ @@ -1005,20 +1010,21 @@ static int get_zeros_padding(unsigned char *input, size_t input_len, * but a trivial get_padding function */ static int get_no_padding(unsigned char *input, size_t input_len, - size_t *data_len) + size_t *data_len, size_t *invalid_padding) { if (NULL == input || NULL == data_len) { return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; } *data_len = input_len; - + *invalid_padding = 0; return 0; } #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ -int mbedtls_cipher_finish(mbedtls_cipher_context_t *ctx, - unsigned char *output, size_t *olen) +int mbedtls_cipher_finish_padded(mbedtls_cipher_context_t *ctx, + unsigned char *output, size_t *olen, + size_t *invalid_padding) { if (ctx->cipher_info == NULL) { return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; @@ -1034,6 +1040,7 @@ int mbedtls_cipher_finish(mbedtls_cipher_context_t *ctx, #endif /* MBEDTLS_USE_PSA_CRYPTO && !MBEDTLS_DEPRECATED_REMOVED */ *olen = 0; + *invalid_padding = 0; #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) /* CBC mode requires padding so we make sure a call to @@ -1110,7 +1117,7 @@ int mbedtls_cipher_finish(mbedtls_cipher_context_t *ctx, /* Set output size for decryption */ if (MBEDTLS_DECRYPT == ctx->operation) { return ctx->get_padding(output, mbedtls_cipher_get_block_size(ctx), - olen); + olen, invalid_padding); } /* Set output size for encryption */ @@ -1124,20 +1131,16 @@ int mbedtls_cipher_finish(mbedtls_cipher_context_t *ctx, return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; } -int mbedtls_cipher_finish_padded(mbedtls_cipher_context_t *ctx, - unsigned char *output, size_t *olen, - size_t *invalid_padding) +int mbedtls_cipher_finish(mbedtls_cipher_context_t *ctx, + unsigned char *output, size_t *olen) { - *invalid_padding = 0; - int ret = mbedtls_cipher_finish(ctx, output, olen); -#if defined(MBEDTLS_CIPHER_PADDING_PKCS7) || \ - defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS) || \ - defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN) - if (ret == MBEDTLS_ERR_CIPHER_INVALID_PADDING) { - ret = 0; - *invalid_padding = SIZE_MAX; + size_t invalid_padding = 0; + int ret = mbedtls_cipher_finish_padded(ctx, output, olen, + &invalid_padding); + if (ret == 0) { + ret = mbedtls_ct_error_if_else_0(invalid_padding, + MBEDTLS_ERR_CIPHER_INVALID_PADDING); } -#endif return ret; } @@ -1410,14 +1413,17 @@ int mbedtls_cipher_crypt(mbedtls_cipher_context_t *ctx, return ret; } - if ((ret = mbedtls_cipher_finish(ctx, output + *olen, - &finish_olen)) != 0) { + size_t invalid_padding = 0; + if ((ret = mbedtls_cipher_finish_padded(ctx, output + *olen, + &finish_olen, + &invalid_padding)) != 0) { return ret; } - *olen += finish_olen; - return 0; + ret = mbedtls_ct_error_if_else_0(invalid_padding, + MBEDTLS_ERR_CIPHER_INVALID_PADDING); + return ret; } #if defined(MBEDTLS_CIPHER_MODE_AEAD) diff --git a/library/cipher_invasive.h b/library/cipher_invasive.h index 702f8f73e9..e82a0a7f99 100644 --- a/library/cipher_invasive.h +++ b/library/cipher_invasive.h @@ -20,7 +20,8 @@ MBEDTLS_STATIC_TESTABLE int mbedtls_get_pkcs_padding(unsigned char *input, size_t input_len, - size_t *data_len); + size_t *data_len, + size_t *invalid_padding); #endif diff --git a/tests/suites/test_suite_cipher.function b/tests/suites/test_suite_cipher.function index fbc48b7974..9e3e026834 100644 --- a/tests/suites/test_suite_cipher.function +++ b/tests/suites/test_suite_cipher.function @@ -1475,8 +1475,8 @@ exit: /* END_CASE */ /* BEGIN_CASE depends_on:MBEDTLS_CIPHER_MODE_CBC */ -void check_padding(int pad_mode, data_t *input, int ret, int dlen_check - ) +void check_padding(int pad_mode, data_t *input, + int expected_ret, int dlen_check) { mbedtls_cipher_info_t cipher_info; mbedtls_cipher_context_t ctx; @@ -1489,10 +1489,20 @@ void check_padding(int pad_mode, data_t *input, int ret, int dlen_check TEST_ASSERT(0 == mbedtls_cipher_set_padding_mode(&ctx, pad_mode)); - - TEST_ASSERT(ret == ctx.get_padding(input->x, input->len, &dlen)); - if (0 == ret) { - TEST_ASSERT(dlen == (size_t) dlen_check); + size_t invalid_padding = 42; + int ret = ctx.get_padding(input->x, input->len, &dlen, &invalid_padding); + switch (expected_ret) { + case 0: + TEST_EQUAL(ret, 0); + TEST_EQUAL(invalid_padding, 0); + TEST_EQUAL(dlen, dlen_check); + break; + case MBEDTLS_ERR_CIPHER_INVALID_PADDING: + TEST_EQUAL(ret, 0); + TEST_EQUAL(invalid_padding, SIZE_MAX); + break; + default: + TEST_EQUAL(ret, expected_ret); } } /* END_CASE */ @@ -1585,14 +1595,27 @@ void get_pkcs_padding(data_t *decrypted_block, int exp_ret, int exp_len) { int ret; size_t calculated_len; + size_t invalid_padding; TEST_CF_SECRET(decrypted_block->x, decrypted_block->len); ret = mbedtls_get_pkcs_padding(decrypted_block->x, decrypted_block->len, - &calculated_len); + &calculated_len, &invalid_padding); - TEST_EQUAL(ret, exp_ret); - if (exp_ret == 0) { - TEST_EQUAL(calculated_len, exp_len); + switch (exp_ret) { + case 0: + TEST_EQUAL(ret, 0); + TEST_EQUAL(invalid_padding, 0); + TEST_EQUAL(calculated_len, exp_len); + break; + + case MBEDTLS_ERR_CIPHER_INVALID_PADDING: + TEST_EQUAL(ret, 0); + TEST_EQUAL(invalid_padding, ~(size_t) 0); + break; + + default: + TEST_EQUAL(ret, exp_ret); + break; } } /* END_CASE */ From 46ebc3a758c061312855b7faec4bff785509e792 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Sun, 27 Jul 2025 21:20:47 +0200 Subject: [PATCH 09/16] Note that the decrypted length is sensitive when there was padding The decrypted length reveals the amount of padding that was eliminated, and thus reveals partial information about the last ciphertext block. Signed-off-by: Gilles Peskine --- include/mbedtls/cipher.h | 9 +++++++++ tests/suites/test_suite_cipher.function | 3 +++ 2 files changed, 12 insertions(+) diff --git a/include/mbedtls/cipher.h b/include/mbedtls/cipher.h index 3778f44551..616c5543c9 100644 --- a/include/mbedtls/cipher.h +++ b/include/mbedtls/cipher.h @@ -991,6 +991,11 @@ int mbedtls_cipher_update(mbedtls_cipher_context_t *ctx, * buffer of at least block_size Bytes. * \param olen The length of the data written to the \p output buffer. * This may not be \c NULL. + * Note that when decrypting in a mode with padding, + * the actual output length is sensitive and may be + * used to mount a padding oracle attack (see warning + * above), although less efficiently than through + * the invalid-padding condition. * * \return \c 0 on success. * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on @@ -1025,6 +1030,10 @@ int mbedtls_cipher_finish(mbedtls_cipher_context_t *ctx, * buffer of at least block_size Bytes. * \param[out] olen The length of the data written to the \p output buffer. * This may not be \c NULL. + * Note that when decrypting in a mode with padding, + * the actual output length is sensitive and may be + * used to mount a padding oracle attack (see warning + * on mbedtls_cipher_finish()). * \param[out] invalid_padding * If this function returns \c 0 on decryption, * \p *invalid_padding is \c 0 if the ciphertext was diff --git a/tests/suites/test_suite_cipher.function b/tests/suites/test_suite_cipher.function index 9e3e026834..ac0264e3d9 100644 --- a/tests/suites/test_suite_cipher.function +++ b/tests/suites/test_suite_cipher.function @@ -921,6 +921,7 @@ void decrypt_test_vec_cf(int cipher_id, int pad_mode, data_t *key, total_len += outlen; int actual_finish_result = mbedtls_cipher_finish(&ctx, output + outlen, &outlen); + TEST_CF_PUBLIC(&outlen, sizeof(outlen)); TEST_EQUAL(actual_finish_result, expected_finish_result); if (0 != expected_finish_result) { /* Check output parameter is set to the least-harmful value on error */ @@ -1083,6 +1084,7 @@ void decrypt_padded_test_vec_cf(int cipher_id, int pad_mode, data_t *key, int actual_finish_result = mbedtls_cipher_finish_padded(&ctx, output + outlen, &outlen, &invalid_padding); + TEST_CF_PUBLIC(&outlen, sizeof(outlen)); switch (expected_finish_result) { case 0: TEST_EQUAL(actual_finish_result, 0); @@ -1439,6 +1441,7 @@ void test_vec_crypt_cf(int cipher_id, int pad_mode, int operation, data_t *key, mbedtls_cipher_crypt(&ctx, iv->len ? iv->x : NULL, iv->len, input->x, input->len, output, &outlen); + TEST_CF_PUBLIC(&outlen, sizeof(outlen)); TEST_EQUAL(expected_finish_result, actual_finish_result); /* check plaintext only if everything went fine */ From 4eba1cc364c2a973f660e19d4398ac4f009cd7dc Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 8 Aug 2025 13:30:03 +0200 Subject: [PATCH 10/16] Improve outcome reporting of additional valgrind_cf testing Signed-off-by: Gilles Peskine --- tests/scripts/components-configuration-crypto.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/scripts/components-configuration-crypto.sh b/tests/scripts/components-configuration-crypto.sh index 6b12bb9af5..580de3dd75 100644 --- a/tests/scripts/components-configuration-crypto.sh +++ b/tests/scripts/components-configuration-crypto.sh @@ -23,6 +23,11 @@ test_with_valgrind () { ## Exclude suites that contain some constant-time tests, but whose focus ## isn't on constant-time tests. test_with_valgrind_constant_time () { + # Use a different configuration name in the outcome file if we're doing + # additional valgrind testing on top of non-instrumented testing. + if [[ $MBEDTLS_TEST_CONFIGURATION != *valgrind_cf* ]]; then + declare MBEDTLS_TEST_CONFIGURATION="${MBEDTLS_TEST_CONFIGURATION}+valgrind_cf" + fi declare GLOBIGNORE="tests/suites/test_suite_constant_time_hmac.data" test_with_valgrind tests/suites/*constant_time*.data } From beb53af31ff92e25c92c0d862cb94f430560f1f1 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 8 Aug 2025 13:35:46 +0200 Subject: [PATCH 11/16] Expand the ignore patterns for test_full_block_cipher_psa_dispatch Some tests from `test_suite_cipher.constant_time.data` follow the same pattern as `test_suite_cipher.aes.data` and so have the same coverage discrepancy. Signed-off-by: Gilles Peskine --- tests/scripts/analyze_outcomes.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/scripts/analyze_outcomes.py b/tests/scripts/analyze_outcomes.py index 52034a1973..9d03d1db46 100755 --- a/tests/scripts/analyze_outcomes.py +++ b/tests/scripts/analyze_outcomes.py @@ -667,6 +667,12 @@ class DriverVSReference_block_cipher_dispatch(outcome_analysis.DriverVSReference 'CMAC null arguments', re.compile('CMAC.* (AES|ARIA|Camellia).*'), ], + 'test_suite_cipher.constant_time': [ + # Like with test_suite_cipher.aes and such, these tests call + # cipher_wrapper in a way that requires the block cipher to + # be built in. + re.compile('.*(AES|ARIA|CAMELLIA).*(encrypt|decrypt).*', re.I), + ], 'test_suite_cipher.padding': [ # Following tests require AES_C/CAMELLIA_C to be enabled, # but these are not available in the accelerated component. From 7db50d070043c94c9c49a5860a23ab72afb97b65 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 7 Aug 2025 23:11:26 +0200 Subject: [PATCH 12/16] Changelog entry for mbedtls_cipher_finish_padded() Signed-off-by: Gilles Peskine --- ChangeLog.d/mbedtls_cipher_finish_padded.txt | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 ChangeLog.d/mbedtls_cipher_finish_padded.txt diff --git a/ChangeLog.d/mbedtls_cipher_finish_padded.txt b/ChangeLog.d/mbedtls_cipher_finish_padded.txt new file mode 100644 index 0000000000..bf2405eb41 --- /dev/null +++ b/ChangeLog.d/mbedtls_cipher_finish_padded.txt @@ -0,0 +1,4 @@ +Features + * The new function mbedtls_cipher_finish_padded() is similar to + mbedtls_cipher_finish(), but makes it easier to process invalid-padding + conditions in constant time. From b4b1920f7a7c36f7ea71d431e159f9a08be3102a Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 8 Aug 2025 13:28:22 +0200 Subject: [PATCH 13/16] We now run some tests with MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND Addresses https://github.com/Mbed-TLS/mbedtls/issues/9586 . This is not a fully satisfactory resolution, because we don't run every constant-flow test with Valgrind in PR jobs, only a small subset. We should improve the coverage/resource balance. Signed-off-by: Gilles Peskine --- tests/scripts/analyze_outcomes.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/scripts/analyze_outcomes.py b/tests/scripts/analyze_outcomes.py index 9d03d1db46..7b43145151 100755 --- a/tests/scripts/analyze_outcomes.py +++ b/tests/scripts/analyze_outcomes.py @@ -98,9 +98,6 @@ class CoverageTask(outcome_analysis.CoverageTask): 'Config: MBEDTLS_SHA256_USE_A64_CRYPTO_ONLY', 'Config: MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY', 'Config: MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY', - # We don't run test_suite_config when we test this. - # https://github.com/Mbed-TLS/mbedtls/issues/9586 - 'Config: MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND', ], 'test_suite_config.psa_boolean': [ # We don't test with HMAC disabled. From f845e9d1113c9459b3b313e1b0d71ddc66b130fb Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 25 Aug 2025 16:48:42 +0200 Subject: [PATCH 14/16] Minor documentation improvements Signed-off-by: Gilles Peskine --- include/mbedtls/cipher.h | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/include/mbedtls/cipher.h b/include/mbedtls/cipher.h index 616c5543c9..e547152155 100644 --- a/include/mbedtls/cipher.h +++ b/include/mbedtls/cipher.h @@ -885,23 +885,24 @@ int mbedtls_cipher_set_iv(mbedtls_cipher_context_t *ctx, * * \note With non-AEAD ciphers, the order of calls for each message * is as follows: - * 1. mbedtls_cipher_set_iv() if the mode uses an IV/nonce. - * 2. mbedtls_cipher_reset() - * 3. mbedtls_cipher_update() one or more times - * 4. mbedtls_cipher_finish() or mbedtls_cipher_finish_padded() + * 1. mbedtls_cipher_set_iv() if the mode uses an IV/nonce; + * 2. mbedtls_cipher_reset(); + * 3. mbedtls_cipher_update() zero, one or more times; + * 4. mbedtls_cipher_finish_padded() (recommended for decryption + * if the mode uses padding) or mbedtls_cipher_finish(). * . * This sequence can be repeated to encrypt or decrypt multiple * messages with the same key. * * \note With AEAD ciphers, the order of calls for each message * is as follows: - * 1. mbedtls_cipher_set_iv() if the mode uses an IV/nonce. - * 2. mbedtls_cipher_reset() - * 3. mbedtls_cipher_update_ad() - * 4. mbedtls_cipher_update() one or more times - * 5. mbedtls_cipher_finish() or mbedtls_cipher_finish_padded() + * 1. mbedtls_cipher_set_iv() if the mode uses an IV/nonce; + * 2. mbedtls_cipher_reset(); + * 3. mbedtls_cipher_update_ad(); + * 4. mbedtls_cipher_update() zero, one or more times; + * 5. mbedtls_cipher_finish() (or mbedtls_cipher_finish_padded()); * 6. mbedtls_cipher_check_tag() (for decryption) or - * mbedtls_cipher_write_tag() (for encryption). + * mbedtls_cipher_write_tag() (for encryption). * . * This sequence can be repeated to encrypt or decrypt multiple * messages with the same key. @@ -982,7 +983,7 @@ int mbedtls_cipher_update(mbedtls_cipher_context_t *ctx, * Therefore applications that call this function for * decryption with a cipher that involves padding * should take care around error handling. Preferably, - * such applicatios should use + * such applications should use * mbedtls_cipher_finish_padded() instead of this function. * * \param ctx The generic cipher context. This must be initialized and @@ -1061,7 +1062,8 @@ int mbedtls_cipher_finish_padded(mbedtls_cipher_context_t *ctx, /** * \brief This function writes a tag for AEAD ciphers. * Currently supported with GCM and ChaCha20+Poly1305. - * This must be called after mbedtls_cipher_finish(). + * This must be called after mbedtls_cipher_finish() + * or mbedtls_cipher_finish_padded(). * * \param ctx The generic cipher context. This must be initialized, * bound to a key, and have just completed a cipher @@ -1080,7 +1082,8 @@ int mbedtls_cipher_write_tag(mbedtls_cipher_context_t *ctx, /** * \brief This function checks the tag for AEAD ciphers. * Currently supported with GCM and ChaCha20+Poly1305. - * This must be called after mbedtls_cipher_finish(). + * This must be called after mbedtls_cipher_finish() + * or mbedtls_cipher_finish_padded(). * * \param ctx The generic cipher context. This must be initialized. * \param tag The buffer holding the tag. This must be a readable From 94e4e15748d7018c4a8aa6c63f554b21ab754b58 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 25 Aug 2025 16:53:54 +0200 Subject: [PATCH 15/16] Explain the near-duplication of test function for constant-flow tests Signed-off-by: Gilles Peskine --- tests/suites/test_suite_cipher.function | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/suites/test_suite_cipher.function b/tests/suites/test_suite_cipher.function index ac0264e3d9..96c336086b 100644 --- a/tests/suites/test_suite_cipher.function +++ b/tests/suites/test_suite_cipher.function @@ -873,6 +873,13 @@ exit: /* END_CASE */ /* BEGIN_CASE */ +/* Similar to decrypt_test_vec, but with constant-flow assertions. + * We use a separate test function so that we can run the functional tests + * in all configurations where the underlying cipher is enabled, and + * run the constant-flow tests only in configurations where the underlying + * cipher is constant-time. In particular, AES test cases need to depend + * on HAVE_CONSTANT_TIME_AES. + */ void decrypt_test_vec_cf(int cipher_id, int pad_mode, data_t *key, data_t *iv, data_t *cipher, data_t *clear, data_t *ad, data_t *tag, @@ -1033,6 +1040,13 @@ exit: /* END_CASE */ /* BEGIN_CASE */ +/* Similar to decrypt_padded_test_vec, but with constant-flow assertions. + * We use a separate test function so that we can run the functional tests + * in all configurations where the underlying cipher is enabled, and + * run the constant-flow tests only in configurations where the underlying + * cipher is constant-time. In particular, AES test cases need to depend + * on HAVE_CONSTANT_TIME_AES. + */ void decrypt_padded_test_vec_cf(int cipher_id, int pad_mode, data_t *key, data_t *iv, data_t *cipher, data_t *clear, data_t *ad, data_t *tag, @@ -1404,6 +1418,13 @@ exit: /* END_CASE */ /* BEGIN_CASE depends_on:MBEDTLS_CIPHER_MODE_WITH_PADDING */ +/* Similar to test_vec_crypt, but with constant-flow assertions. + * We use a separate test function so that we can run the functional tests + * in all configurations where the underlying cipher is enabled, and + * run the constant-flow tests only in configurations where the underlying + * cipher is constant-time. In particular, AES test cases need to depend + * on HAVE_CONSTANT_TIME_AES. + */ void test_vec_crypt_cf(int cipher_id, int pad_mode, int operation, data_t *key, data_t *iv, data_t *input, data_t *result, int expected_finish_result, int use_psa) From 44765c4b9b104ad390d3525626aa4e72320c423b Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Tue, 26 Aug 2025 13:11:27 +0200 Subject: [PATCH 16/16] Test invalid_padding against all-bits-one `SIZE_MAX` and `~(size_t) 0` are the same, but since the documentation says "all-bits-one", write it that way in the test code. Signed-off-by: Gilles Peskine --- tests/suites/test_suite_cipher.function | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/suites/test_suite_cipher.function b/tests/suites/test_suite_cipher.function index 96c336086b..1a4d4799ea 100644 --- a/tests/suites/test_suite_cipher.function +++ b/tests/suites/test_suite_cipher.function @@ -1010,7 +1010,7 @@ void decrypt_padded_test_vec(int cipher_id, int pad_mode, data_t *key, break; case MBEDTLS_ERR_CIPHER_INVALID_PADDING: TEST_EQUAL(actual_finish_result, 0); - TEST_EQUAL(invalid_padding, SIZE_MAX); + TEST_EQUAL(invalid_padding, ~(size_t) 0); break; default: TEST_EQUAL(actual_finish_result, expected_finish_result); @@ -1106,7 +1106,7 @@ void decrypt_padded_test_vec_cf(int cipher_id, int pad_mode, data_t *key, break; case MBEDTLS_ERR_CIPHER_INVALID_PADDING: TEST_EQUAL(actual_finish_result, 0); - TEST_EQUAL(invalid_padding, SIZE_MAX); + TEST_EQUAL(invalid_padding, ~(size_t) 0); break; default: TEST_EQUAL(actual_finish_result, expected_finish_result); @@ -1523,7 +1523,7 @@ void check_padding(int pad_mode, data_t *input, break; case MBEDTLS_ERR_CIPHER_INVALID_PADDING: TEST_EQUAL(ret, 0); - TEST_EQUAL(invalid_padding, SIZE_MAX); + TEST_EQUAL(invalid_padding, ~(size_t) 0); break; default: TEST_EQUAL(ret, expected_ret);