Contact Details
lxd_dong@bupt.edu.cn
Version
V5.9.1
Description
Client Certificate Extensions Offered-List Inconsistency
Conclusion
This note concerns extensions in a client-sent TLS 1.3 Certificate message:
they must correspond to extensions previously offered by the server in
CertificateRequest.
wolfSSL parses CertificateEntry extensions, but in the current default build
there is no stable hard-check path showing that a client certificate extension
is rejected solely because it was not present in the server's earlier
CertificateRequest extension list. This should not be classified as fully
satisfied.
Standard Text
RFC 8446 Section 4.4.2, "Certificate":
https://www.rfc-editor.org/rfc/rfc8446.html#section-4.4.2
extensions: A set of extension values for the CertificateEntry. The
"Extension" format is defined in Section 4.2. Valid extensions
for server certificates at present include the OCSP Status
extension [RFC6066] and the SignedCertificateTimestamp extension
[RFC6962]; future extensions may be defined for this message as
well. Extensions in the Certificate message from the server MUST
correspond to ones from the ClientHello message. Extensions in
the Certificate message from the client MUST correspond to
extensions in the CertificateRequest message from the server. If
an extension applies to the entire chain, it SHOULD be included in
the first CertificateEntry.
The directly relevant sentence for this case is:
Extensions in the Certificate message from the client MUST correspond to
extensions in the CertificateRequest message from the server.
wolfSSL Source Evidence
CertificateEntry Extensions Are Parsed
In internal.c, wolfSSL extracts each
CertificateEntry extension block and passes it into TLSX_Parse():
args->exts[args->totalCerts].length = extSz;
args->exts[args->totalCerts].buffer = input + args->idx;
args->idx += extSz;
listSz -= extSz + OPAQUE16_LEN;
WOLFSSL_MSG_EX("\tParsing %d bytes of cert extensions",
args->exts[args->totalCerts].length);
#if !defined(NO_TLS)
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST)
ssl->response_idx = args->totalCerts;
#endif
ret = TLSX_Parse(ssl, args->exts[args->totalCerts].buffer,
(word16)args->exts[args->totalCerts].length,
certificate, NULL);
#endif /* !NO_TLS */
So the issue is not that certificate extensions are ignored entirely. The
question is whether wolfSSL enforces the offered-list correspondence required
by RFC 8446.
Generic Extension Parser
In tls.c, TLSX_Parse() treats
client_hello and certificate_request as request-like messages:
byte isRequest = (msgType == client_hello ||
msgType == certificate_request);
The certificate message is not included in this isRequest condition.
Message-Position Check Is Not the Same as Offered-List Check
For status_request, tls.c allows the
extension in a TLS 1.3 certificate message:
if (IsAtLeastTLSv1_3(ssl->version)) {
if (msgType != client_hello &&
msgType != certificate_request &&
msgType != certificate)
return EXT_NOT_ALLOWED;
}
ret = CSR_PARSE(ssl, input + offset, size, isRequest);
This checks whether the extension type is allowed in the message. It does not
by itself prove that the extension was offered in the previous
CertificateRequest.
The Stronger Check Is Feature-Dependent
When certificate status request support is enabled,
tls.c contains logic that can reject an
unexpected status_request:
if (!csr) /* unexpected extension */
return TLSX_HandleUnsupportedExtension(ssl);
The rejection helper sends unsupported_extension; see
tls.c:
int TLSX_HandleUnsupportedExtension(WOLFSSL* ssl)
{
SendAlert(ssl, alert_fatal, unsupported_extension);
WOLFSSL_ERROR_VERBOSE(UNSUPPORTED_EXTENSION);
return UNSUPPORTED_EXTENSION;
}
However, in the current default build this path is compiled out. The relevant
macros in tls.c reduce CSR_PARSE to a
successful no-op:
#define CSR_FREE_ALL(data, heap) WC_DO_NOTHING
#define CSR_GET_SIZE(a, b) 0
#define CSR_WRITE(a, b, c) 0
#define CSR_PARSE(a, b, c, d) 0
The default build configuration also shows that
HAVE_CERTIFICATE_STATUS_REQUEST and HAVE_OCSP are not enabled; see
options.h.
Evidence Scope
The minimal runtime probe is
test_id253_254_tlsx_parse_runtime.c.
In the current default static build, the client object initializes, while the
server object does not initialize cleanly. Therefore, this client-certificate
case is mainly based on source-path analysis, while the server-certificate case has direct runtime evidence.
Classification
The current wolfSSL behavior is closer to checking whether an extension type is
generally allowed in a certificate message, not to enforcing a hard
offered-list correspondence against the previous CertificateRequest.
Reproduction steps
No response
Relevant log output
Contact Details
lxd_dong@bupt.edu.cn
Version
V5.9.1
Description
Client Certificate Extensions Offered-List Inconsistency
Conclusion
This note concerns extensions in a client-sent TLS 1.3
Certificatemessage:they must correspond to extensions previously offered by the server in
CertificateRequest.wolfSSL parses
CertificateEntryextensions, but in the current default buildthere is no stable hard-check path showing that a client certificate extension
is rejected solely because it was not present in the server's earlier
CertificateRequestextension list. This should not be classified as fullysatisfied.
Standard Text
RFC 8446 Section 4.4.2, "Certificate":
https://www.rfc-editor.org/rfc/rfc8446.html#section-4.4.2
The directly relevant sentence for this case is:
wolfSSL Source Evidence
CertificateEntry Extensions Are Parsed
In internal.c, wolfSSL extracts each
CertificateEntryextension block and passes it intoTLSX_Parse():So the issue is not that certificate extensions are ignored entirely. The
question is whether wolfSSL enforces the offered-list correspondence required
by RFC 8446.
Generic Extension Parser
In tls.c,
TLSX_Parse()treatsclient_helloandcertificate_requestas request-like messages:The
certificatemessage is not included in thisisRequestcondition.Message-Position Check Is Not the Same as Offered-List Check
For
status_request, tls.c allows theextension in a TLS 1.3
certificatemessage:This checks whether the extension type is allowed in the message. It does not
by itself prove that the extension was offered in the previous
CertificateRequest.The Stronger Check Is Feature-Dependent
When certificate status request support is enabled,
tls.c contains logic that can reject an
unexpected
status_request:The rejection helper sends
unsupported_extension; seetls.c:
However, in the current default build this path is compiled out. The relevant
macros in tls.c reduce
CSR_PARSEto asuccessful no-op:
The default build configuration also shows that
HAVE_CERTIFICATE_STATUS_REQUESTandHAVE_OCSPare not enabled; seeoptions.h.
Evidence Scope
The minimal runtime probe is
test_id253_254_tlsx_parse_runtime.c.
In the current default static build, the client object initializes, while the
server object does not initialize cleanly. Therefore, this client-certificate
case is mainly based on source-path analysis, while the server-certificate case has direct runtime evidence.
Classification
The current wolfSSL behavior is closer to checking whether an extension type is
generally allowed in a
certificatemessage, not to enforcing a hardoffered-list correspondence against the previous
CertificateRequest.Reproduction steps
No response
Relevant log output