CRL enhancements for revoked entries

This commit is contained in:
Paul Adelsbach
2026-02-27 15:26:17 -08:00
parent 1c8d593af7
commit 22d7550f8e
10 changed files with 570 additions and 56 deletions
+73 -13
View File
@@ -42,6 +42,9 @@ CRL Options:
#include <wolfssl/wolfcrypt/logging.h>
#include <wolfssl/wolfcrypt/ecc.h>
#include <wolfssl/wolfcrypt/rsa.h>
#if defined(OPENSSL_EXTRA)
#include <wolfssl/openssl/x509v3.h>
#endif
#ifndef NO_STRING_H
#include <string.h>
@@ -93,6 +96,9 @@ int InitCRL(WOLFSSL_CRL* crl, WOLFSSL_CERT_MANAGER* cm)
(void)ret;
}
#endif
#if defined(OPENSSL_EXTRA)
crl->revokedStack = NULL;
#endif
return 0;
}
@@ -250,6 +256,14 @@ static void CRL_Entry_free(CRL_Entry* crle, void* heap)
return;
}
#ifdef CRL_STATIC_REVOKED_LIST
#if defined(OPENSSL_EXTRA)
{
int i;
for (i = 0; i < CRL_MAX_REVOKED_CERTS; i++) {
XFREE(crle->certs[i].extensions, heap, DYNAMIC_TYPE_REVOKED);
}
}
#endif
XMEMSET(crle->certs, 0, CRL_MAX_REVOKED_CERTS*sizeof(RevokedCert));
#else
{
@@ -258,6 +272,9 @@ static void CRL_Entry_free(CRL_Entry* crle, void* heap)
for (tmp = crle->certs; tmp != NULL; tmp = next) {
next = tmp->next;
#if defined(OPENSSL_EXTRA)
XFREE(tmp->extensions, heap, DYNAMIC_TYPE_REVOKED);
#endif
XFREE(tmp, heap, DYNAMIC_TYPE_REVOKED);
}
@@ -312,6 +329,12 @@ void FreeCRL(WOLFSSL_CRL* crl, int dynamic)
XFREE(crl->monitors[1].path, crl->heap, DYNAMIC_TYPE_CRL_MONITOR);
#endif
#if defined(OPENSSL_EXTRA)
if (crl->revokedStack != NULL) {
wolfSSL_sk_pop_free(crl->revokedStack, NULL);
crl->revokedStack = NULL;
}
#endif
XFREE(crl->currentEntry, crl->heap, DYNAMIC_TYPE_CRL_ENTRY);
crl->currentEntry = NULL;
while(tmp) {
@@ -1231,6 +1254,20 @@ static RevokedCert *DupRevokedCertList(RevokedCert* in, void* heap)
XMEMCPY(tmp->revDate, current->revDate,
MAX_DATE_SIZE);
tmp->revDateFormat = current->revDateFormat;
tmp->reasonCode = current->reasonCode;
#if defined(OPENSSL_EXTRA)
tmp->extensions = NULL;
tmp->extensionsSz = 0;
if (current->extensions != NULL && current->extensionsSz > 0) {
tmp->extensions = (byte*)XMALLOC(current->extensionsSz, heap,
DYNAMIC_TYPE_REVOKED);
if (tmp->extensions != NULL) {
XMEMCPY(tmp->extensions, current->extensions,
current->extensionsSz);
tmp->extensionsSz = current->extensionsSz;
}
}
#endif
tmp->next = NULL;
if (prev != NULL)
prev->next = tmp;
@@ -1244,6 +1281,9 @@ static RevokedCert *DupRevokedCertList(RevokedCert* in, void* heap)
while (head != NULL) {
current = head;
head = head->next;
#if defined(OPENSSL_EXTRA)
XFREE(current->extensions, heap, DYNAMIC_TYPE_REVOKED);
#endif
XFREE(current, heap, DYNAMIC_TYPE_REVOKED);
}
return NULL;
@@ -2360,10 +2400,8 @@ WOLFSSL_X509_CRL* wolfSSL_X509_CRL_new(void)
#ifdef WOLFSSL_CERT_GEN
/* Add a revoked certificate entry to CRL.
* crl: target CRL
* rev: serial number of revoked certificate
* rev: revoked certificate entry (serial, date, reason, etc.)
* Returns WOLFSSL_SUCCESS on success.
* TODO: support other fields for OpenSSL compatibility: revocationDate,
* extensions, issuer, etc.
*/
int wolfSSL_X509_CRL_add_revoked(WOLFSSL_X509_CRL* crl,
WOLFSSL_X509_REVOKED* rev)
@@ -2371,7 +2409,6 @@ int wolfSSL_X509_CRL_add_revoked(WOLFSSL_X509_CRL* crl,
CRL_Entry* entry;
RevokedCert* rc;
RevokedCert* curr;
WOLFSSL_ASN1_TIME revDate;
WOLFSSL_ENTER("wolfSSL_X509_CRL_add_revoked");
@@ -2379,16 +2416,14 @@ int wolfSSL_X509_CRL_add_revoked(WOLFSSL_X509_CRL* crl,
return BAD_FUNC_ARG;
}
entry = crl->crlList;
if (entry == NULL) {
if (rev->revocationDate != NULL && (rev->revocationDate->length <= 0 ||
(unsigned)rev->revocationDate->length > sizeof(rc->revDate))) {
return BAD_FUNC_ARG;
}
/* Set the revocation date to the current time */
XMEMSET(&revDate, 0, sizeof(revDate));
if (wolfSSL_ASN1_TIME_adj(&revDate, XTIME(NULL), 0, 0) == NULL) {
WOLFSSL_MSG("Failed to get current time");
return BAD_STATE_E;
entry = crl->crlList;
if (entry == NULL) {
return BAD_FUNC_ARG;
}
{
@@ -2427,8 +2462,25 @@ int wolfSSL_X509_CRL_add_revoked(WOLFSSL_X509_CRL* crl,
rc->serialSz = serialSz;
}
XMEMCPY(rc->revDate, revDate.data, revDate.length);
rc->revDateFormat = (byte)revDate.type;
/* Use caller-provided revocation date, or fall back to current time */
if (rev->revocationDate != NULL && rev->revocationDate->length > 0) {
XMEMCPY(rc->revDate, rev->revocationDate->data,
(size_t)rev->revocationDate->length);
rc->revDateFormat = (byte)rev->revocationDate->type;
}
else {
WOLFSSL_ASN1_TIME revDate;
XMEMSET(&revDate, 0, sizeof(revDate));
if (wolfSSL_ASN1_TIME_adj(&revDate, XTIME(NULL), 0, 0) == NULL) {
WOLFSSL_MSG("Failed to get current time");
XFREE(rc, crl->heap, DYNAMIC_TYPE_REVOKED);
return BAD_STATE_E;
}
XMEMCPY(rc->revDate, revDate.data, revDate.length);
rc->revDateFormat = (byte)revDate.type;
}
rc->reasonCode = rev->reason;
rc->next = NULL;
/* Add to end of list */
@@ -2442,6 +2494,12 @@ int wolfSSL_X509_CRL_add_revoked(WOLFSSL_X509_CRL* crl,
}
entry->totalCerts++;
/* Invalidate cached STACK_OF(X509_REVOKED) since list changed */
if (crl->revokedStack != NULL) {
wolfSSL_sk_pop_free(crl->revokedStack, NULL);
crl->revokedStack = NULL;
}
WOLFSSL_LEAVE("wolfSSL_X509_CRL_add_revoked", WOLFSSL_SUCCESS);
return WOLFSSL_SUCCESS;
}
@@ -2513,7 +2571,9 @@ int wolfSSL_X509_CRL_add_revoked_cert(WOLFSSL_X509_CRL* crl,
XMEMCPY(serialInt->data, cert->serial, cert->serialSz);
serialInt->length = cert->serialSz;
XMEMSET(&revoked, 0, sizeof(revoked));
revoked.serialNumber = serialInt;
revoked.reason = CRL_REASON_NONE;
/* Add the revoked certificate entry */
ret = wolfSSL_X509_CRL_add_revoked(crl, &revoked);
+9
View File
@@ -168,6 +168,7 @@ static void* wolfssl_sk_node_get_data(WOLFSSL_STACK* node, int no_static)
case STACK_TYPE_X509_OBJ:
case STACK_TYPE_DIST_POINT:
case STACK_TYPE_X509_CRL:
case STACK_TYPE_X509_REVOKED:
case STACK_TYPE_GENERAL_SUBTREE:
default:
ret = node->data.generic;
@@ -213,6 +214,7 @@ static void wolfssl_sk_node_set_data(WOLFSSL_STACK* node, WOLF_STACK_TYPE type,
case STACK_TYPE_X509_OBJ:
case STACK_TYPE_DIST_POINT:
case STACK_TYPE_X509_CRL:
case STACK_TYPE_X509_REVOKED:
case STACK_TYPE_GENERAL_SUBTREE:
default:
node->data.generic = (void*)data;
@@ -494,6 +496,7 @@ static int wolfssl_sk_dup_data(WOLFSSL_STACK* dst, WOLFSSL_STACK* src)
case STACK_TYPE_BY_DIR_entry:
case STACK_TYPE_BY_DIR_hash:
case STACK_TYPE_DIST_POINT:
case STACK_TYPE_X509_REVOKED:
case STACK_TYPE_GENERAL_SUBTREE:
default:
WOLFSSL_MSG("Unsupported stack type");
@@ -688,6 +691,7 @@ void* wolfSSL_sk_value(const WOLFSSL_STACK* sk, int i)
case STACK_TYPE_X509_OBJ:
case STACK_TYPE_DIST_POINT:
case STACK_TYPE_X509_CRL:
case STACK_TYPE_X509_REVOKED:
case STACK_TYPE_GENERAL_SUBTREE:
default:
val = sk->data.generic;
@@ -940,6 +944,11 @@ static wolfSSL_sk_freefunc wolfssl_sk_get_free_func(WOLF_STACK_TYPE type)
func = (wolfSSL_sk_freefunc)wolfSSL_X509_CRL_free;
#endif
break;
case STACK_TYPE_X509_REVOKED:
#if defined(HAVE_CRL) && defined(OPENSSL_EXTRA)
func = (wolfSSL_sk_freefunc)wolfSSL_X509_REVOKED_free;
#endif
break;
case STACK_TYPE_CIPHER:
/* Static copy kept in node. */
case STACK_TYPE_NULL:
+178 -20
View File
@@ -9571,16 +9571,16 @@ const WOLFSSL_ASN1_INTEGER* wolfSSL_X509_REVOKED_get0_serial_number(const
return NULL;
}
#ifndef NO_WOLFSSL_STUB
const WOLFSSL_ASN1_TIME* wolfSSL_X509_REVOKED_get0_revocation_date(const
WOLFSSL_X509_REVOKED *rev)
{
WOLFSSL_STUB("wolfSSL_X509_REVOKED_get0_revocation_date");
WOLFSSL_ENTER("wolfSSL_X509_REVOKED_get0_revocation_date");
(void) rev;
if (rev != NULL) {
return rev->revocationDate;
}
return NULL;
}
#endif
#ifndef NO_BIO
@@ -10760,34 +10760,192 @@ WOLFSSL_ASN1_TIME* wolfSSL_X509_gmtime_adj(WOLFSSL_ASN1_TIME *s, long adj)
}
#endif
#ifndef NO_WOLFSSL_STUB
int wolfSSL_sk_X509_REVOKED_num(WOLFSSL_X509_REVOKED* revoked)
int wolfSSL_sk_X509_REVOKED_num(WOLFSSL_STACK* sk)
{
(void)revoked;
WOLFSSL_STUB("sk_X509_REVOKED_num");
WOLFSSL_ENTER("wolfSSL_sk_X509_REVOKED_num");
if (sk != NULL) {
return (int)sk->num;
}
return 0;
}
#endif
#ifndef NO_WOLFSSL_STUB
WOLFSSL_X509_REVOKED* wolfSSL_X509_CRL_get_REVOKED(WOLFSSL_X509_CRL* crl)
/* Free a WOLFSSL_X509_REVOKED and all its owned memory. */
void wolfSSL_X509_REVOKED_free(WOLFSSL_X509_REVOKED* rev)
{
(void)crl;
WOLFSSL_STUB("X509_CRL_get_REVOKED");
if (rev == NULL) {
return;
}
wolfSSL_ASN1_INTEGER_free(rev->serialNumber);
wolfSSL_ASN1_TIME_free(rev->revocationDate);
if (rev->extensions != NULL) {
wolfSSL_sk_pop_free(rev->extensions, NULL);
}
if (rev->issuer != NULL) {
wolfSSL_sk_pop_free(rev->issuer, NULL);
}
XFREE(rev, NULL, DYNAMIC_TYPE_OPENSSL);
}
#ifdef HAVE_CRL
/* Build a WOLFSSL_X509_REVOKED from an internal RevokedCert.
* Caller takes ownership of the returned object. */
static WOLFSSL_X509_REVOKED* RevokedCertToRevoked(RevokedCert* rc, int seq)
{
WOLFSSL_X509_REVOKED* rev;
WOLFSSL_ASN1_INTEGER* serial;
if (rc == NULL) {
return NULL;
}
rev = (WOLFSSL_X509_REVOKED*)XMALLOC(sizeof(WOLFSSL_X509_REVOKED), NULL,
DYNAMIC_TYPE_OPENSSL);
if (rev == NULL) {
return NULL;
}
XMEMSET(rev, 0, sizeof(WOLFSSL_X509_REVOKED));
/* Serial number */
serial = wolfSSL_ASN1_INTEGER_new();
if (serial == NULL) {
XFREE(rev, NULL, DYNAMIC_TYPE_OPENSSL);
return NULL;
}
if (rc->serialSz > 0 && rc->serialSz <= EXTERNAL_SERIAL_SIZE) {
serial->data = (unsigned char*)XMALLOC((size_t)rc->serialSz, NULL,
DYNAMIC_TYPE_OPENSSL);
if (serial->data == NULL) {
wolfSSL_ASN1_INTEGER_free(serial);
XFREE(rev, NULL, DYNAMIC_TYPE_OPENSSL);
return NULL;
}
XMEMCPY(serial->data, rc->serialNumber, (size_t)rc->serialSz);
serial->length = rc->serialSz;
serial->dataMax = rc->serialSz;
serial->isDynamic = 1;
}
rev->serialNumber = serial;
/* Revocation date */
{
WOLFSSL_ASN1_TIME* revDate = wolfSSL_ASN1_TIME_new();
if (revDate != NULL) {
int dateLen = 0;
/* Determine date length from the format byte */
if (rc->revDateFormat == ASN_UTC_TIME ||
rc->revDateFormat == ASN_GENERALIZED_TIME) {
/* Find actual length: dates are null-terminated strings in
* revDate buffer up to MAX_DATE_SIZE */
while (dateLen < MAX_DATE_SIZE && rc->revDate[dateLen] != 0)
dateLen++;
}
if (dateLen > 0 && dateLen < MAX_DATE_SIZE) {
XMEMCPY(revDate->data, rc->revDate, (size_t)dateLen);
revDate->length = dateLen;
revDate->type = rc->revDateFormat;
}
}
rev->revocationDate = revDate;
}
/* Reason code */
rev->reason = rc->reasonCode;
/* Sequence (load order) */
rev->sequence = seq;
/* issuer: left as NULL (indirect CRL not yet supported) */
/* extensions: left as NULL for now (raw DER available in RevokedCert
* but decoded STACK_OF(X509_EXTENSION) build not yet implemented) */
return rev;
}
#endif /* HAVE_CRL */
WOLFSSL_STACK* wolfSSL_X509_CRL_get_REVOKED(WOLFSSL_X509_CRL* crl)
{
WOLFSSL_ENTER("wolfSSL_X509_CRL_get_REVOKED");
if (crl == NULL) {
return NULL;
}
#if defined(OPENSSL_EXTRA) && defined(HAVE_CRL)
/* Return cached stack if already built */
if (crl->revokedStack != NULL) {
return crl->revokedStack;
}
/* Build the stack from the internal RevokedCert linked list */
if (crl->crlList != NULL) {
WOLFSSL_STACK* sk;
RevokedCert* rc;
int seq = 0;
sk = wolfSSL_sk_new_null();
if (sk == NULL) {
return NULL;
}
sk->type = STACK_TYPE_X509_REVOKED;
for (rc = crl->crlList->certs; rc != NULL; rc = rc->next) {
WOLFSSL_X509_REVOKED* rev = RevokedCertToRevoked(rc, seq);
if (rev == NULL) {
/* Clean up on failure */
wolfSSL_sk_pop_free(sk, NULL);
return NULL;
}
/* Push to stack. wolfSSL_sk_push returns total count on success. */
if (wolfSSL_sk_push(sk, rev) <= 0) {
wolfSSL_X509_REVOKED_free(rev);
wolfSSL_sk_pop_free(sk, NULL);
return NULL;
}
seq++;
}
crl->revokedStack = sk;
return sk;
}
#endif /* OPENSSL_EXTRA && HAVE_CRL */
return NULL;
}
#endif
#ifndef NO_WOLFSSL_STUB
WOLFSSL_X509_REVOKED* wolfSSL_sk_X509_REVOKED_value(
WOLFSSL_X509_REVOKED* revoked, int value)
WOLFSSL_STACK* sk, int idx)
{
(void)revoked;
(void)value;
WOLFSSL_STUB("sk_X509_REVOKED_value");
WOLFSSL_ENTER("wolfSSL_sk_X509_REVOKED_value");
if (sk == NULL) {
return NULL;
}
return (WOLFSSL_X509_REVOKED*)wolfSSL_sk_value(sk, idx);
}
/* Extension accessors for WOLFSSL_X509_REVOKED */
int wolfSSL_X509_REVOKED_get_ext_count(const WOLFSSL_X509_REVOKED* rev)
{
WOLFSSL_ENTER("wolfSSL_X509_REVOKED_get_ext_count");
if (rev != NULL && rev->extensions != NULL) {
return (int)rev->extensions->num;
}
return 0;
}
WOLFSSL_X509_EXTENSION* wolfSSL_X509_REVOKED_get_ext(
const WOLFSSL_X509_REVOKED* rev, int loc)
{
WOLFSSL_ENTER("wolfSSL_X509_REVOKED_get_ext");
if (rev != NULL && rev->extensions != NULL) {
return (WOLFSSL_X509_EXTENSION*)wolfSSL_sk_value(rev->extensions, loc);
}
return NULL;
}
#endif
#endif /* OPENSSL_EXTRA */
+109 -11
View File
@@ -20956,6 +20956,9 @@ static int test_sk_X509_CRL_decode(void)
WOLFSSL_ASN1_INTEGER* asnInt = NULL;
const WOLFSSL_ASN1_INTEGER* sn = NULL;
XMEMSET(&revoked, 0, sizeof(revoked));
revoked.reason = CRL_REASON_NONE;
#if (!defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM)) || \
!defined(NO_BIO)
XMEMSET(&empty, 0, sizeof(X509_CRL));
@@ -21075,13 +21078,32 @@ static int test_sk_X509_CRL_decode(void)
WOLFSSL_SUCCESS);
ExpectIntEQ(len, 1);
#ifndef NO_WOLFSSL_STUB
/* Test X509_CRL_get_REVOKED and stack iteration */
ExpectIntEQ(wolfSSL_sk_X509_REVOKED_num(NULL), 0);
ExpectIntEQ(wolfSSL_sk_X509_REVOKED_num(&revoked), 0);
ExpectNull(wolfSSL_X509_CRL_get_REVOKED(NULL));
ExpectNull(wolfSSL_X509_CRL_get_REVOKED(crl));
ExpectNull(wolfSSL_sk_X509_REVOKED_value(NULL, 0));
ExpectNull(wolfSSL_sk_X509_REVOKED_value(&revoked, 0));
{
WOLFSSL_STACK* revokedSk = NULL;
ExpectNotNull(revokedSk = wolfSSL_X509_CRL_get_REVOKED(crl));
if (revokedSk != NULL) {
int numRevoked = wolfSSL_sk_X509_REVOKED_num(revokedSk);
ExpectIntGT(numRevoked, 0);
/* Verify first revoked entry has a serial number */
{
WOLFSSL_X509_REVOKED* r = NULL;
ExpectNotNull(r = wolfSSL_sk_X509_REVOKED_value(revokedSk, 0));
if (r != NULL) {
ExpectNotNull(r->serialNumber);
/* Verify revocation date is populated */
ExpectNotNull(
wolfSSL_X509_REVOKED_get0_revocation_date(r));
/* Verify sequence field (first entry should be 0) */
ExpectIntEQ(r->sequence, 0);
}
}
}
ExpectNull(wolfSSL_sk_X509_REVOKED_value(NULL, 0));
}
#ifndef NO_WOLFSSL_STUB
ExpectIntEQ(wolfSSL_X509_CRL_verify(NULL, NULL), 0);
ExpectIntEQ(X509_OBJECT_set1_X509_CRL(NULL, NULL), 0);
ExpectIntEQ(X509_OBJECT_set1_X509(NULL, NULL), 0);
@@ -21097,10 +21119,9 @@ static int test_sk_X509_CRL_decode(void)
ExpectNull(wolfSSL_X509_REVOKED_get0_serial_number(NULL));
ExpectNotNull(sn = wolfSSL_X509_REVOKED_get0_serial_number(&revoked));
ExpectPtrEq(sn, asnInt);
#ifndef NO_WOLFSSL_STUB
ExpectNull(wolfSSL_X509_REVOKED_get0_revocation_date(NULL));
/* revoked on stack has no revocationDate set, so should be NULL */
ExpectNull(wolfSSL_X509_REVOKED_get0_revocation_date(&revoked));
#endif
wolfSSL_ASN1_INTEGER_free(asnInt);
ExpectTrue((fp = XFOPEN("./certs/crl/crl.pem", "rb")) != XBADFILE);
@@ -21130,6 +21151,71 @@ static int test_sk_X509_CRL_decode(void)
return EXPECT_RESULT();
}
#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && !defined(NO_CERTS) && \
defined(HAVE_CRL) && defined(WOLFSSL_CERT_GEN)
/* Ensure oversized caller-provided revocationDate is rejected. */
static int test_wolfSSL_X509_CRL_add_revoked_oversized_revocation_date(void)
{
EXPECT_DECLS;
WOLFSSL_X509_CRL* crl = NULL;
WOLFSSL_ASN1_INTEGER* serial = NULL;
WOLFSSL_X509_REVOKED revoked;
WOLFSSL_ASN1_TIME revDate;
byte serialData[] = { 0x01 };
XMEMSET(&revoked, 0, sizeof(revoked));
XMEMSET(&revDate, 0, sizeof(revDate));
ExpectNotNull(crl = wolfSSL_X509_CRL_new());
ExpectNotNull(serial = wolfSSL_ASN1_INTEGER_new());
if (serial != NULL) {
serial->data = serialData;
serial->dataMax = (int)sizeof(serialData);
serial->length = (int)sizeof(serialData);
serial->isDynamic = 0;
}
revDate.length = MAX_DATE_SIZE + 1; /* intentionally too large */
revDate.type = ASN_GENERALIZED_TIME;
revoked.serialNumber = serial;
revoked.revocationDate = &revDate;
revoked.reason = CRL_REASON_NONE;
ExpectIntEQ(wolfSSL_X509_CRL_add_revoked(crl, &revoked), BAD_FUNC_ARG);
wolfSSL_ASN1_INTEGER_free(serial);
wolfSSL_X509_CRL_free(crl);
return EXPECT_RESULT();
}
#endif
#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && !defined(NO_CERTS) && \
defined(HAVE_CRL) && !defined(NO_FILESYSTEM) && \
!defined(NO_STDIO_FILESYSTEM)
/* Ensure reason-code parsing handles optional critical BOOLEAN in entry ext. */
static int test_wolfSSL_X509_CRL_reason_critical_boolean(void)
{
EXPECT_DECLS;
int reasonCode = CRL_REASON_NONE;
/* One Extension SEQUENCE with:
* OID: 2.5.29.21 (CRL Reason Code)
* critical: TRUE
* extnValue: OCTET STRING wrapping ENUMERATED 2 (CA compromise) */
static const byte ext[] = {
0x30, 0x0d, 0x06, 0x03, 0x55, 0x1d, 0x15,
0x01, 0x01, 0xff, 0x04, 0x03, 0x0a, 0x01, 0x02
};
ExpectIntEQ(wc_ParseCRLReasonFromExtensions(ext, (word32)sizeof(ext),
&reasonCode), 0);
ExpectIntEQ(reasonCode, CRL_REASON_CA_COMPROMISE);
return EXPECT_RESULT();
}
#endif
#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && !defined(NO_CERTS) && \
defined(HAVE_CRL) && !defined(NO_FILESYSTEM) && \
!defined(NO_STDIO_FILESYSTEM) && defined(WOLFSSL_CERT_GEN)
@@ -21176,9 +21262,9 @@ static int generate_crl_test(const char* keyFile, const char* certFile,
.type = 0 }
};
WOLFSSL_X509_REVOKED revoked[3] = {
{ .serialNumber = &serialsToRevoke[0] },
{ .serialNumber = &serialsToRevoke[1] },
{ .serialNumber = &serialsToRevoke[2] }
{ .serialNumber = &serialsToRevoke[0], .reason = CRL_REASON_NONE },
{ .serialNumber = &serialsToRevoke[1], .reason = CRL_REASON_NONE },
{ .serialNumber = &serialsToRevoke[2], .reason = CRL_REASON_NONE }
};
WOLFSSL_X509* certToRevoke = NULL;
@@ -21451,7 +21537,10 @@ static int test_wolfSSL_X509_CRL_sign_large(void)
ExpectIntEQ(wolfSSL_X509_CRL_set_nextUpdate(crl, &asnTime),
WOLFSSL_SUCCESS);
ExpectNotNull(revoked.serialNumber = wolfSSL_ASN1_INTEGER_new());
XMEMSET(&revoked, 0, sizeof(revoked));
revoked.serialNumber = wolfSSL_ASN1_INTEGER_new();
ExpectNotNull(revoked.serialNumber);
revoked.reason = CRL_REASON_NONE;
if (revoked.serialNumber != NULL) {
revoked.serialNumber->data = serial;
revoked.serialNumber->length = (int)sizeof(serial);
@@ -32804,6 +32893,15 @@ TEST_CASE testCases[] = {
TEST_DECL(test_sk_X509),
/* OpenSSL sk_X509_CRL API test */
TEST_DECL(test_sk_X509_CRL_decode),
#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && !defined(NO_CERTS) && \
defined(HAVE_CRL) && defined(WOLFSSL_CERT_GEN)
TEST_DECL(test_wolfSSL_X509_CRL_add_revoked_oversized_revocation_date),
#endif
#if (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) && !defined(NO_CERTS) && \
defined(HAVE_CRL) && !defined(NO_FILESYSTEM) && \
!defined(NO_STDIO_FILESYSTEM)
TEST_DECL(test_wolfSSL_X509_CRL_reason_critical_boolean),
#endif
TEST_DECL(test_sk_X509_CRL_encode),
TEST_DECL(test_wolfSSL_X509_CRL_sign_large),
+149 -5
View File
@@ -2760,7 +2760,7 @@ static int SetASNNull(byte* output)
#endif
#ifndef NO_CERTS
#ifndef WOLFSSL_ASN_TEMPLATE
#if !defined(WOLFSSL_ASN_TEMPLATE) || defined(HAVE_CRL)
/* Get the DER/BER encoding of an ASN.1 BOOLEAN.
*
* input Buffer holding DER/BER encoded data.
@@ -2770,7 +2770,7 @@ static int SetASNNull(byte* output)
* ASN_PARSE_E when the BOOLEAN tag is not found or length is not 1.
* Otherwise, 0 to indicate the value was false and 1 to indicate true.
*/
static int GetBoolean(const byte* input, word32* inOutIdx, word32 maxIdx)
WC_MAYBE_UNUSED static int GetBoolean(const byte* input, word32* inOutIdx, word32 maxIdx)
{
word32 idx = *inOutIdx;
byte b;
@@ -2790,7 +2790,7 @@ static int GetBoolean(const byte* input, word32* inOutIdx, word32 maxIdx)
*inOutIdx = idx;
return b;
}
#endif
#endif /* !WOLFSSL_ASN_TEMPLATE || HAVE_CRL */
#endif /* !NO_CERTS*/
@@ -41047,6 +41047,77 @@ enum {
#define revokedASN_Length (sizeof(revokedASN) / sizeof(ASNItem))
#endif
/* CRL Reason Code OID: 2.5.29.21 */
static const byte crlReasonOid[] = { 0x55, 0x1d, 0x15 };
/* Parse CRL entry extensions to extract the reason code.
* Sets *reasonCode if found, otherwise leaves it unchanged. */
static void ParseCRL_ReasonCode(const byte* buff, word32 idx, word32 maxIdx,
int* reasonCode)
{
while (idx < maxIdx) {
int len;
word32 end;
word32 localIdx;
byte tag;
/* Each extension is a SEQUENCE */
if (GetSequence(buff, &idx, &len, maxIdx) < 0) {
break;
}
end = idx + (word32)len;
/* Check for CRL Reason OID: 2.5.29.21 */
if (end - idx >= (word32)(2 + sizeof(crlReasonOid)) &&
buff[idx] == ASN_OBJECT_ID &&
buff[idx + 1] == sizeof(crlReasonOid) &&
XMEMCMP(buff + idx + 2, crlReasonOid,
sizeof(crlReasonOid)) == 0) {
/* Skip past the OID */
idx += 2 + (word32)sizeof(crlReasonOid);
/* Skip optional critical BOOLEAN */
localIdx = idx;
if (GetASNTag(buff, &localIdx, &tag, end) == 0 &&
tag == ASN_BOOLEAN) {
/* Consume full BOOLEAN TLV (tag + length + value). */
if (GetBoolean(buff, &idx, end) < 0) {
break;
}
}
/* Get OCTET STRING wrapping the ENUMERATED */
if (GetOctetString(buff, &idx, &len, end) >= 0) {
/* Parse ENUMERATED reason value */
localIdx = idx;
if (GetASNTag(buff, &localIdx, &tag, end) == 0 &&
tag == ASN_ENUMERATED) {
int reasonLen;
idx = localIdx;
if (GetLength(buff, &idx, &reasonLen, end) >= 0 &&
reasonLen == 1) {
*reasonCode = (int)buff[idx];
}
}
}
}
idx = end;
}
}
#ifdef HAVE_CRL
/* Test-visible helper: parse reasonCode from encoded Extension list bytes. */
WOLFSSL_TEST_VIS int wc_ParseCRLReasonFromExtensions(const byte* ext,
word32 extSz,
int* reasonCode)
{
if (ext == NULL || reasonCode == NULL) {
return BAD_FUNC_ARG;
}
ParseCRL_ReasonCode(ext, 0, extSz, reasonCode);
return 0;
}
#endif
/* Get Revoked Cert list, 0 on success */
static int GetRevoked(RevokedCert* rcert, const byte* buff, word32* idx,
DecodedCRL* dcrl, word32 maxIdx)
@@ -41087,6 +41158,7 @@ static int GetRevoked(RevokedCert* rcert, const byte* buff, word32* idx,
WOLFSSL_MSG("Alloc Revoked Cert failed");
return MEMORY_E;
}
XMEMSET(rc, 0, sizeof(RevokedCert));
ret = wc_GetSerialNumber(buff, idx, rc->serialNumber, &rc->serialSz,maxIdx);
if (ret < 0) {
WOLFSSL_MSG("wc_GetSerialNumber error");
@@ -41108,7 +41180,41 @@ static int GetRevoked(RevokedCert* rcert, const byte* buff, word32* idx,
return ret;
}
#endif
/* skip extensions */
/* Initialize reason code to absent */
rc->reasonCode = -1;
/* Parse CRL entry extensions if present */
if (*idx < end) {
word32 extIdx = *idx;
int extLen;
byte tag;
/* Check for SEQUENCE tag (extensions wrapper) */
if (GetASNTag(buff, &extIdx, &tag, end) == 0 &&
tag == (ASN_SEQUENCE | ASN_CONSTRUCTED)) {
word32 seqIdx = extIdx - 1; /* back up to re-read tag */
if (GetSequence(buff, &seqIdx, &extLen, end) >= 0) {
word32 extEnd = seqIdx + (word32)extLen;
#if defined(OPENSSL_EXTRA)
/* Store raw DER of extensions for OpenSSL compat API */
{
word32 rawStart = *idx;
word32 rawLen = end - rawStart;
rc->extensions = (byte*)XMALLOC(rawLen, dcrl->heap,
DYNAMIC_TYPE_REVOKED);
if (rc->extensions != NULL) {
XMEMCPY(rc->extensions, buff + rawStart, rawLen);
rc->extensionsSz = rawLen;
}
}
#endif
ParseCRL_ReasonCode(buff, seqIdx, extEnd, &rc->reasonCode);
}
}
}
*idx = end;
return 0;
@@ -41134,6 +41240,9 @@ static int GetRevoked(RevokedCert* rcert, const byte* buff, word32* idx,
if (rc == NULL) {
ret = MEMORY_E;
}
if (ret == 0) {
XMEMSET(rc, 0, sizeof(RevokedCert));
}
#endif /* CRL_STATIC_REVOKED_LIST */
CALLOC_ASNGETDATA(dataASN, revokedASN_Length, ret, dcrl->heap);
@@ -41158,7 +41267,39 @@ static int GetRevoked(RevokedCert* rcert, const byte* buff, word32* idx,
? dataASN[REVOKEDASN_IDX_TIME_UTC].tag
: dataASN[REVOKEDASN_IDX_TIME_GT].tag;
/* TODO: use extensions, only v2 */
/* Initialize reason code to absent */
rc->reasonCode = -1;
/* Parse CRL entry extensions (v2 only) */
if (dataASN[REVOKEDASN_IDX_TIME_EXT].length > 0) {
word32 extOff = dataASN[REVOKEDASN_IDX_TIME_EXT].offset;
word32 extLen = dataASN[REVOKEDASN_IDX_TIME_EXT].length;
word32 extEnd = extOff + extLen;
word32 extIdx2 = extOff;
#if defined(OPENSSL_EXTRA)
/* Store raw DER of extensions for OpenSSL compat API.
* Include the outer SEQUENCE tag+length. */
{
/* Back up to include the SEQUENCE header. We know the
* content starts at extOff, so the header is just before.
* Use the raw buffer start from before GetASN_Items. */
word32 seqHdrSz = 0;
/* The outer SEQUENCE header is at most 4 bytes before
* content. Rather than guess, store just the content. */
rc->extensions = (byte*)XMALLOC(extLen, dcrl->heap,
DYNAMIC_TYPE_REVOKED);
if (rc->extensions != NULL) {
XMEMCPY(rc->extensions, buff + extOff, extLen);
rc->extensionsSz = extLen;
}
(void)seqHdrSz;
}
#endif
ParseCRL_ReasonCode(buff, extIdx2, extEnd, &rc->reasonCode);
}
/* Add revoked certificate to chain. */
#ifndef CRL_STATIC_REVOKED_LIST
rc->next = dcrl->certs;
@@ -41170,6 +41311,9 @@ static int GetRevoked(RevokedCert* rcert, const byte* buff, word32* idx,
FREE_ASNGETDATA(dataASN, dcrl->heap);
#ifndef CRL_STATIC_REVOKED_LIST
if ((ret != 0) && (rc != NULL)) {
#if defined(OPENSSL_EXTRA)
XFREE(rc->extensions, dcrl->heap, DYNAMIC_TYPE_REVOKED);
#endif
XFREE(rc, dcrl->heap, DYNAMIC_TYPE_CRL);
}
(void)rcert;
+5
View File
@@ -2589,6 +2589,9 @@ struct WOLFSSL_CRL {
#endif
#ifdef OPENSSL_ALL
wolfSSL_Ref ref;
#endif
#if defined(OPENSSL_EXTRA)
WOLFSSL_STACK* revokedStack; /* cached STACK_OF(X509_REVOKED) */
#endif
void* heap; /* heap hint for dynamic memory */
};
@@ -5318,6 +5321,7 @@ typedef enum {
STACK_TYPE_X509_NAME_ENTRY = 17,
STACK_TYPE_X509_REQ_ATTR = 18,
STACK_TYPE_GENERAL_SUBTREE = 19,
STACK_TYPE_X509_REVOKED = 20,
} WOLF_STACK_TYPE;
#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
@@ -5352,6 +5356,7 @@ struct WOLFSSL_STACK {
WOLFSSL_X509_OBJECT* x509_obj;
WOLFSSL_DIST_POINT* dp;
WOLFSSL_X509_CRL* crl;
WOLFSSL_X509_REVOKED* revoked;
} data;
void* heap; /* memory heap hint */
WOLFSSL_STACK* next;
+3
View File
@@ -882,6 +882,9 @@ wolfSSL_X509_STORE_set_verify_cb((WOLFSSL_X509_STORE *)(s), (WOLFSSL_X509_STORE_
#define X509_REVOKED_get0_serialNumber wolfSSL_X509_REVOKED_get0_serial_number
#define X509_REVOKED_get0_revocationDate wolfSSL_X509_REVOKED_get0_revocation_date
#define X509_REVOKED_free wolfSSL_X509_REVOKED_free
#define X509_REVOKED_get_ext_count wolfSSL_X509_REVOKED_get_ext_count
#define X509_REVOKED_get_ext wolfSSL_X509_REVOKED_get_ext
#define X509_check_purpose(x, id, ca) 0
+18
View File
@@ -98,6 +98,24 @@ struct WOLFSSL_X509_EXTENSION {
#define WOLFSSL_GEN_RID 8
#define WOLFSSL_GEN_IA5 9
/* CRL reason codes per RFC 5280 section 5.3.1 */
#ifndef CRL_REASON_UNSPECIFIED
#ifndef CRL_REASON_NONE
#define CRL_REASON_NONE (-1)
#endif
#define CRL_REASON_UNSPECIFIED 0
#define CRL_REASON_KEY_COMPROMISE 1
#define CRL_REASON_CA_COMPROMISE 2
#define CRL_REASON_AFFILIATION_CHANGED 3
#define CRL_REASON_SUPERSEDED 4
#define CRL_REASON_CESSATION_OF_OPERATION 5
#define CRL_REASON_CERTIFICATE_HOLD 6
/* value 7 is not used */
#define CRL_REASON_REMOVE_FROM_CRL 8
#define CRL_REASON_PRIVILEGE_WITHDRAWN 9
#define CRL_REASON_AA_COMPROMISE 10
#endif
typedef WOLF_STACK_OF(WOLFSSL_ACCESS_DESCRIPTION) WOLFSSL_AUTHORITY_INFO_ACCESS;
WOLFSSL_API WOLFSSL_BASIC_CONSTRAINTS* wolfSSL_BASIC_CONSTRAINTS_new(void);
+16 -7
View File
@@ -885,10 +885,14 @@ struct WOLFSSL_X509_VERIFY_PARAM {
#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */
typedef struct WOLFSSL_X509_REVOKED {
WOLFSSL_ASN1_INTEGER* serialNumber; /* stunnel dereference */
/* TODO: add other fields to match OpenSSL's X509_REVOKED
* (struct x509_revoked_st) such as revocationDate, extensions, etc.
* Then update wolfSSL_X509_CRL_add_revoked to handle those fields. */
WOLFSSL_ASN1_INTEGER* serialNumber; /* certificate serial number */
WOLFSSL_ASN1_TIME* revocationDate; /* revocation date */
WOLFSSL_STACK* extensions; /* STACK_OF(X509_EXTENSION) */
WOLFSSL_STACK* issuer; /* STACK_OF(GENERAL_NAME) for
* indirect CRL (currently NULL) */
int reason; /* CRL reason code, -1 if absent */
int sequence; /* tracks original order of entries
* in the CRL for iteration */
} WOLFSSL_X509_REVOKED;
typedef enum {
@@ -2447,7 +2451,7 @@ WOLFSSL_API WOLFSSL_ASN1_TIME *wolfSSL_X509_time_adj(WOLFSSL_ASN1_TIME *asnTime,
long offset_sec, time_t *in_tm);
WOLFSSL_API WOLFSSL_ASN1_TIME* wolfSSL_X509_gmtime_adj(WOLFSSL_ASN1_TIME* s,
long adj);
WOLFSSL_API int wolfSSL_sk_X509_REVOKED_num(WOLFSSL_X509_REVOKED* revoked);
WOLFSSL_API int wolfSSL_sk_X509_REVOKED_num(WOLFSSL_STACK* sk);
WOLFSSL_API void wolfSSL_X509_STORE_CTX_set_time(WOLFSSL_X509_STORE_CTX* ctx,
unsigned long flags,
time_t t);
@@ -2479,9 +2483,9 @@ WOLFSSL_API int wolfSSL_X509_load_crl_file(WOLFSSL_X509_LOOKUP *ctx,
WOLFSSL_API int wolfSSL_X509_load_cert_crl_file(WOLFSSL_X509_LOOKUP *ctx,
const char *file, int type);
#endif
WOLFSSL_API WOLFSSL_X509_REVOKED* wolfSSL_X509_CRL_get_REVOKED(WOLFSSL_X509_CRL* crl);
WOLFSSL_API WOLFSSL_STACK* wolfSSL_X509_CRL_get_REVOKED(WOLFSSL_X509_CRL* crl);
WOLFSSL_API WOLFSSL_X509_REVOKED* wolfSSL_sk_X509_REVOKED_value(
WOLFSSL_X509_REVOKED* revoked,int value);
WOLFSSL_STACK* sk, int idx);
WOLFSSL_API WOLFSSL_ASN1_INTEGER* wolfSSL_X509_get_serialNumber(WOLFSSL_X509* x509);
WOLFSSL_API void wolfSSL_ASN1_INTEGER_free(WOLFSSL_ASN1_INTEGER* in);
WOLFSSL_API WOLFSSL_ASN1_INTEGER* wolfSSL_ASN1_INTEGER_new(void);
@@ -3589,6 +3593,11 @@ const WOLFSSL_ASN1_INTEGER* wolfSSL_X509_REVOKED_get0_serial_number(const
WOLFSSL_API
const WOLFSSL_ASN1_TIME* wolfSSL_X509_REVOKED_get0_revocation_date(const
WOLFSSL_X509_REVOKED *rev);
WOLFSSL_API void wolfSSL_X509_REVOKED_free(WOLFSSL_X509_REVOKED* rev);
WOLFSSL_API int wolfSSL_X509_REVOKED_get_ext_count(
const WOLFSSL_X509_REVOKED* rev);
WOLFSSL_API WOLFSSL_X509_EXTENSION* wolfSSL_X509_REVOKED_get_ext(
const WOLFSSL_X509_REVOKED* rev, int loc);
#ifndef NO_FILESYSTEM
#ifndef NO_STDIO_FILESYSTEM
+10
View File
@@ -2412,6 +2412,11 @@ WOLFSSL_LOCAL int wc_ValidateDateWithTime(const byte* date, byte format,
#endif
WOLFSSL_TEST_VIS int wc_AsnSetSkipDateCheck(int skip_p);
WOLFSSL_LOCAL int wc_AsnGetSkipDateCheck(void);
#ifdef HAVE_CRL
WOLFSSL_TEST_VIS int wc_ParseCRLReasonFromExtensions(const byte* ext,
word32 extSz,
int* reasonCode);
#endif
/* ASN.1 helper functions */
#ifdef WOLFSSL_CERT_GEN
@@ -2842,6 +2847,11 @@ struct RevokedCert {
RevokedCert* next;
byte revDate[MAX_DATE_SIZE];
byte revDateFormat;
int reasonCode; /* CRL reason code, -1 if absent */
#if defined(OPENSSL_EXTRA)
byte* extensions; /* raw DER of crlEntryExtensions */
word32 extensionsSz;
#endif
};
#ifndef CRL_MAX_NUM_SZ