Class RelatedCertificateTool

java.lang.Object
org.bouncycastle.cert.RelatedCertificateTool

public class RelatedCertificateTool extends Object
Operator-style helpers for building and verifying the two wire-format pieces defined by RFC 9763 ("Related Certificates for Use in Multiple Authentications within a Protocol"):
  • the RelatedCertificate certificate extension carried on an end-entity certificate (OID X509ObjectIdentifiers.id_pe_relatedCert / Extension.relatedCertificate), and
  • the RequesterCertificate 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

invalid reference
RequesterCertificate#toAttribute()
and
invalid reference
RequesterCertificate#fromAttribute(org.bouncycastle.asn1.pkcs.Attribute)
.
  • Method Summary

    Modifier and Type
    Method
    Description
    static org.bouncycastle.asn1.x509.RelatedCertificate
    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, 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(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").

    Methods inherited from class Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Method Details

    • createRelatedCertificate

      public static org.bouncycastle.asn1.x509.RelatedCertificate createRelatedCertificate(X509CertificateHolder relatedCert, DigestCalculator digestCalculator) throws IOException
      Compute the 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()).
      Parameters:
      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.
      Throws:
      IOException - if the related certificate cannot be encoded or the digest calculator's output stream rejects bytes.
    • isRelatedCertificate

      public static boolean isRelatedCertificate(org.bouncycastle.asn1.x509.RelatedCertificate extensionValue, X509CertificateHolder relatedCert, DigestCalculatorProvider digestProvider) throws OperatorCreationException, IOException
      Recompute the digest specified in a RelatedCertificate extension value over the supplied candidate certificate and report whether it matches the stored hash.
      Parameters:
      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.
      Throws:
      OperatorCreationException
      IOException
    • writeSignatureInput

      public static void writeSignatureInput(OutputStream out, org.bouncycastle.asn1.cms.IssuerAndSerialNumber certID, org.bouncycastle.asn1.cms.BinaryTime requestTime) throws IOException
      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"). 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).
      Throws:
      IOException
    • createRequesterCertificate

      public static org.bouncycastle.asn1.cms.RequesterCertificate createRequesterCertificate(org.bouncycastle.asn1.cms.IssuerAndSerialNumber certID, org.bouncycastle.asn1.cms.BinaryTime requestTime, String[] locationInfo, ContentSigner signer) throws IOException
      Build a fully-signed RequesterCertificate value. The supplied ContentSigner must be configured with the private key of the certificate identified by certID.
      Throws:
      IOException
    • verifyRequesterCertificate

      public static boolean verifyRequesterCertificate(org.bouncycastle.asn1.cms.RequesterCertificate value, ContentVerifier verifier) throws IOException
      Verify the signature carried in 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).
      Throws:
      IOException
    • toAttribute

      public 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.
    • fromAttribute

      public static org.bouncycastle.asn1.cms.RequesterCertificate fromAttribute(org.bouncycastle.asn1.pkcs.Attribute attribute)
      Extract a RequesterCertificate value from a PKCS#9 Attribute.
      Throws:
      IllegalArgumentException - if the attribute is not of type PKCSObjectIdentifiers.id_aa_relatedCertRequest or does not carry exactly one value.