Repository navigation
std.cryptography: Validate basicConstraints cA and keyCertSign in chain_verify_path - #3340
Conversation
…in_verify_path When traversing intermediate certificates in chain_verify_path, verify that candidate issuers assert basicConstraints cA=TRUE and keyUsage keyCertSign before accepting them as intermediate authorities. Signed-off-by: Adil Alperen Çiftci <adilalperenciftci@users.noreply.github.com>
There was a problem hiding this comment.
Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.
An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.
The leaf-as-intermediate test passed without the fix: the leaf's subject never matches its own issuer, so the path was rejected for want of an issuer before the cA check ran. Replace it with openssl-made chains whose names and signatures are all valid and whose signer is a cA=FALSE certificate, a CA without keyCertSign, or a CA with no keyUsage (accepted). Removing the check fails the first two; dropping the no-keyUsage allowance fails the third and the P-384 chain. The SAN, basicConstraints and keyUsage branches each repeated the skip of the optional critical BOOLEAN; read_extn_value does it once. decode_basic_constraints now requires the SEQUENCE tag. Security changelog fragment; it says aether-lang-dev#3303 is only partly fixed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks - looking |
|
@nicolas-maman your unpushed work for #3310 and #3311 almost certainly edits the same chain_verify_path, so you could well have a merge conflict. |
|
Waiting on Nic's input, Adil - thanks for making this contrib. You look to be quite the security researcher :) |
|
@adilalperenciftci let me check your work, sorry I missed this. Thank you for your contribution! |
|
Looks good, thank you once again. |
|
Hi @adilalperenciftci, what interests you about Aether may we ask? |
hi, i came across aether while looking into actor-based languages. the actor model without a vm or gc got me intrested, so i started going through the repo and open issues. i saw #3303 and picked up the missing ca/key usage checks. i enjoy working on security code, especially tls/x509 validation, so it seemed like a good place to contribute. |
|
@adilalperenciftci thanks for this, and welcome. As you no doubt saw, I pushed a follow-up commit onto your branch: your leaf-as-intermediate test was rejecting the chain before the We're doing security research in the Aether repos too, and since your background is runtime security and PKI, some of it may interest you. Containment in the language itself
Running other languages' code under the same grant list
Up a level: infrastructure as an Aether composition aeo is an orchestrator written in Aether. One composition brings up and tears down a dependency-ordered tree of FreeBSD jails, bhyve VMs, Linux containers (podman/docker/LXC), KVM VMs and bubblewrap sandboxes. Its confinement is one grammar ( Issues or PRs against any of these are welcome. A bypass of a boundary we claim is the most useful kind. But also any ideas you have for an IaC tech that should scale from hobbyist to in-house cloud soltions for corporates |
aether-lang-dev#3303, aether-lang-dev#1298) This extends aether-lang-dev#3340 by Adil Alperen Ciftci, which made an issuing certificate need basicConstraints cA and, with a keyUsage, keyCertSign (LeafCert.is_ca, has_key_usage, key_cert_sign; read_extn_value, decode_basic_constraints, decode_key_usage). Path validation reads those fields; his decoders are extended for the rest. The pure TLS client accepted any path to a trust anchor whose DNs matched and whose signatures verified. New tls13_cert.validate_chain(leaf, intermediates, anchors, at, purpose, max_depth): a bounded depth-first search over every candidate path that accepts one where every signature verifies, every certificate is inside its validity period, every issuer is a v3 CA (is_ca) with keyCertSign when it has a keyUsage, within its pathLenConstraint, extendedKeyUsage allows the purpose wherever it is listed, DNS and IP name constraints hold, and no certificate has an unknown critical, repeated or malformed extension. The certificate parser now records version, pathLenConstraint, the keyUsage bits, extendedKeyUsage and nameConstraints. The client calls it; chain_verify_path now calls it for a server at the current time. aether-lang-dev#3340's decoders are made strict where they were lenient: a keyUsage that is not a BIT STRING, a repeated extension, and a BOOLEAN other than 0x00 or 0xFF (cA, or the critical flag) now make the certificate malformed instead of reading as no keyUsage, the last copy, or TRUE. Test crypto_tls13_chain: a CA's end entity (cA FALSE, and with no basicConstraints) signing a certificate for another host is refused through chain_verify_path (both accepted before the fix), plus keyUsage, pathLen, EKU, name constraint, critical extension and validity cases; and three issuers aether-lang-dev#3340's code accepted (seen: 3 FAILURES on e33816a's tls13_cert): keyUsage as an OCTET STRING, keyUsage twice, cA as the BOOLEAN 0x01. aether-lang-dev#3340's three chains in crypto_tls13_cert still pass.
Part of #3303 (the CA-flag hole; the rest of RFC 5280 path validation listed there stays open).
Root cause
std/cryptography/tls13_cert'schain_verify_pathwalked intermediate certificates checking only subject/issuer DN matching and the signature, neverbasicConstraints.cAorkeyUsage.keyCertSign. A leaf certificate a trusted CA issued could therefore act as an intermediate and sign a certificate for any host.Solution
LeafCertrecordsis_ca,has_key_usageandkey_cert_sign.read_extn_valuehelper skips the optionalcriticalflag for these and for subjectAltName.find_issuer_unusedaccepts an issuer only whenis_ca == 1and, if keyUsage is present,keyCertSign == 1.tests/integration/crypto_tls13_certhas openssl-made chains whose names and signatures are all valid and whose signer is acA=FALSEcertificate (rejected), a CA withoutkeyCertSign(rejected), or a CA with no keyUsage extension (accepted). Removing the check fails the first two.new_changelogs/.