diff --git a/src/tls.c b/src/tls.c index b854b8f8cd..09e6c92174 100644 --- a/src/tls.c +++ b/src/tls.c @@ -16086,11 +16086,18 @@ static int TLSX_EchChangeSNI(WOLFSSL* ssl, TLSX** pEchX, if (serverNameX == NULL && ssl->ctx && ssl->ctx->extensions) { serverNameX = TLSX_Find(ssl->ctx->extensions, TLSX_SERVER_NAME); - extensions = &ssl->ctx->extensions; + if (serverNameX != NULL) + extensions = &ssl->ctx->extensions; + } + + /* ECH requires an inner SNI to be present for ClientHelloInner. + * Without it, fail instead of mutating extension lists. */ + if (serverNameX == NULL) { + ret = BAD_FUNC_ARG; } /* store the inner server name */ - if (serverNameX != NULL) { + if (ret == 0 && serverNameX != NULL) { char* hostName = ((SNI*)serverNameX->data)->data.host_name; word32 hostNameSz = (word32)XSTRLEN(hostName) + 1; @@ -16101,15 +16108,19 @@ static int TLSX_EchChangeSNI(WOLFSSL* ssl, TLSX** pEchX, XMEMCPY(serverName, hostName, hostNameSz); } - /* remove the inner server name */ - TLSX_Remove(extensions, TLSX_SERVER_NAME, ssl->heap); + /* only swap the SNI if one was found; extensions is non-NULL if an + * SNI entry was found on ssl->extensions or ctx->extensions */ + if (ret == 0 && extensions != NULL) { + /* remove the inner server name */ + TLSX_Remove(extensions, TLSX_SERVER_NAME, ssl->heap); - /* set the public name as the server name */ - if ((ret = TLSX_UseSNI(extensions, WOLFSSL_SNI_HOST_NAME, - ((WOLFSSL_ECH*)echX->data)->echConfig->publicName, - XSTRLEN(((WOLFSSL_ECH*)echX->data)->echConfig->publicName), - ssl->heap)) == WOLFSSL_SUCCESS) - ret = 0; + /* set the public name as the server name */ + if ((ret = TLSX_UseSNI(extensions, WOLFSSL_SNI_HOST_NAME, + ((WOLFSSL_ECH*)echX->data)->echConfig->publicName, + XSTRLEN(((WOLFSSL_ECH*)echX->data)->echConfig->publicName), + ssl->heap)) == WOLFSSL_SUCCESS) + ret = 0; + } } *pServerNameX = serverNameX; *pExtensions = extensions; @@ -16122,10 +16133,12 @@ static int TLSX_EchRestoreSNI(WOLFSSL* ssl, char* serverName, { int ret = 0; - if (serverNameX != NULL) { - /* remove the public name SNI */ + /* always remove the publicName SNI we injected, regardless of whether + * there was a prior inner SNI to restore */ + if (extensions != NULL) TLSX_Remove(extensions, TLSX_SERVER_NAME, ssl->heap); + if (serverNameX != NULL) { /* restore the inner server name */ ret = TLSX_UseSNI(extensions, WOLFSSL_SNI_HOST_NAME, serverName, XSTRLEN(serverName), ssl->heap); diff --git a/src/x509_str.c b/src/x509_str.c index 2c48c41964..90113caede 100644 --- a/src/x509_str.c +++ b/src/x509_str.c @@ -318,6 +318,11 @@ static void SetupStoreCtxError_ex(WOLFSSL_X509_STORE_CTX* ctx, int ret, { int error = GetX509Error(ret); + /* Do not overwrite a previously recorded error with success; preserve + * the worst-seen error across the chain walk. */ + if (error == 0 && ctx->error != 0) + return; + wolfSSL_X509_STORE_CTX_set_error(ctx, error); wolfSSL_X509_STORE_CTX_set_error_depth(ctx, depth); } @@ -635,9 +640,14 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) if (ctx->store->verify_cb) { ret = ctx->store->verify_cb(0, ctx); if (ret != WOLFSSL_SUCCESS) { + ret = WOLFSSL_FAILURE; goto exit; } } + else { + ret = WOLFSSL_FAILURE; + goto exit; + } } else #endif { @@ -2174,4 +2184,3 @@ int wolfSSL_X509_STORE_set1_param(WOLFSSL_X509_STORE *ctx, #endif /* !WOLFCRYPT_ONLY */ #endif /* !WOLFSSL_X509_STORE_INCLUDED */ - diff --git a/tests/api/test_evp_cipher.c b/tests/api/test_evp_cipher.c index b4e37df7a2..1e88da9979 100644 --- a/tests/api/test_evp_cipher.c +++ b/tests/api/test_evp_cipher.c @@ -1915,6 +1915,7 @@ int test_wolfssl_EVP_chacha20_poly1305(void) byte cipherText[sizeof(plainText)]; byte decryptedText[sizeof(plainText)]; byte tag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]; + byte badTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]; EVP_CIPHER_CTX* ctx = NULL; int outSz; @@ -1979,6 +1980,28 @@ int test_wolfssl_EVP_chacha20_poly1305(void) EVP_CIPHER_CTX_free(ctx); ctx = NULL; + /* Negative test: forged (all-zero) tag must be rejected. */ + XMEMSET(badTag, 0, sizeof(badTag)); + ExpectNotNull((ctx = EVP_CIPHER_CTX_new())); + ExpectIntEQ(EVP_DecryptInit_ex(ctx, EVP_chacha20_poly1305(), NULL, + NULL, NULL), WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, + CHACHA20_POLY1305_AEAD_IV_SIZE, NULL), WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, + CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE, badTag), + WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv), + WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_DecryptUpdate(ctx, NULL, &outSz, aad, sizeof(aad)), + WOLFSSL_SUCCESS); + ExpectIntEQ(EVP_DecryptUpdate(ctx, decryptedText, &outSz, cipherText, + sizeof(cipherText)), WOLFSSL_SUCCESS); + /* EVP_DecryptFinal_ex MUST return failure on tag mismatch */ + ExpectIntNE(EVP_DecryptFinal_ex(ctx, decryptedText, &outSz), + WOLFSSL_SUCCESS); + EVP_CIPHER_CTX_free(ctx); + ctx = NULL; + /* Test partial Inits. CipherInit() allow setting of key and iv * in separate calls. */ ExpectNotNull((ctx = EVP_CIPHER_CTX_new())); diff --git a/tests/api/test_ossl_x509_str.c b/tests/api/test_ossl_x509_str.c index 111994a347..99b82877c3 100644 --- a/tests/api/test_ossl_x509_str.c +++ b/tests/api/test_ossl_x509_str.c @@ -1074,6 +1074,56 @@ int test_X509_STORE_InvalidCa(void) ExpectIntEQ(X509_STORE_CTX_init(ctx, str, cert, untrusted), 1); ExpectIntEQ(X509_verify_cert(ctx), 1); ExpectIntEQ(last_errcode, X509_V_ERR_INVALID_CA); + /* Defense in depth: ctx->error must not be clobbered back to X509_V_OK + * by the later successful verification of the intermediate against the + * trusted root. The worst-seen error must persist. */ + ExpectIntEQ(X509_STORE_CTX_get_error(ctx), X509_V_ERR_INVALID_CA); + + X509_free(cert); + X509_STORE_free(str); + X509_STORE_CTX_free(ctx); + sk_X509_pop_free(untrusted, NULL); +#endif + return EXPECT_RESULT(); +} + +int test_X509_STORE_InvalidCa_NoCallback(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_ALL) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) + const char* filename = "./certs/intermediate/ca_false_intermediate/" + "test_int_not_cacert.pem"; + const char* srvfile = "./certs/intermediate/ca_false_intermediate/" + "test_sign_bynoca_srv.pem"; + X509_STORE_CTX* ctx = NULL; + X509_STORE* str = NULL; + XFILE fp = XBADFILE; + X509* cert = NULL; + STACK_OF(X509)* untrusted = NULL; + + ExpectTrue((fp = XFOPEN(srvfile, "rb")) + != XBADFILE); + ExpectNotNull(cert = PEM_read_X509(fp, 0, 0, 0 )); + if (fp != XBADFILE) { + XFCLOSE(fp); + fp = XBADFILE; + } + + ExpectNotNull(str = X509_STORE_new()); + ExpectNotNull(ctx = X509_STORE_CTX_new()); + ExpectNotNull(untrusted = sk_X509_new_null()); + + /* Create cert chain stack with an intermediate that is CA:FALSE. */ + ExpectIntEQ(test_X509_STORE_untrusted_load_cert_to_stack(filename, + untrusted), TEST_SUCCESS); + + ExpectIntEQ(X509_STORE_load_locations(str, + "./certs/intermediate/ca_false_intermediate/test_ca.pem", + NULL), 1); + ExpectIntEQ(X509_STORE_CTX_init(ctx, str, cert, untrusted), 1); + /* No verify callback: verification must fail on CA:FALSE issuer. */ + ExpectIntNE(X509_verify_cert(ctx), 1); + ExpectIntEQ(X509_STORE_CTX_get_error(ctx), X509_V_ERR_INVALID_CA); X509_free(cert); X509_STORE_free(str); @@ -1793,4 +1843,3 @@ int test_X509_STORE_No_SSL_CTX(void) #endif return EXPECT_RESULT(); } - diff --git a/tests/api/test_ossl_x509_str.h b/tests/api/test_ossl_x509_str.h index 9525a3a187..6737046453 100644 --- a/tests/api/test_ossl_x509_str.h +++ b/tests/api/test_ossl_x509_str.h @@ -31,6 +31,7 @@ int test_wolfSSL_X509_STORE_CTX(void); int test_wolfSSL_X509_STORE_CTX_ex(void); int test_X509_STORE_untrusted(void); int test_X509_STORE_InvalidCa(void); +int test_X509_STORE_InvalidCa_NoCallback(void); int test_wolfSSL_X509_STORE_CTX_trusted_stack_cleanup(void); int test_wolfSSL_X509_STORE_CTX_get_issuer(void); int test_wolfSSL_X509_STORE_set_flags(void); @@ -51,6 +52,7 @@ int test_X509_STORE_No_SSL_CTX(void); TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_X509_STORE_CTX_ex), \ TEST_DECL_GROUP("ossl_x509_store", test_X509_STORE_untrusted), \ TEST_DECL_GROUP("ossl_x509_store", test_X509_STORE_InvalidCa), \ + TEST_DECL_GROUP("ossl_x509_store", test_X509_STORE_InvalidCa_NoCallback), \ TEST_DECL_GROUP("ossl_x509_store", \ test_wolfSSL_X509_STORE_CTX_trusted_stack_cleanup), \ TEST_DECL_GROUP("ossl_x509_store", \ diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index cb4258e634..41b01031c4 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -10217,8 +10217,9 @@ int wc_AesGcmDecrypt(Aes* aes, byte* out, const byte* in, word32 sz, /* If the sz is non-zero, both in and out must be set. If sz is 0, * in and out are don't cares, as this is is the GMAC case. */ if (aes == NULL || iv == NULL || (sz != 0 && (in == NULL || out == NULL)) || - authTag == NULL || authTagSz > WC_AES_BLOCK_SIZE || authTagSz == 0 || - ivSz == 0 || ((authInSz > 0) && (authIn == NULL))) + authTag == NULL || authTagSz > WC_AES_BLOCK_SIZE || + authTagSz < WOLFSSL_MIN_AUTH_TAG_SZ || ivSz == 0 || + ((authInSz > 0) && (authIn == NULL))) { return BAD_FUNC_ARG; } @@ -10781,8 +10782,8 @@ int wc_AesGcmDecrypt(Aes* aes, byte* out, const byte* in, word32 sz, /* If the sz is non-zero, both in and out must be set. If sz is 0, * in and out are don't cares, as this is is the GMAC case. */ if (aes == NULL || iv == NULL || (sz != 0 && (in == NULL || out == NULL)) || - authTag == NULL || authTagSz > WC_AES_BLOCK_SIZE || authTagSz == 0 || - ivSz == 0) { + authTag == NULL || authTagSz > WC_AES_BLOCK_SIZE || + authTagSz < WOLFSSL_MIN_AUTH_TAG_SZ || ivSz == 0) { return BAD_FUNC_ARG; } @@ -12473,7 +12474,7 @@ int wc_AesGcmEncryptFinal(Aes* aes, byte* authTag, word32 authTagSz) /* Check validity of parameters. */ if ((aes == NULL) || (authTag == NULL) || (authTagSz > WC_AES_BLOCK_SIZE) || - (authTagSz == 0)) { + (authTagSz < WOLFSSL_MIN_AUTH_TAG_SZ)) { ret = BAD_FUNC_ARG; } @@ -16377,9 +16378,7 @@ int wc_local_CmacUpdateAes(struct Cmac *cmac, const byte* in, word32 inSz) { in += add; if (cmac->bufferSz == WC_AES_BLOCK_SIZE && inSz != 0) { - if (cmac->totalSz != 0) { - xorbuf(cmac->buffer, cmac->digest, WC_AES_BLOCK_SIZE); - } + xorbuf(cmac->buffer, cmac->digest, WC_AES_BLOCK_SIZE); ret = AesEncrypt_preFetchOpt(aes, cmac->buffer, cmac->digest, &did_prefetches); if (ret == 0) { diff --git a/wolfcrypt/src/cmac.c b/wolfcrypt/src/cmac.c index 66e45f9247..ba579516d1 100644 --- a/wolfcrypt/src/cmac.c +++ b/wolfcrypt/src/cmac.c @@ -238,9 +238,7 @@ int wc_CmacUpdate(Cmac* cmac, const byte* in, word32 inSz) inSz -= add; if (cmac->bufferSz == WC_AES_BLOCK_SIZE && inSz != 0) { - if (cmac->totalSz != 0) { - xorbuf(cmac->buffer, cmac->digest, WC_AES_BLOCK_SIZE); - } + xorbuf(cmac->buffer, cmac->digest, WC_AES_BLOCK_SIZE); wc_AesEncryptDirect(&cmac->aes, cmac->digest, cmac->buffer); cmac->totalSz += WC_AES_BLOCK_SIZE; diff --git a/wolfcrypt/src/eccsi.c b/wolfcrypt/src/eccsi.c index b4cf859e50..d919dd8a34 100644 --- a/wolfcrypt/src/eccsi.c +++ b/wolfcrypt/src/eccsi.c @@ -2159,6 +2159,18 @@ static int eccsi_calc_j(EccsiKey* key, const mp_int* hem, const byte* sig, if (err == 0) { err = eccsi_decode_sig_s(key, sig, sigSz, s); } + /* Validate s is in [1, q-1]: reject zero or out-of-range second signature + * component. With s=0, [s](...) yields the point at infinity whose + * affine x-coordinate is 0, making the final mp_cmp(0,0) accept any + * forged signature. */ + if (err == 0) { + if (mp_iszero(s)) { + err = MP_ZERO_E; + } + else if (mp_cmp(s, &key->params.order) != MP_LT) { + err = ECC_OUT_OF_RANGE_E; + } + } /* [s]( [HE]G + [r]Y ) */ if (err == 0) { err = eccsi_mulmod_point(key, s, j, j, 1); @@ -2238,6 +2250,19 @@ int wc_VerifyEccsiHash(EccsiKey* key, enum wc_HashType hashType, err = mp_montgomery_setup(¶ms->prime, &mp); } + /* Validate r is in [1, q-1]: reject zero or out-of-range first signature + * component before any scalar multiplication takes place. + * Without this check, r=0 causes J_x=0 and the final mp_cmp(0,0)==MP_EQ + * comparison accepts the forged signature unconditionally. */ + if (err == 0) { + if (mp_iszero(r)) { + err = MP_ZERO_E; + } + else if (mp_cmp(r, ¶ms->order) != MP_LT) { + err = ECC_OUT_OF_RANGE_E; + } + } + /* Step 1: Validate PVT is on curve */ if (err == 0) { err = wc_ecc_is_point(pvt, ¶ms->a, ¶ms->b, ¶ms->prime); @@ -2273,6 +2298,16 @@ int wc_VerifyEccsiHash(EccsiKey* key, enum wc_HashType hashType, key->params.haveBase = 0; } + /* Defense-in-depth: reject J = point at infinity before the final + * comparison. Catches any future path that might reach this point + * with a neutral-element result (e.g. s = 0 mod q for a non-zero + * encoded s). */ + if (err == 0) { + if (wc_ecc_point_is_at_infinity(j)) { + err = ECC_INF_E; + } + } + /* Step 6: Jx fitting, compare with r */ if (err == 0) { jx = &key->tmp; diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index fc4f68eb9f..df8d9b860b 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -1499,16 +1499,33 @@ int wolfSSL_EVP_CipherFinal(WOLFSSL_EVP_CIPHER_CTX *ctx, unsigned char *out, * HAVE_FIPS_VERSION >= 2 */ #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) case WC_CHACHA20_POLY1305_TYPE: + { + byte computedTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]; + if (!ctx->enc) { + /* Save the expected tag before _Final() overwrites + * ctx->authTag */ + XMEMCPY(computedTag, ctx->authTag, sizeof(computedTag)); + } if (wc_ChaCha20Poly1305_Final(&ctx->cipher.chachaPoly, ctx->authTag) != 0) { WOLFSSL_MSG("wc_ChaCha20Poly1305_Final failed"); return WOLFSSL_FAILURE; } - else { - *outl = 0; - return WOLFSSL_SUCCESS; + if (!ctx->enc) { + /* ctx->authTag now holds computed tag; computedTag holds + * expected */ + int tagErr = wc_ChaCha20Poly1305_CheckTag(computedTag, + ctx->authTag); + ForceZero(computedTag, sizeof(computedTag)); + if (tagErr != 0) { + WOLFSSL_MSG("ChaCha20-Poly1305 tag mismatch"); + return WOLFSSL_FAILURE; + } } - break; + *outl = 0; + return WOLFSSL_SUCCESS; + } + break; #endif #ifdef WOLFSSL_SM4_GCM case WC_SM4_GCM_TYPE: @@ -3698,6 +3715,10 @@ int wolfSSL_EVP_PKEY_keygen_init(WOLFSSL_EVP_PKEY_CTX *ctx) return WOLFSSL_SUCCESS; } +#ifdef HAVE_ECC +static int ECC_populate_EVP_PKEY(WOLFSSL_EVP_PKEY* pkey, WOLFSSL_EC_KEY *key); +#endif + int wolfSSL_EVP_PKEY_keygen(WOLFSSL_EVP_PKEY_CTX *ctx, WOLFSSL_EVP_PKEY **ppkey) { @@ -3752,6 +3773,8 @@ int wolfSSL_EVP_PKEY_keygen(WOLFSSL_EVP_PKEY_CTX *ctx, ret = wolfSSL_EC_KEY_generate_key(pkey->ecc); if (ret == WOLFSSL_SUCCESS) { pkey->ownEcc = 1; + if (ECC_populate_EVP_PKEY(pkey, pkey->ecc) != WOLFSSL_SUCCESS) + ret = WOLFSSL_FAILURE; } } break; @@ -9504,7 +9527,15 @@ static int ECC_populate_EVP_PKEY(WOLFSSL_EVP_PKEY* pkey, WOLFSSL_EC_KEY *key) else #endif /* HAVE_PKCS8 */ { - if (ecc->type == ECC_PRIVATEKEY_ONLY) { + if (ecc->type == ECC_PRIVATEKEY_ONLY || + (ecc->type == ECC_PRIVATEKEY && + mp_iszero(ecc->pubkey.x))) { + /* Reconstruct public key from private scalar. This covers + * both ECC_PRIVATEKEY_ONLY keys and ECC_PRIVATEKEY keys whose + * public-key point was never populated (e.g. when only + * EC_KEY_set_private_key was called, SetECKeyInternal copies + * the zero-initialized pub_key point and marks the type as + * ECC_PRIVATEKEY, leaving pubkey.x == 0). */ if (wc_ecc_make_pub(ecc, NULL) != MP_OKAY) { return WOLFSSL_FAILURE; } diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 9efec15ec7..174c04d632 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -140,6 +140,7 @@ struct PKCS7State { word32 nonceSz; /* size of nonce stored */ word32 aadSz; /* size of additional AEAD data */ word32 tagSz; /* size of tag for AEAD */ + word32 icvSz; /* expected ICV/MAC size from AlgoID parameter */ word32 contentSz; word32 currContIdx; /* index of current content */ word32 currContSz; /* size of current content */ @@ -14235,6 +14236,10 @@ int wc_PKCS7_DecodeAuthEnvelopedData(wc_PKCS7* pkcs7, byte* in, if (ret == 0 && GetMyVersion(pkiMsg, &idx, &macSz, pkiMsgSz) < 0) { ret = ASN_PARSE_E; } + if (ret == 0 && (macSz <= 0 || macSz > WC_AES_BLOCK_SIZE)) { + WOLFSSL_MSG("AuthEnvelopedData invalid MAC length"); + ret = ASN_PARSE_E; + } if (ret == 0) { explicitOctet = 0; @@ -14280,7 +14285,8 @@ int wc_PKCS7_DecodeAuthEnvelopedData(wc_PKCS7* pkcs7, byte* in, break; } - /* store nonce for later */ + /* store nonce and macSz for later */ + pkcs7->stream->icvSz = (word32)macSz; if (nonceSz > 0) { pkcs7->stream->nonceSz = (word32)nonceSz; pkcs7->stream->nonce = (byte*)XMALLOC((word32)nonceSz, @@ -14471,6 +14477,7 @@ int wc_PKCS7_DecodeAuthEnvelopedData(wc_PKCS7* pkcs7, byte* in, encodedAttribSz = pkcs7->stream->aadSz; encodedAttribs = pkcs7->stream->aad; } + macSz = (int)pkcs7->stream->icvSz; #endif @@ -14487,6 +14494,17 @@ int wc_PKCS7_DecodeAuthEnvelopedData(wc_PKCS7* pkcs7, byte* in, ret = ASN_PARSE_E; } authTagSz = (word32)length; + if (ret == 0 && authTagSz != (word32)macSz) { + WOLFSSL_MSG("AuthEnvelopedData authTag size mismatch"); + ret = ASN_PARSE_E; + } + if (ret == 0 && + (encOID == AES128GCMb || encOID == AES192GCMb || + encOID == AES256GCMb) && + authTagSz < WOLFSSL_MIN_AUTH_TAG_SZ) { + WOLFSSL_MSG("AuthEnvelopedData GCM authTag too small"); + ret = ASN_PARSE_E; + } #ifndef NO_PKCS7_STREAM /* there might not be enough data for the auth tag too */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 755aa94358..8077342566 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -57721,6 +57721,9 @@ static wc_test_ret_t pkcs7authenveloped_run_vectors(byte* rsaCert, word32 rsaCer wc_test_ret_t ret = 0; int testSz = 0, i; int envelopedSz, decodedSz; +#ifdef HAVE_AESGCM + int tagTruncationChecked = 0; +#endif byte *enveloped = NULL; byte *decoded = NULL; @@ -58232,6 +58235,45 @@ static wc_test_ret_t pkcs7authenveloped_run_vectors(byte* rsaCert, word32 rsaCer ERROR_OUT(WC_TEST_RET_ENC_NC, out); } +#ifdef HAVE_AESGCM + if (tagTruncationChecked == 0 && + (testVectors[i].encryptOID == AES128GCMb || + testVectors[i].encryptOID == AES192GCMb || + testVectors[i].encryptOID == AES256GCMb) && + testVectors[i].authAttribsSz == 0 && + testVectors[i].unauthAttribsSz == 0 && + envelopedSz > (WC_AES_BLOCK_SIZE + 2)) { + int macIdx = envelopedSz - (WC_AES_BLOCK_SIZE + 2); + byte* tampered = NULL; + + /* For plain DER output without unauthenticated attributes, the + * MAC OCTET STRING is the final field. */ + if (enveloped[macIdx] == ASN_OCTET_STRING && + enveloped[macIdx + 1] == WC_AES_BLOCK_SIZE) { + tampered = (byte*)XMALLOC((word32)envelopedSz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER); + if (tampered == NULL) { + wc_PKCS7_Free(pkcs7); + ERROR_OUT(WC_TEST_RET_ENC_ERRNO, out); + } + XMEMCPY(tampered, enveloped, (word32)envelopedSz); + tampered[macIdx + 1] = 1; + + decodedSz = wc_PKCS7_DecodeAuthEnvelopedData(pkcs7, tampered, + (word32)envelopedSz, decoded, PKCS7_BUF_SIZE); + + XFREE(tampered, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + tampered = NULL; + + if (decodedSz > 0) { + wc_PKCS7_Free(pkcs7); + ERROR_OUT(WC_TEST_RET_ENC_NC, out); + } + tagTruncationChecked = 1; + } + } +#endif + #ifdef PKCS7_OUTPUT_TEST_BUNDLES /* output pkcs7 envelopedData for external testing */ pkcs7File = XFOPEN(testVectors[i].outFileName, "wb"); diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index a0c79c5e84..4929b61cb4 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -3429,6 +3429,8 @@ extern void uITRON4_free(void *p) ; /* Default AES minimum auth tag sz, allow user to override */ #ifndef WOLFSSL_MIN_AUTH_TAG_SZ #define WOLFSSL_MIN_AUTH_TAG_SZ 12 +#elif WOLFSSL_MIN_AUTH_TAG_SZ < 1 + #error WOLFSSL_MIN_AUTH_TAG_SZ must be at least 1 #endif