Skip to content

Commit c438241

Browse files
committed
fix: chain static CRL revoked list
1 parent b0afe82 commit c438241

4 files changed

Lines changed: 111 additions & 3 deletions

File tree

‎.github/configs/os-check-linux.json‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -601,5 +601,8 @@
601601
"run": [["./wolfcrypt/test/testwolfcrypt"]]},
602602
{"name": "postauth-no-compat",
603603
"comment": "Post-handshake auth without OPENSSL_EXTRA, which otherwise compiles out the handshake-end unload of SSL-owned certs and keys.",
604-
"configure": ["--enable-postauth", "--enable-sessioncerts"]}
604+
"configure": ["--enable-postauth", "--enable-sessioncerts"]},
605+
{"name": "all-crl-static-revoked-list",
606+
"comment": "CRL_STATIC_REVOKED_LIST swaps the revoked cert linked list for a fixed sorted array. Nothing else in this matrix defines it, so the static list tests in tests/api/test_certman.c and the compat layer CRL code on the array (print, get_REVOKED, CRL generation) are built nowhere else.",
607+
"configure": ["--enable-all", "CPPFLAGS=-DCRL_STATIC_REVOKED_LIST"]}
605608
]

‎src/crl.c‎

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,9 @@ static int CompareRevokedCert(const RevokedCert* a, const RevokedCert* b)
130130
}
131131

132132
/* Sort revoked cert array in-place using insertion sort. The array is bounded
133-
* by CRL_MAX_REVOKED_CERTS so O(n^2) is fine. */
133+
* by CRL_MAX_REVOKED_CERTS so O(n^2) is fine. Then chain the entries through
134+
* next, so code that walks the revoked list (wc_MakeCRL_ex,
135+
* wolfSSL_X509_CRL_print, wolfSSL_X509_CRL_get_REVOKED) sees every entry. */
134136
static void SortCRL_CertList(RevokedCert* certs, int totalCerts)
135137
{
136138
int i, j;
@@ -145,6 +147,9 @@ static void SortCRL_CertList(RevokedCert* certs, int totalCerts)
145147
}
146148
XMEMCPY(&certs[j + 1], &tmp, sizeof(RevokedCert));
147149
}
150+
for (i = 0; i < totalCerts; i++) {
151+
certs[i].next = (i + 1 < totalCerts) ? &certs[i + 1] : NULL;
152+
}
148153
}
149154
#endif /* CRL_STATIC_REVOKED_LIST */
150155

@@ -1417,6 +1422,8 @@ static int DupRevokedCertList(CRL_Entry* dupl, const CRL_Entry* ent, void* heap)
14171422
if (DupRevokedCert(&dupl->certs[i], &ent->certs[i], heap) != 0)
14181423
return MEMORY_E;
14191424
}
1425+
/* DupRevokedCert() cleared next, relink within dupl's own array */
1426+
SortCRL_CertList(dupl->certs, ent->totalCerts);
14201427
#else
14211428
RevokedCert* current;
14221429
RevokedCert* prev = NULL;
@@ -2594,7 +2601,9 @@ int wolfSSL_X509_CRL_add_revoked(WOLFSSL_X509_CRL* crl,
25942601
{
25952602
CRL_Entry* entry;
25962603
RevokedCert* rc;
2604+
#ifndef CRL_STATIC_REVOKED_LIST
25972605
RevokedCert* curr;
2606+
#endif
25982607

25992608
WOLFSSL_ENTER("wolfSSL_X509_CRL_add_revoked");
26002609

@@ -2611,6 +2620,12 @@ int wolfSSL_X509_CRL_add_revoked(WOLFSSL_X509_CRL* crl,
26112620
if (entry == NULL) {
26122621
return BAD_FUNC_ARG;
26132622
}
2623+
#ifdef CRL_STATIC_REVOKED_LIST
2624+
/* Same limit and error as the parser, GetRevoked() */
2625+
if (entry->totalCerts >= CRL_MAX_REVOKED_CERTS) {
2626+
return MEMORY_E;
2627+
}
2628+
#endif
26142629

26152630
{
26162631
const byte* serial = rev->serialNumber->data;
@@ -2669,6 +2684,13 @@ int wolfSSL_X509_CRL_add_revoked(WOLFSSL_X509_CRL* crl,
26692684
rc->reasonCode = rev->reason;
26702685
rc->next = NULL;
26712686

2687+
#ifdef CRL_STATIC_REVOKED_LIST
2688+
/* Copy into the fixed array and keep it sorted for FindRevokedSerial */
2689+
XMEMCPY(&entry->certs[entry->totalCerts], rc, sizeof(RevokedCert));
2690+
XFREE(rc, crl->heap, DYNAMIC_TYPE_REVOKED);
2691+
entry->totalCerts++;
2692+
SortCRL_CertList(entry->certs, entry->totalCerts);
2693+
#else
26722694
/* Add to end of list */
26732695
if (entry->certs == NULL) {
26742696
entry->certs = rc;
@@ -2679,6 +2701,7 @@ int wolfSSL_X509_CRL_add_revoked(WOLFSSL_X509_CRL* crl,
26792701
curr->next = rc;
26802702
}
26812703
entry->totalCerts++;
2704+
#endif
26822705

26832706
/* Invalidate cached STACK_OF(X509_REVOKED) since list changed */
26842707
if (crl->revokedStack != NULL) {

‎tests/api.c‎

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30412,6 +30412,30 @@ static int test_wolfSSL_X509_CRL_reason_critical_boolean(void)
3041230412
defined(HAVE_CRL) && !defined(NO_FILESYSTEM) && \
3041330413
!defined(NO_STDIO_FILESYSTEM) && defined(WOLFSSL_CERT_GEN) && \
3041430414
!defined(NO_ASN_TIME)
30415+
#ifdef CRL_STATIC_REVOKED_LIST
30416+
/* The static revoked list is kept sorted, not in add order, so match a decoded
30417+
* entry against the serials not matched yet, want[n] being the cert serial.
30418+
* Returns 1 when it matched one. */
30419+
static int crl_match_revoked(const RevokedCert* rev, byte want[][1], int n,
30420+
const byte* certSerial, int certSerialSz,
30421+
int* used)
30422+
{
30423+
int k;
30424+
30425+
for (k = 0; k <= n; k++) {
30426+
const byte* s = (k < n) ? want[k] : certSerial;
30427+
int sz = (k < n) ? (int)sizeof(want[0]) : certSerialSz;
30428+
30429+
if ((*used & (1 << k)) == 0 && rev->serialSz == sz &&
30430+
XMEMCMP(rev->serialNumber, s, (size_t)sz) == 0) {
30431+
*used |= 1 << k;
30432+
return 1;
30433+
}
30434+
}
30435+
return 0;
30436+
}
30437+
#endif
30438+
3041530439
/* Helper function to create, sign, and write a CRL */
3041630440
static int generate_crl_test(const char* keyFile, const char* certFile,
3041730441
const char* derFile, const char* pemFile,
@@ -30580,7 +30604,14 @@ static int generate_crl_test(const char* keyFile, const char* certFile,
3058030604
revokedCount = 0;
3058130605
if (EXPECT_SUCCESS() && decodedCrl != NULL && decodedCrl->crlList != NULL) {
3058230606
RevokedCert* rev = decodedCrl->crlList->certs;
30607+
#ifdef CRL_STATIC_REVOKED_LIST
30608+
int used = 0;
30609+
#endif
3058330610
while (rev != NULL) {
30611+
#ifdef CRL_STATIC_REVOKED_LIST
30612+
ExpectIntEQ(crl_match_revoked(rev, serialsToRevokeBytes,
30613+
numSerials, certSerial, certSerialSz, &used), 1);
30614+
#else
3058430615
if (revokedCount == 0) {
3058530616
/* Last added (cert serial) appears first in decoded list */
3058630617
ExpectIntEQ(rev->serialSz, certSerialSz);
@@ -30595,6 +30626,7 @@ static int generate_crl_test(const char* keyFile, const char* certFile,
3059530626
ExpectIntEQ(XMEMCMP(rev->serialNumber,
3059630627
serialsToRevokeBytes[idx], rev->serialSz), 0);
3059730628
}
30629+
#endif
3059830630
revokedCount++;
3059930631
rev = rev->next;
3060030632
}
@@ -30625,7 +30657,14 @@ static int generate_crl_test(const char* keyFile, const char* certFile,
3062530657
revokedCount = 0;
3062630658
if (EXPECT_SUCCESS() && decodedCrl != NULL && decodedCrl->crlList != NULL) {
3062730659
RevokedCert* rev = decodedCrl->crlList->certs;
30660+
#ifdef CRL_STATIC_REVOKED_LIST
30661+
int used = 0;
30662+
#endif
3062830663
while (rev != NULL) {
30664+
#ifdef CRL_STATIC_REVOKED_LIST
30665+
ExpectIntEQ(crl_match_revoked(rev, serialsToRevokeBytes,
30666+
numSerials, certSerial, certSerialSz, &used), 1);
30667+
#else
3062930668
if (revokedCount == 0) {
3063030669
ExpectIntEQ(rev->serialSz, certSerialSz);
3063130670
ExpectIntEQ(XMEMCMP(rev->serialNumber, certSerial,
@@ -30638,6 +30677,7 @@ static int generate_crl_test(const char* keyFile, const char* certFile,
3063830677
ExpectIntEQ(XMEMCMP(rev->serialNumber,
3063930678
serialsToRevokeBytes[idx], rev->serialSz), 0);
3064030679
}
30680+
#endif
3064130681
revokedCount++;
3064230682
rev = rev->next;
3064330683
}
@@ -30713,6 +30753,12 @@ static int test_wolfSSL_X509_CRL_sign_large(void)
3071330753
XFILE fp = XBADFILE;
3071430754
int i;
3071530755
byte serial[4];
30756+
#if defined(CRL_STATIC_REVOKED_LIST) && CRL_MAX_REVOKED_CERTS < 1024
30757+
/* The static list holds at most CRL_MAX_REVOKED_CERTS entries */
30758+
const int numRevoked = CRL_MAX_REVOKED_CERTS;
30759+
#else
30760+
const int numRevoked = 1024;
30761+
#endif
3071630762

3071730763
ExpectTrue((fp = XFOPEN(testRsaCertFile, "rb")) != XBADFILE);
3071830764
if (fp != XBADFILE) {
@@ -30743,14 +30789,22 @@ static int test_wolfSSL_X509_CRL_sign_large(void)
3074330789
revoked.serialNumber->length = (int)sizeof(serial);
3074430790
}
3074530791

30746-
for (i = 1; i <= 1024; i++) {
30792+
for (i = 1; i <= numRevoked; i++) {
3074730793
serial[0] = (byte)(i & 0xff);
3074830794
serial[1] = (byte)((i >> 8) & 0xff);
3074930795
serial[2] = (byte)((i >> 16) & 0xff);
3075030796
serial[3] = (byte)((i >> 24) & 0xff);
3075130797
ExpectIntEQ(wolfSSL_X509_CRL_add_revoked(crl, &revoked),
3075230798
WOLFSSL_SUCCESS);
3075330799
}
30800+
#ifdef CRL_STATIC_REVOKED_LIST
30801+
if (numRevoked == CRL_MAX_REVOKED_CERTS) {
30802+
/* Full, so the next one is refused the same way the parser does */
30803+
serial[0] = (byte)(i & 0xff);
30804+
ExpectIntEQ(wolfSSL_X509_CRL_add_revoked(crl, &revoked),
30805+
WC_NO_ERR_TRACE(MEMORY_E));
30806+
}
30807+
#endif
3075430808

3075530809
ExpectTrue((fp = XFOPEN(testRsaKeyFile, "rb")) != XBADFILE);
3075630810
if (fp != XBADFILE) {

‎tests/api/test_certman.c‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2648,6 +2648,34 @@ int test_wolfSSL_CRL_static_revoked_list(void)
26482648
sizeof_server_cert_der_2048), WC_NO_ERR_TRACE(CRL_CERT_REVOKED));
26492649

26502650
wolfSSL_CertManagerFree(cm);
2651+
2652+
#if defined(OPENSSL_EXTRA) && !defined(NO_BIO) && defined(XSNPRINTF) && \
2653+
!defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM)
2654+
{
2655+
/* The compat layer walks the revoked list through next, so the static
2656+
* array has to be chained for every entry, not just the first. Before
2657+
* the fix get_REVOKED returned 1 entry and X509_CRL_print crashed. */
2658+
WOLFSSL_X509_CRL* crl = NULL;
2659+
WOLFSSL_BIO* bio = NULL;
2660+
char* out = NULL;
2661+
2662+
ExpectNotNull(crl = wolfSSL_d2i_X509_CRL(NULL, crl_multi_revoked,
2663+
(int)sizeof(crl_multi_revoked)));
2664+
ExpectIntEQ(wolfSSL_sk_X509_REVOKED_num(
2665+
wolfSSL_X509_CRL_get_REVOKED(crl)), 3);
2666+
2667+
ExpectNotNull(bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem()));
2668+
ExpectIntEQ(wolfSSL_X509_CRL_print(bio, crl), WOLFSSL_SUCCESS);
2669+
ExpectIntEQ(wolfSSL_BIO_write(bio, "", 1), 1);
2670+
ExpectIntGT(wolfSSL_BIO_get_mem_data(bio, &out), 0);
2671+
ExpectNotNull(out ? XSTRSTR(out, "Serial Number: 1 (0x1)") : NULL);
2672+
ExpectNotNull(out ? XSTRSTR(out, "Serial Number: 2 (0x2)") : NULL);
2673+
ExpectNotNull(out ? XSTRSTR(out, "Serial Number: 5 (0x5)") : NULL);
2674+
2675+
wolfSSL_BIO_free(bio);
2676+
wolfSSL_X509_CRL_free(crl);
2677+
}
2678+
#endif
26512679
#endif
26522680
return EXPECT_RESULT();
26532681
}

0 commit comments

Comments
 (0)