Merge pull request #10737 from kareem-wolfssl/zd21998

X509 validation fixes
This commit is contained in:
David Garske
2026-07-08 09:48:26 -07:00
committed by GitHub
6 changed files with 497 additions and 0 deletions
+58
View File
@@ -13657,6 +13657,57 @@ static int PatternHasWildcardInALabel(const char* pattern, word32 patternLen)
return 0;
}
/* Validate the placement of a wildcard ('*') in a presented identifier per
* RFC 6125 sec. 6.4.3 / RFC 9525 sec. 6.3 and CA/Browser Forum Baseline
* Requirements sec. 3.2.2.6:
* - a wildcard may only appear in the left-most label of the pattern, and
* - a left-most label consisting solely of the wildcard ("*") may match only
* when at least two further labels (i.e. at least two dots) follow it.
*
* This rejects a bare "*" (matches any single-label name), "*.com" (wildcard
* immediately to the left of a registry/public suffix), and
* "foo.*.example.com" (wildcard not in the left-most label), while still
* accepting the legitimate "*.example.com" form. Partial left-most wildcards
* such as "a*" or "a*b*" retain their existing matching behavior - they are
* not bare wildcard labels and are not subject to the two-label requirement.
* pattern/patternLen must already have any single trailing FQDN dot stripped.
*
* Returns 1 if the pattern has no wildcard or its wildcard placement is
* acceptable, 0 otherwise. */
static int WildcardPlacementOK(const char* pattern, word32 patternLen)
{
word32 i;
int sawWildcard = 0;
int sawDot = 0;
int dots = 0;
for (i = 0; i < patternLen; i++) {
if (pattern[i] == '*') {
/* A wildcard is only permitted in the left-most label: reject any
* '*' that appears after a label separator. */
if (sawDot)
return 0;
sawWildcard = 1;
}
else if (pattern[i] == '.') {
sawDot = 1;
dots++;
}
}
if (!sawWildcard)
return 1;
/* A left-most label that is exactly "*" (a bare wildcard label) requires at
* least two further labels. This rejects a bare "*" (0 dots) and "*.tld"
* (1 dot) but still allows "*.example.com" (2 dots). */
if (pattern[0] == '*' && (patternLen == 1 || pattern[1] == '.') &&
dots < 2)
return 0;
return 1;
}
/* Match names with wildcards, each wildcard can represent a single name
component or fragment but not multiple names, i.e.,
*.z.com matches y.z.com but not x.y.z.com
@@ -13713,6 +13764,13 @@ int MatchDomainName(const char* pattern, int patternLen, const char* str,
}
}
/* RFC 6125 sec. 6.4.3 / RFC 9525 sec. 6.3 + CA/Browser Forum BR
* sec. 3.2.2.6: reject a pattern whose wildcard is not confined to the
* left-most label, or that has fewer than two labels to the right of the
* wildcard (e.g. "*", "*.com", "foo.*.example.com"). */
if (!WildcardPlacementOK(pattern, (word32)patternLen))
return 0;
while (patternLen > 0) {
/* Get the next pattern char to evaluate */
char p = (char)XTOLOWER((unsigned char)*pattern);
+116
View File
@@ -629,6 +629,108 @@ static int X509StoreCertIsTrusted(WOLFSSL_X509_STORE* store,
return 0;
}
/* Enforce the BasicConstraints pathLenConstraint (RFC 5280 sec. 4.2.1.9 and
* the path validation rules in sec. 6.1.4 (l)/(m)) over the certification path
* assembled in ctx->chain.
*
* wolfSSL_X509_verify_cert() authenticates each certificate individually via
* the CertManager, which parses every certificate as CERT_TYPE. The issuer
* pathLen check in ParseCertRelative() is gated on a non-CERT_TYPE certificate
* type (it is reached on the TLS handshake path via CHAIN_CERT_TYPE), so the
* OpenSSL-compatibility path never enforced it. Re-create that check here over
* the completed path so that a CA asserting pathlen:N cannot issue more than N
* subordinate intermediate CAs.
*
* ctx->chain is ordered leaf first (index 0) up to the trust anchor (highest
* index). Walk from the trust anchor down toward the leaf, tracking the
* remaining number of non-self-issued intermediate certificates permitted.
* The budget is only enforced once some CA in the path actually asserts a
* pathLenConstraint; an explicit "haveConstraint" flag tracks that, so every
* value 0..WOLFSSL_MAX_PATH_LEN (the parser's hard cap on pathLenConstraint)
* is a usable budget rather than overloading the cap as a "no constraint"
* sentinel. The leaf (index 0) issues nothing and is therefore not subject to
* the constraint.
*
* Returns WOLFSSL_SUCCESS if the path satisfies every pathLenConstraint, or
* WOLFSSL_FAILURE (with ctx->error set) on the first violation. */
static int X509StoreCheckPathLen(WOLFSSL_X509_STORE_CTX* ctx)
{
int num;
int i;
word32 maxPathLen = 0;
byte haveConstraint = 0;
WOLFSSL_X509* anchor;
if (ctx == NULL || ctx->chain == NULL)
return WOLFSSL_SUCCESS;
num = wolfSSL_sk_X509_num(ctx->chain);
/* A pathLen violation requires at least one intermediate between the leaf
* (index 0) and the trust anchor, i.e. a chain of three or more. */
if (num < 3)
return WOLFSSL_SUCCESS;
/* The trust anchor (top of chain) is not part of the prospective
* certification path (RFC 5280 sec. 6.1): it does not consume path-length
* budget, and the loop below runs from num-2 down to 1 so the anchor is
* never processed as an intermediate. A self-signed anchor that asserts its
* own pathLenConstraint does still bound the path, matching
* ParseCertRelative()'s trust-anchor handling, so seed the budget from
* it. */
anchor = wolfSSL_sk_X509_value(ctx->chain, num - 1);
if (anchor != NULL && anchor->isCa && anchor->basicConstPlSet) {
maxPathLen = (word32)anchor->pathLength;
haveConstraint = 1;
}
for (i = num - 2; i >= 1; i--) {
WOLFSSL_X509* cert = wolfSSL_sk_X509_value(ctx->chain, i);
int selfIssued;
if (cert == NULL)
continue;
selfIssued =
(wolfSSL_X509_NAME_cmp(&cert->issuer, &cert->subject) == 0);
/* RFC 5280 sec. 6.1.4 (l): a non-self-issued *CA* certificate consumes
* one unit of the issuer's remaining path length budget. Gate on isCa
* to match ParseCertRelative() (wolfcrypt/src/asn.c) and the (m) step
* below, so a non-CA intermediate tolerated via verify_cb does not
* trigger a false PATH_LENGTH_EXCEEDED. Only meaningful once a CA above
* has asserted a constraint (haveConstraint). */
if (!selfIssued && cert->isCa && haveConstraint) {
if (maxPathLen == 0) {
SetupStoreCtxError_ex(ctx,
WOLFSSL_X509_V_ERR_PATH_LENGTH_EXCEEDED, i);
#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
/* Allow an application verify callback to override, matching
* the INVALID_CA handling in wolfSSL_X509_verify_cert(). */
if (ctx->store != NULL && ctx->store->verify_cb != NULL &&
ctx->store->verify_cb(0, ctx) == 1) {
/* Overridden: keep walking without decrementing (budget is
* already exhausted). */
continue;
}
#endif
return WOLFSSL_FAILURE;
}
maxPathLen--;
}
/* RFC 5280 sec. 6.1.4 (m): tighten the budget with this CA's own
* pathLenConstraint, if present. The first constraint encountered seeds
* the budget; subsequent ones only ever lower it. */
if (cert->isCa && cert->basicConstPlSet &&
(!haveConstraint || (word32)cert->pathLength < maxPathLen)) {
maxPathLen = (word32)cert->pathLength;
haveConstraint = 1;
}
}
return WOLFSSL_SUCCESS;
}
/* Verifies certificate chain using WOLFSSL_X509_STORE_CTX
* returns 1 on success or <= 0 on failure.
*/
@@ -828,6 +930,13 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
* chain at a caller-trusted certificate. */
ctx->error = 0;
ret = WOLFSSL_SUCCESS;
/* The caller-trusted certificate terminates the path:
* it is the anchor, so stop here rather than falling
* through to the "finish building the chain" push below,
* which would add ctx->current_cert to ctx->chain a
* second time. Mirrors the self-issued terminus break
* above; the depth>0/done==0 success path accepts it. */
break;
} else {
X509VerifyCertSetupRetry(ctx, certs, failedCerts,
&depth, origDepth);
@@ -878,6 +987,13 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
ret = WOLFSSL_FAILURE;
}
/* RFC 5280 sec. 6.1.4: the per-certificate CertManager verification above
* does not enforce the issuer's BasicConstraints pathLenConstraint on this
* API path, so check it over the assembled path before reporting success. */
if (ret == WOLFSSL_SUCCESS) {
ret = X509StoreCheckPathLen(ctx);
}
exit:
/* Copy back failed certs. */
numFailedCerts = wolfSSL_sk_X509_num(failedCerts);
+76
View File
@@ -1862,6 +1862,82 @@ int test_wolfSSL_X509_check_host_embedded_nul_san(void)
return EXPECT_RESULT();
}
/* Verify that MatchDomainName() enforces RFC 6125 sec. 6.4.3 / RFC 9525
* sec. 6.3 and CA/Browser Forum BR sec. 3.2.2.6 wildcard placement rules:
* a wildcard is confined to the left-most label, and a bare wildcard label
* ("*") requires at least two further labels. Regression test for the
* x509-limbo findings that "*", "*.com" and "foo.*.example.com" were matched.
*
* MatchDomainName() is exposed for testing via the visibility mechanism
* declared in wolfssl/internal.h. */
int test_wolfSSL_MatchDomainName_wildcard(void)
{
EXPECT_DECLS;
#if !defined(NO_ASN) && !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS)
static const struct {
const char* pattern;
const char* host;
unsigned int flags;
int expected; /* 1 = match, 0 = no match */
const char* note;
} cases[] = {
/* --- The reported forbidden patterns must NOT match. --- */
/* Bare wildcard: matches any single-label name. */
{ "*", "com", 0, 0, "bare wildcard" },
{ "*", "anything", 0, 0,
"bare wildcard 2" },
/* Wildcard not in the left-most label. */
{ "foo.*.example.com", "foo.bar.example.com", 0, 0,
"wildcard in middle label" },
{ "foo.*.example.com", "foo.x.example.com", 0, 0,
"wildcard in middle label 2" },
/* Bare wildcard immediately left of a public/registry suffix. */
{ "*.com", "example.com", 0, 0,
"public-suffix wildcard" },
{ "*.com", "evil.com", 0, 0,
"public-suffix wildcard 2" },
/* Two label-spanning wildcards: the second is not left-most. */
{ "*.*.example.com", "a.b.example.com", 0, 0,
"second wildcard not left-most" },
/* --- Legitimate wildcards must still match. --- */
{ "*.example.com", "foo.example.com", 0, 1,
"single left-most wildcard" },
{ "*.example.com", "bar.example.com", 0, 1,
"single left-most wildcard 2" },
/* Two labels after the wildcard is sufficient; no public-suffix list
* is consulted (matching OpenSSL). */
{ "*.co.uk", "foo.co.uk", 0, 1,
"two labels after wildcard" },
/* Partial left-most wildcards retain their existing behavior and are
* not subject to the bare-wildcard two-label requirement. */
{ "a*.example.com", "abc.example.com", 0, 1,
"partial left-most wildcard" },
/* A wildcard never spans a label separator. */
{ "*.example.com", "foo.bar.example.com", 0, 0,
"wildcard does not cross a dot" },
};
size_t i;
for (i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
int got = MatchDomainName(
cases[i].pattern, (int)XSTRLEN(cases[i].pattern),
cases[i].host, (word32)XSTRLEN(cases[i].host),
cases[i].flags);
ExpectIntEQ(got, cases[i].expected);
if (! EXPECT_SUCCESS()) {
fprintf(stderr,
"MatchDomainName(\"%s\", \"%s\", flags=0x%x) = %d, "
"expected %d (%s)\n",
cases[i].pattern, cases[i].host, cases[i].flags,
got, cases[i].expected, cases[i].note);
break;
}
}
#endif /* !NO_ASN && !WOLFCRYPT_ONLY && !NO_CERTS */
return EXPECT_RESULT();
}
int test_wolfSSL_X509_max_altnames(void)
{
EXPECT_DECLS;
+2
View File
@@ -51,6 +51,7 @@ int test_wolfSSL_X509_name_match3(void);
int test_wolfssl_local_IsValidFQDN(void);
int test_wolfSSL_MatchDomainName_idn(void);
int test_wolfSSL_X509_check_host_embedded_nul_san(void);
int test_wolfSSL_MatchDomainName_wildcard(void);
int test_wolfSSL_X509_max_altnames(void);
int test_wolfSSL_X509_max_name_constraints(void);
int test_wolfSSL_X509_check_ca(void);
@@ -85,6 +86,7 @@ int test_wolfSSL_X509_cmp(void);
TEST_DECL_GROUP("ossl_x509", test_wolfssl_local_IsValidFQDN), \
TEST_DECL_GROUP("ossl_x509", test_wolfSSL_MatchDomainName_idn), \
TEST_DECL_GROUP("ossl_x509", test_wolfSSL_X509_check_host_embedded_nul_san),\
TEST_DECL_GROUP("ossl_x509", test_wolfSSL_MatchDomainName_wildcard), \
TEST_DECL_GROUP("ossl_x509", test_wolfSSL_X509_max_altnames), \
TEST_DECL_GROUP("ossl_x509", test_wolfSSL_X509_max_name_constraints), \
TEST_DECL_GROUP("ossl_x509", test_wolfSSL_X509_check_ca), \
+233
View File
@@ -957,6 +957,239 @@ static int test_wolfSSL_X509_STORE_CTX_ex12(void)
#endif
#endif
/* Regression test for the x509-limbo "pathlen" finding:
* wolfSSL_X509_verify_cert() must enforce the BasicConstraints
* pathLenConstraint (RFC 5280 sec. 4.2.1.9 / sec. 6.1.4). A CA asserting
* pathlen:0 may only issue end-entity certificates; it must not be permitted
* to issue a further intermediate CA. Reuses the certs/test-pathlen chains
* (see certs/test-pathlen/assemble-chains.sh):
*
* ca-cert -> chainF-ICA2 (CA, pathlen:0) -> chainF-ICA1 (CA) -> entity
*
* chainF-ICA1 is an intermediate CA following the pathlen:0 chainF-ICA2, which
* RFC 5280 sec. 6.1.4 forbids, so the chain must be rejected with
* X509_V_ERR_PATH_LENGTH_EXCEEDED. Before the fix this OpenSSL-compatibility
* path accepted the chain because each certificate was verified individually
* (as CERT_TYPE) without the issuer pathLen check the TLS handshake path
* performs. */
int test_wolfSSL_X509_verify_cert_pathlen(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
!defined(NO_FILESYSTEM) && !defined(NO_RSA)
X509* root = NULL;
X509* ica2 = NULL;
X509* ica1 = NULL;
X509* leaf = NULL;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* inter = NULL;
ExpectNotNull(root = test_wolfSSL_X509_STORE_CTX_ex_helper(
"./certs/ca-cert.pem"));
ExpectNotNull(ica2 = test_wolfSSL_X509_STORE_CTX_ex_helper(
"./certs/test-pathlen/chainF-ICA2-pathlen0.pem"));
ExpectNotNull(ica1 = test_wolfSSL_X509_STORE_CTX_ex_helper(
"./certs/test-pathlen/chainF-ICA1-pathlen1.pem"));
ExpectNotNull(leaf = test_wolfSSL_X509_STORE_CTX_ex_helper(
"./certs/test-pathlen/chainF-entity.pem"));
ExpectNotNull(store = X509_STORE_new());
ExpectIntEQ(X509_STORE_add_cert(store, root), 1);
ExpectNotNull(inter = sk_X509_new_null());
ExpectIntGT(sk_X509_push(inter, ica2), 0);
ExpectIntGT(sk_X509_push(inter, ica1), 0);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, leaf, inter), 1);
/* Must be rejected: chainF-ICA1 violates chainF-ICA2's pathlen:0. */
ExpectIntNE(X509_verify_cert(ctx), 1);
ExpectIntEQ(X509_STORE_CTX_get_error(ctx),
X509_V_ERR_PATH_LENGTH_EXCEEDED);
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
sk_X509_free(inter);
X509_free(root);
X509_free(ica2);
X509_free(ica1);
X509_free(leaf);
#endif /* OPENSSL_EXTRA && !NO_CERTS && !NO_FILESYSTEM && !NO_RSA */
return EXPECT_RESULT();
}
/* Positive control: a legitimate chain whose intermediates assert pathlen:1
* then pathlen:0 must still verify, guarding pathLen enforcement against
* over-rejection. Reuses the certs/test-pathlen chainB:
*
* ca-cert -> chainB-ICA2 (CA, pathlen:1) -> chainB-ICA1 (CA, pathlen:0)
* -> entity
*
* chainB-ICA2 permits one following intermediate (chainB-ICA1), so the chain
* is valid. */
int test_wolfSSL_X509_verify_cert_pathlen_ok(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
!defined(NO_FILESYSTEM) && !defined(NO_RSA)
X509* root = NULL;
X509* ica2 = NULL;
X509* ica1 = NULL;
X509* leaf = NULL;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* inter = NULL;
ExpectNotNull(root = test_wolfSSL_X509_STORE_CTX_ex_helper(
"./certs/ca-cert.pem"));
ExpectNotNull(ica2 = test_wolfSSL_X509_STORE_CTX_ex_helper(
"./certs/test-pathlen/chainB-ICA2-pathlen1.pem"));
ExpectNotNull(ica1 = test_wolfSSL_X509_STORE_CTX_ex_helper(
"./certs/test-pathlen/chainB-ICA1-pathlen0.pem"));
ExpectNotNull(leaf = test_wolfSSL_X509_STORE_CTX_ex_helper(
"./certs/test-pathlen/chainB-entity.pem"));
ExpectNotNull(store = X509_STORE_new());
ExpectIntEQ(X509_STORE_add_cert(store, root), 1);
ExpectNotNull(inter = sk_X509_new_null());
ExpectIntGT(sk_X509_push(inter, ica2), 0);
ExpectIntGT(sk_X509_push(inter, ica1), 0);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, leaf, inter), 1);
ExpectIntEQ(X509_verify_cert(ctx), 1);
ExpectIntEQ(X509_STORE_CTX_get_error(ctx), X509_V_OK);
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
sk_X509_free(inter);
X509_free(root);
X509_free(ica2);
X509_free(ica1);
X509_free(leaf);
#endif /* OPENSSL_EXTRA && !NO_CERTS && !NO_FILESYSTEM && !NO_RSA */
return EXPECT_RESULT();
}
#if defined(OPENSSL_ALL) && !defined(NO_CERTS) && \
!defined(NO_FILESYSTEM) && !defined(NO_RSA)
/* Records whether the pathLen violation was surfaced to the verify callback,
* then overrides it (returns 1) so verification continues - exercising the
* verify_cb override branch in X509StoreCheckPathLen(). */
static int pathlen_override_seen = 0;
static int pathlen_override_cb(int ok, X509_STORE_CTX *ctx)
{
(void)ok;
if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_PATH_LENGTH_EXCEEDED)
pathlen_override_seen = 1;
return 1; /* override: accept despite the error */
}
#endif
/* A verify callback that returns 1 must be able to override the pathLen
* violation, matching the INVALID_CA override handling in
* wolfSSL_X509_verify_cert(). Reuses the rejecting chainF: with the override
* callback installed the same chain must now verify, and the callback must have
* observed X509_V_ERR_PATH_LENGTH_EXCEEDED. */
int test_wolfSSL_X509_verify_cert_pathlen_override(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_ALL) && !defined(NO_CERTS) && \
!defined(NO_FILESYSTEM) && !defined(NO_RSA)
X509* root = NULL;
X509* ica2 = NULL;
X509* ica1 = NULL;
X509* leaf = NULL;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* inter = NULL;
pathlen_override_seen = 0;
ExpectNotNull(root = test_wolfSSL_X509_STORE_CTX_ex_helper(
"./certs/ca-cert.pem"));
ExpectNotNull(ica2 = test_wolfSSL_X509_STORE_CTX_ex_helper(
"./certs/test-pathlen/chainF-ICA2-pathlen0.pem"));
ExpectNotNull(ica1 = test_wolfSSL_X509_STORE_CTX_ex_helper(
"./certs/test-pathlen/chainF-ICA1-pathlen1.pem"));
ExpectNotNull(leaf = test_wolfSSL_X509_STORE_CTX_ex_helper(
"./certs/test-pathlen/chainF-entity.pem"));
ExpectNotNull(store = X509_STORE_new());
ExpectIntEQ(X509_STORE_add_cert(store, root), 1);
X509_STORE_set_verify_cb(store, pathlen_override_cb);
ExpectNotNull(inter = sk_X509_new_null());
ExpectIntGT(sk_X509_push(inter, ica2), 0);
ExpectIntGT(sk_X509_push(inter, ica1), 0);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, leaf, inter), 1);
/* The callback overrides the violation, so verification now succeeds... */
ExpectIntEQ(X509_verify_cert(ctx), 1);
/* ...and the callback must actually have seen the pathLen error. */
ExpectIntEQ(pathlen_override_seen, 1);
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
sk_X509_free(inter);
X509_free(root);
X509_free(ica2);
X509_free(ica1);
X509_free(leaf);
#endif /* OPENSSL_ALL && !NO_CERTS && !NO_FILESYSTEM && !NO_RSA */
return EXPECT_RESULT();
}
/* The trust anchor's own pathLenConstraint must bound the path (matching
* OpenSSL's -partial_chain behavior and wolfSSL's native ParseCertRelative).
* Trust chainF-ICA2 (pathlen:0) directly as a partial-chain anchor and verify
* the entity through chainF-ICA1 (a CA): chainF-ICA1 exceeds the anchor's
* pathlen:0, so it must be rejected. This exercises the anchor-seeding branch
* of X509StoreCheckPathLen() (the violation comes from the anchor's constraint,
* not an intermediate's). */
int test_wolfSSL_X509_verify_cert_pathlen_anchor(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
!defined(NO_FILESYSTEM) && !defined(NO_RSA)
X509* ica2 = NULL;
X509* ica1 = NULL;
X509* leaf = NULL;
X509_STORE* store = NULL;
X509_STORE_CTX* ctx = NULL;
STACK_OF(X509)* inter = NULL;
ExpectNotNull(ica2 = test_wolfSSL_X509_STORE_CTX_ex_helper(
"./certs/test-pathlen/chainF-ICA2-pathlen0.pem"));
ExpectNotNull(ica1 = test_wolfSSL_X509_STORE_CTX_ex_helper(
"./certs/test-pathlen/chainF-ICA1-pathlen1.pem"));
ExpectNotNull(leaf = test_wolfSSL_X509_STORE_CTX_ex_helper(
"./certs/test-pathlen/chainF-entity.pem"));
/* Trust the pathlen:0 intermediate directly as a partial-chain anchor. */
ExpectNotNull(store = X509_STORE_new());
ExpectIntEQ(X509_STORE_add_cert(store, ica2), 1);
ExpectIntEQ(X509_STORE_set_flags(store, X509_V_FLAG_PARTIAL_CHAIN), 1);
ExpectNotNull(inter = sk_X509_new_null());
ExpectIntGT(sk_X509_push(inter, ica1), 0);
ExpectNotNull(ctx = X509_STORE_CTX_new());
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, leaf, inter), 1);
/* Must be rejected: chainF-ICA1 exceeds anchor chainF-ICA2's pathlen:0. */
ExpectIntNE(X509_verify_cert(ctx), 1);
ExpectIntEQ(X509_STORE_CTX_get_error(ctx),
X509_V_ERR_PATH_LENGTH_EXCEEDED);
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
sk_X509_free(inter);
X509_free(ica2);
X509_free(ica1);
X509_free(leaf);
#endif /* OPENSSL_EXTRA && !NO_CERTS && !NO_FILESYSTEM && !NO_RSA */
return EXPECT_RESULT();
}
int test_wolfSSL_X509_STORE_CTX_ex(void)
{
EXPECT_DECLS;
+12
View File
@@ -29,6 +29,10 @@ int test_wolfSSL_X509_STORE_check_time(void);
int test_wolfSSL_X509_STORE_CTX_get0_store(void);
int test_wolfSSL_X509_STORE_CTX(void);
int test_wolfSSL_X509_STORE_CTX_ex(void);
int test_wolfSSL_X509_verify_cert_pathlen(void);
int test_wolfSSL_X509_verify_cert_pathlen_ok(void);
int test_wolfSSL_X509_verify_cert_pathlen_override(void);
int test_wolfSSL_X509_verify_cert_pathlen_anchor(void);
int test_X509_verify_cert_untrusted_inter(void);
int test_X509_verify_cert_ca_no_keycertsign(void);
int test_X509_STORE_untrusted(void);
@@ -53,6 +57,14 @@ int test_wolfSSL_CTX_set_cert_store(void);
test_wolfSSL_X509_STORE_CTX_get0_store), \
TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_X509_STORE_CTX), \
TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_X509_STORE_CTX_ex), \
TEST_DECL_GROUP("ossl_x509_store", \
test_wolfSSL_X509_verify_cert_pathlen), \
TEST_DECL_GROUP("ossl_x509_store", \
test_wolfSSL_X509_verify_cert_pathlen_ok), \
TEST_DECL_GROUP("ossl_x509_store", \
test_wolfSSL_X509_verify_cert_pathlen_override), \
TEST_DECL_GROUP("ossl_x509_store", \
test_wolfSSL_X509_verify_cert_pathlen_anchor), \
TEST_DECL_GROUP("ossl_x509_store", test_X509_verify_cert_untrusted_inter), \
TEST_DECL_GROUP("ossl_x509_store", \
test_X509_verify_cert_ca_no_keycertsign), \