feat(x509): ECDSA CA signers, and two certificate defects they uncovered - #82
Merged
Merged
Conversation
An ECDSA signer could be described but never adapted: CaSignAlgorithm named no curve, and an SPKI import cannot infer one. The ECDSA arm now carries namedCurve, and that is the whole fix - the r||s to DER re-encoding X.509 needs is already done by the certificate generator. Adds ecdsaSignatureDerToP1363, since KMS signers hand back DER. Driving an EC-keyed CA end to end found two more. createVerify was given the signature algorithm identifier, which resolves to a digest for RSA only, so every EC certificate threw "Invalid digest" and could not be verified whether or not its signature was good. And createCertificateFromCsr took its extensions from the self-signed profile, putting keyCertSign on certificates an issuing CA signs; it now matches openssl's [usr_cert], which is a change to what it emits.
erossignon
force-pushed
the
feat/ecdsa-ca-signer
branch
from
August 22, 2026 17:02
7a8bbc6 to
ef7955b
Compare
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.
Adds ECDSA support to
CaSigner, and fixes two certificate defects that only became visible once an EC-keyed CA was exercised end to end.Downstream of node-opcua-pki#50, which needs this released before its CI can pass.
1. ECDSA signers (
feat)An ECDSA signer could be described by
CaSignAlgorithmbut never adapted:webCryptoFromSignerhas to import the signer's public key, and an SPKI import cannot infer a curve it was not given.The ECDSA arm now carries
namedCurve, and that is the whole fix.Worth recording, because it was previously believed otherwise: the
r || sto DER re-encoding that X.509 needs is already done by the certificate generator. No signature handling changed. Certificates produced this way verify underopenssl verifyand reportSignature Algorithm: ecdsa-with-SHA256.Declaring the wrong curve is safe rather than subtly broken: the SPKI bytes state the real curve, so
importKeyrejects the mismatch instead of yielding a key that signs into the void. There is a test for that.ecdsaSignatureDerToP1363sign()is defined to return whatSubtleCrypto.signreturns, which for ECDSA is the fixed-widthr || sof IEEE P1363. Cloud KMS, AWS KMS and PKCS#11 tokens all return DER instead, so this is the part an integrator gets wrong, and the failure mode is a certificate that simply does not verify. The helper does the conversion, refuses input that is not DER (i.e. calling it twice), and pads coordinates to the curve width rather than the input width.2. EC certificates could never be verified (
fix)createVerifywas handed the signature algorithm identifier. That works for RSA only because OpenSSL resolvessha256WithRSAEncryptionto a digest. ECC algorithms have no name in the OID table, so an EC certificate arrived as1.2.840.10045.4.3.2and threwInvalid digest.Every EC certificate and CRL was unverifiable, whether or not its signature was good. The digest is named inside the algorithm either way, so it is now named directly. Unrecognized identifiers still pass through untouched, which leaves RSASSA-PSS — whose digest lives in the parameters — exactly as it was.
3.
keyCertSignon CA-issued certificates (fix) — behaviour changecreateCertificateFromCsrtook its extensions fromgetAttributes, which describes a self-signed certificate: it grantskeyCertSign(historically, because such a certificate signs itself) and omitskeyAgreement. Applied to a certificate an issuing CA signs, that told every validator the subject may issue certificates of its own.openssl cakeyCertSignkeyAgreementThe profile now matches openssl's
[usr_cert], which is what makes a natively issued certificate interchangeable with an openssl-issued one. Subordinate CAs are unaffected and still get the CA profile.This changes the extensions on certificates issued through this primitive. Nothing re-signs existing certificates, and the old ones remain valid; they simply carry a usage bit they should not have.
Verification
ecdsaSignatureDerToP1363against a real DER signature fromnode:cryptoplus its padding and malformed-input edges, EC self-signed verification (and the negative case, so the fix cannot turn "cannot verify" into "verifies anything"), and the issued-certificate profile.opensslin thenode-opcua-pkibranch: EC-issued chains and EC-signed CRLs both verify, and all three CA backends now emit an identical profile.Notes for release
Suggested version 5.9.0 — one feature, two fixes.
The
CaSignAlgorithmECDSA arm gains a requirednamedCurve, so{ name: "ECDSA", hash }becomes a type error. Any such code failed at runtime already.Curve coverage
P-256, P-384 and P-521, with SHA-256/384/512. That set is what WebCrypto offers. Of the curves OPC UA names for application instance certificates (OPC 10000-12, 7.8.4.10 to 7.8.4.16), this covers
nistP256andnistP384;brainpoolP256r1,brainpoolP384r1,curve25519andcurve448would each need a signing path that does not go through WebCrypto.🤖 Generated with Claude Code