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
150 changes: 150 additions & 0 deletions doc/dox_comments/header_files/asn_public.h
Original file line number Diff line number Diff line change
Expand Up @@ -1067,6 +1067,156 @@ int wc_SetSubjectBuffer(Cert* cert, const byte* der, int derSz);
*/
int wc_SetAltNamesBuffer(Cert* cert, const byte* der, int derSz);

/*!
\ingroup ASN

\brief This function allocates a single subject alternative name (SAN)
entry, copies the supplied name into it, sets its GeneralName type and
length, and appends it to the linked list pointed to by entries. The name
is duplicated internally, so the caller's buffer need not outlive the call.
The resulting list can be encoded with wc_FlattenAltNames and must be freed
with FreeAltNames.

\return 0 Returned on success.
\return MEMORY_E Returned if dynamic memory allocation fails.
\return BAD_FUNC_ARG Returned if str or entries is NULL, or strLen is
negative; also returned for an ASN_IP_TYPE entry whose length is not a
valid IPv4/IPv6 address, or an ASN_RID_TYPE entry with malformed contents.
\return BUFFER_E Returned if the string representation of an ASN_IP_TYPE or
ASN_RID_TYPE entry does not fit its internal buffer.
\return Other negative error codes may propagate from generating the string
form of ASN_IP_TYPE and ASN_RID_TYPE entries.

\param heap pointer to the heap hint used for allocations (may be NULL)
\param str pointer to the name bytes (e.g. a DNS string, or raw IP octets
for ASN_IP_TYPE)
\param strLen length of str in bytes
\param type GeneralName type (e.g. ASN_DNS_TYPE, ASN_IP_TYPE,
ASN_RFC822_TYPE, ASN_URI_TYPE)
\param entries in/out pointer to the head of the alt-name linked list; a new
entry is appended

_Example_
\code
DNS_entry* list = NULL;
if (wc_SetDNSEntry(NULL, "example.com", 11, ASN_DNS_TYPE, &list) != 0) {
// error adding alt name
}
// ... encode with wc_FlattenAltNames, then:
FreeAltNames(list, NULL);
\endcode

\note This helper (along with wc_FlattenAltNames and FreeAltNames) is
exported from the library only when WOLFSSL_PUBLIC_ASN, OPENSSL_EXTRA,
OPENSSL_EXTRA_X509_SMALL, or WOLFSSL_TEST_CERT is defined; its prototype
lives in wolfssl/wolfcrypt/asn.h (not asn_public.h) because it uses the
DNS_entry type.

\note This function is gated by WOLFSSL_ASN_TEMPLATE, WOLFSSL_CERT_GEN, and
WOLFSSL_ALT_NAMES, matching its companions wc_FlattenAltNames and
wc_SetAltNamesFromList, so a DNS_entry list built here can always be encoded
by a public API in the same build.

\sa wc_FlattenAltNames
\sa FreeAltNames
*/
int wc_SetDNSEntry(void* heap, const char* str, int strLen, int type,
DNS_entry** entries);

/*!
\ingroup ASN

\brief This function encodes a linked list of subject alternative name
entries into the DER GeneralNames SEQUENCE used as the value of the
subjectAltName certificate extension. The output is suitable for assigning
to Cert.altNames (with the return value stored in Cert.altNamesSz) prior to
signing.

\return >0 the number of bytes written to output (the full SEQUENCE,
including its tag and length).
\return 0 Returned when names is NULL (nothing to encode).
\return BAD_FUNC_ARG Returned if output is NULL.
\return BUFFER_E Returned if output is too small to hold the encoding.

\param output buffer that receives the DER GeneralNames SEQUENCE; size it to
hold the full extension value (e.g. CTC_MAX_ALT_SIZE)
\param outputSz capacity of output in bytes
\param names head of the alt-name linked list to encode (e.g. built with
wc_SetDNSEntry, or taken from a parsed DecodedCert.altNames)

_Example_
\code
Cert cert;
DNS_entry* list = NULL;
// ... populate list with wc_SetDNSEntry ...
int n = wc_FlattenAltNames(cert.altNames, sizeof(cert.altNames), list);
if (n < 0) {
// error encoding alt names
}
cert.altNamesSz = n;
FreeAltNames(list, NULL);
\endcode

\note This helper (along with wc_SetDNSEntry and FreeAltNames) is exported
from the library only when WOLFSSL_PUBLIC_ASN, OPENSSL_EXTRA,
OPENSSL_EXTRA_X509_SMALL, or WOLFSSL_TEST_CERT is defined; its prototype
lives in wolfssl/wolfcrypt/asn.h (not asn_public.h) because it uses the
DNS_entry type.

\sa wc_SetDNSEntry
\sa wc_SetAltNamesFromList
\sa FreeAltNames
\sa wc_SetAltNamesBuffer
*/
int wc_FlattenAltNames(byte* output, word32 outputSz, const DNS_entry* names);

/*!
\ingroup ASN

\brief This function encodes a linked list of subject alternative name
entries directly into a Cert structure, ready for signing. It is a
convenience wrapper around wc_FlattenAltNames: the list is encoded into
cert->altNames and the encoded length is stored in cert->altNamesSz, so the
caller does not have to manage the buffer or size bookkeeping. The supplied
list is not consumed and must still be freed by the caller with
FreeAltNames.

\return 0 Returned on success.
\return BAD_FUNC_ARG Returned if cert is NULL.
\return BUFFER_E Returned if the encoded names do not fit in cert->altNames.

\param cert pointer to the Cert whose altNames/altNamesSz fields are set
\param names head of the alt-name linked list to encode (e.g. built with
wc_SetDNSEntry, or taken from a parsed DecodedCert.altNames); may be NULL,
in which case cert->altNamesSz is set to 0

_Example_
\code
Cert cert;
DNS_entry* list = NULL;
wc_InitCert(&cert);
// ... populate list with wc_SetDNSEntry ...
if (wc_SetAltNamesFromList(&cert, list) != 0) {
// error encoding alt names
}
FreeAltNames(list, NULL);
// ... wc_MakeCert / wc_SignCert ...
\endcode

\note This helper (along with wc_SetDNSEntry, wc_FlattenAltNames, and
FreeAltNames) is exported from the library only when WOLFSSL_PUBLIC_ASN,
OPENSSL_EXTRA, OPENSSL_EXTRA_X509_SMALL, or WOLFSSL_TEST_CERT is defined;
its prototype lives in wolfssl/wolfcrypt/asn.h (not asn_public.h) because it
uses the DNS_entry type. Its DER-input sibling wc_SetAltNamesBuffer is
always exported.

\sa wc_SetDNSEntry
\sa wc_FlattenAltNames
\sa wc_SetAltNamesBuffer
\sa FreeAltNames
*/
int wc_SetAltNamesFromList(Cert* cert, const DNS_entry* names);

/*!
\ingroup ASN

Expand Down
50 changes: 50 additions & 0 deletions wolfcrypt/src/asn.c
Original file line number Diff line number Diff line change
Expand Up @@ -14520,6 +14520,27 @@ static int SetDNSEntry(void* heap, const char* str, int strLen,

return ret;
}

/* Public wrapper for SetDNSEntry(): allocate an alt-name entry that copies the
* given name, set its type/length, and append it to the linked list. The list
* is freed with FreeAltNames() and can be flattened with wc_FlattenAltNames().
* Gated the same as its companions wc_FlattenAltNames()/wc_SetAltNamesFromList()
* so the build-list -> encode flow is always available together. */
#if defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_ALT_NAMES)
int wc_SetDNSEntry(void* heap, const char* str, int strLen, int type,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 [Medium] New public wc_SetDNSEntry() does no argument validation, unlike its sibling wrappers

This PR promotes the previously static internal SetDNSEntry() to a public API via a bare pass-through wrapper. The other two wrappers added in this same PR validate their pointer arguments (wc_SetAltNamesFromList checks cert == NULL, and wc_FlattenAltNames/FlattenAltNames checks output == NULL), but wc_SetDNSEntry performs no validation at all. Because it now accepts caller-supplied values from outside the library, malformed inputs reach SetDNSEntry() directly: a negative strLen flows into XMALLOC((size_t)strLen + 1, ...) and XMEMCPY(dnsEntry_name, str, (size_t)strLen) where the negative value casts to a huge size_t (out-of-bounds copy / crash); a NULL entries is dereferenced in AddDNSEntryToList(*lst...); and a NULL str with non-zero strLen causes a NULL read in XMEMCPY. The doxygen for this function does not document any BAD_FUNC_ARG return for these cases. wolfSSL convention is for public wc_ functions to return a non-void error and validate inputs at the boundary.

Fix: Add boundary validation (NULL str, NULL entries, negative strLen) in the public wrapper and document the BAD_FUNC_ARG return in the doxygen, to be consistent with the other two wrappers added in this PR and with wolfSSL public-API conventions.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

DNS_entry** entries)
{
/* Validate caller-supplied arguments at the public boundary: a negative
* strLen would cast to a huge size_t in the internal allocate/copy, a NULL
* entries list head would be dereferenced, and a NULL str cannot be
* copied. */
if (str == NULL || entries == NULL || strLen < 0) {
return BAD_FUNC_ARG;
}

return SetDNSEntry(heap, str, strLen, type, entries);
}
#endif /* WOLFSSL_CERT_GEN && WOLFSSL_ALT_NAMES */
#endif

/* Set the details of a subject name component into a certificate.
Expand Down Expand Up @@ -26960,6 +26981,15 @@ int FlattenAltNames(byte* output, word32 outputSz, const DNS_entry* names)
return (int)idx;
}

/* Public wrapper for FlattenAltNames(): encode a linked list of alt-name
* entries into the DER GeneralNames SEQUENCE used as the subjectAltName
* extension value. Returns the encoded length, 0 for a NULL list, or a
* negative error code. */
int wc_FlattenAltNames(byte* output, word32 outputSz, const DNS_entry* names)
{
return FlattenAltNames(output, outputSz, names);
}

#endif /* WOLFSSL_ALT_NAMES */
#endif /* WOLFSSL_CERT_GEN */

Expand Down Expand Up @@ -31507,6 +31537,26 @@ int wc_SetAltNamesBuffer(Cert* cert, const byte* der, int derSz)
return(ret);
}

/* Set cert alt names from a linked list of alt-name entries (e.g. built with
* wc_SetDNSEntry()). Encodes the list into cert->altNames and stores the
* length in cert->altNamesSz. Returns 0 on success or a negative error code. */
int wc_SetAltNamesFromList(Cert* cert, const DNS_entry* names)
{
int ret;

if (cert == NULL) {
return BAD_FUNC_ARG;
}

ret = FlattenAltNames(cert->altNames, sizeof(cert->altNames), names);
if (ret < 0) {
return ret;
}

cert->altNamesSz = ret;
return 0;
}

/* Set cert dates from DER buffer */
WOLFSSL_ABI
int wc_SetDatesBuffer(Cert* cert, const byte* der, int derSz)
Expand Down
Loading
Loading