Skip to content

Commit b56cafd

Browse files
authored
Merge pull request #8692 from kareem-wolfssl/zd19563_verify
Update wolfSSL_X509_verify_cert to retry all certs until a valid chain is found.
2 parents 50f25c5 + ef989a4 commit b56cafd

10 files changed

Lines changed: 269 additions & 18 deletions

File tree

851 Bytes
Binary file not shown.
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
Certificate:
2+
Data:
3+
Version: 3 (0x2)
4+
Serial Number: 4113 (0x1011)
5+
Signature Algorithm: sha256WithRSAEncryption
6+
Issuer: C = US, ST = Washington, L = Seattle, O = wolfSSL, OU = Development, CN = wolfSSL Intermediate CA, emailAddress = info@wolfssl.com
7+
Validity
8+
Not Before: Jun 18 22:52:02 2025 GMT
9+
Not After : Jun 13 22:52:02 2045 GMT
10+
Subject: C = US, ST = Washington, L = Seattle, O = wolfSSL, OU = Development, CN = www.wolfssl.com, emailAddress = info@wolfssl.com
11+
Subject Public Key Info:
12+
Public Key Algorithm: id-ecPublicKey
13+
Public-Key: (256 bit)
14+
pub:
15+
04:02:d3:d9:6e:d6:01:8e:45:c8:b9:90:31:e5:c0:
16+
4c:e3:9e:ad:29:38:98:ba:10:d6:e9:09:2a:80:a9:
17+
2e:17:2a:b9:8a:bf:33:83:46:e3:95:0b:e4:77:40:
18+
b5:3b:43:45:33:0f:61:53:7c:37:44:c1:cb:fc:80:
19+
ca:e8:43:ea:a7
20+
ASN1 OID: prime256v1
21+
NIST CURVE: P-256
22+
X509v3 extensions:
23+
X509v3 Subject Key Identifier:
24+
56:8E:9A:C3:F0:42:DE:18:B9:45:55:6E:F9:93:CF:EA:C3:F3:A5:21
25+
X509v3 Authority Key Identifier:
26+
EF:69:E0:F7:D5:1D:E6:99:EC:DC:6D:D0:F7:E2:B9:5C:64:71:83:35
27+
X509v3 Basic Constraints: critical
28+
CA:TRUE, pathlen:1
29+
X509v3 Key Usage: critical
30+
Digital Signature, Certificate Sign, CRL Sign
31+
Signature Algorithm: sha256WithRSAEncryption
32+
Signature Value:
33+
43:55:80:10:fb:06:b8:58:4c:02:3f:43:f7:bb:fd:46:ae:83:
34+
c7:fe:d3:b9:5c:58:00:49:b1:4c:ed:17:84:14:72:02:05:93:
35+
d7:87:b0:27:ff:bf:8a:50:50:26:41:b5:6b:83:8e:eb:46:ab:
36+
bb:da:f8:42:b2:df:3c:41:54:11:18:09:1c:a6:6e:63:56:be:
37+
7a:20:0d:08:d2:c0:25:ce:a4:d0:3d:09:02:fb:7b:41:59:49:
38+
b5:e1:f7:72:84:b4:c7:10:c8:a0:07:64:73:6b:80:06:7a:31:
39+
62:ad:49:92:53:ef:d7:d6:b4:89:9c:15:20:a5:c4:ed:c0:39:
40+
7c:68:f2:19:e0:cf:e5:bb:5a:16:10:d5:de:80:da:0f:0e:91:
41+
0b:39:73:d6:a7:73:b2:b6:2b:c6:fb:bc:33:e6:fd:d9:1c:dc:
42+
48:3d:1e:8b:6b:9f:8f:60:26:69:53:3b:17:ed:62:bd:34:ab:
43+
8c:e4:4c:17:f4:c3:bc:81:63:ad:67:c1:5d:e3:72:ac:a5:8a:
44+
bc:6f:0c:2e:33:81:81:92:20:d4:4b:e0:a3:22:12:d6:b4:27:
45+
1f:37:14:a2:c4:76:c0:3c:29:44:4d:a9:35:67:21:1d:11:7f:
46+
76:98:02:f7:5a:f9:05:cb:2d:3b:39:45:e9:9d:82:9a:20:b0:
47+
c6:56:1c:d4
48+
-----BEGIN CERTIFICATE-----
49+
MIIDTzCCAjegAwIBAgICEBEwDQYJKoZIhvcNAQELBQAwgZ8xCzAJBgNVBAYTAlVT
50+
MRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxlMRAwDgYDVQQK
51+
DAd3b2xmU1NMMRQwEgYDVQQLDAtEZXZlbG9wbWVudDEgMB4GA1UEAwwXd29sZlNT
52+
TCBJbnRlcm1lZGlhdGUgQ0ExHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5j
53+
b20wHhcNMjUwNjE4MjI1MjAyWhcNNDUwNjEzMjI1MjAyWjCBlzELMAkGA1UEBhMC
54+
VVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxEDAOBgNV
55+
BAoMB3dvbGZTU0wxFDASBgNVBAsMC0RldmVsb3BtZW50MRgwFgYDVQQDDA93d3cu
56+
d29sZnNzbC5jb20xHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wWTAT
57+
BgcqhkjOPQIBBggqhkjOPQMBBwNCAAQC09lu1gGORci5kDHlwEzjnq0pOJi6ENbp
58+
CSqAqS4XKrmKvzODRuOVC+R3QLU7Q0UzD2FTfDdEwcv8gMroQ+qno2YwZDAdBgNV
59+
HQ4EFgQUVo6aw/BC3hi5RVVu+ZPP6sPzpSEwHwYDVR0jBBgwFoAU72ng99Ud5pns
60+
3G3Q9+K5XGRxgzUwEgYDVR0TAQH/BAgwBgEB/wIBATAOBgNVHQ8BAf8EBAMCAYYw
61+
DQYJKoZIhvcNAQELBQADggEBAENVgBD7BrhYTAI/Q/e7/Uaug8f+07lcWABJsUzt
62+
F4QUcgIFk9eHsCf/v4pQUCZBtWuDjutGq7va+EKy3zxBVBEYCRymbmNWvnogDQjS
63+
wCXOpNA9CQL7e0FZSbXh93KEtMcQyKAHZHNrgAZ6MWKtSZJT79fWtImcFSClxO3A
64+
OXxo8hngz+W7WhYQ1d6A2g8OkQs5c9anc7K2K8b7vDPm/dkc3Eg9Hotrn49gJmlT
65+
OxftYr00q4zkTBf0w7yBY61nwV3jcqylirxvDC4zgYGSINRL4KMiEta0Jx83FKLE
66+
dsA8KURNqTVnIR0Rf3aYAvda+QXLLTs5RemdgpogsMZWHNQ=
67+
-----END CERTIFICATE-----

certs/intermediate/genintcerts.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,9 @@ create_cert wolfssl_int2_ecc wolfssl_int2_ecc ./certs/ecc-key.pem server-int-ecc
313313
echo "Create ECC Client Certificate signed by intermediate2"
314314
create_cert wolfssl_int2_ecc wolfssl_int2_ecc ./certs/ecc-client-key.pem client-int-ecc-cert usr_cert "wolfSSL Client Chain ECC" 3650
315315

316+
echo "Create alt CA with intentionally invalid AKI"
317+
create_cert wolfssl_root_ecc wolfssl_int ./certs/ca-ecc-key.pem ca-ecc-bad-aki v3_intermediate_ca "www.wolfssl.com" 7300
318+
316319
echo "Generate CRLs for new certificates"
317320
openssl ca -config ./certs/intermediate/wolfssl_root_ecc.cnf -gencrl -crldays 1000 -out ./certs/crl/ca-int-ecc.pem -keyfile ./certs/intermediate/ca-int-ecc-key.pem -cert ./certs/intermediate/ca-int-ecc-cert.pem
318321
check_result $?

certs/intermediate/include.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
EXTRA_DIST += \
66
certs/intermediate/genintcerts.sh \
7+
certs/intermediate/ca-ecc-bad-aki.der \
8+
certs/intermediate/ca-ecc-bad-aki.pem \
79
certs/intermediate/ca-int-cert.der \
810
certs/intermediate/ca-int-cert.pem \
911
certs/intermediate/ca-int-ecc-cert.der \

src/ssl.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6141,6 +6141,55 @@ int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify)
61416141
return ret == 0 ? WOLFSSL_SUCCESS : ret;
61426142
}
61436143

6144+
/* Removes the CA with the passed in subject hash from the
6145+
cert manager's CA cert store. */
6146+
int RemoveCA(WOLFSSL_CERT_MANAGER* cm, byte* hash, int type)
6147+
{
6148+
Signer* current;
6149+
Signer** prev;
6150+
int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE);
6151+
word32 row;
6152+
6153+
WOLFSSL_MSG("Removing a CA");
6154+
6155+
if (cm == NULL || hash == NULL) {
6156+
return BAD_FUNC_ARG;
6157+
}
6158+
6159+
row = HashSigner(hash);
6160+
6161+
if (wc_LockMutex(&cm->caLock) != 0) {
6162+
return BAD_MUTEX_E;
6163+
}
6164+
current = cm->caTable[row];
6165+
prev = &cm->caTable[row];
6166+
while (current) {
6167+
byte* subjectHash;
6168+
6169+
#ifndef NO_SKID
6170+
subjectHash = current->subjectKeyIdHash;
6171+
#else
6172+
subjectHash = current->subjectNameHash;
6173+
#endif
6174+
6175+
if ((current->type == type) &&
6176+
(XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0)) {
6177+
*prev = current->next;
6178+
FreeSigner(current, cm->heap);
6179+
ret = WOLFSSL_SUCCESS;
6180+
break;
6181+
}
6182+
prev = &current->next;
6183+
current = current->next;
6184+
}
6185+
wc_UnLockMutex(&cm->caLock);
6186+
6187+
WOLFSSL_LEAVE("RemoveCA", ret);
6188+
6189+
return ret;
6190+
}
6191+
6192+
61446193
/* Sets the CA with the passed in subject hash
61456194
to the provided type. */
61466195
int SetCAType(WOLFSSL_CERT_MANAGER* cm, byte* hash, int type)

src/x509_str.c

Lines changed: 99 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,64 @@ static int addAllButSelfSigned(WOLF_STACK_OF(WOLFSSL_X509)*to,
404404
return ret;
405405
}
406406

407+
static int X509StoreRemoveCa(WOLFSSL_X509_STORE* store,
408+
WOLFSSL_X509* x509, int type) {
409+
int result = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR);
410+
byte hash[KEYID_SIZE];
411+
412+
if (store != NULL && x509 != NULL && x509->derCert != NULL) {
413+
result = GetHashId(x509->subjKeyId, (int)x509->subjKeyIdSz,
414+
hash, HashIdAlg(x509->sigOID));
415+
if (result) {
416+
result = WOLFSSL_FATAL_ERROR;
417+
} else {
418+
result = RemoveCA(store->cm, hash, type);
419+
}
420+
}
421+
422+
return result;
423+
}
424+
425+
static int X509StoreMoveCert(WOLFSSL_STACK *certs_stack,
426+
WOLFSSL_STACK *dest_stack,
427+
WOLFSSL_X509 *cert) {
428+
int i;
429+
430+
if (certs_stack == NULL || dest_stack == NULL || cert == NULL)
431+
return WOLFSSL_FATAL_ERROR;
432+
433+
for (i = 0; i < wolfSSL_sk_X509_num(certs_stack); i++) {
434+
if (wolfSSL_sk_X509_value(certs_stack, i) == cert) {
435+
wolfSSL_sk_X509_push(dest_stack,
436+
(WOLFSSL_X509*)wolfSSL_sk_pop_node(certs_stack, i));
437+
return WOLFSSL_SUCCESS;
438+
}
439+
}
440+
441+
return WOLFSSL_FAILURE;
442+
}
443+
444+
445+
/* Current certificate failed, but it is possible there is an
446+
* alternative cert with the same subject key which will work.
447+
* Retry until all possible candidate certs are exhausted. */
448+
static int X509VerifyCertSetupRetry(WOLFSSL_X509_STORE_CTX* ctx,
449+
WOLF_STACK_OF(WOLFSSL_X509)* certs, WOLF_STACK_OF(WOLFSSL_X509)* failed,
450+
int* depth, int origDepth) {
451+
int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE);
452+
453+
WOLFSSL_MSG("X509_verify_cert current cert failed, "
454+
"retrying with other certs.");
455+
ret = X509StoreRemoveCa(ctx->store, ctx->current_cert,
456+
WOLFSSL_TEMP_CA);
457+
X509StoreMoveCert(certs, failed, ctx->current_cert);
458+
ctx->current_cert = wolfSSL_sk_X509_pop(ctx->chain);
459+
if (*depth < origDepth)
460+
*depth += 1;
461+
462+
return ret;
463+
}
464+
407465
/* Verifies certificate chain using WOLFSSL_X509_STORE_CTX
408466
* returns 1 on success or <= 0 on failure.
409467
*/
@@ -414,11 +472,14 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
414472
int added = 0;
415473
int i = 0;
416474
int numInterAdd = 0;
475+
int numFailedCerts = 0;
417476
int depth = 0;
477+
int origDepth = 0;
418478
WOLFSSL_X509 *issuer = NULL;
419479
WOLFSSL_X509 *orig = NULL;
420480
WOLF_STACK_OF(WOLFSSL_X509)* certs = NULL;
421481
WOLF_STACK_OF(WOLFSSL_X509)* certsToUse = NULL;
482+
WOLF_STACK_OF(WOLFSSL_X509)* failedCerts = NULL;
422483
WOLFSSL_ENTER("wolfSSL_X509_verify_cert");
423484

424485
if (ctx == NULL || ctx->store == NULL || ctx->store->cm == NULL
@@ -427,6 +488,7 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
427488
}
428489

429490
certs = ctx->store->certs;
491+
430492
if (ctx->setTrustedSk != NULL) {
431493
certs = ctx->setTrustedSk;
432494
}
@@ -450,6 +512,10 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
450512
}
451513
ctx->chain = wolfSSL_sk_X509_new_null();
452514

515+
failedCerts = wolfSSL_sk_X509_new_null();
516+
if (!failedCerts)
517+
return WOLFSSL_FATAL_ERROR;
518+
453519
if (ctx->depth > 0) {
454520
depth = ctx->depth + 1;
455521
}
@@ -458,6 +524,7 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
458524
}
459525

460526
orig = ctx->current_cert;
527+
origDepth = depth;
461528
while(done == 0 && depth > 0) {
462529
issuer = NULL;
463530

@@ -486,23 +553,28 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
486553
goto exit;
487554
}
488555
}
489-
} else {
556+
} else
490557
#endif
491-
ret = X509StoreAddCa(ctx->store, issuer,
492-
WOLFSSL_TEMP_CA);
493-
if (ret != WOLFSSL_SUCCESS) {
494-
goto exit;
495-
}
496-
added = 1;
497-
ret = X509StoreVerifyCert(ctx);
498-
if (ret != WOLFSSL_SUCCESS) {
499-
goto exit;
500-
}
501-
/* Add it to the current chain and look at the issuer cert next */
502-
wolfSSL_sk_X509_push(ctx->chain, ctx->current_cert);
503-
#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
558+
{
559+
ret = X509StoreAddCa(ctx->store, issuer,
560+
WOLFSSL_TEMP_CA);
561+
if (ret != WOLFSSL_SUCCESS) {
562+
X509VerifyCertSetupRetry(ctx, certs, failedCerts,
563+
&depth, origDepth);
564+
continue;
565+
}
566+
added = 1;
567+
ret = X509StoreVerifyCert(ctx);
568+
if (ret != WOLFSSL_SUCCESS) {
569+
if ((origDepth - depth) <= 1)
570+
added = 0;
571+
X509VerifyCertSetupRetry(ctx, certs, failedCerts,
572+
&depth, origDepth);
573+
continue;
574+
}
575+
/* Add it to the current chain and look at the issuer cert next */
576+
wolfSSL_sk_X509_push(ctx->chain, ctx->current_cert);
504577
}
505-
#endif
506578
ctx->current_cert = issuer;
507579
}
508580
else if (ret == WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) {
@@ -515,8 +587,11 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
515587
(added == 1)) {
516588
wolfSSL_sk_X509_push(ctx->chain, ctx->current_cert);
517589
ret = WOLFSSL_SUCCESS;
590+
} else {
591+
X509VerifyCertSetupRetry(ctx, certs, failedCerts,
592+
&depth, origDepth);
593+
continue;
518594
}
519-
goto exit;
520595
}
521596

522597
/* Cert verified, finish building the chain */
@@ -551,6 +626,14 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
551626
}
552627

553628
exit:
629+
/* Copy back failed certs. */
630+
numFailedCerts = wolfSSL_sk_X509_num(failedCerts);
631+
for (i = 0; i < numFailedCerts; i++)
632+
{
633+
wolfSSL_sk_X509_push(certs, wolfSSL_sk_X509_pop(failedCerts));
634+
}
635+
wolfSSL_sk_X509_pop_free(failedCerts, NULL);
636+
554637
/* Remove additional intermediates from init from the store */
555638
if (ctx != NULL && numInterAdd > 0) {
556639
for (i = 0; i < numInterAdd; i++) {
@@ -1390,7 +1473,6 @@ static int X509StoreAddCa(WOLFSSL_X509_STORE* store,
13901473
return result;
13911474
}
13921475

1393-
13941476
int wolfSSL_X509_STORE_add_cert(WOLFSSL_X509_STORE* store, WOLFSSL_X509* x509)
13951477
{
13961478
int result = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR);

tests/api.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20546,6 +20546,50 @@ static int test_wolfSSL_X509_STORE_CTX_ex11(X509_STORE_test_data *testData)
2054620546
X509_STORE_free(store);
2054720547
return EXPECT_RESULT();
2054820548
}
20549+
20550+
static int test_wolfSSL_X509_STORE_CTX_ex12(void)
20551+
{
20552+
EXPECT_DECLS;
20553+
#ifdef HAVE_ECC
20554+
X509_STORE* store = NULL;
20555+
X509_STORE_CTX* ctx = NULL;
20556+
STACK_OF(X509)* chain = NULL;
20557+
X509* rootEccX509 = NULL;
20558+
X509* badAkiX509 = NULL;
20559+
X509* ca1X509 = NULL;
20560+
20561+
const char* intCARootECCFile = "./certs/ca-ecc-cert.pem";
20562+
const char* intCA1ECCFile = "./certs/intermediate/ca-int-ecc-cert.pem";
20563+
const char* intCABadAKIECCFile = "./certs/intermediate/ca-ecc-bad-aki.pem";
20564+
20565+
/* Test case 12, multiple CAs with the same SKI including 1 with intentionally
20566+
bad/unregistered AKI. x509_verify_cert should still form a valid chain
20567+
using the valid CA, ignoring the bad CA. Developed from customer provided
20568+
reproducer. */
20569+
20570+
ExpectNotNull(store = X509_STORE_new());
20571+
ExpectNotNull(rootEccX509 = test_wolfSSL_X509_STORE_CTX_ex_helper(intCARootECCFile));
20572+
ExpectIntEQ(X509_STORE_add_cert(store, rootEccX509), 1);
20573+
ExpectNotNull(badAkiX509 = test_wolfSSL_X509_STORE_CTX_ex_helper(intCABadAKIECCFile));
20574+
ExpectNotNull(ctx = X509_STORE_CTX_new());
20575+
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, badAkiX509, NULL), 1);
20576+
ExpectIntEQ(X509_verify_cert(ctx), 0);
20577+
X509_STORE_CTX_cleanup(ctx);
20578+
20579+
ExpectIntEQ(X509_STORE_add_cert(store, badAkiX509), 1);
20580+
ExpectNotNull(ca1X509 = test_wolfSSL_X509_STORE_CTX_ex_helper(intCA1ECCFile));
20581+
ExpectIntEQ(X509_STORE_CTX_init(ctx, store, ca1X509, NULL), 1);
20582+
ExpectIntEQ(X509_verify_cert(ctx), 1);
20583+
ExpectNotNull(chain = X509_STORE_CTX_get_chain(ctx));
20584+
20585+
X509_STORE_CTX_free(ctx);
20586+
X509_STORE_free(store);
20587+
X509_free(rootEccX509);
20588+
X509_free(badAkiX509);
20589+
X509_free(ca1X509);
20590+
#endif
20591+
return EXPECT_RESULT();
20592+
}
2054920593
#endif
2055020594

2055120595
static int test_wolfSSL_X509_STORE_CTX_ex(void)
@@ -20585,6 +20629,7 @@ static int test_wolfSSL_X509_STORE_CTX_ex(void)
2058520629
ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex9(&testData), 1);
2058620630
ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex10(&testData), 1);
2058720631
ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex11(&testData), 1);
20632+
test_wolfSSL_X509_STORE_CTX_ex12();
2058820633

2058920634
if(testData.x509Ca) {
2059020635
X509_free(testData.x509Ca);

wolfcrypt/src/asn.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14375,7 +14375,7 @@ int CalcHashId_ex(const byte* data, word32 len, byte* hash, int hashAlg)
1437514375
* @return 0 on success.
1437614376
* @return MEMORY_E when dynamic memory allocation fails.
1437714377
*/
14378-
static int GetHashId(const byte* id, int length, byte* hash, int hashAlg)
14378+
int GetHashId(const byte* id, int length, byte* hash, int hashAlg)
1437914379
{
1438014380
int ret;
1438114381

0 commit comments

Comments
 (0)