mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-09 13:20:49 +02:00
x509_str.c: fix partial-chain double-push and rework pathLen tests
- Break out of the chain-build loop after the partial-chain fallback accepts a caller-trusted terminus, so it is pushed to ctx->chain once instead of twice; X509StoreCheckPathLen's anchor-skip is now defensive, not load-bearing. - Drop the now-dead cert == anchor guard and refresh the comment. - Rework the pathLen regression tests: reuse the existing certs/test-pathlen chains (chainF rejects, chainB verifies) instead of inlined report certs.
This commit is contained in:
+13
-7
@@ -672,12 +672,11 @@ static int X509StoreCheckPathLen(WOLFSSL_X509_STORE_CTX* ctx)
|
||||
|
||||
/* 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. 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. The partial-chain branch of
|
||||
* wolfSSL_X509_verify_cert() pushes the terminal certificate twice, so the
|
||||
* anchor pointer can also appear at num-2; it is skipped by pointer below
|
||||
* to avoid double-counting. */
|
||||
* 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;
|
||||
@@ -688,7 +687,7 @@ static int X509StoreCheckPathLen(WOLFSSL_X509_STORE_CTX* ctx)
|
||||
WOLFSSL_X509* cert = wolfSSL_sk_X509_value(ctx->chain, i);
|
||||
int selfIssued;
|
||||
|
||||
if (cert == NULL || cert == anchor)
|
||||
if (cert == NULL)
|
||||
continue;
|
||||
|
||||
selfIssued =
|
||||
@@ -928,6 +927,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);
|
||||
|
||||
+174
-112
@@ -957,113 +957,52 @@ static int test_wolfSSL_X509_STORE_CTX_ex12(void)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && defined(HAVE_ECC)
|
||||
/* 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.
|
||||
* to issue a further intermediate CA. Reuses the certs/test-pathlen chains
|
||||
* (see certs/test-pathlen/assemble-chains.sh):
|
||||
*
|
||||
* root -> ica0 (CA, pathlen:0) -> ica1 (CA, pathlen:0) -> leaf
|
||||
* ca-cert -> chainF-ICA2 (CA, pathlen:0) -> chainF-ICA1 (CA) -> entity
|
||||
*
|
||||
* ica1 is an intermediate CA following ica0, which ica0's pathlen:0 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. */
|
||||
static X509* pathlen_pem_to_x509(const char* pem)
|
||||
{
|
||||
X509* x = NULL;
|
||||
BIO* bio = BIO_new_mem_buf(pem, -1);
|
||||
if (bio != NULL) {
|
||||
x = PEM_read_bio_X509(bio, NULL, NULL, NULL);
|
||||
BIO_free(bio);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
static int test_wolfSSL_X509_verify_cert_pathlen(void)
|
||||
* 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;
|
||||
/* x509-limbo intermediate-pathlen-0 chain (NIST P-256). */
|
||||
static const char* root_pem =
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIBjzCCATWgAwIBAgIUBr1M7Bi+lJsTuNKLX1Me8do6eaQwCgYIKoZIzj0EAwIw\n"
|
||||
"GjEYMBYGA1UEAwwPeDUwOS1saW1iby1yb290MCAXDTcwMDEwMTAwMDAwMVoYDzI5\n"
|
||||
"NjkwNTAzMDAwMDAxWjAaMRgwFgYDVQQDDA94NTA5LWxpbWJvLXJvb3QwWTATBgcq\n"
|
||||
"hkjOPQIBBggqhkjOPQMBBwNCAAQbEiFksWbYAbT6XaE4bwPlfA9TBdDVohu/uCIL\n"
|
||||
"xP51Zj39ZQijgxN9jxXyvCgo8Of/x5M0IHSUuc17eaBD+EEbo1cwVTAPBgNVHRMB\n"
|
||||
"Af8EBTADAQH/MAsGA1UdDwQEAwIBBjAWBgNVHREEDzANggtleGFtcGxlLmNvbTAd\n"
|
||||
"BgNVHQ4EFgQUonHZJ38dXr7snblbNqaxj6KZwOYwCgYIKoZIzj0EAwIDSAAwRQIh\n"
|
||||
"ANxM3gjJ/3FIvHLgFt9MlFXDUZs38+f+90xZ+UWEtg/sAiBwDNrH5LaFE+kGvHih\n"
|
||||
"aXu0ueUy9q+2v7FMk1DqDF5QMA==\n"
|
||||
"-----END CERTIFICATE-----\n";
|
||||
static const char* ica0_pem =
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIB/zCCAaWgAwIBAgIUWQmq3hQYYc2aAeHbkAhBu2TswggwCgYIKoZIzj0EAwIw\n"
|
||||
"GjEYMBYGA1UEAwwPeDUwOS1saW1iby1yb290MCAXDTcwMDEwMTAwMDAwMVoYDzI5\n"
|
||||
"NjkwNTAzMDAwMDAxWjBmMTgwNgYDVQQLDC8zODQ3NTQ4NjM0MDcyNTc1NDQyNDQy\n"
|
||||
"MTQxNDk1NTczNzU0OTc0NTAyNTYxMjE5NjEqMCgGA1UEAwwheDUwOS1saW1iby1p\n"
|
||||
"bnRlcm1lZGlhdGUtcGF0aGxlbi0wMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE\n"
|
||||
"htjb5R5OipW7n8rfvqA7yP/yxpdq9QzwSxC41RjoE//1SX16xsjOAIOYu/1L8iEq\n"
|
||||
"1Y6x7yBnkoFFpWW0R2JN0aN7MHkwEgYDVR0TAQH/BAgwBgEB/wIBADALBgNVHQ8E\n"
|
||||
"BAMCAgQwFgYDVR0RBA8wDYILZXhhbXBsZS5jb20wHwYDVR0jBBgwFoAUonHZJ38d\n"
|
||||
"Xr7snblbNqaxj6KZwOYwHQYDVR0OBBYEFI5psdjr2bzbP8AYzh747r3zKXjzMAoG\n"
|
||||
"CCqGSM49BAMCA0gAMEUCIQChdmrAmCCIGBKdR31PSCKcBFkhqIg1rFH5n9ISC0XT\n"
|
||||
"MwIgBpm/FQrFVRPNXUq3Pjp5nCCQNuusc/UF0WQtogoxMcs=\n"
|
||||
"-----END CERTIFICATE-----\n";
|
||||
static const char* ica1_pem =
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"MIICTDCCAfKgAwIBAgIUUzHoF6QQi7Q1abKHM2OkqXAyhXAwCgYIKoZIzj0EAwIw\n"
|
||||
"ZjE4MDYGA1UECwwvMzg0NzU0ODYzNDA3MjU3NTQ0MjQ0MjE0MTQ5NTU3Mzc1NDk3\n"
|
||||
"NDUwMjU2MTIxOTYxKjAoBgNVBAMMIXg1MDktbGltYm8taW50ZXJtZWRpYXRlLXBh\n"
|
||||
"dGhsZW4tMDAgFw03MDAxMDEwMDAwMDFaGA8yOTY5MDUwMzAwMDAwMVowZzE5MDcG\n"
|
||||
"A1UECwwwNTA4MzE1NzY5OTY4MTEzNTA3Njc4NzYzNDMxNDk4OTE0NTU3NTI4MDQ4\n"
|
||||
"OTc2MzkyMSowKAYDVQQDDCF4NTA5LWxpbWJvLWludGVybWVkaWF0ZS1wYXRobGVu\n"
|
||||
"LTAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQJAU5C0BQNKWv1lpCWYvrbguNZ\n"
|
||||
"7Ru3850SYzxAHVdqoqpXQqz1rxMGkIIQzNk1GhUXbMUVbQD0jvaJcoGfkNO5o3sw\n"
|
||||
"eTASBgNVHRMBAf8ECDAGAQH/AgEAMAsGA1UdDwQEAwICBDAWBgNVHREEDzANggtl\n"
|
||||
"eGFtcGxlLmNvbTAfBgNVHSMEGDAWgBSOabHY69m82z/AGM4e+O698yl48zAdBgNV\n"
|
||||
"HQ4EFgQUCRY9Zhvn1ujILJxVlXN6ngBEGUcwCgYIKoZIzj0EAwIDSAAwRQIhAPWq\n"
|
||||
"eItvUILeT5ZV1sA/2T2KXLmhO+lyaIJKbayTWTluAiBAnlFFqQhLRPC9aXnmvzld\n"
|
||||
"4OQO4zOBVTRVR1fyTaGRLA==\n"
|
||||
"-----END CERTIFICATE-----\n";
|
||||
static const char* leaf_pem =
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIB/jCCAaOgAwIBAgIUUgfgeS9xej4Xq/a8Bg2Dzj3MedEwCgYIKoZIzj0EAwIw\n"
|
||||
"ZzE5MDcGA1UECwwwNTA4MzE1NzY5OTY4MTEzNTA3Njc4NzYzNDMxNDk4OTE0NTU3\n"
|
||||
"NTI4MDQ4OTc2MzkyMSowKAYDVQQDDCF4NTA5LWxpbWJvLWludGVybWVkaWF0ZS1w\n"
|
||||
"YXRobGVuLTAwIBcNNzAwMTAxMDAwMDAxWhgPMjk2OTA1MDMwMDAwMDFaMBYxFDAS\n"
|
||||
"BgNVBAMMC2V4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERG/C\n"
|
||||
"Q3diuQGNPeztXUpMthR9/695MnMj/tpF6NHkEBO91bBKFdjhnievo6XnpfEOer/z\n"
|
||||
"nHvUEwH3UH7swoP3qKN8MHowHQYDVR0OBBYEFMorXKe6f7/o5tnf5iacR/PPM9F3\n"
|
||||
"MB8GA1UdIwQYMBaAFAkWPWYb59boyCycVZVzep4ARBlHMAsGA1UdDwQEAwIHgDAT\n"
|
||||
"BgNVHSUEDDAKBggrBgEFBQcDATAWBgNVHREEDzANggtleGFtcGxlLmNvbTAKBggq\n"
|
||||
"hkjOPQQDAgNJADBGAiEAjQovFZD9svq8vGyuCa82Cq3/YeoHkDyyRalhv4BV7X8C\n"
|
||||
"IQDqXCv7h0gMIVsWOSef8zu4DubHxn7Icm7DwJg0O2lSuw==\n"
|
||||
"-----END CERTIFICATE-----\n";
|
||||
#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \
|
||||
!defined(NO_FILESYSTEM) && !defined(NO_RSA)
|
||||
X509* root = NULL;
|
||||
X509* ica0 = 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 = pathlen_pem_to_x509(root_pem));
|
||||
ExpectNotNull(ica0 = pathlen_pem_to_x509(ica0_pem));
|
||||
ExpectNotNull(ica1 = pathlen_pem_to_x509(ica1_pem));
|
||||
ExpectNotNull(leaf = pathlen_pem_to_x509(leaf_pem));
|
||||
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, ica0), 0);
|
||||
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: ica1 violates ica0's pathlen:0 constraint. */
|
||||
/* 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);
|
||||
@@ -1072,57 +1011,184 @@ static int test_wolfSSL_X509_verify_cert_pathlen(void)
|
||||
X509_STORE_free(store);
|
||||
sk_X509_free(inter);
|
||||
X509_free(root);
|
||||
X509_free(ica0);
|
||||
X509_free(ica2);
|
||||
X509_free(ica1);
|
||||
X509_free(leaf);
|
||||
#endif /* OPENSSL_EXTRA && !NO_CERTS && !NO_FILESYSTEM && !NO_RSA */
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
#if !defined(NO_FILESYSTEM) && !defined(NO_RSA)
|
||||
/* Positive control: a legitimate chain whose intermediates assert pathlen:1
|
||||
* must still verify, guarding the pathLen enforcement against over-rejection.
|
||||
* then pathlen:0 must still verify, guarding pathLen enforcement against
|
||||
* over-rejection. Reuses the certs/test-pathlen chainB:
|
||||
*
|
||||
* ca-cert -> ca-int (pathlen:1) -> ca-int2 (pathlen:1) -> server-chain
|
||||
* ca-cert -> chainB-ICA2 (CA, pathlen:1) -> chainB-ICA1 (CA, pathlen:0)
|
||||
* -> entity
|
||||
*
|
||||
* ca-int permits one following intermediate (ca-int2), so the chain is valid. */
|
||||
static int test_wolfSSL_X509_verify_cert_pathlen_ok(void)
|
||||
* chainB-ICA2 permits one following intermediate (chainB-ICA1), so the chain
|
||||
* is valid. */
|
||||
int test_wolfSSL_X509_verify_cert_pathlen_ok(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
X509* ca = NULL;
|
||||
X509* caInt = NULL;
|
||||
X509* caInt2 = NULL;
|
||||
#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(ca = test_wolfSSL_X509_STORE_CTX_ex_helper(
|
||||
ExpectNotNull(root = test_wolfSSL_X509_STORE_CTX_ex_helper(
|
||||
"./certs/ca-cert.pem"));
|
||||
ExpectNotNull(caInt = test_wolfSSL_X509_STORE_CTX_ex_helper(
|
||||
"./certs/intermediate/ca-int-cert.pem"));
|
||||
ExpectNotNull(caInt2 = test_wolfSSL_X509_STORE_CTX_ex_helper(
|
||||
"./certs/intermediate/ca-int2-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/intermediate/server-chain.pem"));
|
||||
"./certs/test-pathlen/chainB-entity.pem"));
|
||||
|
||||
ExpectNotNull(store = X509_STORE_new());
|
||||
ExpectIntEQ(X509_STORE_add_cert(store, ca), 1);
|
||||
ExpectIntEQ(X509_STORE_add_cert(store, caInt), 1);
|
||||
ExpectIntEQ(X509_STORE_add_cert(store, caInt2), 1);
|
||||
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, NULL), 1);
|
||||
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);
|
||||
X509_free(ca);
|
||||
X509_free(caInt);
|
||||
X509_free(caInt2);
|
||||
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();
|
||||
}
|
||||
#endif /* !NO_FILESYSTEM && !NO_RSA */
|
||||
#endif /* OPENSSL_EXTRA && !NO_CERTS && HAVE_ECC */
|
||||
|
||||
int test_wolfSSL_X509_STORE_CTX_ex(void)
|
||||
{
|
||||
@@ -1169,10 +1235,6 @@ int test_wolfSSL_X509_STORE_CTX_ex(void)
|
||||
&testData), 1);
|
||||
#ifdef HAVE_ECC
|
||||
ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex12(), 1);
|
||||
ExpectIntEQ(test_wolfSSL_X509_verify_cert_pathlen(), 1);
|
||||
#if !defined(NO_FILESYSTEM) && !defined(NO_RSA)
|
||||
ExpectIntEQ(test_wolfSSL_X509_verify_cert_pathlen_ok(), 1);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if(testData.x509Ca) {
|
||||
|
||||
@@ -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), \
|
||||
|
||||
Reference in New Issue
Block a user