Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 25 additions & 12 deletions src/tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
Expand All @@ -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);
Expand Down
11 changes: 10 additions & 1 deletion src/x509_str.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -2174,4 +2184,3 @@ int wolfSSL_X509_STORE_set1_param(WOLFSSL_X509_STORE *ctx,
#endif /* !WOLFCRYPT_ONLY */

#endif /* !WOLFSSL_X509_STORE_INCLUDED */

23 changes: 23 additions & 0 deletions tests/api/test_evp_cipher.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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()));
Expand Down
51 changes: 50 additions & 1 deletion tests/api/test_ossl_x509_str.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -1793,4 +1843,3 @@ int test_X509_STORE_No_SSL_CTX(void)
#endif
return EXPECT_RESULT();
}

2 changes: 2 additions & 0 deletions tests/api/test_ossl_x509_str.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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", \
Expand Down
15 changes: 7 additions & 8 deletions wolfcrypt/src/aes.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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) {
Expand Down
4 changes: 1 addition & 3 deletions wolfcrypt/src/cmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
35 changes: 35 additions & 0 deletions wolfcrypt/src/eccsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -2238,6 +2250,19 @@ int wc_VerifyEccsiHash(EccsiKey* key, enum wc_HashType hashType,
err = mp_montgomery_setup(&params->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, &params->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, &params->a, &params->b, &params->prime);
Expand Down Expand Up @@ -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;
Expand Down
41 changes: 36 additions & 5 deletions wolfcrypt/src/evp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down
Loading
Loading