1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "net/cert/multi_log_ct_verifier.h" 6 7 #include <string> 8 9 #include "base/file_util.h" 10 #include "base/files/file_path.h" 11 #include "net/base/capturing_net_log.h" 12 #include "net/base/net_errors.h" 13 #include "net/base/net_log.h" 14 #include "net/base/test_data_directory.h" 15 #include "net/cert/ct_log_verifier.h" 16 #include "net/cert/ct_serialization.h" 17 #include "net/cert/ct_verify_result.h" 18 #include "net/cert/pem_tokenizer.h" 19 #include "net/cert/signed_certificate_timestamp.h" 20 #include "net/cert/x509_certificate.h" 21 #include "net/test/cert_test_util.h" 22 #include "net/test/ct_test_util.h" 23 #include "testing/gtest/include/gtest/gtest.h" 24 25 namespace net { 26 27 namespace { 28 29 const char kLogDescription[] = "somelog"; 30 31 class MultiLogCTVerifierTest : public ::testing::Test { 32 public: 33 virtual void SetUp() OVERRIDE { 34 scoped_ptr<CTLogVerifier> log( 35 CTLogVerifier::Create(ct::GetTestPublicKey(), kLogDescription)); 36 ASSERT_TRUE(log); 37 38 verifier_.reset(new MultiLogCTVerifier()); 39 verifier_->AddLog(log.Pass()); 40 std::string der_test_cert(ct::GetDerEncodedX509Cert()); 41 chain_ = X509Certificate::CreateFromBytes( 42 der_test_cert.data(), 43 der_test_cert.length()); 44 ASSERT_TRUE(chain_); 45 } 46 47 bool CheckForSingleVerifiedSCTInResult(const ct::CTVerifyResult& result) { 48 return (result.verified_scts.size() == 1U) && 49 result.invalid_scts.empty() && 50 result.unknown_logs_scts.empty() && 51 result.verified_scts[0]->log_description == kLogDescription; 52 } 53 54 bool CheckForSCTOrigin( 55 const ct::CTVerifyResult& result, 56 ct::SignedCertificateTimestamp::Origin origin) { 57 return (result.verified_scts.size() > 0) && 58 (result.verified_scts[0]->origin == origin); 59 } 60 61 bool CheckForEmbeddedSCTInNetLog(CapturingNetLog& net_log) { 62 CapturingNetLog::CapturedEntryList entries; 63 net_log.GetEntries(&entries); 64 if (entries.size() != 2) 65 return false; 66 67 const CapturingNetLog::CapturedEntry& received(entries[0]); 68 std::string embedded_scts; 69 if (!received.GetStringValue("embedded_scts", &embedded_scts)) 70 return false; 71 if (embedded_scts.empty()) 72 return false; 73 74 //XXX(eranm): entries[1] is the NetLog message with the checked SCTs. 75 //When CapturedEntry has methods to get a dictionary, rather than just 76 //a string, add more checks here. 77 78 return true; 79 } 80 81 bool CheckPrecertificateVerification(scoped_refptr<X509Certificate> chain) { 82 ct::CTVerifyResult result; 83 CapturingNetLog net_log; 84 BoundNetLog bound_net_log = 85 BoundNetLog::Make(&net_log, NetLog::SOURCE_CONNECT_JOB); 86 return (verifier_->Verify(chain, std::string(), std::string(), &result, 87 bound_net_log) == OK) && 88 CheckForSingleVerifiedSCTInResult(result) && 89 CheckForSCTOrigin( 90 result, ct::SignedCertificateTimestamp::SCT_EMBEDDED) && 91 CheckForEmbeddedSCTInNetLog(net_log); 92 } 93 94 protected: 95 scoped_ptr<MultiLogCTVerifier> verifier_; 96 scoped_refptr<X509Certificate> chain_; 97 }; 98 99 TEST_F(MultiLogCTVerifierTest, VerifiesEmbeddedSCT) { 100 scoped_refptr<X509Certificate> chain( 101 CreateCertificateChainFromFile(GetTestCertsDirectory(), 102 "ct-test-embedded-cert.pem", 103 X509Certificate::FORMAT_AUTO)); 104 ASSERT_TRUE(chain); 105 ASSERT_TRUE(CheckPrecertificateVerification(chain)); 106 } 107 108 TEST_F(MultiLogCTVerifierTest, VerifiesEmbeddedSCTWithPreCA) { 109 scoped_refptr<X509Certificate> chain( 110 CreateCertificateChainFromFile(GetTestCertsDirectory(), 111 "ct-test-embedded-with-preca-chain.pem", 112 X509Certificate::FORMAT_AUTO)); 113 ASSERT_TRUE(chain); 114 ASSERT_TRUE(CheckPrecertificateVerification(chain)); 115 } 116 117 TEST_F(MultiLogCTVerifierTest, VerifiesEmbeddedSCTWithIntermediate) { 118 scoped_refptr<X509Certificate> chain(CreateCertificateChainFromFile( 119 GetTestCertsDirectory(), 120 "ct-test-embedded-with-intermediate-chain.pem", 121 X509Certificate::FORMAT_AUTO)); 122 ASSERT_TRUE(chain); 123 ASSERT_TRUE(CheckPrecertificateVerification(chain)); 124 } 125 126 TEST_F(MultiLogCTVerifierTest, 127 VerifiesEmbeddedSCTWithIntermediateAndPreCA) { 128 scoped_refptr<X509Certificate> chain(CreateCertificateChainFromFile( 129 GetTestCertsDirectory(), 130 "ct-test-embedded-with-intermediate-preca-chain.pem", 131 X509Certificate::FORMAT_AUTO)); 132 ASSERT_TRUE(chain); 133 ASSERT_TRUE(CheckPrecertificateVerification(chain)); 134 } 135 136 TEST_F(MultiLogCTVerifierTest, 137 VerifiesSCTOverX509Cert) { 138 std::string sct(ct::GetTestSignedCertificateTimestamp()); 139 140 std::string sct_list; 141 ASSERT_TRUE(ct::EncodeSCTListForTesting(sct, &sct_list)); 142 143 ct::CTVerifyResult result; 144 EXPECT_EQ(OK, 145 verifier_->Verify(chain_, std::string(), sct_list, &result, 146 BoundNetLog())); 147 ASSERT_TRUE(CheckForSingleVerifiedSCTInResult(result)); 148 ASSERT_TRUE(CheckForSCTOrigin( 149 result, ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION)); 150 } 151 152 TEST_F(MultiLogCTVerifierTest, 153 IdentifiesSCTFromUnknownLog) { 154 std::string sct(ct::GetTestSignedCertificateTimestamp()); 155 156 // Change a byte inside the Log ID part of the SCT so it does 157 // not match the log used in the tests 158 sct[15] = 't'; 159 160 std::string sct_list; 161 ASSERT_TRUE(ct::EncodeSCTListForTesting(sct, &sct_list)); 162 163 ct::CTVerifyResult result; 164 EXPECT_NE(OK, 165 verifier_->Verify(chain_, std::string(), sct_list, &result, 166 BoundNetLog())); 167 EXPECT_EQ(1U, result.unknown_logs_scts.size()); 168 EXPECT_EQ("", result.unknown_logs_scts[0]->log_description); 169 } 170 171 } // namespace 172 173 } // namespace net 174