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); }