Class MerkleTreeCertificateValidator

java.lang.Object
org.bouncycastle.cert.plants.MerkleTreeCertificateValidator

public class MerkleTreeCertificateValidator extends Object
Validates a Merkle Tree Certificate (MTC) per Section 7.2 of draft-ietf-plants-merkle-tree-certs.

The validator stands in for the per-certificate signature verification step of RFC 5280 path validation (Section 6.1.3 step (a)(1)) when the issuer is a Merkle Tree CA. validateCertificate(X509CertificateHolder, MerkleTreeCertificateValidator.ValidationParams) decodes the MTCProof carried in the certificate's signatureValue, recomputes the entry hash from the TBSCertificate, evaluates the inclusion proof against the supplied MerkleTreeHash, and then either matches the resulting subtree hash against a

invalid reference
ValidationParams.TrustedSubtree
or counts valid cosignatures against the relying party's MTCCosignerVerifierProvider until minCosignatures is met.

  • Field Details

    • ID_ALG_MTC_PROOF

      public static final String ID_ALG_MTC_PROOF
      Dotted-decimal form of MTCObjectIdentifiers.id_alg_mtcProof, the signatureAlgorithm of an MTC certificate.
  • Constructor Details

    • MerkleTreeCertificateValidator

      public MerkleTreeCertificateValidator()
  • Method Details

    • validateCertificate

      public static boolean validateCertificate(X509CertificateHolder certHolder, MerkleTreeCertificateValidator.ValidationParams params) throws IOException
      Validates a Merkle Tree certificate per Section 7.2. Always returns true on success; any validation failure is signalled as a SecurityException.
      Parameters:
      certHolder - the certificate to validate
      params - validation parameters
      Throws:
      SecurityException - if the certificate is rejected
      IllegalArgumentException - if the certificate is not a Merkle Tree certificate
      IOException - if the certificate cannot be parsed
    • computeEntryHash

      public static byte[] computeEntryHash(X509CertificateHolder certHolder, MerkleTreeHash hashFunc) throws IOException
      Convenience overload of computeEntryHash(X509CertificateHolder, byte[], MerkleTreeHash) with an empty extensions list (the wire form is two zero bytes, the uint16 length prefix). Use this when the certificate has no log-entry extensions.
      Throws:
      IOException
    • computeEntryHash

      public static byte[] computeEntryHash(org.bouncycastle.asn1.x509.TBSCertificate tbsCert, MerkleTreeHash hashFunc) throws IOException
      Convenience overload of computeEntryHash(TBSCertificate, byte[], MerkleTreeHash) with an empty extensions list. Useful when the caller has a TBSCertificate in hand (for instance during issuance, before the signature is computed) and doesn't want to build a placeholder X509CertificateHolder solely to satisfy the holder-based overload.
      Throws:
      IOException
    • computeEntryHash

      public static byte[] computeEntryHash(byte[] tbsCertDer, MerkleTreeHash hashFunc) throws IOException
      Convenience overload of computeEntryHash(byte[], byte[], MerkleTreeHash) with an empty extensions list. Use this when the DER encoding of the TBSCertificate is already in hand (e.g. captured from a streaming ContentSigner) to avoid the parse + re-encode round trip via TBSCertificate.
      Throws:
      IOException
    • computeSubtreeHash

      public static byte[] computeSubtreeHash(byte[] tbsCertDer, byte[] inclusionProof, MerkleTreeHash hashFunc) throws IOException
      Combined "leaf hash + climb one level" for the simple case of a size-two subtree [0, 2) where the EE has exactly one sibling leaf. Equivalent to hashFunc.hashNode(computeEntryHash(tbsCertDer, hashFunc), inclusionProof). The extensions list is empty.
      Throws:
      IOException
    • computeEntryHash

      public static byte[] computeEntryHash(X509CertificateHolder certHolder, byte[] extensionsWire, MerkleTreeHash hashFunc) throws IOException
      Computes the entry hash for a certificate by transforming its TBSCertificate into the equivalent MerkleTreeCertEntry of type tbs_cert_entry and hashing per Section 5.2.1 / Section 7.2.

      The single-pass procedure (Section 7.2):

      1. Write the extensions field from the MTCProof (the on-wire bytes including the 2-byte length prefix) to the hash.
      2. Write the big-endian, two-byte tbs_cert_entry value (0x0001).
      3. Write the TBSCertificate contents octets up to subjectPublicKeyInfo.
      4. Write the subjectPublicKeyInfo's algorithm field.
      5. Write 0x04 L H where L is the hash length and H is HASH(SPKI).
      6. Write the remaining TBSCertificate contents octets.
      7. Finalize.
      Parameters:
      extensionsWire - the extensions<0..2^16-1> field exactly as it appears at the start of the corresponding MTCProof (use MTCProof.getExtensionsWire())
      Throws:
      IOException
    • computeEntryHash

      public static byte[] computeEntryHash(org.bouncycastle.asn1.x509.TBSCertificate tbsCert, byte[] extensionsWire, MerkleTreeHash hashFunc) throws IOException
      TBSCertificate variant of computeEntryHash(X509CertificateHolder, byte[], MerkleTreeHash). The hash depends only on the to-be-signed structure, so callers that haven't yet wrapped the TBSCertificate in a signed X509CertificateHolder can compute the entry hash directly.
      Throws:
      IOException
    • computeEntryHash

      public static byte[] computeEntryHash(byte[] tbsCertDer, byte[] extensionsWire, MerkleTreeHash hashFunc) throws IOException
      Raw-DER variant of computeEntryHash(TBSCertificate, byte[], MerkleTreeHash) — skips the parse + re-encode round trip when the TBSCertificate is already in hand as DER bytes.
      Throws:
      IOException
    • writeEntryHashInput

      public static void writeEntryHashInput(X509CertificateHolder certHolder, byte[] extensionsWire, MerkleTreeHash hashFunc, OutputStream out) throws IOException
      Streams the byte sequence that computeEntryHash(X509CertificateHolder, MerkleTreeHash) hashes into the supplied OutputStream. Equivalent in output to building a ByteArrayOutputStream and finishing with hashFunc.hashLeaf(baos.toByteArray()), but lets callers pipe the bytes directly into a streaming digest (e.g. org.bouncycastle.crypto.io.DigestOutputStream or java.security.DigestOutputStream) so the MerkleTreeCertEntry never lives fully in memory.

      hashFunc is still required because Section 7.2's single-pass procedure (step 8) hashes the SubjectPublicKeyInfo separately via MerkleTreeHash.hashRaw(byte[]) and writes only its hash into the entry stream.

      Parameters:
      certHolder - the X.509 certificate
      extensionsWire - the MTCProof.getExtensionsWire() bytes (or {0, 0} for an empty extensions list)
      hashFunc - hash function used for the SPKI hash; the caller computes the leaf hash separately (typically by feeding the leaf-tag byte 0x00 into a digest first, then piping out into the same digest)
      out - destination for the streamed entry bytes
      Throws:
      IOException
    • writeEntryHashInput

      public static void writeEntryHashInput(org.bouncycastle.asn1.x509.TBSCertificate tbsCert, byte[] extensionsWire, MerkleTreeHash hashFunc, OutputStream out) throws IOException
      Throws:
      IOException
    • writeEntryHashInput

      public static void writeEntryHashInput(byte[] tbsCertDer, byte[] extensionsWire, MerkleTreeHash hashFunc, OutputStream out) throws IOException
      Raw-DER variant of writeEntryHashInput(TBSCertificate, byte[], MerkleTreeHash, OutputStream) — skips the parse + re-encode round trip when the TBSCertificate is already in hand as DER bytes (e.g. captured from a streaming ContentSigner).
      Throws:
      IOException
    • extractCaIdFromIssuer

      public static byte[] extractCaIdFromIssuer(org.bouncycastle.asn1.x500.X500Name issuer) throws IOException
      Extracts the binary CA trust anchor ID from the issuer field of a Merkle Tree certificate. Per Section 5.1 of the draft the issuer name has a single RDN with a single attribute. For initial experimentation the attribute type is id_rdna_trustAnchorID (1.3.6.1.4.1.44363.47.1) with a UTF8String value of the dotted-decimal trust anchor ID; for the production encoding the value is a RELATIVE-OID. Both are accepted; the return value is the binary trust anchor ID per Section 3 of draft-ietf-tls-trust-anchor-ids.
      Throws:
      IOException