Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 95 additions & 18 deletions wolfcrypt/src/asn.c
Original file line number Diff line number Diff line change
Expand Up @@ -12471,7 +12471,10 @@ void FreeAltNames(DNS_entry* altNames, void* heap)
altNames->ridStringStored = 0;
}
#endif
XFREE(altNames, heap, DYNAMIC_TYPE_ALTNAME);
/* Only free heap nodes; no-heap pool nodes aren't owned. */
if (altNames->entryStored) {
XFREE(altNames, heap, DYNAMIC_TYPE_ALTNAME);
}
altNames = tmp;
}
}
Expand All @@ -12483,6 +12486,7 @@ 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));
ret->entryStored = 1; /* heap-allocated node; FreeAltNames frees it */
}
(void)heap;
return ret;
Expand Down Expand Up @@ -12631,7 +12635,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) {
Expand All @@ -12641,6 +12647,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) {
Expand All @@ -12659,6 +12676,7 @@ static int StoreKey(DecodedCert* cert, const byte* source, word32* srcIdx,

*srcIdx += (word32)length;
}
#endif
}

return ret;
Expand Down Expand Up @@ -13299,7 +13317,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) {
Expand Down Expand Up @@ -13369,6 +13389,11 @@ 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: reference the key in place; source must outlive the cert. */
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,
Expand All @@ -13383,6 +13408,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);

Expand Down Expand Up @@ -14466,13 +14492,55 @@ 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 synthesise an ipString; 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)) {
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);
Expand Down Expand Up @@ -14517,6 +14585,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;
}
Expand Down Expand Up @@ -18813,7 +18882,7 @@ 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;
Expand Down Expand Up @@ -18875,7 +18944,7 @@ static int DecodeOtherName(DecodedCert* cert, const byte* input,
break;
default:
WOLFSSL_MSG("\tadding unsupported OID");
ret = SetDNSEntry(cert->heap, name, len, ASN_OTHER_TYPE,
ret = SetDNSEntry(cert->heap, WC_DNS_POOL(cert), name, len, ASN_OTHER_TYPE,
&cert->altNames);
break;
}
Expand Down Expand Up @@ -18925,7 +18994,7 @@ static int DecodeGeneralName(const byte* input, word32* inOutIdx, byte tag,
if (ret != 0) {
return ret;
}
ret = SetDNSEntry(cert->heap, (const char*)(input + idx), len,
ret = SetDNSEntry(cert->heap, WC_DNS_POOL(cert), (const char*)(input + idx), len,
ASN_DNS_TYPE, &cert->altNames);
if (ret == 0) {
idx += (word32)len;
Expand All @@ -18944,7 +19013,7 @@ static int DecodeGeneralName(const byte* input, word32* inOutIdx, byte tag,
return ASN_PARSE_E;
}

ret = SetDNSEntry(cert->heap, (const char*)(input + idxDir), strLen,
ret = SetDNSEntry(cert->heap, WC_DNS_POOL(cert), (const char*)(input + idxDir), strLen,
ASN_DIR_TYPE, &cert->altDirNames);
if (ret == 0) {
idx += (word32)len;
Expand All @@ -18956,7 +19025,7 @@ static int DecodeGeneralName(const byte* input, word32* inOutIdx, byte tag,
if (ret != 0) {
return ret;
}
ret = SetDNSEntry(cert->heap, (const char*)(input + idx), len,
ret = SetDNSEntry(cert->heap, WC_DNS_POOL(cert), (const char*)(input + idx), len,
ASN_RFC822_TYPE, &cert->altEmailNames);
if (ret == 0) {
idx += (word32)len;
Expand Down Expand Up @@ -19007,7 +19076,7 @@ static int DecodeGeneralName(const byte* input, word32* inOutIdx, byte tag,
}
#endif

ret = SetDNSEntry(cert->heap, (const char*)(input + idx), len,
ret = SetDNSEntry(cert->heap, WC_DNS_POOL(cert), (const char*)(input + idx), len,
ASN_URI_TYPE, &cert->altNames);
if (ret == 0) {
idx += (word32)len;
Expand Down Expand Up @@ -19040,7 +19109,7 @@ 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,
ret = SetDNSEntry(cert->heap, WC_DNS_POOL(cert), (const char*)(input + idx), len,
ASN_IP_TYPE, &cert->altNames);
if (ret == 0) {
idx += (word32)len;
Expand Down Expand Up @@ -19072,7 +19141,7 @@ 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,
ret = SetDNSEntry(cert->heap, WC_DNS_POOL(cert), (const char*)(input + idx), len,
ASN_RID_TYPE, &cert->altNames);
if (ret == 0) {
idx += (word32)len;
Expand All @@ -19088,7 +19157,7 @@ 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,
ret = SetDNSEntry(cert->heap, WC_DNS_POOL(cert), (const char*)(input + idx), len,
ASN_OTHER_TYPE, &cert->altOtherNamesRaw);
if (ret != 0) {
return ret;
Expand Down Expand Up @@ -23949,7 +24018,14 @@ int FillSigner(Signer* signer, DecodedCert* cert, int type, DerBuffer *der)
signer->publicKey = cert->publicKey;
signer->pubKeySize = cert->pubKeySize;
}
#ifdef WC_ASN_NO_HEAP
else if ((cert->publicKey != NULL) && (cert->pubKeySize > 0)) {
/* Borrowed key (points into source); fail rather than retain it. */
ret = MEMORY_E;
}
#endif

if (ret == 0) {
if (cert->subjectCNStored) {
signer->nameLen = cert->subjectCNLen;
signer->name = cert->subjectCN;
Expand Down Expand Up @@ -23992,6 +24068,7 @@ int FillSigner(Signer* signer, DecodedCert* cert, int type, DerBuffer *der)
cert->excludedNames = NULL;
#endif
signer->type = (byte)type;
}
}
return ret;
}
Expand Down Expand Up @@ -38532,7 +38609,7 @@ 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,
ret = SetDNSEntry(acert->heap, WC_DNS_POOL(acert), (const char*)(input + idx), len,
ASN_DNS_TYPE, entries);
if (ret == 0) {
idx += (word32)len;
Expand All @@ -38551,15 +38628,15 @@ static int DecodeAcertGeneralName(const byte* input, word32* inOutIdx,
return ASN_PARSE_E;
}

ret = SetDNSEntry(acert->heap, (const char*)(input + idxDir), strLen,
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,
ret = SetDNSEntry(acert->heap, WC_DNS_POOL(acert), (const char*)(input + idx), len,
ASN_RFC822_TYPE, entries);
if (ret == 0) {
idx += (word32)len;
Expand Down Expand Up @@ -38606,7 +38683,7 @@ static int DecodeAcertGeneralName(const byte* input, word32* inOutIdx,
}
#endif

ret = SetDNSEntry(acert->heap, (const char*)(input + idx), len,
ret = SetDNSEntry(acert->heap, WC_DNS_POOL(acert), (const char*)(input + idx), len,
ASN_URI_TYPE, entries);
if (ret == 0) {
idx += (word32)len;
Expand All @@ -38624,7 +38701,7 @@ 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,
ret = SetDNSEntry(acert->heap, WC_DNS_POOL(acert), (const char*)(input + idx), len,
ASN_IP_TYPE, entries);
if (ret == 0) {
idx += (word32)len;
Expand All @@ -38635,7 +38712,7 @@ 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,
ret = SetDNSEntry(acert->heap, WC_DNS_POOL(acert), (const char*)(input + idx), len,
ASN_RID_TYPE, entries);
if (ret == 0) {
idx += (word32)len;
Expand Down
37 changes: 37 additions & 0 deletions wolfcrypt/test/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -25950,6 +25950,39 @@ static wc_test_ret_t cert_bad_asn1_test(void)
return ret;
}

#if 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. */
static wc_test_ret_t cert_no_malloc_test(void)
{
DecodedCert cert;
wc_test_ret_t ret;

WOLFSSL_ENTER("cert_no_malloc_test");

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) ||
(cert.publicKey < cert.source) ||
(cert.publicKey >= cert.source + cert.maxIdx))) {
ret = WC_TEST_RET_ENC_NC;
}
if ((ret == 0) && (cert.altNames != NULL) &&
(cert.altNames->entryStored != 0)) {
ret = WC_TEST_RET_ENC_NC;
}
#endif
FreeDecodedCert(&cert);

return ret;
}
#endif /* USE_CERT_BUFFERS_2048 && !NO_RSA */

WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cert_test(void)
{
#if !defined(NO_FILESYSTEM)
Expand Down Expand Up @@ -26025,6 +26058,10 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cert_test(void)
ret = cert_asn1_test();
if (ret == 0)
ret = cert_bad_asn1_test();
#if defined(USE_CERT_BUFFERS_2048) && !defined(NO_RSA)
if (ret == 0)
ret = cert_no_malloc_test();
#endif

return ret;
}
Expand Down
Loading
Loading