Certificates, requests and CRLs¶
crypto/x509 parses certificates, certificate requests and revocation lists that use composite
keys, but it cannot create or verify them. compositex509 fills that gap. Its functions take the
same arguments as their crypto/x509 counterparts and call crypto/x509 unchanged when no
composite key is involved, so one code path serves every key type.
| Task | crypto/x509 |
compositex509 |
|---|---|---|
| Issue a certificate | CreateCertificate |
CreateCertificate |
| Create a certificate request | CreateCertificateRequest |
CreateCertificateRequest |
| Create a revocation list | CreateRevocationList |
CreateRevocationList |
| Verify a certificate signature | cert.CheckSignatureFrom(parent) |
CheckSignatureFrom(cert, parent) |
| Verify a request signature | csr.CheckSignature() |
CheckCertificateRequestSignature(csr) |
| Verify a revocation list signature | rl.CheckSignatureFrom(issuer) |
CheckRevocationListSignatureFrom(rl, issuer) |
| Read a public key | ParsePKIXPublicKey |
ParsePKIXPublicKey |
Issuing certificates¶
CreateCertificate handles every combination:
- a composite CA signing a composite, ECDSA, RSA, Ed25519 or ML-DSA subject key
- an ECDSA, RSA, Ed25519 or ML-DSA CA signing a composite subject key
- neither key composite, which goes straight to
x509.CreateCertificate
der, err := compositex509.CreateCertificate(rand.Reader, template, caCert, subjectKey, caKey)
A few rules differ from crypto/x509:
template.SignatureAlgorithmmust be zero when the CA key is composite. The algorithm follows from the key.- A composite subject key may only sign. Its key usage must include at least one of
DigitalSignature,ContentCommitment,CertSignorCRLSign. It must not includeKeyEncipherment,DataEncipherment,KeyAgreement,EncipherOnlyorDecipherOnly, as section 5.2 of the draft requires. A key usage extension inExtraExtensionsis checked the same way. - A CA certificate without
SubjectKeyIdgets the first 20 bytes of the SHA-256 hash of the composite public key, ascrypto/x509does for other keys.
Every certificate is signed, verified against the signer's public key and parsed before it is returned.
Certificate requests¶
A composite key signs its own request, which proves possession of both components:
der, err := compositex509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{
Subject: pkix.Name{CommonName: "device-0001"},
}, key)
A CA checks the request and extracts the key before issuing:
csr, err := x509.ParseCertificateRequest(der)
if err != nil {
return err
}
if err := compositex509.CheckCertificateRequestSignature(csr); err != nil {
return err
}
subjectKey, err := compositex509.ParsePKIXPublicKey(csr.RawSubjectPublicKeyInfo)
csr.PublicKey is nil for a composite key, so always read it through ParsePKIXPublicKey.
Revocation lists¶
der, err := compositex509.CreateRevocationList(rand.Reader, template, caCert, caKey)
The composite signer must hold the key named in the issuer certificate.
Verifying chains¶
x509.Certificate.Verify cannot follow a composite signature, so chain building through a
composite certificate fails. Check each link with CheckSignatureFrom, which applies the same
basic constraints and key usage checks as crypto/x509, then apply the remaining path validation
rules your application needs, such as validity periods, name constraints and revocation.
if err := compositex509.CheckSignatureFrom(leaf, intermediate); err != nil {
return err
}
if err := compositex509.CheckSignatureFrom(intermediate, root); err != nil {
return err
}
SignatureAlgorithm reports which composite algorithm signed a DER certificate, request or
revocation list.
Other signed structures¶
OCSP responses, timestamps and similar structures sign the DER encoding of a to-be-signed part
under an algorithm identifier. Sign that encoding with an empty context and no pre-hash. Write the
algorithm identifier with Algorithm.OID() and absent parameters:
signature, err := key.Sign(rand.Reader, tbsDER, nil)
if err != nil {
return err
}
algorithm := pkix.AlgorithmIdentifier{Algorithm: key.Algorithm().OID()}
Verify with compositemldsa.Verify(publicKey, tbsDER, signature, nil).