public class RelatedCertificateTool
extends java.lang.Object
RelatedCertificate certificate extension carried on an
end-entity certificate (OID
X509ObjectIdentifiers.id_pe_relatedCert
/ Extension.relatedCertificate), andRequesterCertificate CSR attribute value the requester
includes in the CSR to prove they hold the private key of the related
certificate (attribute OID
PKCSObjectIdentifiers.id_aa_relatedCertRequest).The intended use case is post-quantum migration: an end entity that
already holds a traditional certificate requests a parallel post-quantum
certificate by including a id-aa-relatedCertRequest attribute in
the new CSR; the CA verifies the requester controls both private keys,
then issues the new certificate carrying a RelatedCertificate
extension that pins the traditional certificate by digest. A verifier
seeing both certificates can then assert with assurance that they
identify the same principal.
This class is JCA-free and lightweight-crypto-free: it consumes
DigestCalculator / DigestCalculatorProvider /
ContentSigner / ContentVerifier from
org.bouncycastle.operator, so both the lightweight (BC) and JCA
bindings of those operator interfaces are equally usable. Wrapping /
unwrapping the value as a PKCS#9 Attribute
lives on the value class itself — see RequesterCertificate#toAttribute()
and RequesterCertificate#fromAttribute(org.bouncycastle.asn1.pkcs.Attribute).
| Modifier and Type | Method and Description |
|---|---|
static org.bouncycastle.asn1.x509.RelatedCertificate |
createRelatedCertificate(X509CertificateHolder relatedCert,
DigestCalculator digestCalculator)
Compute the
RelatedCertificate extension value identifying the
supplied certificate by digest. |
static org.bouncycastle.asn1.cms.RequesterCertificate |
createRequesterCertificate(org.bouncycastle.asn1.cms.IssuerAndSerialNumber certID,
org.bouncycastle.asn1.cms.BinaryTime requestTime,
java.lang.String[] locationInfo,
ContentSigner signer)
Build a fully-signed
RequesterCertificate value. |
static org.bouncycastle.asn1.cms.RequesterCertificate |
fromAttribute(org.bouncycastle.asn1.pkcs.Attribute attribute)
Extract a
RequesterCertificate value from a PKCS#9
Attribute. |
static boolean |
isRelatedCertificate(org.bouncycastle.asn1.x509.RelatedCertificate extensionValue,
X509CertificateHolder relatedCert,
DigestCalculatorProvider digestProvider)
Recompute the digest specified in a
RelatedCertificate extension
value over the supplied candidate certificate and report whether it
matches the stored hash. |
static org.bouncycastle.asn1.pkcs.Attribute |
toAttribute(org.bouncycastle.asn1.cms.RequesterCertificate value)
Wrap a
RequesterCertificate value as a PKCS#9 Attribute
carrying PKCSObjectIdentifiers.id_aa_relatedCertRequest, ready to
drop into a CertificationRequestInfo attributes set. |
static boolean |
verifyRequesterCertificate(org.bouncycastle.asn1.cms.RequesterCertificate value,
ContentVerifier verifier)
Verify the signature carried in
value using the supplied
ContentVerifier. |
static void |
writeSignatureInput(java.io.OutputStream out,
org.bouncycastle.asn1.cms.IssuerAndSerialNumber certID,
org.bouncycastle.asn1.cms.BinaryTime requestTime)
Write the bytes the
signature
field must cover straight into out: the DER encoding of
certID followed by the DER encoding of requestTime, per
RFC 9763 sec. 4.1 ("concatenation of DER-encoded IssuerAndSerialNumber
and BinaryTime"). |
public static org.bouncycastle.asn1.x509.RelatedCertificate createRelatedCertificate(X509CertificateHolder relatedCert, DigestCalculator digestCalculator) throws java.io.IOException
RelatedCertificate extension value identifying the
supplied certificate by digest. Per RFC 9763 sec. 3.2 the digest input
is the DER encoding of the entire Certificate structure (i.e.
the value returned by X509CertificateHolder.getEncoded()).relatedCert - the related end-entity certificate to bind.digestCalculator - a calculator configured for the desired digest
algorithm; its
AlgorithmIdentifier is copied verbatim into the
extension's hashAlgorithm field.java.io.IOException - if the related certificate cannot be encoded or the
digest calculator's output stream rejects bytes.public static boolean isRelatedCertificate(org.bouncycastle.asn1.x509.RelatedCertificate extensionValue,
X509CertificateHolder relatedCert,
DigestCalculatorProvider digestProvider)
throws OperatorCreationException,
java.io.IOException
RelatedCertificate extension
value over the supplied candidate certificate and report whether it
matches the stored hash.extensionValue - the parsed RelatedCertificate extension
value, e.g. via
RelatedCertificate.getInstance(ext.getParsedValue()).relatedCert - the candidate related certificate.digestProvider - a provider able to instantiate a
DigestCalculator for the
hashAlgorithm carried by
extensionValue.OperatorCreationExceptionjava.io.IOExceptionpublic static void writeSignatureInput(java.io.OutputStream out,
org.bouncycastle.asn1.cms.IssuerAndSerialNumber certID,
org.bouncycastle.asn1.cms.BinaryTime requestTime)
throws java.io.IOException
signature
field must cover straight into out: the DER encoding of
certID followed by the DER encoding of requestTime, per
RFC 9763 sec. 4.1 ("concatenation of DER-encoded IssuerAndSerialNumber
and BinaryTime"). This is NOT wrapped in an outer SEQUENCE —
implementations that hash a SEQUENCE will fail to interoperate. The two
structures are streamed directly so no intermediate byte[] is
materialised; pass a ContentSigner / ContentVerifier
output stream (or a ByteArrayOutputStream if you need the bytes).java.io.IOExceptionpublic static org.bouncycastle.asn1.cms.RequesterCertificate createRequesterCertificate(org.bouncycastle.asn1.cms.IssuerAndSerialNumber certID,
org.bouncycastle.asn1.cms.BinaryTime requestTime,
java.lang.String[] locationInfo,
ContentSigner signer)
throws java.io.IOException
RequesterCertificate value. The supplied
ContentSigner must be configured with the private key of the
certificate identified by certID.java.io.IOExceptionpublic static boolean verifyRequesterCertificate(org.bouncycastle.asn1.cms.RequesterCertificate value,
ContentVerifier verifier)
throws java.io.IOException
value using the supplied
ContentVerifier. The verifier must be configured with the public
key of the certificate identified by value.getCertID() and the
signature algorithm the CSR signer used (RFC 9763 carries no
AlgorithmIdentifier with the signature, so the caller must derive it
from the related certificate's SPKI plus any local policy).java.io.IOExceptionpublic static org.bouncycastle.asn1.pkcs.Attribute toAttribute(org.bouncycastle.asn1.cms.RequesterCertificate value)
RequesterCertificate value as a PKCS#9 Attribute
carrying PKCSObjectIdentifiers.id_aa_relatedCertRequest, ready to
drop into a CertificationRequestInfo attributes set.public static org.bouncycastle.asn1.cms.RequesterCertificate fromAttribute(org.bouncycastle.asn1.pkcs.Attribute attribute)
RequesterCertificate value from a PKCS#9
Attribute.java.lang.IllegalArgumentException - if the attribute is not of type
PKCSObjectIdentifiers.id_aa_relatedCertRequest or does
not carry exactly one value.