| /* Copyright (c) 2023, Google Inc. |
| * |
| * Permission to use, copy, modify, and/or distribute this software for any |
| * purpose with or without fee is hereby granted, provided that the above |
| * copyright notice and this permission notice appear in all copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
| * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
| * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ |
| |
| #include <string.h> |
| |
| #include <optional> |
| #include <vector> |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| #include <openssl/pki/verify.h> |
| #include <openssl/pki/verify_error.h> |
| #include <openssl/sha.h> |
| |
| #include "test_helpers.h" |
| |
| namespace bssl { |
| |
| static std::unique_ptr<VerifyTrustStore> MozillaRootStore() { |
| std::string diagnostic; |
| return VerifyTrustStore::FromDER( |
| bssl::ReadTestFileToString( |
| "testdata/verify_unittest/mozilla_roots.der"), |
| &diagnostic); |
| } |
| |
| using ::testing::UnorderedElementsAre; |
| |
| static std::string GetTestdata(std::string_view filename) { |
| return bssl::ReadTestFileToString("testdata/verify_unittest/" + |
| std::string(filename)); |
| } |
| |
| TEST(VerifyTest, GoogleChain) { |
| const std::string leaf = GetTestdata("google-leaf.der"); |
| const std::string intermediate1 = GetTestdata("google-intermediate1.der"); |
| const std::string intermediate2 = GetTestdata("google-intermediate2.der"); |
| CertificateVerifyOptions opts; |
| opts.leaf_cert = leaf; |
| opts.intermediates = {intermediate1, intermediate2}; |
| opts.time = 1499727444; |
| std::unique_ptr<VerifyTrustStore> roots = MozillaRootStore(); |
| opts.trust_store = roots.get(); |
| |
| VerifyError error; |
| ASSERT_TRUE(CertificateVerify(opts, &error)) << error.DiagnosticString(); |
| |
| opts.intermediates = {}; |
| EXPECT_FALSE(CertificateVerify(opts, &error)); |
| ASSERT_EQ(error.Code(), VerifyError::StatusCode::PATH_NOT_FOUND) |
| << error.DiagnosticString(); |
| } |
| |
| |
| TEST(VerifyTest, ExtraIntermediates) { |
| const std::string leaf = GetTestdata("google-leaf.der"); |
| const std::string intermediate1 = GetTestdata("google-intermediate1.der"); |
| const std::string intermediate2 = GetTestdata("google-intermediate2.der"); |
| |
| CertificateVerifyOptions opts; |
| opts.leaf_cert = leaf; |
| std::string diagnostic; |
| const auto cert_pool_status = CertPool::FromCerts( |
| { |
| intermediate1, |
| intermediate2, |
| }, |
| &diagnostic); |
| ASSERT_TRUE(cert_pool_status) << diagnostic; |
| opts.extra_intermediates = cert_pool_status.get(); |
| opts.time = 1499727444; |
| std::unique_ptr<VerifyTrustStore> roots = MozillaRootStore(); |
| opts.trust_store = roots.get(); |
| |
| VerifyError error; |
| ASSERT_TRUE(CertificateVerify(opts, &error)) << error.DiagnosticString(); |
| } |
| |
| TEST(VerifyTest, AllPaths) { |
| const std::string leaf = GetTestdata("lencr-leaf.der"); |
| const std::string intermediate1 = GetTestdata("lencr-intermediate-r3.der"); |
| const std::string intermediate2 = |
| GetTestdata("lencr-root-x1-cross-signed.der"); |
| const std::string root1 = GetTestdata("lencr-root-x1.der"); |
| const std::string root2 = GetTestdata("lencr-root-dst-x3.der"); |
| |
| std::vector<std::string> expected_path1 = {leaf, intermediate1, root1}; |
| std::vector<std::string> expected_path2 = {leaf, intermediate1, intermediate2, |
| root2}; |
| |
| CertificateVerifyOptions opts; |
| opts.leaf_cert = leaf; |
| opts.intermediates = {intermediate1, intermediate2}; |
| opts.time = 1699404611; |
| std::unique_ptr<VerifyTrustStore> roots = MozillaRootStore(); |
| opts.trust_store = roots.get(); |
| |
| auto paths = CertificateVerifyAllPaths(opts); |
| ASSERT_TRUE(paths); |
| EXPECT_EQ(2U, paths.value().size()); |
| EXPECT_THAT(paths.value(), |
| UnorderedElementsAre(expected_path1, expected_path2)); |
| } |
| |
| TEST(VerifyTest, DepthLimit) { |
| const std::string leaf = GetTestdata("google-leaf.der"); |
| const std::string intermediate1 = GetTestdata("google-intermediate1.der"); |
| const std::string intermediate2 = GetTestdata("google-intermediate2.der"); |
| CertificateVerifyOptions opts; |
| opts.leaf_cert = leaf; |
| opts.intermediates = {intermediate1, intermediate2}; |
| opts.time = 1499727444; |
| // Set the |max_path_building_depth| explicitly to test the non-default case. |
| // Depth of 5 is enough to successfully find a path. |
| opts.max_path_building_depth = 5; |
| std::unique_ptr<VerifyTrustStore> roots = MozillaRootStore(); |
| opts.trust_store = roots.get(); |
| |
| VerifyError error; |
| ASSERT_TRUE(CertificateVerify(opts, &error)) << error.DiagnosticString(); |
| |
| // Depth of 2 is not enough to find a path. |
| opts.max_path_building_depth = 2; |
| EXPECT_FALSE(CertificateVerify(opts, &error)); |
| ASSERT_EQ(error.Code(), VerifyError::StatusCode::PATH_DEPTH_LIMIT_REACHED) |
| << error.DiagnosticString(); |
| } |
| |
| } // namespace bssl |