From 5c93f9739b080a25fd0158eb932eb67c5cea4527 Mon Sep 17 00:00:00 2001 From: Yosuke Shimizu Date: Wed, 15 Jul 2026 16:42:18 +0900 Subject: [PATCH] Handle TLS CBC bad padding in DES3 without a padding oracle --- src/wp_des.c | 300 ++++++++++++++++-- test/test_tls_cbc.c | 729 +++++++++++++++++++++++++++++++++++++++----- test/unit.c | 8 + test/unit.h | 8 + 4 files changed, 952 insertions(+), 93 deletions(-) diff --git a/src/wp_des.c b/src/wp_des.c index 896dbb80..48956d87 100644 --- a/src/wp_des.c +++ b/src/wp_des.c @@ -39,11 +39,21 @@ typedef struct wp_Des3BlockCtx { /** wolfSSL DES object. */ Des3 des3; + /** Provider context - needed for wolfCrypt RNG access. */ + WOLFPROV_CTX *provCtx; + /** Cipher mode - CBC or ECB. */ int mode; unsigned int tls_version; + /** Pointer to the MAC extracted from a decrypted TLS record. */ + unsigned char *tlsmac; + /** Size of the MAC expected in TLS records. */ + size_t tlsmacsize; + /** Whether tlsmac was separately allocated. */ + int tlsmacAlloced; + /** Length of key in bytes. */ size_t keyLen; /** Length of IV in bytes */ @@ -79,6 +89,9 @@ static int wp_des3_block_set_ctx_params(wp_Des3BlockCtx *ctx, */ static void wp_des3_block_freectx(wp_Des3BlockCtx *ctx) { + if (ctx->tlsmacAlloced) { + OPENSSL_free(ctx->tlsmac); + } wc_Des3Free(&ctx->des3); OPENSSL_clear_free(ctx, sizeof(*ctx)); } @@ -98,8 +111,24 @@ static void *wp_des3_block_dupctx(wp_Des3BlockCtx *src) dst = OPENSSL_malloc(sizeof(*dst)); } if (dst != NULL) { - /* TODO: copying des3 may not work if it has pointers in it. */ + /* Safe byte-copy: Des3 owns no heap as used here (sync, no async + * devId); async offload would need a deep copy. */ XMEMCPY(dst, src, sizeof(*src)); + dst->tlsmac = NULL; + dst->tlsmacAlloced = 0; + /* Deep-copy tlsmac to avoid double-free between src and dst. */ + if (src->tlsmacAlloced && src->tlsmac != NULL) { + dst->tlsmac = OPENSSL_malloc(src->tlsmacsize); + if (dst->tlsmac == NULL) { + /* dst->des3 aliases src's - must not wc_Des3Free it here. */ + OPENSSL_clear_free(dst, sizeof(*dst)); + dst = NULL; + } + else { + XMEMCPY(dst->tlsmac, src->tlsmac, src->tlsmacsize); + dst->tlsmacAlloced = 1; + } + } } return dst; @@ -193,6 +222,7 @@ static const OSSL_PARAM* wp_cipher_gettable_ctx_params(wp_Des3BlockCtx* ctx, OSSL_PARAM_uint(OSSL_CIPHER_PARAM_NUM, NULL), OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_IV, NULL, 0), OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_UPDATED_IV, NULL, 0), + OSSL_PARAM_octet_ptr(OSSL_CIPHER_PARAM_TLS_MAC, NULL, 0), OSSL_PARAM_END }; (void)ctx; @@ -218,6 +248,7 @@ static const OSSL_PARAM* wp_cipher_settable_ctx_params(wp_Des3BlockCtx* ctx, OSSL_PARAM_uint(OSSL_CIPHER_PARAM_NUM, NULL), OSSL_PARAM_uint(OSSL_CIPHER_PARAM_USE_BITS, NULL), OSSL_PARAM_uint(OSSL_CIPHER_PARAM_TLS_VERSION, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_TLS_MAC_SIZE, NULL), OSSL_PARAM_END }; (void)ctx; @@ -405,6 +436,227 @@ static int wp_des3_block_doit(wp_Des3BlockCtx *ctx, unsigned char *out, return rc == 0; } +/** + * Constant-time TLS CBC padding removal and MAC extraction after decryption. + * + * For ETM/no-MAC modes, strips the explicit IV and validates/removes padding. + * For MtE, also extracts the MAC using a constant-time rotation pattern and + * substitutes a random MAC on bad padding so no padding oracle is exposed. + * + * @param [in, out] ctx DES3 block context object. + * @param [in] out Decrypted output buffer. + * @param [in] oLen Length of decrypted data in bytes. + * @param [out] outLen Updated with length after padding/MAC removal. + * @return 1 on success. + * @return 0 on failure. + */ +static int wp_des3_block_tls_dec_record(wp_Des3BlockCtx *ctx, + unsigned char *out, size_t oLen, size_t *outLen) +{ + int ok = 1; + + /* Buffer: [explicit_IV(BS)][payload][MAC(macsize)][padding(pad+1)]. + * Padding validation follows OpenSSL tls1_cbc_remove_padding_and_mac; + * MAC extraction follows the ssl3_cbc_copy_mac rotation pattern. */ + unsigned char *rec; + size_t recLen; + size_t origRecLen; + unsigned char padVal; + size_t overhead; + size_t toCheck; + size_t good; + size_t i, j; + size_t macSize = ctx->tlsmacsize; + + WOLFPROV_ENTER(WP_LOG_COMP_DES, "wp_des3_block_tls_dec_record"); + + /* Free any previously allocated MAC */ + if (ctx->tlsmacAlloced) { + OPENSSL_free(ctx->tlsmac); + ctx->tlsmacAlloced = 0; + ctx->tlsmac = NULL; + } + + /* Below TLS 1.1 there is no explicit per-record IV, so stripping one + * would discard payload. Reject rather than corrupt the record. */ + if (ctx->tls_version == SSL3_VERSION || + ctx->tls_version == TLS1_VERSION) { + ok = 0; + } + + if (ok && (macSize > EVP_MAX_MD_SIZE || + oLen < DES_BLOCK_SIZE + macSize + 1)) { + ok = 0; + } + + if (ok && macSize == 0) { + /* ETM/no-MAC: record layer handled the MAC, so only strip the + * explicit IV and validate+remove padding. */ + unsigned char *ivRec = out + DES_BLOCK_SIZE; + size_t ivRecLen = oLen - DES_BLOCK_SIZE; + unsigned char padV = ivRec[ivRecLen - 1]; + size_t gd = (size_t)0 - ((size_t)( + wp_ct_int_mask_gte((int)ivRecLen, (int)padV + 1) & 1)); + size_t tc = 256; + size_t d; + if (tc > ivRecLen) { + tc = ivRecLen; + } + + for (i = 0; i < tc; i++) { + byte m = wp_ct_int_mask_gte((int)padV, (int)i); + unsigned char bv = ivRec[ivRecLen - 1 - i]; + gd &= ~((size_t)(m & (padV ^ bv))); + } + /* Collapse lower 8 bits to a full-width size_t mask. */ + d = (gd & 0xff) ^ 0xff; + d |= (0 - d); + d >>= (sizeof(size_t) * 8 - 1); + gd = d - 1; + ivRecLen -= gd & ((size_t)padV + 1); + /* ETM/no-MAC: bad padding is a real error (no oracle concern). */ + if (gd == 0) { + ok = 0; + *outLen = 0; + } + else { + *outLen = ivRecLen; + } + } + else if (ok) { + /* 64-byte aligned buffer for cache-line-aware MAC rotation */ + unsigned char rotatedMacBuf[64 + EVP_MAX_MD_SIZE]; + unsigned char *rotatedMac; + unsigned char randMac[EVP_MAX_MD_SIZE]; + size_t macEnd; + size_t macStart; + size_t scanStart = 0; + size_t diff; + byte inMac; + size_t rotateOff; + + /* Align rotatedMac to a 64-byte boundary so the whole MAC buffer + * sits at known positions within one or two cache lines. */ + rotatedMac = rotatedMacBuf + + ((0 - (size_t)rotatedMacBuf) & 63); + + /* For TLS 1.1+/DTLS: skip explicit IV */ + rec = out + DES_BLOCK_SIZE; + recLen = oLen - DES_BLOCK_SIZE; + origRecLen = recLen; + + padVal = rec[recLen - 1]; + overhead = macSize + (size_t)padVal + 1; + + /* CT overhead check: recLen >= overhead, folded into good mask. */ + good = (size_t)0 - + ((size_t)(wp_ct_int_mask_gte((int)recLen, (int)overhead) & 1)); + + /* Validate up to 256 padding bytes in constant time. */ + toCheck = 256; + if (toCheck > recLen) { + toCheck = recLen; + } + + for (i = 0; i < toCheck; i++) { + byte mask = wp_ct_int_mask_gte((int)padVal, (int)i); + unsigned char b = rec[recLen - 1 - i]; + good &= ~((size_t)(mask & (padVal ^ b))); + } + /* Collapse lower 8 bits to a full-width size_t mask. */ + diff = (good & 0xff) ^ 0xff; + diff |= (0 - diff); + diff >>= (sizeof(size_t) * 8 - 1); + good = diff - 1; + + recLen -= good & ((size_t)padVal + 1); + + macEnd = recLen; + macStart = macEnd - macSize; + + recLen -= macSize; + *outLen = recLen; + + #ifndef WP_SINGLE_THREADED + if (wp_provctx_lock_rng(ctx->provCtx)) { + if (wc_RNG_GenerateBlock(wp_provctx_get_rng(ctx->provCtx), + randMac, (word32)macSize) != 0) { + ok = 0; + } + wp_provctx_unlock_rng(ctx->provCtx); + } + else { + /* Cannot safely use the RNG without the lock. */ + ok = 0; + } + #else + if (wc_RNG_GenerateBlock(wp_provctx_get_rng(ctx->provCtx), + randMac, (word32)macSize) != 0) { + ok = 0; + } + #endif + + /* Only build the substitute MAC if RNG succeeded; otherwise randMac + * is unset and must not be read. */ + if (ok) { + ctx->tlsmac = OPENSSL_malloc(macSize); + if (ctx->tlsmac == NULL) { + ok = 0; + } + } + if (ok) { + ctx->tlsmacAlloced = 1; + + /* Scan all bytes that could hold the MAC (position varies). */ + if (origRecLen > macSize + 255 + 1) { + scanStart = origRecLen - (macSize + 255 + 1); + } + + XMEMSET(rotatedMac, 0, EVP_MAX_MD_SIZE); + inMac = 0; + rotateOff = 0; + for (i = scanStart, j = 0; i < origRecLen; i++) { + byte started = wp_ct_int_mask_eq((int)i, (int)macStart); + byte notEnded = wp_ct_int_mask_lt((int)i, (int)macEnd); + unsigned char b = rec[i]; + + inMac |= started; + inMac &= notEnded; + rotateOff |= j & (size_t)started; + rotatedMac[j++] |= b & inMac; + j &= (size_t)wp_ct_int_mask_lt((int)j, (int)macSize); + } + + /* Cache-line-aware un-rotation: load from both halves and + * ct-select so rotateOff does not leak via cache access. */ + for (i = 0; i < macSize; i++) { + byte aux1 = rotatedMac[rotateOff & ~32]; + byte aux2 = rotatedMac[rotateOff | 32]; + byte eqMask = wp_ct_int_mask_eq( + (int)(rotateOff & ~32), (int)rotateOff); + unsigned char real = wp_ct_byte_mask_sel( + eqMask, aux1, aux2); + byte goodMask = (byte)(good & 0xff); + + ctx->tlsmac[i] = wp_ct_byte_mask_sel(goodMask, real, + randMac[i]); + rotateOff++; + rotateOff &= (size_t)wp_ct_int_mask_lt( + (int)rotateOff, (int)macSize); + } + } + } + + /* Report no output on any failure path, never a partial length. */ + if (!ok) { + *outLen = 0; + } + + WOLFPROV_LEAVE(WP_LOG_COMP_DES, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok); + + return ok; +} + /** * Update encryption/decryption with more data. * @@ -493,28 +745,8 @@ static int wp_des3_block_update(wp_Des3BlockCtx *ctx, unsigned char *out, } *outLen = oLen; } - if (ok && (ctx->tls_version > 0) && (!ctx->enc) && - (oLen < (size_t)(2 * DES_BLOCK_SIZE))) { - ok = 0; - } if (ok && (ctx->tls_version > 0) && (!ctx->enc)) { - unsigned char pad = outStart[oLen-1]; - int padStart = DES_BLOCK_SIZE - pad - 1; - unsigned char invalid = (pad < DES_BLOCK_SIZE) - 1; - int i; - - for (i = DES_BLOCK_SIZE - 1; i >= 0; i--) { - byte check = wp_ct_int_mask_gte(i, padStart); - check &= wp_ct_byte_mask_ne(outStart[oLen - DES_BLOCK_SIZE + i], pad); - invalid |= check; - } - ok = invalid == 0; - if (ok) { - *outLen = oLen - pad - 1 - DES_BLOCK_SIZE; - } - else { - *outLen = 0; - } + ok = wp_des3_block_tls_dec_record(ctx, outStart, oLen, outLen); } WOLFPROV_LEAVE(WP_LOG_COMP_DES, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok); @@ -764,6 +996,13 @@ static int wp_des3_block_get_ctx_params(wp_Des3BlockCtx* ctx, OSSL_PARAM params[ ok = 0; } } + if (ok) { + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_TLS_MAC); + if ((p != NULL) && + (!OSSL_PARAM_set_octet_ptr(p, ctx->tlsmac, ctx->tlsmacsize))) { + ok = 0; + } + } WOLFPROV_LEAVE(WP_LOG_COMP_DES, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok); return ok; @@ -787,6 +1026,7 @@ static int wp_des3_block_set_ctx_params(wp_Des3BlockCtx *ctx, if (params != NULL) { unsigned int val; int set; + size_t macSz = ctx->tlsmacsize; if (!wp_params_get_uint(params, OSSL_CIPHER_PARAM_PADDING, &val, &set)) { @@ -812,6 +1052,20 @@ static int wp_des3_block_set_ctx_params(wp_Des3BlockCtx *ctx, &ctx->tls_version, NULL))) { ok = 0; } + if (ok && (!wp_params_get_size_t(params, OSSL_CIPHER_PARAM_TLS_MAC_SIZE, + &macSz))) { + ok = 0; + } + if (ok && (macSz != ctx->tlsmacsize)) { + /* Any stored MAC was sized for the old value - drop it so tlsmac + * is never shorter than tlsmacsize. */ + if (ctx->tlsmacAlloced) { + OPENSSL_free(ctx->tlsmac); + ctx->tlsmacAlloced = 0; + } + ctx->tlsmac = NULL; + ctx->tlsmacsize = macSz; + } } WOLFPROV_LEAVE(WP_LOG_COMP_DES, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok); @@ -865,12 +1119,12 @@ static wp_Des3BlockCtx* wp_des3_block_##lcmode##_newctx( \ WOLFPROV_CTX *provCtx) \ { \ wp_Des3BlockCtx *ctx = NULL; \ - (void)provCtx; \ if (wolfssl_prov_is_running()) { \ ctx = OPENSSL_zalloc(sizeof(*ctx)); \ } \ if (ctx != NULL) { \ wp_des3_block_init_ctx(ctx, kBits, ivBits, EVP_CIPH_##UCMODE##_MODE); \ + ctx->provCtx = provCtx; \ } \ return ctx; \ } diff --git a/test/test_tls_cbc.c b/test/test_tls_cbc.c index 14c98fb4..a538ce3b 100644 --- a/test/test_tls_cbc.c +++ b/test/test_tls_cbc.c @@ -436,28 +436,98 @@ int test_aes_tls_cbc_bad_pad(void *data) #define DES3_BS 8 -/* - * DES3 TLS CBC negative padding test. - * Exercises wp_ct_byte_mask_ne in the DES3 TLS constant-time padding path. - * DES3 TLS does not use TLS_MAC_SIZE/TLS_MAC -- it only validates padding. - */ +/* New DES3 TLS cipher ctx at tlsVer. A NULL macLen omits TLS_MAC_SIZE + * entirely, as an ETM/no-MAC record layer does; passing it exercises the MtE + * path. Returns NULL on failure. */ +static EVP_CIPHER_CTX *des3_tls_ctx(EVP_CIPHER *cipher, + const unsigned char *key, const unsigned char *iv, unsigned int tlsVer, + const size_t *macLen, int enc) +{ + int err = 0; + EVP_CIPHER_CTX *ctx = NULL; + OSSL_PARAM params[3]; + size_t macSz = 0; + int n = 0; + + ctx = EVP_CIPHER_CTX_new(); + err = ctx == NULL; + + if (err == 0) { + err = EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, enc) != 1; + } + if (err == 0) { + params[n++] = OSSL_PARAM_construct_uint(OSSL_CIPHER_PARAM_TLS_VERSION, + &tlsVer); + if (macLen != NULL) { + macSz = *macLen; + params[n++] = OSSL_PARAM_construct_size_t( + OSSL_CIPHER_PARAM_TLS_MAC_SIZE, &macSz); + } + params[n] = OSSL_PARAM_construct_end(); + err = EVP_CIPHER_CTX_set_params(ctx, params) != 1; + } + if (err != 0) { + EVP_CIPHER_CTX_free(ctx); + ctx = NULL; + } + + return ctx; +} + +/* Encrypt a TLS 1.2 record [explicit_IV][pt][mac] into buf. A NULL mac builds + * an ETM/no-MAC record. Returns 0 on success with encLen set. */ +static int des3_tls_record(EVP_CIPHER *cipher, const unsigned char *key, + const unsigned char *iv, const unsigned char *pt, size_t ptLen, + const unsigned char *mac, size_t macLen, unsigned char *buf, int *encLen) +{ + int err = 0; + EVP_CIPHER_CTX *ctx = NULL; + int inLen = DES3_BS + (int)ptLen; + + ctx = des3_tls_ctx(cipher, key, iv, TLS1_2_VERSION, + mac != NULL ? &macLen : NULL, 1); + err = ctx == NULL; + + if (err == 0) { + memcpy(buf, iv, DES3_BS); + if (ptLen > 0) { + memcpy(buf + DES3_BS, pt, ptLen); + } + if (mac != NULL) { + memcpy(buf + DES3_BS + ptLen, mac, macLen); + inLen += (int)macLen; + } + err = EVP_CipherUpdate(ctx, buf, encLen, buf, inLen) != 1; + } + + EVP_CIPHER_CTX_free(ctx); + return err; +} + +/* DES3 TLS CBC bad padding: MtE (macSize>0) must return success and substitute + * a random MAC (padding oracle defense), so the extracted TLS_MAC must not + * match the original. */ static int test_des3_tls_cbc_bad_pad_helper(OSSL_LIB_CTX *libCtx) { int err = 0; EVP_CIPHER *cipher = NULL; EVP_CIPHER_CTX *ctx = NULL; - OSSL_PARAM params[2]; - unsigned int tlsVer = TLS1_2_VERSION; + OSSL_PARAM getParams[2]; + int macSize = 20; + size_t macSz = (size_t)macSize; unsigned char key[24]; unsigned char iv[DES3_BS]; - /* 10 bytes of plaintext. Padding: off=10%8=2, pad=8-2-1=5, padded=16. */ - unsigned char pt[10]; + unsigned char mac[20]; + /* 16 bytes plaintext: record is [IV(8)][pt(16)][MAC(20)] = 44, pads to 48. */ + unsigned char pt[16]; unsigned char buf[64]; int encLen = 0; int decLen = 0; + unsigned char *tlsMac = NULL; memset(key, 0xAA, sizeof(key)); memset(iv, 0xBB, sizeof(iv)); + memset(mac, 0xCC, sizeof(mac)); memset(pt, 0x42, sizeof(pt)); cipher = EVP_CIPHER_fetch(libCtx, "DES-EDE3-CBC", ""); @@ -465,29 +535,11 @@ static int test_des3_tls_cbc_bad_pad_helper(OSSL_LIB_CTX *libCtx) err = 1; } - /* Encrypt in TLS mode. */ - if (err == 0) { - ctx = EVP_CIPHER_CTX_new(); - if (ctx == NULL) { - err = 1; - } - } + /* Encrypt a valid TLS record: [explicit_IV][plaintext][MAC]. */ if (err == 0) { - err = EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, 1) != 1; - } - if (err == 0) { - params[0] = OSSL_PARAM_construct_uint(OSSL_CIPHER_PARAM_TLS_VERSION, - &tlsVer); - params[1] = OSSL_PARAM_construct_end(); - err = EVP_CIPHER_CTX_set_params(ctx, params) != 1; + err = des3_tls_record(cipher, key, iv, pt, sizeof(pt), mac, sizeof(mac), + buf, &encLen); } - if (err == 0) { - /* Copy plaintext into buf; the provider pads in-place in the output. */ - memcpy(buf, pt, sizeof(pt)); - err = EVP_CipherUpdate(ctx, buf, &encLen, buf, (int)sizeof(pt)) != 1; - } - EVP_CIPHER_CTX_free(ctx); - ctx = NULL; /* CBC bit-flip: corrupt a padding byte in the last plaintext block * without touching the pad-length byte at the final position. */ @@ -495,27 +547,35 @@ static int test_des3_tls_cbc_bad_pad_helper(OSSL_LIB_CTX *libCtx) buf[encLen - DES3_BS - 2] ^= 0x01; } - /* Decrypt -- should fail due to bad padding. */ + /* Decrypt -- MtE TLS returns success but substitutes a random MAC. */ if (err == 0) { - ctx = EVP_CIPHER_CTX_new(); - if (ctx == NULL) { - err = 1; - } + ctx = des3_tls_ctx(cipher, key, iv, TLS1_2_VERSION, &macSz, 0); + err = ctx == NULL; } if (err == 0) { - err = EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, 0) != 1; + if (EVP_CipherUpdate(ctx, buf, &decLen, buf, encLen) != 1) { + PRINT_ERR_MSG("DES3 TLS CBC bad-pad: decryption should have " + "succeeded with a randomized MAC but failed"); + err = 1; + } } + + /* Bad padding should have triggered random MAC substitution. */ if (err == 0) { - params[0] = OSSL_PARAM_construct_uint(OSSL_CIPHER_PARAM_TLS_VERSION, - &tlsVer); - params[1] = OSSL_PARAM_construct_end(); - err = EVP_CIPHER_CTX_set_params(ctx, params) != 1; + getParams[0] = OSSL_PARAM_construct_octet_ptr( + OSSL_CIPHER_PARAM_TLS_MAC, (void **)&tlsMac, macSize); + getParams[1] = OSSL_PARAM_construct_end(); + err = EVP_CIPHER_CTX_get_params(ctx, getParams) != 1; } if (err == 0) { - int ret = EVP_CipherUpdate(ctx, buf, &decLen, buf, encLen); - if (ret == 1) { - PRINT_ERR_MSG("DES3 TLS CBC bad-pad: decryption should have failed " - "but succeeded"); + if (tlsMac == NULL) { + PRINT_ERR_MSG("DES3 TLS CBC bad-pad: TLS_MAC must be a non-NULL " + "randomized MAC"); + err = 1; + } + else if (memcmp(tlsMac, mac, macSize) == 0) { + PRINT_ERR_MSG("DES3 TLS CBC bad-pad: MAC should have been " + "randomized but matches original"); err = 1; } } @@ -544,15 +604,12 @@ int test_des3_tls_cbc_dec(void *data) int err = 0; EVP_CIPHER *cipher = NULL; EVP_CIPHER_CTX *ctx = NULL; - OSSL_PARAM params[2]; - unsigned int tlsVer = TLS1_2_VERSION; unsigned char key[24]; unsigned char iv[DES3_BS]; /* 37 bytes: not block-aligned, so padding is non-trivial. */ unsigned char pt[37]; unsigned char buf[64]; unsigned char *out = NULL; - int ptLen = (int)sizeof(pt); int encLen = 0; int l1 = 0; int l2 = 0; @@ -573,55 +630,587 @@ int test_des3_tls_cbc_dec(void *data) /* Encrypt the record [explicit_IV][plaintext] in TLS mode. */ if (err == 0) { - ctx = EVP_CIPHER_CTX_new(); + err = des3_tls_record(cipher, key, iv, pt, sizeof(pt), NULL, 0, buf, + &encLen); + } + + /* Output buffer sized to the produced plaintext so an overread past the + * written region is caught under sanitizers. */ + if (err == 0) { + out = OPENSSL_malloc((size_t)(encLen - DES3_BS)); + err = out == NULL; + } + + /* Decrypt in TLS mode split across two updates. */ + if (err == 0) { + ctx = des3_tls_ctx(cipher, key, iv, TLS1_2_VERSION, NULL, 0); err = ctx == NULL; } if (err == 0) { - err = EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, 1) != 1; + /* Only the second update completes the record; must succeed. */ + (void)EVP_CipherUpdate(ctx, out, &l1, buf, split); + err = EVP_CipherUpdate(ctx, out + l1, &l2, buf + split, + encLen - split) != 1; } + + OPENSSL_free(out); + EVP_CIPHER_CTX_free(ctx); + EVP_CIPHER_free(cipher); + return err; +} + +/* DES3 MtE (macSize>0) TLS 1.2 CBC decrypt of a valid record: verifies the + * recovered plaintext, its length, and that the extracted TLS_MAC equals the + * original MAC. */ +int test_des3_tls_cbc_mte(void *data) +{ + int err = 0; + EVP_CIPHER *cipher = NULL; + EVP_CIPHER_CTX *ctx = NULL; + OSSL_PARAM getParams[2]; + int macSize = 20; + size_t macSz = (size_t)macSize; + unsigned char key[24]; + unsigned char iv[DES3_BS]; + unsigned char mac[20]; + unsigned char pt[16]; + unsigned char buf[64]; + unsigned char *tlsMac = NULL; + int encLen = 0; + int decLen = 0; + + (void)data; + + memset(key, 0xAA, sizeof(key)); + memset(iv, 0xBB, sizeof(iv)); + memset(mac, 0xCC, sizeof(mac)); + memset(pt, 0x42, sizeof(pt)); + + PRINT_MSG("DES3 TLS 1.2 CBC MtE decrypt (wolfProvider)"); + + cipher = EVP_CIPHER_fetch(wpLibCtx, "DES-EDE3-CBC", ""); + if (cipher == NULL) { + err = 1; + } + + /* Encrypt a valid record: [explicit_IV][plaintext][MAC]. */ if (err == 0) { - params[0] = OSSL_PARAM_construct_uint(OSSL_CIPHER_PARAM_TLS_VERSION, - &tlsVer); - params[1] = OSSL_PARAM_construct_end(); - err = EVP_CIPHER_CTX_set_params(ctx, params) != 1; + err = des3_tls_record(cipher, key, iv, pt, sizeof(pt), mac, sizeof(mac), + buf, &encLen); } + + /* Decrypt the whole record in one update; must succeed. */ if (err == 0) { - memcpy(buf, iv, DES3_BS); - memcpy(buf + DES3_BS, pt, ptLen); - err = EVP_CipherUpdate(ctx, buf, &encLen, buf, DES3_BS + ptLen) != 1; + ctx = des3_tls_ctx(cipher, key, iv, TLS1_2_VERSION, &macSz, 0); + err = ctx == NULL; + } + if (err == 0) { + err = EVP_CipherUpdate(ctx, buf, &decLen, buf, encLen) != 1; + } + + /* Length excludes the explicit IV, MAC and padding. */ + if (err == 0 && decLen != (int)sizeof(pt)) { + PRINT_ERR_MSG("DES3 TLS CBC MtE: unexpected plaintext length %d", + decLen); + err = 1; + } + /* Recovered plaintext sits after the explicit IV block. */ + if (err == 0 && memcmp(buf + DES3_BS, pt, sizeof(pt)) != 0) { + PRINT_ERR_MSG("DES3 TLS CBC MtE: recovered plaintext mismatch"); + err = 1; + } + + /* Valid padding: extracted MAC must equal the original. */ + if (err == 0) { + getParams[0] = OSSL_PARAM_construct_octet_ptr( + OSSL_CIPHER_PARAM_TLS_MAC, (void **)&tlsMac, macSize); + getParams[1] = OSSL_PARAM_construct_end(); + err = EVP_CIPHER_CTX_get_params(ctx, getParams) != 1; + } + if (err == 0) { + if (tlsMac == NULL || memcmp(tlsMac, mac, macSize) != 0) { + PRINT_ERR_MSG("DES3 TLS CBC MtE: extracted MAC does not match " + "original"); + err = 1; + } + } + + EVP_CIPHER_CTX_free(ctx); + EVP_CIPHER_free(cipher); + return err; +} + +/* DES3 ETM/no-MAC (macSize==0) TLS 1.2 CBC decrypt of a valid record in a + * single update: asserts the recovered payload length and content once the + * explicit IV is stripped and padding removed. */ +int test_des3_tls_cbc_etm(void *data) +{ + int err = 0; + EVP_CIPHER *cipher = NULL; + EVP_CIPHER_CTX *ctx = NULL; + unsigned char key[24]; + unsigned char iv[DES3_BS]; + /* 37 bytes: not block-aligned, so padding is non-trivial. */ + unsigned char pt[37]; + unsigned char buf[64]; + int ptLen = (int)sizeof(pt); + int encLen = 0; + int decLen = 0; + int i; + + (void)data; + + memset(key, 0xAA, sizeof(key)); + memset(iv, 0xBB, sizeof(iv)); + /* Distinct bytes so a wrong recovery offset is caught, not just a length. */ + for (i = 0; i < ptLen; i++) { + pt[i] = (unsigned char)(i + 1); + } + + PRINT_MSG("DES3 TLS 1.2 CBC ETM/no-MAC decrypt (wolfProvider)"); + + cipher = EVP_CIPHER_fetch(wpLibCtx, "DES-EDE3-CBC", ""); + if (cipher == NULL) { + err = 1; + } + + /* Encrypt the record [explicit_IV][plaintext] in TLS mode with no MAC. */ + if (err == 0) { + err = des3_tls_record(cipher, key, iv, pt, sizeof(pt), NULL, 0, buf, + &encLen); + } + + /* Decrypt the whole record in one update; must succeed. */ + if (err == 0) { + ctx = des3_tls_ctx(cipher, key, iv, TLS1_2_VERSION, NULL, 0); + err = ctx == NULL; + } + if (err == 0) { + err = EVP_CipherUpdate(ctx, buf, &decLen, buf, encLen) != 1; + } + + /* Length excludes the explicit IV and padding (no MAC in ETM mode). */ + if (err == 0 && decLen != ptLen) { + PRINT_ERR_MSG("DES3 TLS CBC ETM: unexpected plaintext length %d", + decLen); + err = 1; + } + /* Recovered plaintext sits after the explicit IV block. */ + if (err == 0 && memcmp(buf + DES3_BS, pt, ptLen) != 0) { + PRINT_ERR_MSG("DES3 TLS CBC ETM: recovered plaintext mismatch"); + err = 1; + } + + EVP_CIPHER_CTX_free(ctx); + EVP_CIPHER_free(cipher); + return err; +} + +/* DES3 ETM/no-MAC (macSize==0) TLS 1.2 CBC decrypt with corrupted padding: + * unlike MtE (random-MAC substitution), no-MAC mode has no padding-oracle + * concern, so bad padding must make decryption fail. */ +int test_des3_tls_cbc_etm_bad_pad(void *data) +{ + int err = 0; + EVP_CIPHER *cipher = NULL; + EVP_CIPHER_CTX *ctx = NULL; + unsigned char key[24]; + unsigned char iv[DES3_BS]; + /* 37 bytes: not block-aligned, matching the positive ETM test's record. */ + unsigned char pt[37]; + unsigned char buf[64]; + int encLen = 0; + int decLen = 0; + + (void)data; + + memset(key, 0xAA, sizeof(key)); + memset(iv, 0xBB, sizeof(iv)); + memset(pt, 0x42, sizeof(pt)); + + PRINT_MSG("DES3 TLS 1.2 CBC ETM/no-MAC bad padding (wolfProvider)"); + + cipher = EVP_CIPHER_fetch(wpLibCtx, "DES-EDE3-CBC", ""); + if (cipher == NULL) { + err = 1; + } + + /* Encrypt a valid record [explicit_IV][plaintext] with no MAC. */ + if (err == 0) { + err = des3_tls_record(cipher, key, iv, pt, sizeof(pt), NULL, 0, buf, + &encLen); + } + + /* CBC bit-flip: corrupt a padding byte in the last plaintext block + * without touching the pad-length byte at the final position. */ + if (err == 0) { + buf[encLen - DES3_BS - 2] ^= 0x01; + } + + /* Decrypt in ETM mode: bad padding must fail, not substitute a MAC. */ + if (err == 0) { + ctx = des3_tls_ctx(cipher, key, iv, TLS1_2_VERSION, NULL, 0); + err = ctx == NULL; + } + if (err == 0) { + if (EVP_CipherUpdate(ctx, buf, &decLen, buf, encLen) == 1) { + PRINT_ERR_MSG("DES3 TLS CBC ETM bad-pad: decryption should have " + "failed but succeeded"); + err = 1; + } + } + + EVP_CIPHER_CTX_free(ctx); + EVP_CIPHER_free(cipher); + return err; +} + +/* Copying a DES3 TLS ctx after an MtE decrypt must deep-copy the extracted + * MAC: a shallow copy would share one buffer and double-free on cleanup. */ +int test_des3_tls_cbc_dup(void *data) +{ + int err = 0; + EVP_CIPHER *cipher = NULL; + EVP_CIPHER_CTX *ctx = NULL; + EVP_CIPHER_CTX *dup = NULL; + OSSL_PARAM getParams[2]; + int macSize = 20; + size_t macSz = (size_t)macSize; + unsigned char key[24]; + unsigned char iv[DES3_BS]; + unsigned char mac[20]; + unsigned char pt[16]; + unsigned char buf[64]; + unsigned char *srcMac = NULL; + unsigned char *dupMac = NULL; + int encLen = 0; + int decLen = 0; + + (void)data; + + memset(key, 0xAA, sizeof(key)); + memset(iv, 0xBB, sizeof(iv)); + memset(mac, 0xCC, sizeof(mac)); + memset(pt, 0x42, sizeof(pt)); + + PRINT_MSG("DES3 TLS 1.2 CBC ctx copy deep-copies the extracted MAC"); + + cipher = EVP_CIPHER_fetch(wpLibCtx, "DES-EDE3-CBC", ""); + if (cipher == NULL) { + err = 1; + } + if (err == 0) { + err = des3_tls_record(cipher, key, iv, pt, sizeof(pt), mac, sizeof(mac), + buf, &encLen); + } + + /* Decrypt so the ctx holds a heap-allocated tlsmac. */ + if (err == 0) { + ctx = des3_tls_ctx(cipher, key, iv, TLS1_2_VERSION, &macSz, 0); + err = ctx == NULL; + } + if (err == 0) { + err = EVP_CipherUpdate(ctx, buf, &decLen, buf, encLen) != 1; + } + if (err == 0) { + getParams[0] = OSSL_PARAM_construct_octet_ptr( + OSSL_CIPHER_PARAM_TLS_MAC, (void **)&srcMac, macSize); + getParams[1] = OSSL_PARAM_construct_end(); + err = EVP_CIPHER_CTX_get_params(ctx, getParams) != 1; + } + if (err == 0 && (srcMac == NULL || memcmp(srcMac, mac, macSize) != 0)) { + PRINT_ERR_MSG("DES3 TLS CBC dup: source MAC does not match original"); + err = 1; + } + + /* Copy the ctx and read the MAC back out of the copy. */ + if (err == 0) { + dup = EVP_CIPHER_CTX_new(); + err = dup == NULL; + } + if (err == 0) { + err = EVP_CIPHER_CTX_copy(dup, ctx) != 1; + } + if (err == 0) { + getParams[0] = OSSL_PARAM_construct_octet_ptr( + OSSL_CIPHER_PARAM_TLS_MAC, (void **)&dupMac, macSize); + getParams[1] = OSSL_PARAM_construct_end(); + err = EVP_CIPHER_CTX_get_params(dup, getParams) != 1; + } + if (err == 0 && (dupMac == NULL || memcmp(dupMac, mac, macSize) != 0)) { + PRINT_ERR_MSG("DES3 TLS CBC dup: copied MAC does not match original"); + err = 1; + } + /* A shallow copy would hand back the source's own buffer. */ + if (err == 0 && dupMac == srcMac) { + PRINT_ERR_MSG("DES3 TLS CBC dup: MAC buffer shared with source"); + err = 1; + } + + EVP_CIPHER_CTX_free(dup); + EVP_CIPHER_CTX_free(ctx); + EVP_CIPHER_free(cipher); + return err; +} + +/* Records the decrypt must reject up front: an oversized TLS MAC size, which + * would otherwise overrun the internal randMac buffer, and a record too short + * to hold the explicit IV, MAC and pad-length byte. */ +int test_des3_tls_cbc_bad_len(void *data) +{ + int err = 0; + EVP_CIPHER *cipher = NULL; + EVP_CIPHER_CTX *ctx = NULL; + size_t bigMacSz = (size_t)EVP_MAX_MD_SIZE + 1; + size_t macSz = 20; + unsigned char key[24]; + unsigned char iv[DES3_BS]; + unsigned char buf[64]; + int decLen = 0; + + (void)data; + + memset(key, 0xAA, sizeof(key)); + memset(iv, 0xBB, sizeof(iv)); + memset(buf, 0x00, sizeof(buf)); + + PRINT_MSG("DES3 TLS 1.2 CBC decrypt rejects an oversized MAC size"); + + cipher = EVP_CIPHER_fetch(wpLibCtx, "DES-EDE3-CBC", ""); + if (cipher == NULL) { + err = 1; + } + if (err == 0) { + ctx = des3_tls_ctx(cipher, key, iv, TLS1_2_VERSION, &bigMacSz, 0); + err = ctx == NULL; + } + if (err == 0 && EVP_CipherUpdate(ctx, buf, &decLen, buf, 48) == 1) { + PRINT_ERR_MSG("DES3 TLS CBC: oversized MAC size was accepted"); + err = 1; } EVP_CIPHER_CTX_free(ctx); ctx = NULL; - /* Output buffer sized to the produced plaintext so an overread past the - * written region is caught under sanitizers. */ + PRINT_MSG("DES3 TLS 1.2 CBC decrypt rejects a too-short record"); + + /* The sub-test above decrypted buf in place; start from a known state. */ + memset(buf, 0x00, sizeof(buf)); + if (err == 0) { - out = OPENSSL_malloc((size_t)(encLen - DES3_BS)); - err = out == NULL; + ctx = des3_tls_ctx(cipher, key, iv, TLS1_2_VERSION, &macSz, 0); + err = ctx == NULL; + } + /* 24 < DES3_BS + 20 + 1: too short to hold IV, MAC and pad length. */ + if (err == 0 && EVP_CipherUpdate(ctx, buf, &decLen, buf, 24) == 1) { + PRINT_ERR_MSG("DES3 TLS CBC: too-short record was accepted"); + err = 1; } - /* Decrypt in TLS mode split across two updates. */ + EVP_CIPHER_CTX_free(ctx); + EVP_CIPHER_free(cipher); + return err; +} + +/* Below TLS 1.1 there is no explicit per-record IV. The decrypt strips one + * unconditionally, so these versions must be rejected, not silently + * stripped of 8 bytes of payload. */ +int test_des3_tls_cbc_old_version(void *data) +{ + int err = 0; + EVP_CIPHER *cipher = NULL; + EVP_CIPHER_CTX *ctx = NULL; + size_t macSz = 20; + unsigned char key[24]; + unsigned char iv[DES3_BS]; + unsigned char mac[20]; + unsigned char pt[16]; + unsigned char buf[64]; + int encLen = 0; + int decLen = 0; + + (void)data; + + memset(key, 0xAA, sizeof(key)); + memset(iv, 0xBB, sizeof(iv)); + memset(mac, 0xCC, sizeof(mac)); + memset(pt, 0x42, sizeof(pt)); + + PRINT_MSG("DES3 TLS CBC decrypt rejects TLS 1.0 and SSLv3"); + + cipher = EVP_CIPHER_fetch(wpLibCtx, "DES-EDE3-CBC", ""); + if (cipher == NULL) { + err = 1; + } + /* A well-formed record; only the version makes it unacceptable. */ if (err == 0) { - ctx = EVP_CIPHER_CTX_new(); + err = des3_tls_record(cipher, key, iv, pt, sizeof(pt), mac, sizeof(mac), + buf, &encLen); + } + + if (err == 0) { + ctx = des3_tls_ctx(cipher, key, iv, TLS1_VERSION, &macSz, 0); err = ctx == NULL; } + if (err == 0 && EVP_CipherUpdate(ctx, buf, &decLen, buf, encLen) == 1) { + PRINT_ERR_MSG("DES3 TLS CBC: TLS 1.0 record was accepted"); + err = 1; + } + EVP_CIPHER_CTX_free(ctx); + ctx = NULL; + if (err == 0) { - err = EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, 0) != 1; + ctx = des3_tls_ctx(cipher, key, iv, SSL3_VERSION, &macSz, 0); + err = ctx == NULL; + } + if (err == 0 && EVP_CipherUpdate(ctx, buf, &decLen, buf, encLen) == 1) { + PRINT_ERR_MSG("DES3 TLS CBC: SSLv3 record was accepted"); + err = 1; + } + + EVP_CIPHER_CTX_free(ctx); + EVP_CIPHER_free(cipher); + return err; +} + +/* Minimal MtE record with an empty payload, [IV 8][pt 0][MAC 20]: drives the + * output length to 0 and the MAC start to 0, the tightest decrypt boundary. */ +int test_des3_tls_cbc_empty_pt(void *data) +{ + int err = 0; + EVP_CIPHER *cipher = NULL; + EVP_CIPHER_CTX *ctx = NULL; + OSSL_PARAM getParams[2]; + int macSize = 20; + size_t macSz = (size_t)macSize; + unsigned char key[24]; + unsigned char iv[DES3_BS]; + unsigned char mac[20]; + unsigned char buf[64]; + unsigned char *tlsMac = NULL; + int encLen = 0; + int decLen = 0; + + (void)data; + + memset(key, 0xAA, sizeof(key)); + memset(iv, 0xBB, sizeof(iv)); + memset(mac, 0xCC, sizeof(mac)); + + PRINT_MSG("DES3 TLS 1.2 CBC MtE decrypt of an empty payload"); + + cipher = EVP_CIPHER_fetch(wpLibCtx, "DES-EDE3-CBC", ""); + if (cipher == NULL) { + err = 1; } if (err == 0) { - params[0] = OSSL_PARAM_construct_uint(OSSL_CIPHER_PARAM_TLS_VERSION, - &tlsVer); + err = des3_tls_record(cipher, key, iv, NULL, 0, mac, sizeof(mac), buf, + &encLen); + } + if (err == 0) { + ctx = des3_tls_ctx(cipher, key, iv, TLS1_2_VERSION, &macSz, 0); + err = ctx == NULL; + } + if (err == 0) { + err = EVP_CipherUpdate(ctx, buf, &decLen, buf, encLen) != 1; + } + if (err == 0 && decLen != 0) { + PRINT_ERR_MSG("DES3 TLS CBC empty payload: unexpected length %d", + decLen); + err = 1; + } + /* The MAC must still be extracted correctly with macStart at 0. */ + if (err == 0) { + getParams[0] = OSSL_PARAM_construct_octet_ptr( + OSSL_CIPHER_PARAM_TLS_MAC, (void **)&tlsMac, macSize); + getParams[1] = OSSL_PARAM_construct_end(); + err = EVP_CIPHER_CTX_get_params(ctx, getParams) != 1; + } + if (err == 0 && (tlsMac == NULL || memcmp(tlsMac, mac, macSize) != 0)) { + PRINT_ERR_MSG("DES3 TLS CBC empty payload: extracted MAC mismatch"); + err = 1; + } + + EVP_CIPHER_CTX_free(ctx); + EVP_CIPHER_free(cipher); + return err; +} + +/* Growing TLS_MAC_SIZE after a decrypt must drop the stored MAC: it was sized + * for the old value, so readers trusting the new size would over-read it. */ +int test_des3_tls_cbc_macsize_change(void *data) +{ + int err = 0; + EVP_CIPHER *cipher = NULL; + EVP_CIPHER_CTX *ctx = NULL; + EVP_CIPHER_CTX *dup = NULL; + OSSL_PARAM params[2]; + OSSL_PARAM getParams[2]; + size_t macSz = 20; + size_t bigMacSz = 48; + unsigned char key[24]; + unsigned char iv[DES3_BS]; + unsigned char mac[20]; + unsigned char pt[16]; + unsigned char buf[64]; + unsigned char sentinel = 0; + unsigned char *tlsMac = &sentinel; + int encLen = 0; + int decLen = 0; + + (void)data; + + memset(key, 0xAA, sizeof(key)); + memset(iv, 0xBB, sizeof(iv)); + memset(mac, 0xCC, sizeof(mac)); + memset(pt, 0x42, sizeof(pt)); + + PRINT_MSG("DES3 TLS 1.2 CBC MAC size change drops the stale MAC"); + + cipher = EVP_CIPHER_fetch(wpLibCtx, "DES-EDE3-CBC", ""); + if (cipher == NULL) { + err = 1; + } + if (err == 0) { + err = des3_tls_record(cipher, key, iv, pt, sizeof(pt), mac, sizeof(mac), + buf, &encLen); + } + + /* Decrypt with a 20-byte MAC size: tlsmac is a 20-byte allocation. */ + if (err == 0) { + ctx = des3_tls_ctx(cipher, key, iv, TLS1_2_VERSION, &macSz, 0); + err = ctx == NULL; + } + if (err == 0) { + err = EVP_CipherUpdate(ctx, buf, &decLen, buf, encLen) != 1; + } + + /* Grow the MAC size; the 20-byte MAC must not survive as a 48-byte one. */ + if (err == 0) { + params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_TLS_MAC_SIZE, + &bigMacSz); params[1] = OSSL_PARAM_construct_end(); err = EVP_CIPHER_CTX_set_params(ctx, params) != 1; } if (err == 0) { - /* Only the second update completes the record; must succeed. */ - (void)EVP_CipherUpdate(ctx, out, &l1, buf, split); - err = EVP_CipherUpdate(ctx, out + l1, &l2, buf + split, - encLen - split) != 1; + getParams[0] = OSSL_PARAM_construct_octet_ptr( + OSSL_CIPHER_PARAM_TLS_MAC, (void **)&tlsMac, 0); + getParams[1] = OSSL_PARAM_construct_end(); + err = EVP_CIPHER_CTX_get_params(ctx, getParams) != 1; + } + if (err == 0 && tlsMac != NULL) { + PRINT_ERR_MSG("DES3 TLS CBC: stale MAC survived a MAC size change"); + err = 1; + } + /* Copying now must not read the new size out of the old allocation. */ + if (err == 0) { + dup = EVP_CIPHER_CTX_new(); + err = dup == NULL; + } + if (err == 0) { + err = EVP_CIPHER_CTX_copy(dup, ctx) != 1; } - OPENSSL_free(out); + EVP_CIPHER_CTX_free(dup); EVP_CIPHER_CTX_free(ctx); EVP_CIPHER_free(cipher); return err; diff --git a/test/unit.c b/test/unit.c index c802390c..4883f61f 100644 --- a/test/unit.c +++ b/test/unit.c @@ -537,6 +537,14 @@ TEST_CASE test_case[] = { #if !defined(HAVE_FIPS) || defined(WP_ALLOW_NON_FIPS) TEST_DECL(test_des3_tls_cbc_bad_pad, NULL), TEST_DECL(test_des3_tls_cbc_dec, NULL), + TEST_DECL(test_des3_tls_cbc_mte, NULL), + TEST_DECL(test_des3_tls_cbc_etm, NULL), + TEST_DECL(test_des3_tls_cbc_etm_bad_pad, NULL), + TEST_DECL(test_des3_tls_cbc_dup, NULL), + TEST_DECL(test_des3_tls_cbc_bad_len, NULL), + TEST_DECL(test_des3_tls_cbc_empty_pt, NULL), + TEST_DECL(test_des3_tls_cbc_macsize_change, NULL), + TEST_DECL(test_des3_tls_cbc_old_version, NULL), #endif #endif diff --git a/test/unit.h b/test/unit.h index 6b617944..1a937055 100644 --- a/test/unit.h +++ b/test/unit.h @@ -546,6 +546,14 @@ int test_aes_tls_cbc_split(void *data); #if !defined(HAVE_FIPS) || defined(WP_ALLOW_NON_FIPS) int test_des3_tls_cbc_bad_pad(void *data); int test_des3_tls_cbc_dec(void *data); +int test_des3_tls_cbc_mte(void *data); +int test_des3_tls_cbc_etm(void *data); +int test_des3_tls_cbc_etm_bad_pad(void *data); +int test_des3_tls_cbc_dup(void *data); +int test_des3_tls_cbc_bad_len(void *data); +int test_des3_tls_cbc_empty_pt(void *data); +int test_des3_tls_cbc_macsize_change(void *data); +int test_des3_tls_cbc_old_version(void *data); #endif #endif