Add native API for TLS 1.3 certificate_authorities extension - #11089
Draft
julek-wolfssl wants to merge 2 commits into
Draft
Add native API for TLS 1.3 certificate_authorities extension#11089julek-wolfssl wants to merge 2 commits into
julek-wolfssl wants to merge 2 commits into
Conversation
RFC 8446 4.2.4 certificate_authorities (extension type 47) was only
wired up behind OPENSSL_EXTRA via the client_ca_names / ca_names /
peer_ca_names WOLF_STACK_OF(WOLFSSL_X509_NAME) stacks. Users without
the OpenSSL compat layer had no way to send or inspect the extension.
This commit introduces a native API gated on WOLFSSL_TLS13:
- CertificateAuthority node: singly-linked list with a flexible-array
DN buffer holding the inner DER-encoded Name content (no SEQUENCE
header). TLSX_CertificateAuthorities_Add/FreeAll manage the list.
Everything is gated on WOLFSSL_TLS13 && !NO_CERTS &&
!WOLFSSL_NO_CA_NAMES.
- Storage on WOLFSSL_CTX (ws_ca_names) and WOLFSSL (ws_ca_names +
ws_peer_ca_names); SSL shadows CTX via the WS_CA_NAMES helper.
- Public API mirroring UseSNI style:
wolfSSL_UseCertificateAuthority / CTX variant
wolfSSL_ClearCertificateAuthorities / CTX variant
wolfSSL_GetPeerCertificateAuthorityCount
wolfSSL_GetPeerCertificateAuthority (index-based, copy-out)
The library prepends the DER SEQUENCE header on the wire and strips
it on parse, so callers pass the raw subject content straight from
wc_GetDecodedCertSubjectRaw (new accessor on DecodedCert).
- TLSX_CA_Names_Write is a single emitter matching the PHA_GET_SIZE /
PHA_WRITE style (int return, word16* pSz accumulator); macros pass
NULL when sizing and the output buffer when serializing. It walks
the compat stack first (when OPENSSL_EXTRA is on) then the native
list, enforcing the RFC 8446 per-DN cap and capping the whole
extension payload (outer length included) at WOLFSSL_MAX_16BIT so
the word16 size accumulator stays exact, returning BUFFER_ERROR on
overflow.
- TLSX_CA_Names_Parse always populates ws_peer_ca_names and, when
OPENSSL_EXTRA is compiled in, additionally populates peer_ca_names
through the existing InitDecodedCert/GetName/CopyDecodedName path.
Length validation enforces the RFC 8446 DistinguishedName<1..2^16-1>
and authorities<3..2^16-1> bounds.
- TLSX_GetSize now propagates non-zero ret by breaking out of the
walk, matching TLSX_Write.
- Teardown paths in SSL_CtxResourceFree and wolfSSL_ResourceFree free
the native lists on the owning heap.
Tests in tests/api/test_tls_ext.c cover argument validation, size
limits, send/receive counts, handshake round-trips on SSL and CTX, a
cert_cb scenario that feeds DecodedCert subjects to the API (with
params loop for TLS 1.3 and DTLS 1.3), the existing OPENSSL_EXTRA
cases, and a bad-extension regression. Documentation for all new API
functions is in doc/dox_comments/header_files/.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds a wolfSSL-native API (gated on WOLFSSL_TLS13) for sending and inspecting the TLS 1.3 certificate_authorities extension (RFC 8446 §4.2.4), making the feature available without requiring the OpenSSL compatibility layer.
Changes:
- Introduces a native
CertificateAuthoritylinked-list representation, stored onWOLFSSL_CTX/WOLFSSL, with emit/parse support integrated into TLS extensions. - Adds public APIs to configure advertised CA DNs and to query peer-provided CA DNs, plus a new
wc_GetDecodedCertSubjectRaw()accessor to supply correctly-formatted DN content. - Adds API tests covering argument validation, size limits, handshake round-trips (SSL + CTX), and a
cert_cbscenario.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| wolfssl/wolfcrypt/asn_public.h | Declares new public accessor for raw subject DN content (wc_GetDecodedCertSubjectRaw). |
| wolfcrypt/src/asn.c | Implements wc_GetDecodedCertSubjectRaw() returning the inner subject Name SEQUENCE content pointer/length. |
| wolfssl/ssl.h | Adds the new public native certificate_authorities API declarations and header-level documentation. |
| wolfssl/internal.h | Adds native CA list node type and storage fields in WOLFSSL_CTX/WOLFSSL, plus helper macro for CTX fallback. |
| src/tls.c | Implements native CA list management and unified extension sizing/writing/parsing for compat + native sources. |
| src/ssl_api_ext.c | Implements the new public native APIs (Use/Clear/GetPeerCount/GetPeerByIndex). |
| src/ssl_api_cert.c | Tightens OpenSSL-compat CA-names code compilation guards to OPENSSL_EXTRA. |
| src/internal.c | Adds teardown of native lists and adjusts CA-names-related guards in resource free paths. |
| tests/api/test_tls_ext.h | Adds prototypes for new native API tests. |
| tests/api/test_tls_ext.c | Adds comprehensive native API tests, including handshake and cert-callback coverage. |
| tests/api.c | Registers new tests in the main API test list. |
| doc/dox_comments/header_files/ssl.h | Adds doxygen documentation for the new SSL/CTX APIs and peer getters. |
| doc/dox_comments/header_files/asn_public.h | Adds doxygen documentation for wc_GetDecodedCertSubjectRaw(). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Only advertise the extension when the emitter would produce at least one DN. HasAnyCANames() asks TLSX_CA_Names_Write() in size-only mode rather than restating its filtering, so the two cannot drift; a compat stack holding only NULL/empty names no longer emits an empty authorities vector, which RFC 8446 4.2.4 forbids. It reports true on error so an oversized list still fails at write time instead of silently dropping the extension. TLSX_CA_Names_Write() takes a const WOLFSSL* now that it is called from a predicate. - TLSX_CertificateAuthorities_Add() appends instead of prepending, so wire order matches call order as the docs state. The handshake test asserts that order rather than ignoring it. - Scope the MSVC C4200 suppression with warning(push)/(pop) so it does not leak into the rest of the translation unit. - Document MEMORY_ERROR, not MEMORY_E, as the allocation failure return; that is what the implementation returns.
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated no new comments.
Suppressed comments (3)
doc/dox_comments/header_files/asn_public.h:4417
- The lifetime/ownership statement is incorrect:
subjectRawpoints into the source DER buffer passed towc_InitDecodedCert, whichDecodedCertdoes not own. A caller can keep theDecodedCertalive but free/reuse that source buffer and then dereference a dangling pointer. Document that the source DER must remain alive while the returned pointer is used.
The returned pointer and size reference the inner content of the subject
Name SEQUENCE (i.e. the bytes after the SEQUENCE tag and length). The
pointer aliases memory inside the DecodedCert and must not be freed by
the caller. The data remains valid until the DecodedCert is freed.
wolfcrypt/src/asn.c:23312
cert->subjectRawaliasescert->source, andInitDecodedCertexplicitly does not own that source buffer. This comment currently gives the opposite ownership impression and could lead future callers to rely only on theDecodedCertlifetime. State that the input DER buffer controls this pointer's lifetime.
src/tls.c:7864- This still accepts an empty
authoritiesvector (00 00). RFC 8446 definesauthorities<3..2^16-1>, so an extension that is present must contain at least three vector bytes; accepting zero bypasses the stated malformed-extension validation. Reject every post-prefix length below 3.
if (length > 0 && length < 3)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
RFC 8446 4.2.4
certificate_authorities(extension type 47) was previously only accessible behindOPENSSL_EXTRAvia theclient_ca_names/ca_names/peer_ca_namesWOLF_STACK_OF(WOLFSSL_X509_NAME)stacks, leaving users without the OpenSSL compat layer no way to send or inspect the extension. This adds a native API gated onWOLFSSL_TLS13.New
CertificateAuthoritynode type: a singly-linked list with a flexible-array DN buffer holding the inner DER-encoded Name content (no SEQUENCE header).TLSX_CertificateAuthorities_Add/FreeAllmanage the list, gated onWOLFSSL_TLS13 && !NO_CERTS && !WOLFSSL_NO_CA_NAMES.Storage added on
WOLFSSL_CTX(ws_ca_names) andWOLFSSL(ws_ca_names+ws_peer_ca_names); SSL shadows CTX via theWS_CA_NAMEShelper.New public API mirroring the UseSNI style:
wolfSSL_UseCertificateAuthority/ CTX variantwolfSSL_ClearCertificateAuthorities/ CTX variantwolfSSL_GetPeerCertificateAuthorityCountwolfSSL_GetPeerCertificateAuthority(index-based, copy-out)The library prepends the DER SEQUENCE header on the wire and strips it on parse, so callers pass the raw subject content straight from
wc_GetDecodedCertSubjectRaw(new accessor onDecodedCert).TLSX_CA_Names_Writeis a single emitter matching thePHA_GET_SIZE/PHA_WRITEstyle (int return,word16* pSzaccumulator); macros pass NULL when sizing and the output buffer when serializing. It walks the compat stack first (whenOPENSSL_EXTRAis on) then the native list, enforcing the RFC 8446 per-DN cap and capping the whole extension payload (outer length included) atWOLFSSL_MAX_16BITso theword16size accumulator stays exact, returningBUFFER_ERRORon overflow.TLSX_CA_Names_Parsealways populatesws_peer_ca_namesand, whenOPENSSL_EXTRAis compiled in, additionally populatespeer_ca_namesthrough the existingInitDecodedCert/GetName/CopyDecodedNamepath. Length validation enforces the RFC 8446DistinguishedName<1..2^16-1>andauthorities<3..2^16-1>bounds.TLSX_GetSizenow propagates a non-zeroretby breaking out of the walk, matchingTLSX_Write.Teardown paths in
SSL_CtxResourceFreeandwolfSSL_ResourceFreefree the native lists on the owning heap.Tests added in
tests/api/test_tls_ext.ccover argument validation, size limits, send/receive counts, handshake round-trips on SSL and CTX, acert_cbscenario feedingDecodedCertsubjects to the API (with a params loop for TLS 1.3 and DTLS 1.3), the existingOPENSSL_EXTRAcases, and a bad-extension regression. Documentation for all new API functions is added underdoc/dox_comments/header_files/.