Skip to content

Commit aeeacc6

Browse files
committed
preTBS: replace re-encode reconstruction with byte-exact extension excision
The previous wc_GeneratePreTBS reconstructed the preTBS by copying DecodedCert metadata into a transient Cert and feeding it through MakeAnyCert. Audit showed this approach is fundamentally fragile for X9.146 interop: - Re-encoding can never guarantee byte-identical output to the issuer's original TBSCertificate. Extension order, criticality flags (the encoder hardcodes KU=critical, has no knob for EKU / CertPolicies / CRLDP / CertPolicies criticality), DN canonical encoding, integer min-encoding and many other DER details all have to align with whatever produced the original cert. - DecodedCert only models a fixed set of extensions; AIA, Name Constraints, Policy Constraints/Mappings, CT SCTs, OCSP Must Staple, Subject Information Access and any vendor extension are silently dropped. - Even within the modelled set, basicConstCrit, AKID authorityCertIssuer/SerialNumber, and the ACME identifier extension were never copied; the encoder ignored most criticality flags anyway. - issRaw / sbjRaw are bounded by sizeof(CertName) (~352B) so long DNs hit BUFFER_E. X9.146 specifies the preTBS as exactly the TBSCertificate with the altSignatureValue extension removed - byte for byte. The new implementation does exactly that: - Verifier-side (cert has altSigValue): - Locate the [3] EXPLICIT wrapper using DecodedCert.extensions / extensionsIdx / extensionsSz. - Walk Extension items, find the one whose extnValue OCTET STRING is dCert->altSigValDer (pointer overlap into source). - Recompute the inner Extensions SEQUENCE / [3] EXPLICIT / outer TBS SEQUENCE lengths. - Emit: new TBS header + TBS prefix verbatim + new [3] header + new inner SEQ header + extensions before altSigVal verbatim + extensions after altSigVal verbatim. - Issuer-side fast path (cert has no altSigValue yet, used while computing the alt signature input): copy the parsed TBS verbatim. Embedded-friendly: zero heap allocations, ~60 bytes of stack, single forward parse of the extensions list, three XMEMCPY calls into the caller's buffer. Function no longer depends on WOLFSSL_CERT_GEN / WOLFSSL_CERT_EXT / WOLFSSL_ALT_NAMES / SetDatesFromDcert / SetAltNamesFromDcert / MakeAnyCert / MakeCertReq. Removed scaffolding (only existed to feed the old reconstruction path; pure dead-weight under the new approach): - DecodedCert.rawPublicKey / rawPubKeySize - Cert.pubKeyDer / pubKeyLen - GetCertKey raw-SPKI capture - MakeAnyCert / MakeCertReq "pre-encoded SPKI" fast paths - MakeAnyCert / MakeCertReq keyType-only validation relaxation - SetAltNamesFromDcert altEmailNames merge + criticality propagation (was working around DecodedCert -> Cert metadata loss; not needed when we don't go through Cert) - AddDNSEntryToList ordering change (was workaround for SAN order in re-encoded preTBS) - WOLFSSL_ALT_NAMES force-enable in settings.h DUAL_ALG_CERTS block (was only required by the SetAltNamesFromDcert call) CSR preTBS support deliberately left out: CSR extensions sit inside the attributes field, not under a [3] EXPLICIT wrapper, so excision needs a different walker. wc_GeneratePreTBS now returns NOT_COMPILED_IN for CSRs; the existing dual-alg-cert verify flow does not exercise CSRs. Verified with --enable-dual-alg-certs --enable-experimental (default) and additionally --enable-dilithium --enable-mldsa + -DWOLFSSL_CUSTOM_OID -DHAVE_OID_ENCODING -DHAVE_OID_DECODING: - Both configs build clean under -Werror. - tests/unit.test reports 0 failures. - test_dual_alg_support, test_dual_alg_crit_ext_support and test_dual_alg_ecdsa_mldsa all pass under the dilithium config - the latter exercises the issuer-side fast path (TBS verbatim) and the test_dual_alg_support TLS handshake exercises the verifier-side excision path against an actual peer cert.
1 parent f77fdad commit aeeacc6

4 files changed

Lines changed: 216 additions & 284 deletions

File tree

0 commit comments

Comments
 (0)