Implement MTC plants-04 CA cosignature verification.

(Verifying the other cosignatures will be handled in a followup.)

Bug: 452983502
Change-Id: I0e546b282f307d2c53fcd88c7ea2fc4982de1042
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/96487
Reviewed-by: David Benjamin <davidben@google.com>
Presubmit-BoringSSL-Verified: boringssl-scoped@luci-project-accounts.iam.gserviceaccount.com <boringssl-scoped@luci-project-accounts.iam.gserviceaccount.com>
Commit-Queue: Matt Mueller <mattm@google.com>
diff --git a/gen/sources.bzl b/gen/sources.bzl
index a92991a..656d77f 100644
--- a/gen/sources.bzl
+++ b/gen/sources.bzl
@@ -2323,6 +2323,12 @@
     "pki/testdata/path_builder_unittest/mtc/mtc-leaf.pem",
     "pki/testdata/path_builder_unittest/mtc_plants04/leaf.pem",
     "pki/testdata/path_builder_unittest/mtc_plants04/mtc-ica.pem",
+    "pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-duplicate_ca_signer.pem",
+    "pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-3cosigners.pem",
+    "pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-cosigner_wrong_order.pem",
+    "pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-duplicate_ca_signer.pem",
+    "pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-no_ca_signer.pem",
+    "pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone.pem",
     "pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf.pem",
     "pki/testdata/path_builder_unittest/multi-root-A-by-B.pem",
     "pki/testdata/path_builder_unittest/multi-root-B-by-C.pem",
diff --git a/gen/sources.cmake b/gen/sources.cmake
index 36e9796..1520f0c 100644
--- a/gen/sources.cmake
+++ b/gen/sources.cmake
@@ -2381,6 +2381,12 @@
   pki/testdata/path_builder_unittest/mtc/mtc-leaf.pem
   pki/testdata/path_builder_unittest/mtc_plants04/leaf.pem
   pki/testdata/path_builder_unittest/mtc_plants04/mtc-ica.pem
+  pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-duplicate_ca_signer.pem
+  pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-3cosigners.pem
+  pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-cosigner_wrong_order.pem
+  pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-duplicate_ca_signer.pem
+  pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-no_ca_signer.pem
+  pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone.pem
   pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf.pem
   pki/testdata/path_builder_unittest/multi-root-A-by-B.pem
   pki/testdata/path_builder_unittest/multi-root-B-by-C.pem
diff --git a/gen/sources.gni b/gen/sources.gni
index 8172b50..a3baf28 100644
--- a/gen/sources.gni
+++ b/gen/sources.gni
@@ -2323,6 +2323,12 @@
   "pki/testdata/path_builder_unittest/mtc/mtc-leaf.pem",
   "pki/testdata/path_builder_unittest/mtc_plants04/leaf.pem",
   "pki/testdata/path_builder_unittest/mtc_plants04/mtc-ica.pem",
+  "pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-duplicate_ca_signer.pem",
+  "pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-3cosigners.pem",
+  "pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-cosigner_wrong_order.pem",
+  "pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-duplicate_ca_signer.pem",
+  "pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-no_ca_signer.pem",
+  "pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone.pem",
   "pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf.pem",
   "pki/testdata/path_builder_unittest/multi-root-A-by-B.pem",
   "pki/testdata/path_builder_unittest/multi-root-B-by-C.pem",
diff --git a/gen/sources.json b/gen/sources.json
index 966e727..7c378fd 100644
--- a/gen/sources.json
+++ b/gen/sources.json
@@ -2303,6 +2303,12 @@
       "pki/testdata/path_builder_unittest/mtc/mtc-leaf.pem",
       "pki/testdata/path_builder_unittest/mtc_plants04/leaf.pem",
       "pki/testdata/path_builder_unittest/mtc_plants04/mtc-ica.pem",
+      "pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-duplicate_ca_signer.pem",
+      "pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-3cosigners.pem",
+      "pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-cosigner_wrong_order.pem",
+      "pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-duplicate_ca_signer.pem",
+      "pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-no_ca_signer.pem",
+      "pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone.pem",
       "pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf.pem",
       "pki/testdata/path_builder_unittest/multi-root-A-by-B.pem",
       "pki/testdata/path_builder_unittest/multi-root-B-by-C.pem",
diff --git a/gen/sources.mk b/gen/sources.mk
index f24cef4..41626ba 100644
--- a/gen/sources.mk
+++ b/gen/sources.mk
@@ -2295,6 +2295,12 @@
   pki/testdata/path_builder_unittest/mtc/mtc-leaf.pem \
   pki/testdata/path_builder_unittest/mtc_plants04/leaf.pem \
   pki/testdata/path_builder_unittest/mtc_plants04/mtc-ica.pem \
+  pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-duplicate_ca_signer.pem \
+  pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-3cosigners.pem \
+  pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-cosigner_wrong_order.pem \
+  pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-duplicate_ca_signer.pem \
+  pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-no_ca_signer.pem \
+  pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone.pem \
   pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf.pem \
   pki/testdata/path_builder_unittest/multi-root-A-by-B.pem \
   pki/testdata/path_builder_unittest/multi-root-B-by-C.pem \
diff --git a/pki/path_builder_unittest.cc b/pki/path_builder_unittest.cc
index f83af58..026ce8b 100644
--- a/pki/path_builder_unittest.cc
+++ b/pki/path_builder_unittest.cc
@@ -20,6 +20,8 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
+#include <openssl/base.h>
+#include <openssl/bytestring.h>
 #include <openssl/pool.h>
 #include <openssl/pki/verify.h>
 
@@ -31,6 +33,7 @@
 #include "input.h"
 #include "mock_signature_verify_cache.h"
 #include "parsed_certificate.h"
+#include "signature_algorithm.h"
 #include "simple_path_builder_delegate.h"
 #include "string_util.h"
 #include "test_helpers.h"
@@ -2452,6 +2455,22 @@
   EXPECT_EQ(0xB33F, data->value);
 }
 
+UniquePtr<CRYPTO_BUFFER> ExportPublicKeyFromSeed(Span<const uint8_t> seed) {
+  UniquePtr<EVP_PKEY> pkey(EVP_PKEY_from_private_seed(
+      EVP_pkey_ml_dsa_44(), seed.data(), seed.size()));
+  if (!pkey) {
+    return nullptr;
+  }
+
+  ScopedCBB cbb;
+  if (!CBB_init(cbb.get(), 0) ||
+      !EVP_marshal_public_key(cbb.get(), pkey.get())) {
+    return nullptr;
+  }
+  return UniquePtr<CRYPTO_BUFFER>(
+      CRYPTO_BUFFER_new(CBB_data(cbb.get()), CBB_len(cbb.get()), nullptr));
+}
+
 class PathBuilderMTCPlants04Test : public PathBuilderSimpleChainTest {
  public:
   PathBuilderMTCPlants04Test() = default;
@@ -2471,10 +2490,49 @@
     subtree.range.end = 10;
     std::map<uint16_t, std::vector<TrustedSubtree>> subtrees;
     subtrees[1] = {std::move(subtree)};
-    static constexpr uint8_t ca_id[] = {0x81, 0xfd, 0x59, 0x01};
-    mtc_anchor_ =
-        std::make_shared<MTCAnchor>(MakeSpan(ca_id), std::move(subtrees));
+    TrustedSubtree subtree2;
+    subtree2.range.start = 0;
+    subtree2.range.end = 10;
+    subtree2.hash.fill(1);
+    std::map<uint16_t, std::vector<TrustedSubtree>> subtrees2;
+    subtrees2[1] = {std::move(subtree2)};
+    static constexpr uint8_t kCaId[] = {0x81, 0xfd, 0x59, 0x01};
+    // With ml-dsa it is much more compact to encode the private key seed and
+    // derive the public key from that.
+    static constexpr uint8_t kCaPrivateKeySeed[] = {
+        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+        0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
+        0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f};
+    UniquePtr<CRYPTO_BUFFER> spki = ExportPublicKeyFromSeed(kCaPrivateKeySeed);
+    ASSERT_TRUE(spki);
+    static constexpr uint8_t kCaPrivateKeySeed2[32] = {0x00};
+    UniquePtr<CRYPTO_BUFFER> spki2 =
+        ExportPublicKeyFromSeed(kCaPrivateKeySeed2);
+    ASSERT_TRUE(spki2);
+
+    mtc_anchor_ = std::make_shared<MTCAnchor>(
+        MakeSpan(kCaId), SignatureAlgorithm::kMldsa44, UpRef(spki), subtrees);
     ASSERT_EQ(mtc_anchor_->spec_version(), MTCAnchor::kPlants04);
+
+    mtc_anchor_wrong_key_ = std::make_shared<MTCAnchor>(
+        MakeSpan(kCaId), SignatureAlgorithm::kMldsa44, UpRef(spki2), subtrees);
+    ASSERT_EQ(mtc_anchor_wrong_key_->spec_version(), MTCAnchor::kPlants04);
+
+    mtc_anchor_wrong_subtree_hash_ = std::make_shared<MTCAnchor>(
+        MakeSpan(kCaId), SignatureAlgorithm::kMldsa44, UpRef(spki), subtrees2);
+    ASSERT_EQ(mtc_anchor_wrong_subtree_hash_->spec_version(),
+              MTCAnchor::kPlants04);
+
+    mtc_anchor_no_subtrees_ = std::make_shared<MTCAnchor>(
+        MakeSpan(kCaId), SignatureAlgorithm::kMldsa44, UpRef(spki),
+        std::map<uint16_t, std::vector<TrustedSubtree>>());
+    ASSERT_EQ(mtc_anchor_no_subtrees_->spec_version(), MTCAnchor::kPlants04);
+
+    mtc_anchor_no_subtrees_wrong_key_ = std::make_shared<MTCAnchor>(
+        MakeSpan(kCaId), SignatureAlgorithm::kMldsa44, UpRef(spki2),
+        std::map<uint16_t, std::vector<TrustedSubtree>>());
+    ASSERT_EQ(mtc_anchor_no_subtrees_wrong_key_->spec_version(),
+              MTCAnchor::kPlants04);
   }
 
   CertPathBuilder::Result RunPathBuilder(
@@ -2499,8 +2557,125 @@
   }
 
   std::shared_ptr<MTCAnchor> mtc_anchor_;
+  std::shared_ptr<MTCAnchor> mtc_anchor_wrong_key_;
+  std::shared_ptr<MTCAnchor> mtc_anchor_wrong_subtree_hash_;
+  std::shared_ptr<MTCAnchor> mtc_anchor_no_subtrees_;
+  std::shared_ptr<MTCAnchor> mtc_anchor_no_subtrees_wrong_key_;
 };
 
+TEST_F(PathBuilderMTCPlants04Test, Verification) {
+  std::shared_ptr<const ParsedCertificate> signatureless_leaf;
+  ASSERT_TRUE(ReadTestCert("mtc_plants04/mtc-leaf.pem", &signatureless_leaf));
+  std::shared_ptr<const ParsedCertificate> standalone_leaf;
+  ASSERT_TRUE(
+      ReadTestCert("mtc_plants04/mtc-leaf-standalone.pem", &standalone_leaf));
+
+  TrustStoreInMemory trust_store_with_subtrees;
+  ASSERT_TRUE(trust_store_with_subtrees.AddMTCTrustAnchor(mtc_anchor_));
+  TrustStoreInMemory trust_store_with_subtrees_wrong_key;
+  ASSERT_TRUE(trust_store_with_subtrees_wrong_key.AddMTCTrustAnchor(
+      mtc_anchor_wrong_key_));
+  TrustStoreInMemory trust_store_wrong_subtreehash;
+  ASSERT_TRUE(trust_store_wrong_subtreehash.AddMTCTrustAnchor(
+      mtc_anchor_wrong_subtree_hash_));
+
+  TrustStoreInMemory trust_store_no_subtrees;
+  ASSERT_TRUE(
+      trust_store_no_subtrees.AddMTCTrustAnchor(mtc_anchor_no_subtrees_));
+  TrustStoreInMemory trust_store_no_subtrees_wrong_key;
+  ASSERT_TRUE(trust_store_no_subtrees_wrong_key.AddMTCTrustAnchor(
+      mtc_anchor_no_subtrees_wrong_key_));
+
+  // Signatureless cert should be valid when verified against the anchor
+  // configured with subtrees (regardless of what key the anchor is configured
+  // with).
+  CertPathBuilder::Result result = RunPathBuilder(
+      signatureless_leaf, &trust_store_with_subtrees, nullptr, nullptr);
+  EXPECT_TRUE(result.HasValidPath());
+  result =
+      RunPathBuilder(signatureless_leaf, &trust_store_with_subtrees_wrong_key,
+                     nullptr, nullptr);
+  EXPECT_TRUE(result.HasValidPath());
+
+  // Signatureless cert should fail when verified against either anchor without
+  // subtrees.
+  result = RunPathBuilder(signatureless_leaf, &trust_store_no_subtrees, nullptr,
+                          nullptr);
+  EXPECT_FALSE(result.HasValidPath());
+  result = RunPathBuilder(signatureless_leaf,
+                          &trust_store_no_subtrees_wrong_key, nullptr, nullptr);
+  EXPECT_FALSE(result.HasValidPath());
+
+  // Standalone cert should be valid when verified against the anchor
+  // configured with subtrees (regardless of what key the anchor is configured
+  // with).
+  result = RunPathBuilder(standalone_leaf, &trust_store_with_subtrees, nullptr,
+                          nullptr);
+  EXPECT_TRUE(result.HasValidPath());
+  result = RunPathBuilder(standalone_leaf, &trust_store_with_subtrees_wrong_key,
+                          nullptr, nullptr);
+  EXPECT_TRUE(result.HasValidPath());
+
+  // Standalone should be valid when verified against the anchor without
+  // subtrees only if it has the correct key.
+  result = RunPathBuilder(standalone_leaf, &trust_store_no_subtrees, nullptr,
+                          nullptr);
+  EXPECT_TRUE(result.HasValidPath());
+  result = RunPathBuilder(standalone_leaf, &trust_store_no_subtrees_wrong_key,
+                          nullptr, nullptr);
+  EXPECT_FALSE(result.HasValidPath());
+
+  // Both certs should fail when verified against the anchor with wrong subtree
+  // hash.
+  result = RunPathBuilder(signatureless_leaf, &trust_store_wrong_subtreehash,
+                          nullptr, nullptr);
+  EXPECT_FALSE(result.HasValidPath());
+  result = RunPathBuilder(standalone_leaf, &trust_store_wrong_subtreehash,
+                          nullptr, nullptr);
+  EXPECT_FALSE(result.HasValidPath());
+
+  // Cert with multiple cosigners (including valid CA cosigner) should validate
+  // succesfully, ignoring the unknown cosigners.
+  std::shared_ptr<const ParsedCertificate> standalone_leaf_3_cosigners;
+  ASSERT_TRUE(
+      ReadTestCert("mtc_plants04/mtc-leaf-standalone-3cosigners.pem",
+        &standalone_leaf_3_cosigners));
+  result = RunPathBuilder(standalone_leaf_3_cosigners,
+      &trust_store_no_subtrees, nullptr, nullptr);
+  EXPECT_TRUE(result.HasValidPath());
+  // but it should fail if the CA key is wrong:
+  result = RunPathBuilder(standalone_leaf_3_cosigners,
+      &trust_store_no_subtrees_wrong_key, nullptr, nullptr);
+  EXPECT_FALSE(result.HasValidPath());
+
+  // Cert with a cosigner but no CA cosigner should fail:
+  std::shared_ptr<const ParsedCertificate> standalone_leaf_no_ca_signer;
+  ASSERT_TRUE(
+      ReadTestCert("mtc_plants04/mtc-leaf-standalone-no_ca_signer.pem",
+        &standalone_leaf_no_ca_signer));
+  result = RunPathBuilder(standalone_leaf_no_ca_signer,
+      &trust_store_no_subtrees, nullptr, nullptr);
+  EXPECT_FALSE(result.HasValidPath());
+
+  // Cert with a duplicate CA cosigner should fail:
+  std::shared_ptr<const ParsedCertificate> standalone_leaf_duplicate_ca_signer;
+  ASSERT_TRUE(
+      ReadTestCert("mtc_plants04/mtc-leaf-standalone-duplicate_ca_signer.pem",
+        &standalone_leaf_duplicate_ca_signer));
+  result = RunPathBuilder(standalone_leaf_duplicate_ca_signer,
+      &trust_store_no_subtrees, nullptr, nullptr);
+  EXPECT_FALSE(result.HasValidPath());
+
+  // Cert with a cosigners in non-sorted order should fail:
+  std::shared_ptr<const ParsedCertificate> standalone_leaf_cosigner_wrong_order;
+  ASSERT_TRUE(
+      ReadTestCert("mtc_plants04/mtc-leaf-standalone-cosigner_wrong_order.pem",
+        &standalone_leaf_cosigner_wrong_order));
+  result = RunPathBuilder(standalone_leaf_cosigner_wrong_order,
+      &trust_store_no_subtrees, nullptr, nullptr);
+  EXPECT_FALSE(result.HasValidPath());
+}
+
 TEST_F(PathBuilderMTCPlants04Test, CheckPathAfterVerification) {
   // Set up MTC leaf and its trust anchor.
   std::shared_ptr<const ParsedCertificate> mtc_leaf;
diff --git a/pki/testdata/path_builder_unittest/mtc_plants04/README.md b/pki/testdata/path_builder_unittest/mtc_plants04/README.md
index 3eaecee..1dc9bba 100644
--- a/pki/testdata/path_builder_unittest/mtc_plants04/README.md
+++ b/pki/testdata/path_builder_unittest/mtc_plants04/README.md
@@ -4,6 +4,17 @@
 
 - `mtc-leaf.pem`
   - signatureless MTC issued by an MTC CA
+- `mtc-leaf-standalone.pem`
+  - standalone MTC issued by an MTC CA
+- `mtc-leaf-standalone-3cosigners.pem`
+  - standalone MTC containing the CA cosignature and two other cosignatures.
+- `mtc-leaf-standalone-no_ca_signers.pem`
+  - MTC containing one cosignature, but no CA cosignature.
+- `mtc-leaf-standalone-duplicate_ca_signer.pem`
+  - standalone MTC containing two duplicate CA cosignatures.
+- `mtc-leaf-standalone-cosigner_wrong_order.pem`
+  - standalone MTC containing the CA cosignature and another cosignatures, but
+    the cosignatures are not in sorted order.
 - `mtc-ica.pem`
   - signatureless MTC issued by the same MTC CA
   - its BasicConstraints has `cA=TRUE`
@@ -22,14 +33,8 @@
 2. Copy the certificate PEM to `leaf.pem`
 3. Copy the ICA SPKI base64 to the first `PublicKey` entry in `mtc-config.json`
 
-The next step is to generate the MTC representation of the ICA:
+The next step is to generate the MTCs:
 
-1. Run `mkdir out`
-2. Run
-   `go run github.com/ietf-plants-wg/merkle-tree-certs.git/demo@9029a99bcfa4e91b8b8e9ba646ac386a6e1c208f -config=mtc-config.json -out=out`
-3. Move `out/cert_0_0.pem` to `mtc-ica.pem`
-4. Move `out/cert_1_0.pem` to `mtc-leaf.pem`
-5. Copy the subtree and hash from the command output into
-   `PathBuilderMTCPlants04Test::SetUp`.
-6. Remove other artifacts created by the merkle-tree-certs/demo tool (e.g.
-   `rm -r out`).
+1. Run `generate_mtcs.sh`
+2. Copy the subtree range and hash from the script output into
+PathBuilderMTCPlants04Test::SetUp.
diff --git a/pki/testdata/path_builder_unittest/mtc_plants04/generate_mtcs.sh b/pki/testdata/path_builder_unittest/mtc_plants04/generate_mtcs.sh
new file mode 100755
index 0000000..55cb433
--- /dev/null
+++ b/pki/testdata/path_builder_unittest/mtc_plants04/generate_mtcs.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -e -x
+
+mkdir out
+
+go run github.com/ietf-plants-wg/merkle-tree-certs/demo@9029a99bcfa4e91b8b8e9ba646ac386a6e1c208f -config=mtc-config.json -out=out
+
+mv -v out/cert_0_0.pem mtc-ica.pem
+mv -v out/cert_1_0.pem mtc-leaf.pem
+mv -v out/cert_1_1.pem mtc-leaf-standalone.pem
+mv -v out/cert_1_2.pem mtc-leaf-standalone-3cosigners.pem
+mv -v out/cert_1_3.pem mtc-leaf-standalone-no_ca_signer.pem
+mv -v out/cert_1_4.pem mtc-leaf-standalone-duplicate_ca_signer.pem
+mv -v out/cert_1_5.pem mtc-leaf-standalone-cosigner_wrong_order.pem
+rm -r out
+
diff --git a/pki/testdata/path_builder_unittest/mtc_plants04/mtc-config.json b/pki/testdata/path_builder_unittest/mtc_plants04/mtc-config.json
index 8060d9c..f501a7e 100644
--- a/pki/testdata/path_builder_unittest/mtc_plants04/mtc-config.json
+++ b/pki/testdata/path_builder_unittest/mtc_plants04/mtc-config.json
@@ -4,9 +4,19 @@
   "LogNumber": 1,
   "Cosigners": [
     {
+      "CosignerID": "32473.0",
+      "SignatureAlgorithm": "mldsa44",
+      "PrivateKey": "MDQCAQAwCwYJYIZIAWUDBAMRBCKAIKqqqqqqqqqqqqqqqqqqqqqqoRERERERERERERERERER"
+    },
+    {
       "CosignerID": "32473.1",
       "SignatureAlgorithm": "mldsa44",
       "PrivateKey": "MDQCAQAwCwYJYIZIAWUDBAMRBCKAIAABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4f"
+    },
+    {
+      "CosignerID": "32473.2",
+      "SignatureAlgorithm": "mldsa44",
+      "PrivateKey": "MDQCAQAwCwYJYIZIAWUDBAMRBCKAIKqqqqqqqqqqqqqqqqqqqqoiIiIiIiIiIiIiIiIiIiIi"
     }
   ],
   "Entries": [
@@ -46,6 +56,32 @@
         {
           "SubtreeStart": 0,
           "SubtreeEnd": 10
+        },
+        {
+          "SubtreeStart": 0,
+          "SubtreeEnd": 10,
+          "Cosigners": ["32473.1"]
+        },
+        {
+          "SubtreeStart": 0,
+          "SubtreeEnd": 10,
+          "Cosigners": ["32473.0", "32473.1", "32473.2"]
+        },
+        {
+          "SubtreeStart": 0,
+          "SubtreeEnd": 10,
+          "Cosigners": ["32473.0"]
+        },
+        {
+          "SubtreeStart": 0,
+          "SubtreeEnd": 10,
+          "Cosigners": ["32473.1", "32473.1"]
+        },
+        {
+          "SubtreeStart": 0,
+          "SubtreeEnd": 10,
+          "Cosigners": ["32473.1", "32473.0"],
+          "DontSortCosigners": true
         }
       ]
     },
diff --git a/pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-duplicate_ca_signer.pem b/pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-duplicate_ca_signer.pem
new file mode 100644
index 0000000..1afa8a1
--- /dev/null
+++ b/pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-duplicate_ca_signer.pem
@@ -0,0 +1,113 @@
+-----BEGIN CERTIFICATE-----
+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
+jY6Vm8XIz9vc/AAAAAAAAAAAAAAAAAAACSAyQg==
+-----END CERTIFICATE-----
diff --git a/pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-3cosigners.pem b/pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-3cosigners.pem
new file mode 100644
index 0000000..1cf1bcf
--- /dev/null
+++ b/pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-3cosigners.pem
@@ -0,0 +1,164 @@
+-----BEGIN CERTIFICATE-----
+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
+AAAACxsxRQ==
+-----END CERTIFICATE-----
diff --git a/pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-cosigner_wrong_order.pem b/pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-cosigner_wrong_order.pem
new file mode 100644
index 0000000..b232323
--- /dev/null
+++ b/pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-cosigner_wrong_order.pem
@@ -0,0 +1,113 @@
+-----BEGIN CERTIFICATE-----
+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
+4/Dz9QAAAAAAAAAAAAAAAAAAAAAAAAAAER8qPA==
+-----END CERTIFICATE-----
diff --git a/pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-duplicate_ca_signer.pem b/pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-duplicate_ca_signer.pem
new file mode 100644
index 0000000..a266019
--- /dev/null
+++ b/pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-duplicate_ca_signer.pem
@@ -0,0 +1,113 @@
+-----BEGIN CERTIFICATE-----
+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
+SF9hlJiur7u+2fcAAAAAAAAAAAAAAAAAECEzQw==
+-----END CERTIFICATE-----
diff --git a/pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-no_ca_signer.pem b/pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-no_ca_signer.pem
new file mode 100644
index 0000000..6e55f2a
--- /dev/null
+++ b/pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone-no_ca_signer.pem
@@ -0,0 +1,63 @@
+-----BEGIN CERTIFICATE-----
+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
+QQ==
+-----END CERTIFICATE-----
diff --git a/pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone.pem b/pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone.pem
new file mode 100644
index 0000000..0b08c5f
--- /dev/null
+++ b/pki/testdata/path_builder_unittest/mtc_plants04/mtc-leaf-standalone.pem
@@ -0,0 +1,63 @@
+-----BEGIN CERTIFICATE-----
+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
+OA==
+-----END CERTIFICATE-----
diff --git a/pki/trust_store.cc b/pki/trust_store.cc
index 5f8fef5..e734278 100644
--- a/pki/trust_store.cc
+++ b/pki/trust_store.cc
@@ -203,9 +203,13 @@
 
 MTCAnchor::MTCAnchor(
     bssl::Span<const uint8_t> ca_id,
+    SignatureAlgorithm ca_signature_algorithm,
+    bssl::UniquePtr<CRYPTO_BUFFER> ca_key,
     std::map<uint16_t, std::vector<TrustedSubtree>> trusted_subtrees)
     : spec_version_(MTCAnchor::MtcSpecVersion::kPlants04),
       ca_id_(ca_id.begin(), ca_id.end()),
+      ca_signature_algorithm_(ca_signature_algorithm),
+      ca_key_(std::move(ca_key)),
       trusted_subtrees_(std::move(trusted_subtrees)) {
   CreateSyntheticCert(ca_id);
 }
diff --git a/pki/trust_store.h b/pki/trust_store.h
index 39c74d8..7d201a9 100644
--- a/pki/trust_store.h
+++ b/pki/trust_store.h
@@ -20,11 +20,13 @@
 #include <optional>
 
 #include <openssl/base.h>
+#include <openssl/pool.h>
 #include <openssl/sha2.h>
 
 #include "cert_issuer_source.h"
 #include "merkle_tree.h"
 #include "parsed_certificate.h"
+#include "signature_algorithm.h"
 
 BSSL_NAMESPACE_BEGIN
 
@@ -157,8 +159,12 @@
 
   // Create an MTCAnchor with spec version kPlants04 for a trusted CA with
   // `ca_id` containing the DER encoding of the relative OID of the CA's ID.
+  // `ca_signature_algorithm` and `ca_key` configure the CA cosigner key.
+  // `ca_key` should be a DER-encoded SubjectPublicKeyInfo.
   // The `trusted_subtrees` must be sorted by their subtree ranges.
   MTCAnchor(Span<const uint8_t> ca_id,
+            SignatureAlgorithm ca_signature_algorithm,
+            UniquePtr<CRYPTO_BUFFER> ca_key,
             std::map<uint16_t, std::vector<TrustedSubtree>> trusted_subtrees);
 
   // Returns whether this MTCAnchor represents a valid anchor. This function
@@ -174,6 +180,14 @@
     BSSL_CHECK(spec_version_ == kPlants04);
     return ca_id_;
   }
+  SignatureAlgorithm ca_signature_algorithm() const {
+    BSSL_CHECK(spec_version_ == kPlants04);
+    return ca_signature_algorithm_;
+  }
+  const CRYPTO_BUFFER* ca_key() const {
+    BSSL_CHECK(spec_version_ == kPlants04);
+    return ca_key_.get();
+  }
   // TODO(nharper): Move this function to TrustAnchor.
   der::Input NormalizedSubject() const;
   // TODO(nharper): Remove this function in favor of TrustAnchor's version.
@@ -194,6 +208,8 @@
   MtcSpecVersion spec_version_;
   // (If spec_version_ == kDavidben08, `ca_id` is actually the log id.)
   std::vector<uint8_t> ca_id_;
+  SignatureAlgorithm ca_signature_algorithm_;
+  UniquePtr<CRYPTO_BUFFER> ca_key_;
   std::shared_ptr<const ParsedCertificate> synthetic_cert_;
   // If spec_version_ == kDavidben08, the 0th entry in the map will have the
   // trusted subtrees. Otherwise, this maps from the log_number to the trusted
diff --git a/pki/verify_certificate_chain.cc b/pki/verify_certificate_chain.cc
index 21322c5..f113bf7 100644
--- a/pki/verify_certificate_chain.cc
+++ b/pki/verify_certificate_chain.cc
@@ -17,10 +17,13 @@
 #include <algorithm>
 #include <cassert>
 
+#include <inttypes.h>
+
 #include <openssl/base.h>
 #include <openssl/bytestring.h>
 #include <openssl/digest.h>
 #include <openssl/mem.h>
+#include <openssl/pool.h>
 #include <openssl/sha2.h>
 #include <openssl/span.h>
 
@@ -1264,10 +1267,102 @@
                        expected_subtree_hash->size()) == 0;
 }
 
+static bool VerifyMTCProofSignaturePlants04(
+    const CBS *cosigner_id, Span<const uint8_t> log_id_text, uint64_t start,
+    uint64_t end, const TreeHash &expected_subtree_hash,
+    Span<const uint8_t> signature, SignatureAlgorithm signature_algorithm,
+    const CRYPTO_BUFFER *key_bytes, SignatureVerifyCache *cache) {
+  ScopedCBB cosigned_message;
+  // `cosigner_name` and `log_origin` are the only variable-length parts of
+  // `CosignedMessage`. Allocate the initial buffer size with 48 bytes for those
+  // (16 byte prefix + 32 bytes for the text representation of the
+  // relative-oid.)
+  if (!CBB_init(cosigned_message.get(), 12 + 48 + 8 + 48 + 8 + 8 + 32)) {
+    return false;
+  }
+  // Section 7.2 step 12:
+  // Signatures are verified as described in Section 5.3.1. For each signature
+  // verification, the CosignedMessage structure is constructed as follows:
+  //
+  // Section 5.3.1:
+  //     uint8 label[12] = "subtree/v1\n\0";
+  // (C string constants implicitly have a null terminator, so it's not
+  // explicitly included here:)
+  static constexpr uint8_t kLabel[12] = "subtree/v1\n";
+  if (!CBB_add_bytes(cosigned_message.get(), kLabel, sizeof(kLabel))) {
+    return false;
+  }
+  // Section 7.2: Set the CosignedMessage's cosigner_name based on the cosigner
+  // ID as described in Section 5.3.1.
+  // Section 5.3.1: opaque cosigner_name<1..2^8-1>;
+  static constexpr uint8_t kTaiPrefix[16] = {'o', 'i', 'd', '/', '1', '.',
+                                             '3', '.', '6', '.', '1', '.',
+                                             '4', '.', '1', '.'};
+  UniquePtr<char> cosigner_id_text_buf(
+      CBS_asn1_relative_oid_to_text(cosigner_id));
+  if (!cosigner_id_text_buf) {
+    return false;
+  }
+  Span<const uint8_t> cosigner_id_text =
+      StringAsBytes(cosigner_id_text_buf.get());
+  CBB cosigner_name;
+  if (!CBB_add_u8_length_prefixed(cosigned_message.get(), &cosigner_name) ||
+      !CBB_add_bytes(&cosigner_name, kTaiPrefix, sizeof(kTaiPrefix)) ||
+      !CBB_add_bytes(&cosigner_name, cosigner_id_text.data(),
+                     cosigner_id_text.size())) {
+    return false;
+  }
+
+  // Section 7.2: Set the CosignedMessage's timestamp to zero.
+  // Section 5.3.1: uint64 timestamp;
+  if (!CBB_add_u64(cosigned_message.get(), 0u)) {
+    return false;
+  }
+
+  // Section 7.2: Set the CosignedMessage's log_origin based on log_id as
+  // described in Section 5.3.1.
+  // Section 5.3.1:     opaque log_origin<1..2^8-1>;
+  CBB log_origin;
+  if (!CBB_add_u8_length_prefixed(cosigned_message.get(), &log_origin) ||
+      !CBB_add_bytes(&log_origin, kTaiPrefix, sizeof(kTaiPrefix)) ||
+      !CBB_add_bytes(&log_origin, log_id_text.data(), log_id_text.size())) {
+    return false;
+  }
+
+  // Section 7.2: Set the CosignedMessage's start and end to the MTCProof's
+  // start and end, respectively.
+  // Section 5.3.1: uint64 start;
+  // Section 5.3.1: uint64 end;
+  if (!CBB_add_u64(cosigned_message.get(), start) ||
+      !CBB_add_u64(cosigned_message.get(), end)) {
+    return false;
+  }
+
+  // Section 7.2: Set the CosignedMessage's subtree_hash to
+  // expected_subtree_hash.
+  // Section 5.3.1: HashValue subtree_hash;
+  if (!CBB_add_bytes(cosigned_message.get(), expected_subtree_hash.data(),
+                     expected_subtree_hash.size())) {
+    return false;
+  }
+
+  if (!CBB_flush(cosigned_message.get())) {
+    return false;
+  }
+
+  return VerifySignedData(
+      signature_algorithm,
+      Span<const uint8_t>(CBB_data(cosigned_message.get()),
+                          CBB_len(cosigned_message.get())),
+      der::BitString(signature, 0),
+      Span(CRYPTO_BUFFER_data(key_bytes), CRYPTO_BUFFER_len(key_bytes)), cache);
+}
+
 // This function implements draft-ietf-plants-merkle-tree-certs-04 section 7.2:
 // Verifying Certificate Signatures.
 static bool VerifyMTCDraftPlants04(const ParsedCertificate &cert,
-                                   const MTCAnchor *mtc_anchor) {
+                                   const MTCAnchor *mtc_anchor,
+                                   SignatureVerifyCache *cache) {
   // Step 1: Check that the TBSCertificate's signature field is id-alg-mtcProof
   // (kMtcProofDraftPlants04) with omitted parameters.
   if (cert.signature_algorithm() !=
@@ -1309,17 +1404,14 @@
     return false;
   }
 
-  // Step 6: Let log_id be the log ID constructed from the CA ID in issuer and
-  // the log_number.
-  //
-  // TODO(crbug.com/452983502): This step is only used for standalone
-  // certificate verification, which isn't implemented yet.
+  // Step 6 is only relevant for standalone certificate verification, so we put
+  // it off until we actually need it (in step 12).
 
   // Steps 7, 8, and 9 are done in a single pass as described in the procedure
   // at the end of section 7.2 ("entry_hash can equivalently be computed in a
   // single pass"):
   // 1. Initialize a hash instance.
-  bssl::ScopedEVP_MD_CTX entry_hash_ctx;
+  ScopedEVP_MD_CTX entry_hash_ctx;
   if (!EVP_DigestInit(entry_hash_ctx.get(), EVP_sha256())) {
     return false;
   }
@@ -1444,19 +1536,82 @@
                          expected_subtree_hash->size()) == 0;
   }
 
-  // TODO(crbug.com/452983502): Step 12 would check the MTCProof's signatures
-  // if there's no matching trusted subtree. This implementation does not
-  // support that check yet.
-  return false;
+  // Step 6: Let log_id be the log ID constructed from the CA ID in issuer and
+  // the log_number.
+  //
+  // Use the ca_id from mtc_anchor instead of parsing the id out of issuer. It
+  // should be guaranteed to be the same id, otherwise mtc_anchor would not
+  // have been selected as the anchor for this cert.
+  CBS ca_id(mtc_anchor->ca_id());
+  UniquePtr<char> ca_id_text(CBS_asn1_relative_oid_to_text(&ca_id));
+  if (!ca_id_text) {
+    return false;
+  }
+  // Section 5.1: For each positive integer N, the OID {caID logs(0) N}
+  // represents the issuance log N (Section 5.2).
+  std::string log_id_text = ca_id_text.get();
+  log_id_text += ".0.";
+  char log_number_text[DECIMAL_SIZE(log_number) + 1];
+  snprintf(log_number_text, sizeof(log_number_text), "%" PRIu16, log_number);
+  log_id_text += log_number_text;
+
+  // Step 12. Otherwise, check that the MTCProof's signatures contain a
+  // sufficient set of valid signatures from cosigners to satisfy the relying
+  // party's cosigner requirements (Section 7.3). Unrecognized cosigners MUST
+  // be ignored.
+
+  bool found_valid_ca_signature = false;
+  Span<const uint8_t> prev_cosigner_id;
+  while (CBS_len(&signatures)) {
+    CBS cbs_cosigner_id, signature;
+    if (!CBS_get_u8_length_prefixed(&signatures, &cbs_cosigner_id) ||
+        CBS_len(&cbs_cosigner_id) == 0 ||
+        !CBS_get_u16_length_prefixed(&signatures, &signature)) {
+      return false;
+    }
+    Span<const uint8_t> cosigner_id(cbs_cosigner_id);
+    // Section 6.1: Each element of the signatures field MUST have a unique
+    // cosigner_id. Elements MUST be ordered by cosigner_id as follows:
+    // (Checking the ordering isn't specified as part of the verification
+    // procedure, but it's good to enforce it, and means we don't need to worry
+    // about corner cases like multiple cosignatures with the same id, etc.)
+    if (!prev_cosigner_id.empty()) {
+      // Shorter byte strings are ordered before longer byte strings
+      if (prev_cosigner_id.size() > cosigner_id.size()) {
+        return false;
+      }
+      // Byte strings of the same length are ordered lexicographically
+      if (prev_cosigner_id.size() == cosigner_id.size() &&
+          !std::lexicographical_compare(
+              prev_cosigner_id.begin(), prev_cosigner_id.end(),
+              cosigner_id.begin(), cosigner_id.end())) {
+        return false;
+      }
+    }
+
+    if (cosigner_id == mtc_anchor->ca_id()) {
+      found_valid_ca_signature = VerifyMTCProofSignaturePlants04(
+          &cbs_cosigner_id, StringAsBytes(log_id_text), start, end,
+          expected_subtree_hash.value(), signature,
+          mtc_anchor->ca_signature_algorithm(), mtc_anchor->ca_key(), cache);
+    } else {
+      // TODO(crbug.com/452983502): check other co-signatures too.
+    }
+
+    prev_cosigner_id = cosigner_id;
+  }
+
+  return found_valid_ca_signature;
 }
 
 static bool VerifyMTC(const ParsedCertificate &cert,
-                      const MTCAnchor *mtc_anchor) {
+                      const MTCAnchor *mtc_anchor,
+                      SignatureVerifyCache *cache) {
   switch (mtc_anchor->spec_version()) {
     case MTCAnchor::MtcSpecVersion::kDavidben08:
       return VerifyMTCDraftDavidben08(cert, mtc_anchor);
     case MTCAnchor::MtcSpecVersion::kPlants04:
-      return VerifyMTCDraftPlants04(cert, mtc_anchor);
+      return VerifyMTCDraftPlants04(cert, mtc_anchor, cache);
   }
   return false;
 }
@@ -1498,7 +1653,8 @@
     if (!is_target_cert) {
       *shortcircuit_chain_validation = true;
       errors->AddError(cert_errors::kMaxPathLengthViolated);
-    } else if (!VerifyMTC(cert, working_mtc_anchor_)) {
+    } else if (!VerifyMTC(cert, working_mtc_anchor_,
+                          delegate_->GetVerifyCache())) {
       *shortcircuit_chain_validation = true;
       errors->AddError(cert_errors::kVerifySignedDataFailed);
     }