| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2015 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/tools/ct_mapper/my_visitor.h" |
| 6 |
| 7 #include <algorithm> |
| 8 |
| 9 #include "base/strings/stringprintf.h" |
| 10 #include "net/cert/internal/parsed_certificate.h" |
| 11 #include "net/cert/internal/signature_policy.h" |
| 12 #include "net/cert/internal/trust_store.h" |
| 13 #include "net/cert/internal/verify_certificate_chain.h" |
| 14 #include "net/der/encode_values.h" |
| 15 #include "net/der/input.h" |
| 16 #include "net/tools/ct_mapper/entry.h" |
| 17 #include "net/tools/ct_mapper/metrics.h" |
| 18 #include "net/tools/ct_mapper/visitor.h" |
| 19 |
| 20 namespace net { |
| 21 |
| 22 namespace { |
| 23 |
| 24 bool AddParsedCertificate(const der::Input& cert_data, |
| 25 ParsedCertificateList* chain, |
| 26 CertErrors* errors) { |
| 27 ParseCertificateOptions options; |
| 28 options.allow_invalid_serial_numbers = true; |
| 29 scoped_refptr<ParsedCertificate> cert = |
| 30 ParsedCertificate::CreateWithoutCopyingUnsafe( |
| 31 cert_data.UnsafeData(), cert_data.Length(), options, errors); |
| 32 if (!cert) { |
| 33 return false; |
| 34 } |
| 35 chain->push_back(std::move(cert)); |
| 36 return true; |
| 37 } |
| 38 |
| 39 void LogCertPathErrors(CertPathErrors* errors, |
| 40 const ParsedCertificateList& chain, |
| 41 const std::string& name, |
| 42 const Entry& entry, |
| 43 CertError::Severity severity, |
| 44 Metrics* metrics) { |
| 45 if (errors->ContainsAnyErrorWithSeverity(severity)) { |
| 46 MetricsItem* item = metrics->GetAndIncrementTotal(name); |
| 47 |
| 48 // Identify all the errors. |
| 49 std::set<std::string> error_set; |
| 50 for (size_t i = 0; i < chain.size(); ++i) { |
| 51 CertErrors* cert_errors = errors->GetErrorsForCert(i); |
| 52 for (const auto& error_node : cert_errors->nodes()) { |
| 53 if (error_node.severity == severity) { |
| 54 error_set.insert(error_node.ToDebugString()); |
| 55 } |
| 56 } |
| 57 } |
| 58 |
| 59 for (const auto& error : error_set) { |
| 60 item->GetAndIncrementTotal(error)->AddSampleChain(entry); |
| 61 } |
| 62 } |
| 63 } |
| 64 |
| 65 void LogCertErrors(const CertErrors& errors, |
| 66 const std::string& name, |
| 67 const der::Input& cert, |
| 68 CertError::Severity severity, |
| 69 bool parsing_succeeded, |
| 70 Metrics* metrics) { |
| 71 if (errors.ContainsAnyErrorWithSeverity(severity)) { |
| 72 MetricsItem* item = metrics->GetAndIncrementTotal(name); |
| 73 |
| 74 // Identify all the errors. |
| 75 std::set<std::string> error_set; |
| 76 for (const auto& error_node : errors.nodes()) { |
| 77 if (error_node.severity == severity) { |
| 78 error_set.insert(error_node.ToDebugString()); |
| 79 } |
| 80 } |
| 81 |
| 82 for (const auto& error : error_set) { |
| 83 item->GetAndIncrementTotal(error)->AddSampleCert(cert); |
| 84 } |
| 85 } else if (!parsing_succeeded && severity == CertError::SEVERITY_HIGH) { |
| 86 metrics->GetAndIncrementTotal(name) |
| 87 ->GetAndIncrementTotal("Unknown") |
| 88 ->AddSampleCert(cert); |
| 89 } |
| 90 } |
| 91 |
| 92 bool GetFullChain(const Entry& entry, |
| 93 ParsedCertificateList* chain, |
| 94 Metrics* metrics) { |
| 95 chain->reserve(entry.extra_certs.size() + 1); |
| 96 |
| 97 CertErrors errors; |
| 98 |
| 99 MetricsItem* item = metrics->GetAndIncrementTotal("Parse Certificate"); |
| 100 bool parsing_succeeded = AddParsedCertificate(entry.cert, chain, &errors); |
| 101 |
| 102 if (!parsing_succeeded) { |
| 103 item->GetAndIncrementTotal("Failure"); |
| 104 } else { |
| 105 item->GetAndIncrementTotal("Success"); |
| 106 } |
| 107 |
| 108 LogCertErrors(errors, "Parse certificate Errors", entry.cert, |
| 109 CertError::SEVERITY_HIGH, parsing_succeeded, metrics); |
| 110 LogCertErrors(errors, "Parse certificate Warnings", entry.cert, |
| 111 CertError::SEVERITY_WARNING, parsing_succeeded, metrics); |
| 112 |
| 113 if (!parsing_succeeded) |
| 114 return false; |
| 115 |
| 116 for (const auto& extra_cert : entry.extra_certs) { |
| 117 if (!AddParsedCertificate(extra_cert, chain, &errors)) { |
| 118 return false; |
| 119 } |
| 120 } |
| 121 |
| 122 return true; |
| 123 } |
| 124 |
| 125 base::Time GetTime(const der::GeneralizedTime& der_time) { |
| 126 base::Time::Exploded exploded; |
| 127 exploded.year = der_time.year; |
| 128 exploded.month = der_time.month; |
| 129 exploded.day_of_month = der_time.day; |
| 130 exploded.hour = der_time.hours; |
| 131 exploded.minute = der_time.minutes; |
| 132 exploded.second = der_time.seconds; |
| 133 exploded.millisecond = 0; |
| 134 |
| 135 base::Time t; |
| 136 if (!base::Time::FromUTCExploded(exploded, &t)) |
| 137 return base::Time(); |
| 138 return t; |
| 139 } |
| 140 |
| 141 class MyVisitor : public Visitor { |
| 142 public: |
| 143 MyVisitor() : signature_policy_rsa_1024_(1024) { |
| 144 now_time_ = base::Time::Now(); |
| 145 CHECK(der::EncodeTimeAsGeneralizedTime(now_time_, &now_)); |
| 146 user_initial_policy_set_ = {AnyPolicy()}; |
| 147 } |
| 148 |
| 149 void Visit(const Entry& entry, Metrics* metrics) override { |
| 150 // Count the entry types. |
| 151 { |
| 152 MetricsItem* item = metrics->GetAndIncrementTotal("CT Entry types"); |
| 153 |
| 154 switch (entry.type) { |
| 155 case Entry::Type::kLeafCert: |
| 156 item->GetAndIncrementTotal("Leaf"); |
| 157 break; |
| 158 case Entry::Type::kExtraCert: |
| 159 item->GetAndIncrementTotal("Extra Cert"); |
| 160 break; |
| 161 } |
| 162 } |
| 163 |
| 164 // Parse all the certificate. |
| 165 ParsedCertificateList chain; |
| 166 if (!GetFullChain(entry, &chain, metrics)) |
| 167 return; |
| 168 |
| 169 if (entry.type != Entry::Type::kLeafCert) |
| 170 return; |
| 171 |
| 172 base::Time not_before; |
| 173 base::Time not_after; |
| 174 |
| 175 GetChainExpiration(chain, ¬_before, ¬_after); |
| 176 bool chain_expired = now_time_ < not_before || now_time_ > not_after; |
| 177 |
| 178 if (chain_expired) { |
| 179 // Use the midpoint of the chain's validity. |
| 180 base::Time avg_t = not_before + (not_after - not_before) / 2; |
| 181 |
| 182 der::GeneralizedTime t; |
| 183 der::EncodeTimeAsGeneralizedTime(avg_t, &t); |
| 184 |
| 185 TestVerifyChain(chain, "[expired] ", entry, t, metrics); |
| 186 } else { |
| 187 TestVerifyChain(chain, "", entry, now_, metrics); |
| 188 } |
| 189 } |
| 190 |
| 191 private: |
| 192 void TestVerifyChain(const ParsedCertificateList& chain, |
| 193 const std::string& name_prefix, |
| 194 const Entry& entry, |
| 195 const der::GeneralizedTime& time, |
| 196 Metrics* metrics) { |
| 197 KeyPurpose required_key_purpose = KeyPurpose::SERVER_AUTH; |
| 198 CertPathErrors errors; |
| 199 VerifyCertificateChain( |
| 200 chain, CertificateTrust::ForTrustAnchor(), &signature_policy_rsa_1024_, |
| 201 time, required_key_purpose, InitialExplicitPolicy::kFalse, |
| 202 user_initial_policy_set_, InitialPolicyMappingInhibit ::kFalse, |
| 203 InitialAnyPolicyInhibit::kFalse, nullptr, &errors); |
| 204 |
| 205 // Log whether validation succeeded. |
| 206 { |
| 207 MetricsItem* item = |
| 208 metrics->GetAndIncrementTotal(name_prefix + "Verify Chain"); |
| 209 if (errors.ContainsHighSeverityErrors()) { |
| 210 item->GetAndIncrementTotal("Failure")->AddSampleChain(entry); |
| 211 } else { |
| 212 item->GetAndIncrementTotal("Success"); |
| 213 } |
| 214 } |
| 215 |
| 216 // Log the breakdown of the errors. |
| 217 LogCertPathErrors(&errors, chain, name_prefix + "Verify Chain Errors", |
| 218 entry, CertError::SEVERITY_HIGH, metrics); |
| 219 |
| 220 LogCertPathErrors(&errors, chain, |
| 221 name_prefix + "Verify Chain Warnings", entry, |
| 222 CertError::SEVERITY_WARNING, metrics); |
| 223 } |
| 224 |
| 225 void GetChainExpiration(const ParsedCertificateList& chain, |
| 226 base::Time* not_before, |
| 227 base::Time* not_after) const { |
| 228 *not_before = base::Time(); |
| 229 *not_after = base::Time::Max(); |
| 230 |
| 231 // Determine whether any certificate in the chain (except root) is expired. |
| 232 for (size_t i = 0; i + 1 < chain.size(); ++i) { |
| 233 const auto& tbs = chain[i]->tbs(); |
| 234 *not_before = std::max(GetTime(tbs.validity_not_before), *not_before); |
| 235 *not_after = std::min(GetTime(tbs.validity_not_after), *not_after); |
| 236 } |
| 237 } |
| 238 |
| 239 der::GeneralizedTime now_; |
| 240 base::Time now_time_; |
| 241 std::set<der::Input> user_initial_policy_set_; |
| 242 SimpleSignaturePolicy signature_policy_rsa_1024_; |
| 243 }; |
| 244 |
| 245 class MyVisitorFactory : public VisitorFactory { |
| 246 public: |
| 247 std::unique_ptr<Visitor> Create() override { |
| 248 return base::MakeUnique<MyVisitor>(); |
| 249 } |
| 250 }; |
| 251 |
| 252 } // namespace |
| 253 |
| 254 std::unique_ptr<VisitorFactory> CreateMyVisitorFactory() { |
| 255 return base::MakeUnique<MyVisitorFactory>(); |
| 256 } |
| 257 |
| 258 } // namespace net |
| OLD | NEW |