mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-08-11 05:01:19 +02:00
Merge pull request #10821 from wolfSSL/feature/x509-no-malloc-verify
Add true zero-allocation X.509 certificate verification under WOLFSSL_NO_MALLOC
This commit is contained in:
@@ -82,6 +82,12 @@ jobs:
|
||||
"--enable-staticmemory",
|
||||
"CFLAGS=-DWOLFSSL_NO_MALLOC -pedantic -Wdeclaration-after-statement -Wnull-dereference -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"],
|
||||
"check": false,
|
||||
"run": [["./wolfcrypt/test/testwolfcrypt"]]},
|
||||
{"name": "no-heap-cert", "minutes": 0.8,
|
||||
"configure": ["--enable-rsa", "--enable-keygen", "--enable-ecc",
|
||||
"--enable-acert", "--disable-dh", "--disable-filesystem",
|
||||
"CFLAGS=-DWOLFSSL_NO_MALLOC -DNO_WOLFSSL_MEMORY -DRSA_MIN_SIZE=1024 -DWOLFSSL_TEST_CERT -DUSE_CERT_BUFFERS_2048 -DUSE_CERT_BUFFERS_256 -pedantic -Wdeclaration-after-statement -Wnull-dereference -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"],
|
||||
"check": false,
|
||||
"run": [["./wolfcrypt/test/testwolfcrypt"]]}
|
||||
]
|
||||
EOF
|
||||
|
||||
+133
-37
@@ -156,6 +156,15 @@ ASN Options:
|
||||
* WOLFSSL_ALLOW_CRIT_AKID: Allow critical Auth Key Identifier
|
||||
* WOLFSSL_ALLOW_CRIT_SKID: Allow critical Subject Key Identifier
|
||||
* WC_ASN_UNKNOWN_EXT_CB: Callback for unknown extensions
|
||||
* WC_ASN_NO_HEAP: Zero-allocation cert parse: reference key/alt-name
|
||||
data in the source DER instead of heap copies, so the source buffer must
|
||||
outlive the DecodedCert. Auto-defined when WOLFSSL_NO_MALLOC and
|
||||
NO_WOLFSSL_MEMORY are set without XMALLOC_USER or WOLFSSL_STATIC_MEMORY.
|
||||
Limitation: IP and registeredID SAN entries need a parsed string form that
|
||||
has no in-place source, so such certs are rejected with ASN_PARSE_E. SAN
|
||||
DNS_entry.name is NOT NUL-terminated in this mode; only .len is authoritative.
|
||||
* WC_ASN_MAX_ALTNAMES: No-heap SAN pool slot count (default 8); excess
|
||||
subject alternative names are rejected.
|
||||
*
|
||||
* ASN.1 Parsing:
|
||||
* WOLFSSL_ASN_ALL: Enable all ASN.1 features
|
||||
@@ -12579,7 +12588,14 @@ void FreeAltNames(DNS_entry* altNames, void* heap)
|
||||
altNames->ridStringStored = 0;
|
||||
}
|
||||
#endif
|
||||
XFREE(altNames, heap, DYNAMIC_TYPE_ALTNAME);
|
||||
#ifdef WC_ASN_NO_HEAP
|
||||
/* Only free heap nodes; no-heap pool nodes aren't owned. */
|
||||
if (altNames->entryStored) {
|
||||
XFREE(altNames, heap, DYNAMIC_TYPE_ALTNAME);
|
||||
}
|
||||
#else
|
||||
XFREE(altNames, heap, DYNAMIC_TYPE_ALTNAME);
|
||||
#endif
|
||||
altNames = tmp;
|
||||
}
|
||||
}
|
||||
@@ -12591,6 +12607,9 @@ DNS_entry* AltNameNew(void* heap)
|
||||
ret = (DNS_entry*)XMALLOC(sizeof(DNS_entry), heap, DYNAMIC_TYPE_ALTNAME);
|
||||
if (ret != NULL) {
|
||||
XMEMSET(ret, 0, sizeof(DNS_entry));
|
||||
#ifdef WC_ASN_NO_HEAP
|
||||
ret->entryStored = 1; /* heap-allocated node; FreeAltNames frees it */
|
||||
#endif
|
||||
}
|
||||
(void)heap;
|
||||
return ret;
|
||||
@@ -12739,7 +12758,9 @@ static int StoreKey(DecodedCert* cert, const byte* source, word32* srcIdx,
|
||||
{
|
||||
int ret;
|
||||
int length;
|
||||
#ifndef WC_ASN_NO_HEAP
|
||||
byte* publicKey;
|
||||
#endif
|
||||
|
||||
ret = CheckBitString(source, srcIdx, &length, maxIdx, 1, NULL);
|
||||
if (ret == 0) {
|
||||
@@ -12749,6 +12770,17 @@ static int StoreKey(DecodedCert* cert, const byte* source, word32* srcIdx,
|
||||
}
|
||||
if (ret == 0) {
|
||||
#endif
|
||||
#ifdef WC_ASN_NO_HEAP
|
||||
/* No heap: reference the key in place; source must outlive the cert. */
|
||||
cert->publicKey = (byte*)&source[*srcIdx];
|
||||
cert->pubKeyStored = 0;
|
||||
cert->pubKeySize = (word32)length;
|
||||
#ifdef HAVE_OCSP_RESPONDER
|
||||
cert->publicKeyForHash = cert->publicKey;
|
||||
cert->pubKeyForHashSize = cert->pubKeySize;
|
||||
#endif
|
||||
*srcIdx += (word32)length;
|
||||
#else
|
||||
publicKey = (byte*)XMALLOC((size_t)length, cert->heap,
|
||||
DYNAMIC_TYPE_PUBLIC_KEY);
|
||||
if (publicKey == NULL) {
|
||||
@@ -12767,6 +12799,7 @@ static int StoreKey(DecodedCert* cert, const byte* source, word32* srcIdx,
|
||||
|
||||
*srcIdx += (word32)length;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -13407,7 +13440,9 @@ static int StoreEccKey(DecodedCert* cert, const byte* source, word32* srcIdx,
|
||||
{
|
||||
int ret = 0;
|
||||
DECL_ASNGETDATA(dataASN, eccCertKeyASN_Length);
|
||||
#ifndef WC_ASN_NO_HEAP
|
||||
byte* publicKey;
|
||||
#endif
|
||||
|
||||
/* Validate parameters. */
|
||||
if (pubKey == NULL) {
|
||||
@@ -13477,6 +13512,12 @@ static int StoreEccKey(DecodedCert* cert, const byte* source, word32* srcIdx,
|
||||
#endif
|
||||
/* Store public key data length. */
|
||||
cert->pubKeySize = pubKeyLen;
|
||||
#ifdef WC_ASN_NO_HEAP
|
||||
/* No heap: point at pubKey in the input DER, so that buffer must stay
|
||||
* valid for the DecodedCert's lifetime. */
|
||||
cert->publicKey = (byte*)pubKey;
|
||||
cert->pubKeyStored = 0;
|
||||
#else
|
||||
/* Must allocated space for key.
|
||||
* Don't memcpy into constant pointer so use temp. */
|
||||
publicKey = (byte*)XMALLOC(cert->pubKeySize, cert->heap,
|
||||
@@ -13491,6 +13532,7 @@ static int StoreEccKey(DecodedCert* cert, const byte* source, word32* srcIdx,
|
||||
/* Indicate publicKey needs to be freed. */
|
||||
cert->pubKeyStored = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
FREE_ASNGETDATA(dataASN, cert->heap);
|
||||
|
||||
@@ -14357,7 +14399,7 @@ static const byte rdnChoice[] = {
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_IP_ALT_NAME
|
||||
#if defined(WOLFSSL_IP_ALT_NAME) && !defined(WC_ASN_NO_HEAP)
|
||||
/* used to set the human readable string for the IP address with a ASN_IP_TYPE
|
||||
* DNS entry
|
||||
* return 0 on success
|
||||
@@ -14426,9 +14468,9 @@ static int GenerateDNSEntryIPString(DNS_entry* entry, void* heap)
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* WOLFSSL_IP_ALT_NAME */
|
||||
#endif /* WOLFSSL_IP_ALT_NAME && !WC_ASN_NO_HEAP */
|
||||
|
||||
#ifdef WOLFSSL_RID_ALT_NAME
|
||||
#if defined(WOLFSSL_RID_ALT_NAME) && !defined(WC_ASN_NO_HEAP)
|
||||
/* used to set the human readable string for the registeredID with an
|
||||
* ASN_RID_TYPE DNS entry
|
||||
* return 0 on success
|
||||
@@ -14525,7 +14567,7 @@ static int GenerateDNSEntryRIDString(DNS_entry* entry, void* heap)
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* WOLFSSL_RID_ALT_NAME */
|
||||
#endif /* WOLFSSL_RID_ALT_NAME && !WC_ASN_NO_HEAP */
|
||||
|
||||
#ifdef WOLFSSL_ASN_TEMPLATE
|
||||
|
||||
@@ -14574,13 +14616,57 @@ static int AddDNSEntryToList(DNS_entry** lst, DNS_entry* entry)
|
||||
* @return 0 on success.
|
||||
* @return MEMORY_E when dynamic memory allocation fails.
|
||||
*/
|
||||
static int SetDNSEntry(void* heap, const char* str, int strLen,
|
||||
int type, DNS_entry** entries)
|
||||
/* No-heap SAN entries come from a caller pool; pass NULL,NULL if none. */
|
||||
#ifdef WC_ASN_NO_HEAP
|
||||
#define WC_DNS_POOL(obj) (obj)->altNamePool, &(obj)->altNamePoolUsed
|
||||
#else
|
||||
#define WC_DNS_POOL(obj) NULL, NULL
|
||||
#endif
|
||||
|
||||
static int SetDNSEntry(void* heap, DNS_entry* pool, word32* poolUsed,
|
||||
const char* str, int strLen, int type,
|
||||
DNS_entry** entries)
|
||||
{
|
||||
DNS_entry* dnsEntry;
|
||||
int ret = 0;
|
||||
#ifndef WC_ASN_NO_HEAP
|
||||
char *dnsEntry_name = NULL;
|
||||
#endif
|
||||
|
||||
#ifdef WC_ASN_NO_HEAP
|
||||
/* No heap: borrow a pool slot; name points into the source DER. */
|
||||
(void)heap;
|
||||
#ifdef WOLFSSL_IP_ALT_NAME
|
||||
/* No-heap path can't parse an ipString/ridString; reject rather than skip. */
|
||||
if (type == ASN_IP_TYPE) {
|
||||
return ASN_PARSE_E;
|
||||
}
|
||||
#endif
|
||||
#ifdef WOLFSSL_RID_ALT_NAME
|
||||
if (type == ASN_RID_TYPE) {
|
||||
return ASN_PARSE_E;
|
||||
}
|
||||
#endif
|
||||
if ((pool == NULL) || (*poolUsed >= WC_ASN_MAX_ALTNAMES)) {
|
||||
/* Distinguish pool exhaustion from a real allocation failure. */
|
||||
WOLFSSL_MSG("No-heap SAN pool exhausted; raise WC_ASN_MAX_ALTNAMES");
|
||||
ret = MEMORY_E;
|
||||
dnsEntry = NULL;
|
||||
}
|
||||
else {
|
||||
dnsEntry = &pool[(*poolUsed)++];
|
||||
XMEMSET(dnsEntry, 0, sizeof(*dnsEntry));
|
||||
dnsEntry->type = type;
|
||||
dnsEntry->len = strLen;
|
||||
dnsEntry->name = (char*)str; /* points into the source DER */
|
||||
dnsEntry->nameStored = 0;
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = AddDNSEntryToList(entries, dnsEntry);
|
||||
}
|
||||
#else
|
||||
(void)pool;
|
||||
(void)poolUsed;
|
||||
/* TODO: consider one malloc. */
|
||||
/* Allocate DNS Entry object. */
|
||||
dnsEntry = AltNameNew(heap);
|
||||
@@ -14625,6 +14711,7 @@ static int SetDNSEntry(void* heap, const char* str, int strLen,
|
||||
XFREE(dnsEntry_name, heap, DYNAMIC_TYPE_ALTNAME);
|
||||
XFREE(dnsEntry, heap, DYNAMIC_TYPE_ALTNAME);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -14665,7 +14752,7 @@ int wc_SetDNSEntry(void* heap, const char* str, int strLen, int type,
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
return SetDNSEntry(heap, str, strLen, type, entries);
|
||||
return SetDNSEntry(heap, NULL, NULL, str, strLen, type, entries);
|
||||
}
|
||||
#endif /* WOLFSSL_CERT_GEN && WOLFSSL_ALT_NAMES */
|
||||
#endif
|
||||
@@ -19147,7 +19234,8 @@ static int DecodeOtherHelper(ASNGetData* dataASN, DecodedCert* cert, int oid)
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
ret = SetDNSEntry(cert->heap, buf, (int)bufLen, ASN_OTHER_TYPE, &entry);
|
||||
ret = SetDNSEntry(cert->heap, WC_DNS_POOL(cert), buf, (int)bufLen,
|
||||
ASN_OTHER_TYPE, &entry);
|
||||
if (ret == 0) {
|
||||
#ifdef WOLFSSL_FPKI
|
||||
entry->oidSum = oid;
|
||||
@@ -19209,8 +19297,8 @@ static int DecodeOtherName(DecodedCert* cert, const byte* input,
|
||||
break;
|
||||
default:
|
||||
WOLFSSL_MSG("\tadding unsupported OID");
|
||||
ret = SetDNSEntry(cert->heap, name, len, ASN_OTHER_TYPE,
|
||||
&cert->altNames);
|
||||
ret = SetDNSEntry(cert->heap, WC_DNS_POOL(cert), name, len,
|
||||
ASN_OTHER_TYPE, &cert->altNames);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -19248,8 +19336,9 @@ static int DecodeGeneralName(const byte* input, word32* inOutIdx, byte tag,
|
||||
* reference hostname. The result is DOMAIN_NAME_MISMATCH at verification
|
||||
* time rather than ASN_PARSE_E at parse time. */
|
||||
if (tag == (ASN_CONTEXT_SPECIFIC | ASN_DNS_TYPE)) {
|
||||
ret = SetDNSEntry(cert->heap, (const char*)(input + idx), len,
|
||||
ASN_DNS_TYPE, &cert->altNames);
|
||||
ret = SetDNSEntry(cert->heap, WC_DNS_POOL(cert),
|
||||
(const char*)(input + idx), len, ASN_DNS_TYPE,
|
||||
&cert->altNames);
|
||||
if (ret == 0) {
|
||||
idx += (word32)len;
|
||||
}
|
||||
@@ -19267,16 +19356,18 @@ static int DecodeGeneralName(const byte* input, word32* inOutIdx, byte tag,
|
||||
return ASN_PARSE_E;
|
||||
}
|
||||
|
||||
ret = SetDNSEntry(cert->heap, (const char*)(input + idxDir), strLen,
|
||||
ASN_DIR_TYPE, &cert->altDirNames);
|
||||
ret = SetDNSEntry(cert->heap, WC_DNS_POOL(cert),
|
||||
(const char*)(input + idxDir), strLen, ASN_DIR_TYPE,
|
||||
&cert->altDirNames);
|
||||
if (ret == 0) {
|
||||
idx += (word32)len;
|
||||
}
|
||||
}
|
||||
/* GeneralName choice: rfc822Name */
|
||||
else if (tag == (ASN_CONTEXT_SPECIFIC | ASN_RFC822_TYPE)) {
|
||||
ret = SetDNSEntry(cert->heap, (const char*)(input + idx), len,
|
||||
ASN_RFC822_TYPE, &cert->altEmailNames);
|
||||
ret = SetDNSEntry(cert->heap, WC_DNS_POOL(cert),
|
||||
(const char*)(input + idx), len, ASN_RFC822_TYPE,
|
||||
&cert->altEmailNames);
|
||||
if (ret == 0) {
|
||||
idx += (word32)len;
|
||||
}
|
||||
@@ -19322,8 +19413,9 @@ static int DecodeGeneralName(const byte* input, word32* inOutIdx, byte tag,
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = SetDNSEntry(cert->heap, (const char*)(input + idx), len,
|
||||
ASN_URI_TYPE, &cert->altNames);
|
||||
ret = SetDNSEntry(cert->heap, WC_DNS_POOL(cert),
|
||||
(const char*)(input + idx), len, ASN_URI_TYPE,
|
||||
&cert->altNames);
|
||||
if (ret == 0) {
|
||||
idx += (word32)len;
|
||||
}
|
||||
@@ -19355,8 +19447,9 @@ static int DecodeGeneralName(const byte* input, word32* inOutIdx, byte tag,
|
||||
* ASN_IP_TYPE case under WOLFSSL_GEN_IPADD in src/x509.c).
|
||||
*/
|
||||
else if (tag == (ASN_CONTEXT_SPECIFIC | ASN_IP_TYPE)) {
|
||||
ret = SetDNSEntry(cert->heap, (const char*)(input + idx), len,
|
||||
ASN_IP_TYPE, &cert->altNames);
|
||||
ret = SetDNSEntry(cert->heap, WC_DNS_POOL(cert),
|
||||
(const char*)(input + idx), len, ASN_IP_TYPE,
|
||||
&cert->altNames);
|
||||
if (ret == 0) {
|
||||
idx += (word32)len;
|
||||
}
|
||||
@@ -19387,8 +19480,9 @@ static int DecodeGeneralName(const byte* input, word32* inOutIdx, byte tag,
|
||||
* when ridString is not generated, instead of failing the
|
||||
* whole print operation. */
|
||||
else if (tag == (ASN_CONTEXT_SPECIFIC | ASN_RID_TYPE)) {
|
||||
ret = SetDNSEntry(cert->heap, (const char*)(input + idx), len,
|
||||
ASN_RID_TYPE, &cert->altNames);
|
||||
ret = SetDNSEntry(cert->heap, WC_DNS_POOL(cert),
|
||||
(const char*)(input + idx), len, ASN_RID_TYPE,
|
||||
&cert->altNames);
|
||||
if (ret == 0) {
|
||||
idx += (word32)len;
|
||||
}
|
||||
@@ -19403,8 +19497,9 @@ static int DecodeGeneralName(const byte* input, word32* inOutIdx, byte tag,
|
||||
* the public altNames view (used by OpenSSL-compat APIs) reflects
|
||||
* exactly what the SAN extension carries. */
|
||||
else if (tag == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | ASN_OTHER_TYPE)) {
|
||||
ret = SetDNSEntry(cert->heap, (const char*)(input + idx), len,
|
||||
ASN_OTHER_TYPE, &cert->altOtherNamesRaw);
|
||||
ret = SetDNSEntry(cert->heap, WC_DNS_POOL(cert),
|
||||
(const char*)(input + idx), len, ASN_OTHER_TYPE,
|
||||
&cert->altOtherNamesRaw);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
@@ -24372,6 +24467,7 @@ int FillSigner(Signer* signer, DecodedCert* cert, int type, DerBuffer *der)
|
||||
(void)der;
|
||||
#endif
|
||||
signer->keyOID = cert->keyOID;
|
||||
/* pubKeyStored stays 0 under WC_ASN_NO_HEAP (signer uses heap). */
|
||||
if (cert->pubKeyStored) {
|
||||
signer->publicKey = cert->publicKey;
|
||||
signer->pubKeySize = cert->pubKeySize;
|
||||
@@ -39002,8 +39098,8 @@ static int DecodeAcertGeneralName(const byte* input, word32* inOutIdx,
|
||||
|
||||
/* GeneralName choice: dnsName */
|
||||
if (tag == (ASN_CONTEXT_SPECIFIC | ASN_DNS_TYPE)) {
|
||||
ret = SetDNSEntry(acert->heap, (const char*)(input + idx), len,
|
||||
ASN_DNS_TYPE, entries);
|
||||
ret = SetDNSEntry(acert->heap, WC_DNS_POOL(acert),
|
||||
(const char*)(input + idx), len, ASN_DNS_TYPE, entries);
|
||||
if (ret == 0) {
|
||||
idx += (word32)len;
|
||||
}
|
||||
@@ -39021,16 +39117,16 @@ static int DecodeAcertGeneralName(const byte* input, word32* inOutIdx,
|
||||
return ASN_PARSE_E;
|
||||
}
|
||||
|
||||
ret = SetDNSEntry(acert->heap, (const char*)(input + idxDir), strLen,
|
||||
ASN_DIR_TYPE, entries);
|
||||
ret = SetDNSEntry(acert->heap, WC_DNS_POOL(acert),
|
||||
(const char*)(input + idxDir), strLen, ASN_DIR_TYPE, entries);
|
||||
if (ret == 0) {
|
||||
idx += (word32)len;
|
||||
}
|
||||
}
|
||||
/* GeneralName choice: rfc822Name */
|
||||
else if (tag == (ASN_CONTEXT_SPECIFIC | ASN_RFC822_TYPE)) {
|
||||
ret = SetDNSEntry(acert->heap, (const char*)(input + idx), len,
|
||||
ASN_RFC822_TYPE, entries);
|
||||
ret = SetDNSEntry(acert->heap, WC_DNS_POOL(acert),
|
||||
(const char*)(input + idx), len, ASN_RFC822_TYPE, entries);
|
||||
if (ret == 0) {
|
||||
idx += (word32)len;
|
||||
}
|
||||
@@ -39076,8 +39172,8 @@ static int DecodeAcertGeneralName(const byte* input, word32* inOutIdx,
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = SetDNSEntry(acert->heap, (const char*)(input + idx), len,
|
||||
ASN_URI_TYPE, entries);
|
||||
ret = SetDNSEntry(acert->heap, WC_DNS_POOL(acert),
|
||||
(const char*)(input + idx), len, ASN_URI_TYPE, entries);
|
||||
if (ret == 0) {
|
||||
idx += (word32)len;
|
||||
}
|
||||
@@ -39094,8 +39190,8 @@ static int DecodeAcertGeneralName(const byte* input, word32* inOutIdx,
|
||||
* IP-SAN compat layer). If iPAddress name-constraint enforcement is
|
||||
* ever extended to attribute certificates, this gate must drop. */
|
||||
else if (tag == (ASN_CONTEXT_SPECIFIC | ASN_IP_TYPE)) {
|
||||
ret = SetDNSEntry(acert->heap, (const char*)(input + idx), len,
|
||||
ASN_IP_TYPE, entries);
|
||||
ret = SetDNSEntry(acert->heap, WC_DNS_POOL(acert),
|
||||
(const char*)(input + idx), len, ASN_IP_TYPE, entries);
|
||||
if (ret == 0) {
|
||||
idx += (word32)len;
|
||||
}
|
||||
@@ -39105,8 +39201,8 @@ static int DecodeAcertGeneralName(const byte* input, word32* inOutIdx,
|
||||
#ifdef OPENSSL_ALL
|
||||
/* GeneralName choice: registeredID */
|
||||
else if (tag == (ASN_CONTEXT_SPECIFIC | ASN_RID_TYPE)) {
|
||||
ret = SetDNSEntry(acert->heap, (const char*)(input + idx), len,
|
||||
ASN_RID_TYPE, entries);
|
||||
ret = SetDNSEntry(acert->heap, WC_DNS_POOL(acert),
|
||||
(const char*)(input + idx), len, ASN_RID_TYPE, entries);
|
||||
if (ret == 0) {
|
||||
idx += (word32)len;
|
||||
}
|
||||
|
||||
@@ -1040,6 +1040,10 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t scrypt_test(void);
|
||||
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cert_test(void);
|
||||
static wc_test_ret_t fill_signer_twice_test(void);
|
||||
#endif
|
||||
#if defined(WOLFSSL_TEST_CERT) && defined(USE_CERT_BUFFERS_2048) && \
|
||||
!defined(NO_RSA)
|
||||
static wc_test_ret_t cert_no_malloc_test(void);
|
||||
#endif
|
||||
#if defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_TEST_CERT) && \
|
||||
!defined(NO_FILESYSTEM) && !defined(NO_RSA) && defined(WOLFSSL_GEN_CERT)
|
||||
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t certext_test(void);
|
||||
@@ -3098,6 +3102,14 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\
|
||||
TEST_PASS("FILL SIGNER test passed!\n");
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSL_TEST_CERT) && defined(USE_CERT_BUFFERS_2048) && \
|
||||
!defined(NO_RSA)
|
||||
if ( (ret = cert_no_malloc_test()) != 0)
|
||||
TEST_FAIL("CERT NOMALLOC test failed!\n", ret);
|
||||
else
|
||||
TEST_PASS("CERT NOMALLOC test passed!\n");
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_TEST_CERT) && \
|
||||
!defined(NO_FILESYSTEM) && !defined(NO_RSA) && defined(WOLFSSL_GEN_CERT)
|
||||
if ( (ret = certext_test()) != 0)
|
||||
@@ -26387,6 +26399,85 @@ done:
|
||||
}
|
||||
#endif /* WOLFSSL_TEST_CERT */
|
||||
|
||||
#if defined(WOLFSSL_TEST_CERT) && defined(USE_CERT_BUFFERS_2048) && \
|
||||
!defined(NO_RSA)
|
||||
/* Heap/file-free parse from a const DER buffer; checks in-place refs under
|
||||
* WC_ASN_NO_HEAP. Kept outside the NO_FILESYSTEM cert block so it runs in real
|
||||
* no-malloc/no-filesystem builds. */
|
||||
static wc_test_ret_t cert_no_malloc_test(void)
|
||||
{
|
||||
DecodedCert cert;
|
||||
wc_test_ret_t ret;
|
||||
#if defined(WC_ASN_NO_HEAP) && !defined(WOLFSSL_IP_ALT_NAME)
|
||||
DNS_entry* dns;
|
||||
#endif
|
||||
|
||||
WOLFSSL_ENTER("cert_no_malloc_test");
|
||||
|
||||
#if defined(WC_ASN_NO_HEAP) && defined(WOLFSSL_IP_ALT_NAME)
|
||||
/* server_cert_der_2048 carries an IP SAN that the no-heap path fail-closes
|
||||
* (rejection is gated on WOLFSSL_IP_ALT_NAME); confirm it rather than a
|
||||
* successful parse. */
|
||||
InitDecodedCert(&cert, server_cert_der_2048, sizeof_server_cert_der_2048,
|
||||
NULL);
|
||||
ret = ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL);
|
||||
FreeDecodedCert(&cert);
|
||||
if (ret != WC_NO_ERR_TRACE(ASN_PARSE_E)) {
|
||||
return WC_TEST_RET_ENC_NC;
|
||||
}
|
||||
ret = 0;
|
||||
#else
|
||||
InitDecodedCert(&cert, server_cert_der_2048, sizeof_server_cert_der_2048,
|
||||
NULL);
|
||||
ret = ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL);
|
||||
if ((ret == 0) && ((cert.publicKey == NULL) || (cert.pubKeySize == 0))) {
|
||||
ret = WC_TEST_RET_ENC_NC;
|
||||
}
|
||||
#ifdef WC_ASN_NO_HEAP
|
||||
if ((ret == 0) && ((cert.pubKeyStored != 0) ||
|
||||
((wc_ptr_t)cert.publicKey < (wc_ptr_t)cert.source) ||
|
||||
((wc_ptr_t)cert.publicKey >=
|
||||
(wc_ptr_t)cert.source + cert.maxIdx))) {
|
||||
ret = WC_TEST_RET_ENC_NC;
|
||||
}
|
||||
/* Every SAN node must reference the source DER in place, not a heap copy. */
|
||||
for (dns = cert.altNames; (ret == 0) && (dns != NULL); dns = dns->next) {
|
||||
if ((dns->entryStored != 0) ||
|
||||
((wc_ptr_t)dns->name < (wc_ptr_t)cert.source) ||
|
||||
((wc_ptr_t)dns->name >= (wc_ptr_t)cert.source + cert.maxIdx)) {
|
||||
ret = WC_TEST_RET_ENC_NC;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
FreeDecodedCert(&cert);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_ECC) && defined(USE_CERT_BUFFERS_256)
|
||||
/* ECC leaf with no IP/RID SAN: exercises StoreEccKey in-place key ref. */
|
||||
if (ret == 0) {
|
||||
InitDecodedCert(&cert, ca_ecc_cert_der_256,
|
||||
sizeof_ca_ecc_cert_der_256, NULL);
|
||||
ret = ParseCert(&cert, CERT_TYPE, NO_VERIFY, NULL);
|
||||
if ((ret == 0) &&
|
||||
((cert.publicKey == NULL) || (cert.pubKeySize == 0))) {
|
||||
ret = WC_TEST_RET_ENC_NC;
|
||||
}
|
||||
#ifdef WC_ASN_NO_HEAP
|
||||
if ((ret == 0) && ((cert.pubKeyStored != 0) ||
|
||||
((wc_ptr_t)cert.publicKey < (wc_ptr_t)cert.source) ||
|
||||
((wc_ptr_t)cert.publicKey >=
|
||||
(wc_ptr_t)cert.source + cert.maxIdx))) {
|
||||
ret = WC_TEST_RET_ENC_NC;
|
||||
}
|
||||
#endif
|
||||
FreeDecodedCert(&cert);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* WOLFSSL_TEST_CERT && USE_CERT_BUFFERS_2048 && !NO_RSA */
|
||||
|
||||
#if !defined(NO_ASN_TIME) && !defined(NO_RSA) && defined(WOLFSSL_TEST_CERT) && \
|
||||
!defined(NO_FILESYSTEM)
|
||||
/* Test that FillSigner clears pubKeyStored/subjectCNStored after transferring
|
||||
|
||||
+30
-1
@@ -1502,6 +1502,19 @@ enum KeyIdType {
|
||||
#define WOLFSSL_IP6_ADDR_LEN 16
|
||||
#endif /* OPENSSL_ALL || WOLFSSL_IP_ALT_NAME */
|
||||
|
||||
/* No allocator: reference key/alt-name data in the source DER, not copies. */
|
||||
#if defined(WOLFSSL_NO_MALLOC) && defined(NO_WOLFSSL_MEMORY) && \
|
||||
!defined(XMALLOC_USER) && !defined(WOLFSSL_STATIC_MEMORY)
|
||||
#define WC_ASN_NO_HEAP
|
||||
#endif
|
||||
|
||||
#ifdef WC_ASN_NO_HEAP
|
||||
#ifndef WC_ASN_MAX_ALTNAMES
|
||||
/* Total no-heap SAN pool slots across all lists; excess is rejected. */
|
||||
#define WC_ASN_MAX_ALTNAMES 8
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef struct DNS_entry DNS_entry;
|
||||
|
||||
struct DNS_entry {
|
||||
@@ -1509,7 +1522,8 @@ struct DNS_entry {
|
||||
int type; /* i.e. ASN_DNS_TYPE */
|
||||
int len; /* actual DNS len */
|
||||
const char*
|
||||
name; /* actual DNS name */
|
||||
name; /* actual DNS name; under WC_ASN_NO_HEAP this points into
|
||||
* the source DER and is NOT NUL-terminated - use len */
|
||||
int nameStored;
|
||||
#ifdef WOLFSSL_IP_ALT_NAME
|
||||
char* ipString; /* human readable form of IP address */
|
||||
@@ -1523,6 +1537,9 @@ struct DNS_entry {
|
||||
#ifdef WOLFSSL_FPKI
|
||||
int oidSum; /* provide oid sum for verification */
|
||||
#endif
|
||||
#ifdef WC_ASN_NO_HEAP
|
||||
WC_BITFIELD entryStored:1; /* 1 = heap node to free; 0 = no-heap pool node */
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef WOLFSSL_FPKI
|
||||
@@ -2231,6 +2248,12 @@ struct DecodedCert {
|
||||
/* Appended to preserve the offsets of existing members. */
|
||||
word32 extExtKeyUsageOidCnt; /* Number of EKU KeyPurposeIds seen,
|
||||
* recognized or not */
|
||||
#ifdef WC_ASN_NO_HEAP
|
||||
/* No-heap SAN pool; entries chain through altNames into the source DER.
|
||||
* Adds ~WC_ASN_MAX_ALTNAMES * sizeof(DNS_entry) of stack per parse. */
|
||||
DNS_entry altNamePool[WC_ASN_MAX_ALTNAMES];
|
||||
word32 altNamePoolUsed;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3)
|
||||
@@ -3278,6 +3301,12 @@ struct DecodedAcert {
|
||||
const byte * rawAttr; /* Not owned, points into raw acert. */
|
||||
word32 rawAttrLen;
|
||||
SignatureCtx sigCtx;
|
||||
#ifdef WC_ASN_NO_HEAP
|
||||
/* No-heap alt-name pool, used like DecodedCert.altNamePool.
|
||||
* Adds ~WC_ASN_MAX_ALTNAMES * sizeof(DNS_entry) of stack per parse. */
|
||||
DNS_entry altNamePool[WC_ASN_MAX_ALTNAMES];
|
||||
word32 altNamePoolUsed;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct DecodedAcert DecodedAcert;
|
||||
|
||||
Reference in New Issue
Block a user