Skip to content

Commit e62e724

Browse files
committed
- Handle exactly one block in AES-CTS as plain CBC, matching OpenSSL
- Use the cached IV for split-init AES-CTS in both init orders - consume tls_data_size and equalize hmac block count in final
1 parent fb59d07 commit e62e724

7 files changed

Lines changed: 532 additions & 2 deletions

File tree

include/wolfprovider/internal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,9 @@ int wp_decode_should_skip(int castType, const unsigned char* der, word32 len,
288288
const int* allowedNids, size_t nAllowed);
289289
#endif /* HAVE_FIPS */
290290

291+
int wp_hmac_tls_dummy_blocks(enum wc_HashType hashType, size_t macSize,
292+
size_t tlsDataSize, size_t dataLen);
293+
291294
byte wp_ct_byte_mask_eq(byte a, byte b);
292295
byte wp_ct_byte_mask_ne(byte a, byte b);
293296
byte wp_ct_int_mask_gte(int a, int b);

src/wp_aes_stream.c

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ typedef struct wp_AesStreamCtx {
4848

4949
/** Operation being performed is encryption. */
5050
unsigned int enc:1;
51+
/** An IV has been set. */
52+
unsigned int ivSet:1;
5153

5254
/** Current IV. */
5355
unsigned char iv[AES_BLOCK_SIZE];
@@ -268,6 +270,7 @@ static int wp_aes_init_iv(wp_AesStreamCtx *ctx, const unsigned char *iv,
268270
if (ok) {
269271
XMEMCPY(ctx->iv, iv, ivLen);
270272
XMEMCPY(ctx->oiv, iv, ivLen);
273+
ctx->ivSet = 1;
271274
}
272275

273276
WOLFPROV_LEAVE(WP_LOG_COMP_AES, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok);
@@ -308,6 +311,13 @@ static int wp_aes_stream_init(wp_AesStreamCtx *ctx, const unsigned char *key,
308311
if (ok && (iv != NULL) && (!wp_aes_init_iv(ctx, iv, ivLen))) {
309312
ok = 0;
310313
}
314+
if (ok && (iv == NULL) && ctx->ivSet &&
315+
((ctx->mode == EVP_CIPH_CBC_MODE) ||
316+
(ctx->mode == EVP_CIPH_CFB_MODE))) {
317+
if (!wp_aes_init_iv(ctx, ctx->oiv, ctx->ivLen)) {
318+
ok = 0;
319+
}
320+
}
311321

312322
if (ok && (key != NULL)) {
313323
if (keyLen != ctx->keyLen) {
@@ -321,7 +331,7 @@ static int wp_aes_stream_init(wp_AesStreamCtx *ctx, const unsigned char *key,
321331
}
322332
#endif
323333
WP_CHECK_FIPS_ALGO(WP_CAST_ALGO_AES);
324-
rc = wc_AesSetKey(&ctx->aes, key, (word32)ctx->keyLen, iv,
334+
rc = wc_AesSetKey(&ctx->aes, key, (word32)ctx->keyLen, ctx->iv,
325335
dir);
326336
if (rc != 0) {
327337
WOLFPROV_MSG_DEBUG_RETCODE(WP_LOG_LEVEL_DEBUG, "wc_AesSetKey", rc);
@@ -404,11 +414,24 @@ static int wp_aes_cts_encrypt(wp_AesStreamCtx *ctx, unsigned char *out,
404414
* the existing wolfSSL AES_CTS APIs with FIPS, so the implementation is
405415
* effectively copied here from wolfSSL internals. */
406416

417+
if (inLen == AES_BLOCK_SIZE) {
418+
XMEMCPY(&ctx->aes.reg, ctx->iv, ctx->ivLen);
419+
rc = wc_AesCbcEncrypt(&ctx->aes, out, in, AES_BLOCK_SIZE);
420+
if (rc != 0) {
421+
WOLFPROV_MSG_DEBUG_RETCODE(WP_LOG_LEVEL_DEBUG, "wc_AesCbcEncrypt", rc);
422+
ok = 0;
423+
}
424+
if (ok) {
425+
XMEMCPY(ctx->iv, ctx->aes.reg, ctx->ivLen);
426+
}
427+
return ok;
428+
}
429+
407430
blocks = (int)((inLen + (AES_BLOCK_SIZE - 1)) / AES_BLOCK_SIZE);
408431
blocks -= 2;
409432
XMEMSET(ctsBlock, 0, AES_BLOCK_SIZE * 2);
433+
XMEMCPY(&ctx->aes.reg, ctx->iv, ctx->ivLen);
410434
if (ok && blocks > 0) {
411-
XMEMCPY(&ctx->aes.reg, ctx->iv, ctx->ivLen);
412435
rc = wc_AesCbcEncrypt(&ctx->aes, out, in, blocks * AES_BLOCK_SIZE);
413436
if (rc != 0) {
414437
WOLFPROV_MSG_DEBUG_RETCODE(WP_LOG_LEVEL_DEBUG, "wc_AesCbcEncrypt", rc);
@@ -458,6 +481,19 @@ static int wp_aes_cts_decrypt(wp_AesStreamCtx *ctx, unsigned char *out,
458481
* the existing wolfSSL AES_CTS APIs with FIPS, so the implementation is
459482
* effectively copied here from wolfSSL internals. */
460483

484+
if (inLen == AES_BLOCK_SIZE) {
485+
XMEMCPY(&ctx->aes.reg, ctx->iv, ctx->ivLen);
486+
rc = wc_AesCbcDecrypt(&ctx->aes, out, in, AES_BLOCK_SIZE);
487+
if (rc != 0) {
488+
WOLFPROV_MSG_DEBUG_RETCODE(WP_LOG_LEVEL_DEBUG, "wc_AesCbcDecrypt", rc);
489+
ok = 0;
490+
}
491+
if (ok) {
492+
XMEMCPY(ctx->iv, ctx->aes.reg, ctx->ivLen);
493+
}
494+
return ok;
495+
}
496+
461497
partialSz = inLen % AES_BLOCK_SIZE;
462498
if (partialSz == 0) {
463499
partialSz = AES_BLOCK_SIZE;

src/wp_hmac.c

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ typedef struct wp_HmacCtx {
5151
unsigned char* key;
5252
/** Length of private key in bytes. */
5353
size_t keyLen;
54+
55+
/** Length of the padded TLS record including MAC and padding. */
56+
size_t tlsDataSize;
57+
/** Number of dummy blocks to hash in final to equalize hashing time. */
58+
int tlsDummyBlocks;
5459
} wp_HmacCtx;
5560

5661

@@ -205,6 +210,8 @@ static wp_HmacCtx* wp_hmac_dup(wp_HmacCtx* src)
205210
dst->type = src->type;
206211
dst->size = src->size;
207212
dst->provCtx = src->provCtx;
213+
dst->tlsDataSize = src->tlsDataSize;
214+
dst->tlsDummyBlocks = src->tlsDummyBlocks;
208215

209216
/* Copy the Hmac struct directly to preserve in-progress state.
210217
* wc_HmacCopy is not available in all wolfSSL versions. */
@@ -258,6 +265,64 @@ static int wp_hmac_init(wp_HmacCtx* macCtx, const unsigned char* key,
258265
return ok;
259266
}
260267

268+
/** Length of the TLS record header hashed before the record data. */
269+
#define WP_TLS_HMAC_HEADER_SZ 13
270+
271+
/**
272+
* Count the blocks a hash processes for a message of the given length.
273+
*
274+
* @param [in] len Length of message in bytes.
275+
* @param [in] blockBits Log base 2 of the hash block size.
276+
* @param [in] blockMask Hash block size minus one.
277+
* @param [in] padSz Bytes of padding the hash appends to the message.
278+
* @return Number of blocks processed.
279+
*/
280+
static int wp_hmac_blocks(word32 len, int blockBits, word32 blockMask,
281+
word32 padSz)
282+
{
283+
return (int)(len >> blockBits) +
284+
(wp_ct_int_mask_lt((int)((len + padSz) & blockMask), (int)padSz) & 1);
285+
}
286+
287+
/**
288+
* Calculate the number of dummy blocks to hash when finalizing a TLS record.
289+
*
290+
* @param [in] hashType wolfSSL digest type.
291+
* @param [in] macSize Output size of the digest in bytes.
292+
* @param [in] tlsDataSize Length of the padded record including MAC and
293+
* padding.
294+
* @param [in] dataLen Length of data passed to update in bytes.
295+
* @return Number of dummy blocks to hash. At least one.
296+
*/
297+
int wp_hmac_tls_dummy_blocks(enum wc_HashType hashType, size_t macSize,
298+
size_t tlsDataSize, size_t dataLen)
299+
{
300+
int blockSizeRet = wc_HashGetBlockSize(hashType);
301+
word32 blockSz;
302+
word32 blockMask;
303+
word32 padSz;
304+
word32 realSz;
305+
word32 maxSz;
306+
int blockBits = 0;
307+
308+
if ((blockSizeRet <= 0) || (tlsDataSize <= macSize)) {
309+
return 1;
310+
}
311+
312+
blockSz = (word32)blockSizeRet;
313+
blockMask = blockSz - 1;
314+
while (((word32)1 << blockBits) < blockSz) {
315+
blockBits++;
316+
}
317+
padSz = blockSz >> 3;
318+
319+
realSz = WP_TLS_HMAC_HEADER_SZ + (word32)dataLen;
320+
maxSz = WP_TLS_HMAC_HEADER_SZ + (word32)(tlsDataSize - 1 - macSize);
321+
322+
return 1 + wp_hmac_blocks(maxSz, blockBits, blockMask, padSz) -
323+
wp_hmac_blocks(realSz, blockBits, blockMask, padSz);
324+
}
325+
261326
/**
262327
* Update the MAC state with data.
263328
*
@@ -274,6 +339,11 @@ static int wp_hmac_update(wp_HmacCtx* macCtx, const unsigned char* data,
274339

275340
WOLFPROV_ENTER(WP_LOG_COMP_MAC, "wp_hmac_update");
276341

342+
if (macCtx->tlsDataSize > 0) {
343+
macCtx->tlsDummyBlocks = wp_hmac_tls_dummy_blocks(macCtx->type,
344+
macCtx->size, macCtx->tlsDataSize, dataLen);
345+
}
346+
277347
while (ok && (dataLen > 0)) {
278348
word32 chunk = (!WP_FITS_WORD32(dataLen)) ?
279349
0xFFFFFFFFU : (word32)dataLen;
@@ -323,6 +393,24 @@ static int wp_hmac_final(wp_HmacCtx* macCtx, unsigned char* out, size_t* outl,
323393
ok = 0;
324394
}
325395
}
396+
if (ok && (macCtx->tlsDataSize > 0)) {
397+
unsigned char dummy[WC_MAX_BLOCK_SIZE];
398+
int blockSz = wc_HashGetBlockSize(macCtx->type);
399+
int i;
400+
401+
if (blockSz <= 0) {
402+
ok = 0;
403+
}
404+
XMEMSET(dummy, 0, sizeof(dummy));
405+
for (i = 0; ok && (i < macCtx->tlsDummyBlocks); i++) {
406+
rc = wc_HmacUpdate(&macCtx->hmac, dummy, (word32)blockSz);
407+
if (rc != 0) {
408+
WOLFPROV_MSG_DEBUG_RETCODE(WP_LOG_LEVEL_DEBUG, "wc_HmacUpdate",
409+
rc);
410+
ok = 0;
411+
}
412+
}
413+
}
326414
if (ok) {
327415
*outl = macCtx->size;
328416
}
@@ -402,6 +490,7 @@ static const OSSL_PARAM* wp_hmac_settable_ctx_params(wp_HmacCtx* macCtx,
402490
static const OSSL_PARAM wp_hmac_supported_settable_ctx_params[] = {
403491
OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, NULL, 0),
404492
OSSL_PARAM_octet_string(OSSL_MAC_PARAM_KEY, NULL, 0),
493+
OSSL_PARAM_size_t(OSSL_MAC_PARAM_TLS_DATA_SIZE, NULL),
405494
OSSL_PARAM_END
406495
};
407496
(void)macCtx;
@@ -443,6 +532,15 @@ static int wp_hmac_set_ctx_params(wp_HmacCtx* macCtx, const OSSL_PARAM params[])
443532
ok = 0;
444533
}
445534
}
535+
536+
if (ok) {
537+
const OSSL_PARAM* p = OSSL_PARAM_locate_const(params,
538+
OSSL_MAC_PARAM_TLS_DATA_SIZE);
539+
if ((p != NULL) && (!OSSL_PARAM_get_size_t(p,
540+
&macCtx->tlsDataSize))) {
541+
ok = 0;
542+
}
543+
}
446544
}
447545

448546
WOLFPROV_LEAVE(WP_LOG_COMP_MAC, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok);

0 commit comments

Comments
 (0)