Merge pull request #10714 from Frauschi/zd21992_2

Some more fixes
This commit is contained in:
JacobBarthelmeh
2026-06-17 17:34:15 -06:00
committed by GitHub
7 changed files with 451 additions and 10 deletions
+142 -2
View File
@@ -29404,6 +29404,93 @@ int GetCipherSuiteFromName(const char* name, byte* cipherSuite0,
return ret;
}
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)
/* Classify a cipher suite for OpenSSL-style "!aNULL"/"!eNULL" exclusion.
* anon != 0: match suites that perform NO peer authentication.
* enull != 0: match suites that perform NO encryption.
* Classification is by suite name: the RFC/IANA name when compiled in
* (anonymous suites contain "_anon_", named NULL-cipher suites contain "_NULL"
* - e.g. TLS_DH_anon_*, TLS_ECDH_anon_*, TLS_*_WITH_NULL_*) and the OpenSSL
* short name (ADH/AECDH/...NULL...), which is the only name available under
* NO_ERROR_STRINGS. The TLS 1.3 integrity-only suites (RFC 9150) are
* NULL-encryption too but carry no "NULL" token in their names, so they are
* matched by suite id below. */
static int CipherSuiteExcluded(byte first, byte second, int anon, int enull)
{
int i;
const int sz = GetCipherNamesSize();
#ifdef HAVE_NULL_CIPHER
/* TLS 1.3 integrity-only suites perform no encryption; wolfSSL keys them
* off haveNull in InitSuites(), so honor "!eNULL" for them here too. */
if (enull && (first == ECC_BYTE) &&
((second == TLS_SHA256_SHA256) || (second == TLS_SHA384_SHA384))) {
return 1;
}
#endif
for (i = 0; i < sz; i++) {
if ((cipher_names[i].cipherSuite0 != first) ||
(cipher_names[i].cipherSuite != second)) {
continue;
}
#ifndef NO_CIPHER_SUITE_ALIASES
if (cipher_names[i].flags & WOLFSSL_CIPHER_SUITE_FLAG_NAMEALIAS) {
continue;
}
#endif
#ifndef NO_ERROR_STRINGS
if (cipher_names[i].name_iana != NULL) {
if (anon &&
(XSTRSTR(cipher_names[i].name_iana, "_anon_") != NULL)) {
return 1;
}
if (enull &&
(XSTRSTR(cipher_names[i].name_iana, "_NULL") != NULL)) {
return 1;
}
}
#endif
if (cipher_names[i].name != NULL) {
if (anon && ((XSTRSTR(cipher_names[i].name, "ADH") != NULL) ||
(XSTRSTR(cipher_names[i].name, "AECDH") != NULL))) {
return 1;
}
if (enull && (XSTRSTR(cipher_names[i].name, "NULL") != NULL)) {
return 1;
}
}
break; /* found the suite; not excluded */
}
return 0;
}
/* Drop suites matching an exclusion from the explicit user-suite array
* suites[0..*idx). Used to honor an OpenSSL-style exclusion ("!aNULL",
* "!eNULL"/"!NULL", and the "!aNULL:!eNULL" embedded by DEFAULT): the keyword
* only adjusts the InitSuites mask, so without this an explicitly listed
* anonymous or NULL-cipher suite would survive (anonymous = no peer
* authentication; NULL = no confidentiality). Compacts in place; *idx is a
* byte count of 2-byte suite pairs. */
static void RemoveExcludedSuites(byte* suites, int* idx, int anon, int enull)
{
int i;
int out = 0;
for (i = 0; (i + 1) < *idx; i += 2) {
if (CipherSuiteExcluded(suites[i], suites[i + 1], anon, enull)) {
continue;
}
if (out != i) {
suites[out + 0] = suites[i + 0];
suites[out + 1] = suites[i + 1];
}
out += 2;
}
*idx = out;
}
#endif /* OPENSSL_EXTRA || OPENSSL_ALL */
/**
Set the enabled cipher suites.
@@ -29436,6 +29523,8 @@ static int ParseCipherList(Suites* suites,
word16 haveAES128 = 1; /* allowed by default if compiled in */
word16 haveSHA1 = 1; /* allowed by default if compiled in */
word16 haveRC4 = 1; /* allowed by default if compiled in */
int excludeAnon = 0; /* "!aNULL"/DEFAULT seen (applied at end) */
int excludeNull = 0; /* "!eNULL"/"!NULL"/DEFAULT seen */
#endif
int tls1_3 = 0;
const int suiteSz = GetCipherNamesSize();
@@ -29540,10 +29629,19 @@ static int ParseCipherList(Suites* suites,
}
if (XSTRCMP(name, "DEFAULT") == 0 || XSTRCMP(name, "ALL") == 0) {
if (XSTRCMP(name, "ALL") == 0)
if (XSTRCMP(name, "ALL") == 0) {
/* OpenSSL "ALL" includes anonymous suites and is "all but
* eNULL" (haveNull=0 below stops eNULL generation), but it is
* not a delete directive: unlike DEFAULT it must not set
* excludeAnon/excludeNull, nor clear a prior "!aNULL"/"!eNULL". */
haveSig |= SIG_ANON;
else
}
else {
/* OpenSSL "DEFAULT" embeds "!aNULL:!eNULL" (delete both). */
haveSig &= ~SIG_ANON;
excludeAnon = 1;
excludeNull = 1;
}
haveRSA = 1;
haveDH = 1;
haveECC = 1;
@@ -29585,6 +29683,11 @@ static int ParseCipherList(Suites* suites,
haveSig |= SIG_ANON;
else
haveSig &= ~SIG_ANON;
/* Track exclusion (sticky) so an explicit ADH suite is dropped at
* the end regardless of where "!aNULL" sits in the list; a later
* allowing "aNULL" does not undo it (OpenSSL "!" is permanent). */
if (!allowing)
excludeAnon = 1;
if (allowing) {
/* Allow RSA by default. */
if (!haveECC)
@@ -29599,6 +29702,11 @@ static int ParseCipherList(Suites* suites,
if (XSTRCMP(name, "eNULL") == 0 || XSTRCMP(name, "NULL") == 0) {
haveNull = allowing;
/* Track exclusion (sticky) so an explicit NULL-cipher suite is
* dropped at the end regardless of "!eNULL"/"!NULL" position; a
* later allowing "eNULL" does not undo it. */
if (!allowing)
excludeNull = 1;
if (allowing) {
/* Allow RSA by default. */
if (!haveECC)
@@ -29841,6 +29949,38 @@ static int ParseCipherList(Suites* suites,
}
} while (next);
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)
/* Apply OpenSSL-style category exclusions to the explicitly-listed suites.
* Done here, after the whole list is parsed, so list order does not matter:
* the "!aNULL"/"!eNULL" keywords above only adjust the InitSuites mask
* (which governs generated defaults), never the suites the user named
* explicitly. The excludeAnon/excludeNull flags are set-only / sticky: like
* OpenSSL's permanent "!", once "!aNULL"/"!eNULL" has excluded a category a
* later allowing keyword does not re-enable it - fail closed. */
if (excludeAnon) {
haveSig &= ~SIG_ANON;
RemoveExcludedSuites(suites->suites, &idx, 1, 0);
}
if (excludeNull) {
haveNull = 0;
RemoveExcludedSuites(suites->suites, &idx, 0, 1);
}
/* If the user named suites but every one was excluded, fail like OpenSSL
* (empty list) rather than silently returning an unusable suite set.
* callInitSuites means defaults were also requested, so an empty explicit
* part is fine there. */
if (ret && !callInitSuites && idx == 0) {
/* Commit a fully-consistent empty state: suiteSz 0 with setSuites set
* makes InitSuites() leave it empty (it early-outs on setSuites), so
* this fails closed - no suites offered, no default regeneration. */
suites->suiteSz = 0;
suites->hashSigAlgoSz = 0;
suites->setSuites = 1;
WOLFSSL_MSG("Cipher list empty after !aNULL/!eNULL exclusions");
return 0;
}
#endif
if (ret) {
int keySz = 0;
#ifndef NO_CERTS
+229
View File
@@ -2314,6 +2314,208 @@ static int test_wolfSSL_set_cipher_list_tls13_with_version(void)
return EXPECT_RESULT();
}
/* Build gating for the cipher-list exclusion test. Each sub-test is gated only
* on the BUILD_* macro of the suite it needs, so it cleanly skips (rather than
* failing at runtime) in any build missing it - and the two are independent
* (BUILD_TLS_DH_anon_* already implies HAVE_ANON;
* BUILD_TLS_ECDHE_ECDSA_WITH_NULL_SHA already implies HAVE_NULL_CIPHER). The
* "survivor" suite used only by the mixed (scrub-is-surgical) sub-cases is
* gated separately, so the core exclusion cases still run without it. */
#if defined(OPENSSL_EXTRA) && !defined(NO_WOLFSSL_CLIENT) && \
!defined(WOLFSSL_NO_TLS12)
#if defined(BUILD_TLS_DH_anon_WITH_AES_128_CBC_SHA)
#define TEST_CIPHER_EXCLUDE_ANON
#endif
#if defined(BUILD_TLS_ECDHE_ECDSA_WITH_NULL_SHA)
#define TEST_CIPHER_EXCLUDE_NULL
#endif
#endif
#if defined(TEST_CIPHER_EXCLUDE_ANON) || defined(TEST_CIPHER_EXCLUDE_NULL)
/* Does the parsed suite list on ssl contain the given suite bytes? */
static int test_suites_contains(WOLFSSL* ssl, byte s0, byte s1)
{
int i;
if (ssl == NULL || ssl->suites == NULL)
return 0;
for (i = 0; (i + 1) < ssl->suites->suiteSz; i += 2) {
if ((ssl->suites->suites[i] == s0) &&
(ssl->suites->suites[i + 1] == s1))
return 1;
}
return 0;
}
#endif
/* OpenSSL-style "!aNULL"/"!eNULL" must remove an explicitly-listed anonymous
* (ADH) or NULL-cipher suite from the parsed list, not merely clear the
* InitSuites mask - otherwise a list like "ADH-AES128-SHA:!aNULL" still
* negotiates an unauthenticated (anonymous) suite, defeating the operator's
* intent. Each sub-case uses a fresh WOLFSSL so state cannot bleed across
* calls. */
static int test_wolfSSL_set_cipher_list_exclusions(void)
{
EXPECT_DECLS;
#if defined(TEST_CIPHER_EXCLUDE_ANON) || defined(TEST_CIPHER_EXCLUDE_NULL)
WOLFSSL_CTX* ctx = NULL;
WOLFSSL* ssl = NULL;
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
#ifdef TEST_CIPHER_EXCLUDE_ANON
/* Control: the explicit ADH suite IS recognized and added on its own (so
* the later "absent" checks cannot pass trivially). */
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(wolfSSL_set_cipher_list(ssl, "ADH-AES128-SHA"),
WOLFSSL_SUCCESS);
ExpectIntEQ(test_suites_contains(ssl, CIPHER_BYTE,
TLS_DH_anon_WITH_AES_128_CBC_SHA), 1);
wolfSSL_free(ssl);
ssl = NULL;
/* Reported case: "!aNULL" after the only (anon) suite empties the list,
* which fails like OpenSSL - and leaves no anonymous suite behind. */
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(wolfSSL_set_cipher_list(ssl, "ADH-AES128-SHA:!aNULL"),
WOLFSSL_FAILURE);
ExpectIntEQ(test_suites_contains(ssl, CIPHER_BYTE,
TLS_DH_anon_WITH_AES_128_CBC_SHA), 0);
wolfSSL_free(ssl);
ssl = NULL;
/* Reverse order: "!aNULL" before the suite must also block it. */
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(wolfSSL_set_cipher_list(ssl, "!aNULL:ADH-AES128-SHA"),
WOLFSSL_FAILURE);
ExpectIntEQ(test_suites_contains(ssl, CIPHER_BYTE,
TLS_DH_anon_WITH_AES_128_CBC_SHA), 0);
wolfSSL_free(ssl);
ssl = NULL;
/* Report PoC #3: the suite named by its IANA name must also be dropped
* (classification is by suite bytes, independent of the input name form). */
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(wolfSSL_set_cipher_list(ssl,
"TLS_DH_anon_WITH_AES_128_CBC_SHA:!aNULL"), WOLFSSL_FAILURE);
ExpectIntEQ(test_suites_contains(ssl, CIPHER_BYTE,
TLS_DH_anon_WITH_AES_128_CBC_SHA), 0);
wolfSSL_free(ssl);
ssl = NULL;
#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
/* Mixed list: the authenticated suite survives, only ADH is removed. */
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(wolfSSL_set_cipher_list(ssl,
"ECDHE-RSA-AES128-GCM-SHA256:ADH-AES128-SHA:!aNULL"),
WOLFSSL_SUCCESS);
ExpectIntEQ(test_suites_contains(ssl, CIPHER_BYTE,
TLS_DH_anon_WITH_AES_128_CBC_SHA), 0);
ExpectIntEQ(test_suites_contains(ssl, ECC_BYTE,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256), 1);
wolfSSL_free(ssl);
ssl = NULL;
#endif /* BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 */
/* "DEFAULT" embeds "!aNULL", so an explicit ADH before it is removed. */
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(wolfSSL_set_cipher_list(ssl, "ADH-AES128-SHA:DEFAULT"),
WOLFSSL_SUCCESS);
ExpectIntEQ(test_suites_contains(ssl, CIPHER_BYTE,
TLS_DH_anon_WITH_AES_128_CBC_SHA), 0);
wolfSSL_free(ssl);
ssl = NULL;
/* Sticky/fail-closed: once "!aNULL" excludes anon, a later allowing form
* ("ALL" includes anon defaults) must NOT bring it back, matching
* OpenSSL's permanent "!". The generated default list must contain no ADH. */
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(wolfSSL_set_cipher_list(ssl, "!aNULL:ALL"), WOLFSSL_SUCCESS);
ExpectIntEQ(test_suites_contains(ssl, CIPHER_BYTE,
TLS_DH_anon_WITH_AES_128_CBC_SHA), 0);
wolfSSL_free(ssl);
ssl = NULL;
#endif /* TEST_CIPHER_EXCLUDE_ANON */
#ifdef TEST_CIPHER_EXCLUDE_NULL
/* eNULL: a NULL-cipher suite must likewise be removed by "!eNULL". This
* runs independently of HAVE_ANON, in any NULL-cipher-enabled build. */
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(wolfSSL_set_cipher_list(ssl, "ECDHE-ECDSA-NULL-SHA"),
WOLFSSL_SUCCESS);
ExpectIntEQ(test_suites_contains(ssl, ECC_BYTE,
TLS_ECDHE_ECDSA_WITH_NULL_SHA), 1); /* control: recognized */
wolfSSL_free(ssl);
ssl = NULL;
/* "!eNULL" after the only (NULL-cipher) suite empties the list and fails,
* leaving no NULL-cipher suite behind (no survivor suite needed). */
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(wolfSSL_set_cipher_list(ssl, "ECDHE-ECDSA-NULL-SHA:!eNULL"),
WOLFSSL_FAILURE);
ExpectIntEQ(test_suites_contains(ssl, ECC_BYTE,
TLS_ECDHE_ECDSA_WITH_NULL_SHA), 0);
wolfSSL_free(ssl);
ssl = NULL;
#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
/* Mixed list: the survivor stays, only the NULL-cipher suite is removed. */
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(wolfSSL_set_cipher_list(ssl,
"ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-NULL-SHA:!eNULL"),
WOLFSSL_SUCCESS);
ExpectIntEQ(test_suites_contains(ssl, ECC_BYTE,
TLS_ECDHE_ECDSA_WITH_NULL_SHA), 0); /* NULL cipher dropped */
ExpectIntEQ(test_suites_contains(ssl, ECC_BYTE,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256), 1); /* survivor kept */
wolfSSL_free(ssl);
ssl = NULL;
#ifdef BUILD_TLS_SHA256_SHA256
/* TLS 1.3 integrity-only suite (RFC 9150) has no "NULL" in its name but is
* NULL-encryption; "!eNULL" must still drop it (matched by suite id). */
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(wolfSSL_set_cipher_list(ssl,
"ECDHE-RSA-AES128-GCM-SHA256:TLS13-SHA256-SHA256:!eNULL"),
WOLFSSL_SUCCESS);
ExpectIntEQ(test_suites_contains(ssl, ECC_BYTE,
TLS_SHA256_SHA256), 0); /* integrity-only suite dropped */
ExpectIntEQ(test_suites_contains(ssl, ECC_BYTE,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256), 1); /* survivor kept */
wolfSSL_free(ssl);
ssl = NULL;
/* OpenSSL compat: "ALL" is "all but eNULL" - it does not generate NULL
* suites, but it is not a delete directive, so a following "eNULL"
* re-enables them. (The earlier sticky excludeNull-for-ALL wrongly kept
* them disabled; only "!eNULL"/"DEFAULT" should.) */
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(wolfSSL_set_cipher_list(ssl, "ALL"), WOLFSSL_SUCCESS);
ExpectIntEQ(test_suites_contains(ssl, ECC_BYTE,
TLS_SHA256_SHA256), 0); /* ALL alone: no NULL generated */
wolfSSL_free(ssl);
ssl = NULL;
ExpectNotNull(ssl = wolfSSL_new(ctx));
ExpectIntEQ(wolfSSL_set_cipher_list(ssl, "ALL:eNULL"), WOLFSSL_SUCCESS);
ExpectIntEQ(test_suites_contains(ssl, ECC_BYTE,
TLS_SHA256_SHA256), 1); /* "eNULL" after "ALL" re-enables NULL */
wolfSSL_free(ssl);
ssl = NULL;
#endif /* BUILD_TLS_SHA256_SHA256 */
#endif /* BUILD_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 */
#endif /* TEST_CIPHER_EXCLUDE_NULL */
wolfSSL_CTX_free(ctx);
#endif /* TEST_CIPHER_EXCLUDE_ANON || TEST_CIPHER_EXCLUDE_NULL */
return EXPECT_RESULT();
}
#ifdef TEST_CIPHER_EXCLUDE_ANON
#undef TEST_CIPHER_EXCLUDE_ANON
#endif
#ifdef TEST_CIPHER_EXCLUDE_NULL
#undef TEST_CIPHER_EXCLUDE_NULL
#endif
static int test_wolfSSL_set_alpn_protos_default_fails(void)
{
EXPECT_DECLS;
@@ -16966,6 +17168,32 @@ static int test_wolfSSL_PKCS8_d2i(void)
EVP_PKEY_free(pkey);
pkey = NULL;
#endif
/* A negative length must be rejected before the signed->word32 cast
* (CWE-190 -> CWE-125): length = -1 becomes (word32)0xFFFFFFFF, so the
* decoder believes ~4 GiB are available and reads past the input. The
* same key buffers are decoded with their correct positive length above,
* so these calls fail only because of the negative length. All must
* return NULL; with the guard removed the over-read is reported by ASan
* (and, with a full key, faults outright). */
{
const unsigned char malformed[2] = { 0x30, 0x10 };
const unsigned char* mp;
#ifndef NO_RSA
#ifdef USE_CERT_BUFFERS_1024
const unsigned char* rp = (const unsigned char*)server_key_der_1024;
#else
const unsigned char* rp = (const unsigned char*)server_key_der_2048;
#endif
const unsigned char* rp0 = rp;
ExpectNull(d2i_AutoPrivateKey(NULL, &rp, -1));
rp = rp0;
ExpectNull(d2i_PrivateKey(EVP_PKEY_RSA, NULL, &rp, -1));
#endif
/* The reported PoC: a 2-byte header claiming 16 bytes of absent
* content drives the over-read in the key-type detection loop. */
mp = malformed;
ExpectNull(d2i_AutoPrivateKey(NULL, &mp, -1));
}
#endif /* OPENSSL_ALL */
#ifndef NO_FILESYSTEM
@@ -35084,6 +35312,7 @@ TEST_CASE testCases[] = {
TEST_DECL(test_wolfSSL_set_cipher_list_tls13_keeps_tls12),
TEST_DECL(test_wolfSSL_set_cipher_list_tls12_with_version),
TEST_DECL(test_wolfSSL_set_cipher_list_tls13_with_version),
TEST_DECL(test_wolfSSL_set_cipher_list_exclusions),
TEST_DECL(test_wolfSSL_set_alpn_protos_default_fails),
TEST_DECL(test_wolfSSL_CTX_use_certificate),
TEST_DECL(test_wolfSSL_CTX_use_certificate_file),
+40
View File
@@ -1495,6 +1495,46 @@ int test_DecodeAltNames_length_underflow(void)
return EXPECT_RESULT();
}
/* A certificate must not carry two certificatePolicies extensions
* (non-repeatable per RFC 5280 4.2). DecodeCertExtensions calls
* DecodeExtensionType once per extension; with strict ASN.1 (the default) a
* second certificatePolicies extension must be rejected (ASN_OBJECT_ID_E)
* rather than silently overwriting the first - which happened in
* WOLFSSL_CERT_EXT builds without WOLFSSL_SEP before the duplicate guard was
* extended to cover them. */
int test_DecodeCertExtensions_dup_certpol(void)
{
EXPECT_DECLS;
#if (defined(WOLFSSL_SEP) || defined(WOLFSSL_CERT_EXT)) && \
!defined(WOLFSSL_NO_ASN_STRICT) && !defined(NO_CERTS) && !defined(NO_ASN)
/* Minimal certificatePolicies extnValue: SEQUENCE OF PolicyInformation
* with one policyIdentifier OID 1.2.3.4 (encoded 2A 03 04). */
static const byte policy[] = {
0x30, 0x07, /* certificatePolicies SEQUENCE */
0x30, 0x05, /* PolicyInformation SEQUENCE */
0x06, 0x03, 0x2A, 0x03, 0x04 /* policyIdentifier OID 1.2.3.4 */
};
DecodedCert cert;
int isUnknown = 0;
/* DecodeExtensionType only needs an initialized DecodedCert for its
* bit-fields and policy storage; the source buffer is never parsed here,
* so any non-NULL pointer/size suffices. */
wc_InitDecodedCert(&cert, policy, (word32)sizeof(policy), NULL);
/* First certificatePolicies extension: accepted. */
ExpectIntEQ(DecodeExtensionType(policy, (word32)sizeof(policy),
CERT_POLICY_OID, 0, &cert, &isUnknown), 0);
/* Duplicate certificatePolicies extension: rejected as non-repeatable. */
ExpectIntEQ(DecodeExtensionType(policy, (word32)sizeof(policy),
CERT_POLICY_OID, 0, &cert, &isUnknown),
WC_NO_ERR_TRACE(ASN_OBJECT_ID_E));
wc_FreeDecodedCert(&cert);
#endif
return EXPECT_RESULT();
}
int test_ParseCert_SM3wSM2_short_pubkey(void)
{
EXPECT_DECLS;
+2
View File
@@ -35,6 +35,7 @@ int test_wolfssl_local_MatchUriNameConstraint(void);
int test_wc_DecodeRsaPssParams(void);
int test_SerialNumber0_RootCA(void);
int test_DecodeAltNames_length_underflow(void);
int test_DecodeCertExtensions_dup_certpol(void);
int test_ParseCert_SM3wSM2_short_pubkey(void);
int test_wc_DecodeObjectId(void);
int test_ToTraditional_ex_handcrafted(void);
@@ -54,6 +55,7 @@ int test_ToTraditional_ex_mldsa_bad_params(void);
TEST_DECL_GROUP("asn", test_wc_DecodeRsaPssParams), \
TEST_DECL_GROUP("asn", test_SerialNumber0_RootCA), \
TEST_DECL_GROUP("asn", test_DecodeAltNames_length_underflow), \
TEST_DECL_GROUP("asn", test_DecodeCertExtensions_dup_certpol), \
TEST_DECL_GROUP("asn", test_ParseCert_SM3wSM2_short_pubkey), \
TEST_DECL_GROUP("asn", test_wc_DecodeObjectId), \
TEST_DECL_GROUP("asn", test_ToTraditional_ex_handcrafted), \
+22
View File
@@ -2816,6 +2816,28 @@ int test_ASN1_strings(void)
der = NULL;
}
/* Negative length must be rejected before the signed->word32 cast
* (CWE-190 -> CWE-125). The 2-byte header claims 16 bytes of content
* that are not present in the buffer; passing len = -1 would, without
* the guard, cast to ~4 GiB so GetLength accepts the claimed length and
* d2i_ASN1_STRING over-reads 16 bytes past the buffer. Every wrapper
* must instead return NULL without reading the content. */
{
unsigned char hdr[2];
const unsigned char* p;
hdr[1] = 0x10; /* claim 16 bytes of (absent) content */
p = hdr; hdr[0] = ASN_OCTET_STRING;
ExpectNull(d2i_ASN1_OCTET_STRING(NULL, &p, -1));
p = hdr; hdr[0] = ASN_GENERALSTRING;
ExpectNull(d2i_ASN1_GENERALSTRING(NULL, &p, -1));
p = hdr; hdr[0] = ASN_UTF8STRING;
ExpectNull(d2i_ASN1_UTF8STRING(NULL, &p, -1));
p = hdr; hdr[0] = ASN_BIT_STRING;
ExpectNull(d2i_ASN1_BIT_STRING(NULL, &p, -1));
}
#endif
return EXPECT_RESULT();
}
+11 -4
View File
@@ -21036,8 +21036,9 @@ static int DecodeAltSigVal(const byte* input, int sz, DecodedCert* cert)
* @return MEMORY_E on dynamic memory allocation failure.
* @return Other negative values on error.
*/
int DecodeExtensionType(const byte* input, word32 length, word32 oid,
byte critical, DecodedCert* cert, int *isUnknownExt)
WOLFSSL_TEST_VIS int DecodeExtensionType(const byte* input, word32 length,
word32 oid, byte critical,
DecodedCert* cert, int *isUnknownExt)
{
int ret = 0;
word32 idx = 0;
@@ -21137,11 +21138,17 @@ int DecodeExtensionType(const byte* input, word32 length, word32 oid,
/* Certificate policies. */
case CERT_POLICY_OID:
#ifdef WOLFSSL_SEP
#if defined(WOLFSSL_SEP) || defined(WOLFSSL_CERT_EXT)
/* certificatePolicies is non-repeatable (RFC 5280 4.2). In strict
* mode (the default; VERIFY_AND_SET_OID is a no-op under
* WOLFSSL_NO_ASN_STRICT, like every other extension) reject a
* duplicate regardless of WOLFSSL_SEP - otherwise the second one
* silently overwrites the first (DecodeCertPolicy resets
* extCertPoliciesNb), a policy-authorization confusion. */
VERIFY_AND_SET_OID(cert->extCertPolicySet);
#ifdef WOLFSSL_SEP
cert->extCertPolicyCrit = critical ? 1 : 0;
#endif
#if defined(WOLFSSL_SEP) || defined(WOLFSSL_CERT_EXT)
if (DecodeCertPolicy(input, length, cert) < 0) {
ret = ASN_PARSE_E;
}
+5 -4
View File
@@ -2089,7 +2089,7 @@ struct DecodedCert {
WC_BITFIELD extSubjAltNameSet:1;
WC_BITFIELD inhibitAnyOidSet:1;
WC_BITFIELD selfSigned:1; /* Indicates subject and issuer are same */
#ifdef WOLFSSL_SEP
#if defined(WOLFSSL_SEP) || defined(WOLFSSL_CERT_EXT)
WC_BITFIELD extCertPolicySet:1;
#endif
WC_BITFIELD extCRLdistCrit:1;
@@ -2369,6 +2369,7 @@ typedef enum MimeStatus
#define FreeSigner wc_FreeSigner
#define AllocDer wc_AllocDer
#define FreeDer wc_FreeDer
#define DecodeExtensionType wc_DecodeExtensionType
#endif /* WOLFSSL_API_PREFIX_MAP */
WOLFSSL_LOCAL int HashIdAlg(word32 oidSum);
@@ -2412,9 +2413,9 @@ WOLFSSL_LOCAL int DecodePolicyOID(char *out, word32 outSz, const byte *in,
word32 inSz);
WOLFSSL_LOCAL int EncodePolicyOID(byte *out, word32 *outSz,
const char *in, void* heap);
WOLFSSL_LOCAL int DecodeExtensionType(const byte* input, word32 length,
word32 oid, byte critical,
DecodedCert* cert, int *isUnknownExt);
WOLFSSL_TEST_VIS int DecodeExtensionType(const byte* input, word32 length,
word32 oid, byte critical,
DecodedCert* cert, int *isUnknownExt);
WOLFSSL_LOCAL int CheckCertSignaturePubKey(const byte* cert, word32 certSz,
void* heap, const byte* pubKey, word32 pubKeySz, int pubKeyOID);
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_SMALL_CERT_VERIFY)