Thread the caller's verify setting into trusted-peer loads and parse multi-valued RDNs - #11400
Thread the caller's verify setting into trusted-peer loads and parse multi-valued RDNs#11400julek-wolfssl wants to merge 5 commits into
Conversation
There was a problem hiding this comment.
🔵 Needs a closer look
src/ssl_load.c logs that a trusted-peer load error is ignored but still returns the failing status, creating an inconsistent/fragile return value.
Pull request overview
This PR improves wolfSSL’s OpenSSL-compatibility behavior in certificate loading and X.509 parsing by relaxing strict RFC checks to match what OpenSSL accepts, adding recognition for additional extensions/OIDs, and updating API tests accordingly.
Changes:
- Thread the effective verify mode (including skip-date) into trusted-peer certificate loading paths and avoid attempting trusted-peer loads when the CA load failed.
- Relax parsing/verification behavior to accept legacy certificates (tbs vs outer signatureAlgorithm mismatch, empty subjectAltName, multi-valued RDNs) and recognize/skip critical
qcStatements. - Regenerate/update OID sum definitions and add new regression tests covering the relaxed parsing cases and verify-flag behavior.
File summaries
| File | Description |
|---|---|
wolfssl/wolfcrypt/oid_sum.h |
Adjusts extension OID sum entries (ACME identifier handling) and adds QC_STATEMENTS_OID. |
wolfcrypt/src/asn.c |
Implements relaxed parsing behaviors (multi-valued RDN, empty SAN, signatureAlgorithm mismatch) and skips critical qcStatements. |
wolfcrypt/src/asn_orig.c |
Mirrors relaxed SAN and signatureAlgorithm mismatch handling in the “orig” ASN parser. |
src/ssl_load.c |
Refactors trusted-peer loading helpers to accept caller-provided verify settings and threads skip-date through trusted-peer loads. |
scripts/asn1_oid_sum.pl |
Updates the OID-sum generator inputs for ACME identifier and qcStatements. |
tests/api/test_certman.c |
Adjusts cert manager expectations to reflect skip-date propagation into trusted-peer loads. |
tests/api/test_asn.h |
Registers new ASN parsing tests for the added compatibility behaviors. |
tests/api/test_asn.c |
Adds new fixtures/tests for signatureAlgorithm mismatch, empty SAN, multi-valued RDN, and critical qcStatements. |
tests/api.c |
Adds an API regression test asserting skip-date behavior is preserved when verify-peer is enabled. |
Review details
Suppressed comments (1)
src/ssl_load.c:3175
- In wolfssl_ctx_load_path_file(), the trusted-peer load failure is logged as "Ignoring this error", but the function still returns that failing ret value. This makes the return value inconsistent with the intended behavior (CA load succeeded) and could cause false failure propagation if any caller starts using the return code more strictly.
/* Try loading as a trusted peer certificate with the same
* verification setting as the CA load. */
ret = TrustPeerCertFile(ctx, name, WOLFSSL_FILETYPE_PEM, verify);
if (ret != 1) {
WOLFSSL_MSG("wolfSSL_CTX_trust_peer_cert error. "
"Ignoring this error.");
}
- Files reviewed: 9/9 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
…multi-valued RDNs - Pass the caller's effective verify setting, including WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY -> VERIFY_SKIP_DATE, into the trusted-peer file, path and buffer loads instead of letting wolfSSL_CTX_trust_peer_cert() recompute it, so the flag reaches the trust-peer path. Skip the trusted-peer copy of a CA file when the CA load itself failed, matching the buffer and path loaders. - Parse multi-valued RDNs, where one SET holds several AttributeTypeAndValues. RFC 5280 4.1.2.4 defines a RelativeDistinguishedName as SET SIZE (1..MAX) OF AttributeTypeAndValue, so the packed form is valid and was rejected. The loop is bounded by the SET's own length: an AttributeTypeAndValue outside the SET is rejected rather than folded into the preceding RDN, which would otherwise build a DN that a strict parser does not. The name NID is reset before each one so unknown OIDs are not filed under the previous entry. - Fix the generated ACME identifier OID table, which put both entries in one arm of the sum scheme, breaking builds with WOLFSSL_ACME_OID. Regenerate it consistently with the other extension OIDs.
980d779 to
394b272
Compare
RFC 5280 4.2.1.10 restricts the name constraints extension to CA certificates. The check ran while walking the extensions, reading cert->isCA at the point the extension was reached. isCA is set when basic constraints is decoded, so a CA certificate whose DER encodes name constraints before basic constraints was rejected with ASN_NAME_INVALID_E even though it is conformant. Extension order carries no meaning, so the decision now runs once the walk is done and isCA is final, in both the template and original parsers. Certificates that genuinely carry name constraints outside a CA keep failing with ASN_NAME_INVALID_E. Duplicate extension handling is untouched: a repeated name constraints extension still fails with ASN_OBJECT_ID_E.
The helper sat in the NO_FILESYSTEM guarded part of the file while both callers, wolfSSL_CTX_load_verify_buffer_ex() and wolfSSL_CTX_trust_peer_buffer(), are outside it. Building with --disable-filesystem and trusted peer certificates therefore failed with an implicit declaration. The helper only uses the buffer loaders, so move it next to its callers.
There was a problem hiding this comment.
🟡 Changes recommended
Multi-valued RDN SET membership is lost during decode/re-encode, changing the distinguished name.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (1)
wolfcrypt/src/asn.c:15629
- Using
complete = 0also stopsGetASN_Items()from verifying that the first AttributeTypeAndValue SEQUENCE was fully consumed. A malformed SET whose first SEQUENCE contains one valid OID/value followed by another valid AVA SEQUENCE is therefore accepted: the inner trailing SEQUENCE is parsed by the new loop as if it were a sibling AVA. Check the parsed index against the first SEQUENCE's end before entering the SET-level loop (and add this nested-AVA case to the negative test).
- Files reviewed: 9/9 changed files
- Comments generated: 1
- Review effort level: Balanced
| if ((nid != 0) && (dName != NULL)) { | ||
| /* Add an entry to the X509_NAME. */ | ||
| if (wolfSSL_X509_NAME_add_entry_by_NID(dName, nid, enc, str, | ||
| (int)strLen, -1, -1) != WOLFSSL_SUCCESS) { |
The non-CA certificate is only referenced by the strict-mode rejection case and both certificates only by the name constraints test, so builds defining WOLFSSL_NO_ASN_STRICT or IGNORE_NAME_CONSTRAINTS failed with -Werror=unused-const-variable.
WOLFSSL_X509_TINY without WOLFSSL_X509_TINY_NAME_CONSTRAINTS rejects any name constraints extension outright, so the certificate the test expects to parse is refused with ASN_NAME_INVALID_E. Gate the test and its certificates on the same condition the extension handling uses.
Pass the caller's effective verify setting, including
WOLFSSL_LOAD_FLAG_DATE_ERR_OKAY -> VERIFY_SKIP_DATE, into the
trusted-peer file, path and buffer loads instead of letting
wolfSSL_CTX_trust_peer_cert() recompute it, so the flag reaches the
trust-peer path. Skip the trusted-peer copy of a CA file when the CA
load itself failed, matching the buffer and path loaders.
Parse multi-valued RDNs, where one SET holds several
AttributeTypeAndValues. RFC 5280 4.1.2.4 defines a
RelativeDistinguishedName as SET SIZE (1..MAX) OF
AttributeTypeAndValue, so the packed form is valid and was rejected.
The loop is bounded by the SET's own length: an AttributeTypeAndValue
outside the SET is rejected rather than folded into the preceding RDN,
which would otherwise build a DN that a strict parser does not. The
name NID is reset before each one so unknown OIDs are not filed under
the previous entry.
Fix the generated ACME identifier OID table, which put both entries in
one arm of the sum scheme, breaking builds with WOLFSSL_ACME_OID.
Regenerate it consistently with the other extension OIDs.