| OLD | NEW |
| 1 // Copyright (c) 2017 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/cert/cert_verify_proc_builtin.h" | 5 #include "net/cert/cert_verify_proc_builtin.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #if defined(USE_NSS_CERTS) | |
| 11 #include <cert.h> | |
| 12 #include <pk11pub.h> | |
| 13 #endif | |
| 14 | |
| 15 #include "base/logging.h" | 10 #include "base/logging.h" |
| 16 #include "base/memory/ptr_util.h" | 11 #include "base/memory/ptr_util.h" |
| 17 #include "base/sha1.h" | 12 #include "base/sha1.h" |
| 18 #include "base/strings/string_piece.h" | 13 #include "base/strings/string_piece.h" |
| 19 #include "crypto/sha2.h" | 14 #include "crypto/sha2.h" |
| 20 #include "net/base/net_errors.h" | 15 #include "net/base/net_errors.h" |
| 21 #include "net/cert/asn1_util.h" | 16 #include "net/cert/asn1_util.h" |
| 22 #include "net/cert/cert_status_flags.h" | 17 #include "net/cert/cert_status_flags.h" |
| 23 #include "net/cert/cert_verify_proc.h" | 18 #include "net/cert/cert_verify_proc.h" |
| 24 #include "net/cert/cert_verify_result.h" | 19 #include "net/cert/cert_verify_result.h" |
| 25 #include "net/cert/internal/cert_errors.h" | 20 #include "net/cert/internal/cert_errors.h" |
| 26 #include "net/cert/internal/cert_issuer_source_static.h" | 21 #include "net/cert/internal/cert_issuer_source_static.h" |
| 27 #include "net/cert/internal/parsed_certificate.h" | 22 #include "net/cert/internal/parsed_certificate.h" |
| 28 #include "net/cert/internal/path_builder.h" | 23 #include "net/cert/internal/path_builder.h" |
| 29 #include "net/cert/internal/signature_policy.h" | 24 #include "net/cert/internal/signature_policy.h" |
| 30 #include "net/cert/internal/trust_store_collection.h" | 25 #include "net/cert/internal/system_trust_store.h" |
| 31 #include "net/cert/internal/trust_store_in_memory.h" | |
| 32 #include "net/cert/internal/verify_certificate_chain.h" | 26 #include "net/cert/internal/verify_certificate_chain.h" |
| 33 #include "net/cert/x509_certificate.h" | 27 #include "net/cert/x509_certificate.h" |
| 34 #include "net/cert/x509_util.h" | 28 #include "net/cert/x509_util.h" |
| 35 #include "net/der/encode_values.h" | 29 #include "net/der/encode_values.h" |
| 36 | 30 |
| 37 #if defined(USE_NSS_CERTS) | |
| 38 #include "crypto/nss_util.h" | |
| 39 #include "net/cert/internal/cert_issuer_source_nss.h" | |
| 40 #include "net/cert/internal/trust_store_nss.h" | |
| 41 #include "net/cert/scoped_nss_types.h" | |
| 42 #endif | |
| 43 | |
| 44 namespace net { | 31 namespace net { |
| 45 | 32 |
| 46 namespace { | 33 namespace { |
| 47 | 34 |
| 48 class CertVerifyProcBuiltin : public CertVerifyProc { | 35 class CertVerifyProcBuiltin : public CertVerifyProc { |
| 49 public: | 36 public: |
| 50 CertVerifyProcBuiltin(); | 37 CertVerifyProcBuiltin(); |
| 51 | 38 |
| 52 bool SupportsAdditionalTrustAnchors() const override; | 39 bool SupportsAdditionalTrustAnchors() const override; |
| 53 bool SupportsOCSPStapling() const override; | 40 bool SupportsOCSPStapling() const override; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 95 CertErrors errors; | 82 CertErrors errors; |
| 96 for (auto it = cert_handles.begin(); it != cert_handles.end(); ++it) { | 83 for (auto it = cert_handles.begin(); it != cert_handles.end(); ++it) { |
| 97 scoped_refptr<ParsedCertificate> cert = | 84 scoped_refptr<ParsedCertificate> cert = |
| 98 ParseCertificateFromOSHandle(*it, &errors); | 85 ParseCertificateFromOSHandle(*it, &errors); |
| 99 if (cert) | 86 if (cert) |
| 100 intermediates->AddCert(std::move(cert)); | 87 intermediates->AddCert(std::move(cert)); |
| 101 // TODO(crbug.com/634443): Surface these parsing errors? | 88 // TODO(crbug.com/634443): Surface these parsing errors? |
| 102 } | 89 } |
| 103 } | 90 } |
| 104 | 91 |
| 105 // The SystemTrustStore interface augments the TrustStore interface with some | |
| 106 // additional functionality: | |
| 107 // | |
| 108 // * Determine if a trust anchor was one of the known roots | |
| 109 // * Determine if a trust anchor was one of the "extra" ones that | |
| 110 // was specified during verification. | |
| 111 // | |
| 112 // Implementations of SystemTrustStore create an effective trust | |
| 113 // store that is the composition of: | |
| 114 // | |
| 115 // (1) System trust store | |
| 116 // (2) |additional_trust_anchors|. | |
| 117 // (3) Test certificates (if they are separate from system trust store) | |
| 118 class SystemTrustStore { | |
| 119 public: | |
| 120 virtual ~SystemTrustStore() {} | |
| 121 | |
| 122 virtual TrustStore* GetTrustStore() = 0; | |
| 123 | |
| 124 // TODO(eroman): Can this be exposed through the TrustStore | |
| 125 // interface instead? | |
| 126 virtual CertIssuerSource* GetCertIssuerSource() = 0; | |
| 127 | |
| 128 // IsKnownRoot returns true if the given trust anchor is a standard one (as | |
| 129 // opposed to a user-installed root) | |
| 130 virtual bool IsKnownRoot( | |
| 131 const scoped_refptr<TrustAnchor>& trust_anchor) const = 0; | |
| 132 | |
| 133 virtual bool IsAdditionalTrustAnchor( | |
| 134 const scoped_refptr<TrustAnchor>& trust_anchor) const = 0; | |
| 135 }; | |
| 136 | |
| 137 #if defined(USE_NSS_CERTS) | |
| 138 class SystemTrustStoreNSS : public SystemTrustStore { | |
| 139 public: | |
| 140 explicit SystemTrustStoreNSS(const CertificateList& additional_trust_anchors) | |
| 141 : trust_store_nss_(trustSSL) { | |
| 142 CertErrors errors; | |
| 143 | |
| 144 trust_store_.AddTrustStore(&additional_trust_store_); | |
| 145 for (const auto& x509_cert : additional_trust_anchors) { | |
| 146 scoped_refptr<ParsedCertificate> cert = | |
| 147 ParseCertificateFromOSHandle(x509_cert->os_cert_handle(), &errors); | |
| 148 if (cert) { | |
| 149 additional_trust_store_.AddTrustAnchor( | |
| 150 TrustAnchor::CreateFromCertificateNoConstraints(std::move(cert))); | |
| 151 } | |
| 152 // TODO(eroman): Surface parsing errors of additional trust anchor. | |
| 153 } | |
| 154 | |
| 155 trust_store_.AddTrustStore(&trust_store_nss_); | |
| 156 } | |
| 157 | |
| 158 TrustStore* GetTrustStore() override { return &trust_store_; } | |
| 159 | |
| 160 CertIssuerSource* GetCertIssuerSource() override { | |
| 161 return &cert_issuer_source_nss_; | |
| 162 } | |
| 163 | |
| 164 // IsKnownRoot returns true if the given trust anchor is a standard one (as | |
| 165 // opposed to a user-installed root) | |
| 166 bool IsKnownRoot( | |
| 167 const scoped_refptr<TrustAnchor>& trust_anchor) const override { | |
| 168 // TODO(eroman): Based on how the TrustAnchors are created by this | |
| 169 // integration, there will always be an associated certificate. However this | |
| 170 // contradicts the API for TrustAnchor that states it is optional. | |
| 171 DCHECK(trust_anchor->cert()); | |
| 172 | |
| 173 // TODO(eroman): The overall approach of IsKnownRoot() is inefficient -- it | |
| 174 // requires searching for the trust anchor by DER in NSS, however path | |
| 175 // building already had a handle to it. | |
| 176 SECItem der_cert; | |
| 177 der_cert.data = | |
| 178 const_cast<uint8_t*>(trust_anchor->cert()->der_cert().UnsafeData()); | |
| 179 der_cert.len = trust_anchor->cert()->der_cert().Length(); | |
| 180 der_cert.type = siDERCertBuffer; | |
| 181 ScopedCERTCertificate nss_cert( | |
| 182 CERT_FindCertByDERCert(CERT_GetDefaultCertDB(), &der_cert)); | |
| 183 if (!nss_cert) | |
| 184 return false; | |
| 185 | |
| 186 return IsKnownRoot(nss_cert.get()); | |
| 187 } | |
| 188 | |
| 189 bool IsAdditionalTrustAnchor( | |
| 190 const scoped_refptr<TrustAnchor>& trust_anchor) const override { | |
| 191 return additional_trust_store_.Contains(trust_anchor.get()); | |
| 192 } | |
| 193 | |
| 194 private: | |
| 195 // TODO(eroman): This function was copied verbatim from | |
| 196 // cert_verify_proc_nss.cc | |
| 197 // | |
| 198 // IsKnownRoot returns true if the given certificate is one that we believe | |
| 199 // is a standard (as opposed to user-installed) root. | |
| 200 bool IsKnownRoot(CERTCertificate* root) const { | |
| 201 if (!root || !root->slot) | |
| 202 return false; | |
| 203 | |
| 204 // This magic name is taken from | |
| 205 // http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/security/nss/lib/ckfw
/builtins/constants.c&rev=1.13&mark=86,89#79 | |
| 206 return 0 == strcmp(PK11_GetSlotName(root->slot), "NSS Builtin Objects"); | |
| 207 } | |
| 208 | |
| 209 TrustStoreCollection trust_store_; | |
| 210 TrustStoreInMemory additional_trust_store_; | |
| 211 | |
| 212 TrustStoreNSS trust_store_nss_; | |
| 213 CertIssuerSourceNSS cert_issuer_source_nss_; | |
| 214 }; | |
| 215 #endif | |
| 216 | |
| 217 std::unique_ptr<SystemTrustStore> CreateSystemTrustStore( | |
| 218 const CertificateList& additional_trust_anchors) { | |
| 219 #if defined(USE_NSS_CERTS) | |
| 220 return base::MakeUnique<SystemTrustStoreNSS>(additional_trust_anchors); | |
| 221 #else | |
| 222 // TODO(crbug.com/649017): Integrate with other system trust stores. | |
| 223 NOTIMPLEMENTED(); | |
| 224 return nullptr; | |
| 225 #endif | |
| 226 } | |
| 227 | |
| 228 // Appends the SHA1 and SHA256 hashes of |spki_bytes| to |*hashes|. | 92 // Appends the SHA1 and SHA256 hashes of |spki_bytes| to |*hashes|. |
| 229 void AppendPublicKeyHashes(const der::Input& spki_bytes, | 93 void AppendPublicKeyHashes(const der::Input& spki_bytes, |
| 230 HashValueVector* hashes) { | 94 HashValueVector* hashes) { |
| 231 HashValue sha1(HASH_VALUE_SHA1); | 95 HashValue sha1(HASH_VALUE_SHA1); |
| 232 base::SHA1HashBytes(spki_bytes.UnsafeData(), spki_bytes.Length(), | 96 base::SHA1HashBytes(spki_bytes.UnsafeData(), spki_bytes.Length(), |
| 233 sha1.data()); | 97 sha1.data()); |
| 234 hashes->push_back(sha1); | 98 hashes->push_back(sha1); |
| 235 | 99 |
| 236 HashValue sha256(HASH_VALUE_SHA256); | 100 HashValue sha256(HASH_VALUE_SHA256); |
| 237 crypto::SHA256HashString(spki_bytes.AsStringPiece(), sha256.data(), | 101 crypto::SHA256HashString(spki_bytes.AsStringPiece(), sha256.data(), |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 328 | 192 |
| 329 // Parse the target certificate. | 193 // Parse the target certificate. |
| 330 scoped_refptr<ParsedCertificate> target = ParseCertificateFromOSHandle( | 194 scoped_refptr<ParsedCertificate> target = ParseCertificateFromOSHandle( |
| 331 input_cert->os_cert_handle(), &parsing_errors); | 195 input_cert->os_cert_handle(), &parsing_errors); |
| 332 if (!target) { | 196 if (!target) { |
| 333 // TODO(crbug.com/634443): Surface these parsing errors? | 197 // TODO(crbug.com/634443): Surface these parsing errors? |
| 334 verify_result->cert_status |= CERT_STATUS_INVALID; | 198 verify_result->cert_status |= CERT_STATUS_INVALID; |
| 335 return; | 199 return; |
| 336 } | 200 } |
| 337 | 201 |
| 338 std::unique_ptr<SystemTrustStore> trust_store = | 202 std::unique_ptr<SystemTrustStore> ssl_trust_store = |
| 339 CreateSystemTrustStore(additional_trust_anchors); | 203 CreateSslSystemTrustStore(); |
| 204 |
| 205 for (const auto& x509_cert : additional_trust_anchors) { |
| 206 scoped_refptr<ParsedCertificate> cert = ParseCertificateFromOSHandle( |
| 207 x509_cert->os_cert_handle(), &parsing_errors); |
| 208 if (cert) { |
| 209 ssl_trust_store->AddTrustAnchor( |
| 210 TrustAnchor::CreateFromCertificateNoConstraints(std::move(cert))); |
| 211 } |
| 212 // TODO(eroman): Surface parsing errors of additional trust anchor. |
| 213 } |
| 340 | 214 |
| 341 // TODO(eroman): The path building code in this file enforces its idea of weak | 215 // TODO(eroman): The path building code in this file enforces its idea of weak |
| 342 // keys, and separately cert_verify_proc.cc also checks the chains with its | 216 // keys, and separately cert_verify_proc.cc also checks the chains with its |
| 343 // own policy. These policies should be aligned, to give path building the | 217 // own policy. These policies should be aligned, to give path building the |
| 344 // best chance of finding a good path. | 218 // best chance of finding a good path. |
| 345 // Another difference to resolve is the path building here does not check the | 219 // Another difference to resolve is the path building here does not check the |
| 346 // target certificate's key strength, whereas cert_verify_proc.cc does. | 220 // target certificate's key strength, whereas cert_verify_proc.cc does. |
| 347 SimpleSignaturePolicy signature_policy(1024); | 221 SimpleSignaturePolicy signature_policy(1024); |
| 348 | 222 |
| 349 // Use the current time. | 223 // Use the current time. |
| 350 der::GeneralizedTime verification_time; | 224 der::GeneralizedTime verification_time; |
| 351 if (!der::EncodeTimeAsGeneralizedTime(base::Time::Now(), | 225 if (!der::EncodeTimeAsGeneralizedTime(base::Time::Now(), |
| 352 &verification_time)) { | 226 &verification_time)) { |
| 353 // This really shouldn't be possible unless Time::Now() returned | 227 // This really shouldn't be possible unless Time::Now() returned |
| 354 // something crazy. | 228 // something crazy. |
| 355 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; | 229 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; |
| 356 return; | 230 return; |
| 357 } | 231 } |
| 358 | 232 |
| 359 // Initialize the path builder. | 233 // Initialize the path builder. |
| 360 CertPathBuilder::Result result; | 234 CertPathBuilder::Result result; |
| 361 CertPathBuilder path_builder(target, trust_store->GetTrustStore(), | 235 CertPathBuilder path_builder(target, ssl_trust_store->GetTrustStore(), |
| 362 &signature_policy, verification_time, | 236 &signature_policy, verification_time, |
| 363 KeyPurpose::SERVER_AUTH, &result); | 237 KeyPurpose::SERVER_AUTH, &result); |
| 364 | 238 |
| 365 // Allow the path builder to discover intermediates from the trust store. | 239 // Allow the path builder to discover intermediates from the trust store. |
| 366 if (trust_store->GetCertIssuerSource()) | 240 if (ssl_trust_store->GetCertIssuerSource()) |
| 367 path_builder.AddCertIssuerSource(trust_store->GetCertIssuerSource()); | 241 path_builder.AddCertIssuerSource(ssl_trust_store->GetCertIssuerSource()); |
| 368 | 242 |
| 369 // Allow the path builder to discover the explicitly provided intermediates in | 243 // Allow the path builder to discover the explicitly provided intermediates in |
| 370 // |input_cert|. | 244 // |input_cert|. |
| 371 CertIssuerSourceStatic intermediates; | 245 CertIssuerSourceStatic intermediates; |
| 372 AddIntermediatesToIssuerSource(input_cert, &intermediates); | 246 AddIntermediatesToIssuerSource(input_cert, &intermediates); |
| 373 path_builder.AddCertIssuerSource(&intermediates); | 247 path_builder.AddCertIssuerSource(&intermediates); |
| 374 | 248 |
| 375 // TODO(crbug.com/649017): Allow the path builder to discover intermediates | 249 // TODO(crbug.com/649017): Allow the path builder to discover intermediates |
| 376 // through AIA fetching. | 250 // through AIA fetching. |
| 377 | 251 |
| 378 path_builder.Run(); | 252 path_builder.Run(); |
| 379 | 253 |
| 380 if (result.best_result_index >= result.paths.size()) { | 254 if (result.best_result_index >= result.paths.size()) { |
| 381 // TODO(crbug.com/634443): What errors to communicate? Maybe the path | 255 // TODO(crbug.com/634443): What errors to communicate? Maybe the path |
| 382 // builder should always return some partial path (even if just containing | 256 // builder should always return some partial path (even if just containing |
| 383 // the target), then there is a CertErrors to test. | 257 // the target), then there is a CertErrors to test. |
| 384 verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID; | 258 verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID; |
| 385 return; | 259 return; |
| 386 } | 260 } |
| 387 | 261 |
| 388 // Use the best path that was built. This could be a partial path, or it could | 262 // Use the best path that was built. This could be a partial path, or it could |
| 389 // be a valid complete path. | 263 // be a valid complete path. |
| 390 const CertPathBuilder::ResultPath& partial_path = | 264 const CertPathBuilder::ResultPath& partial_path = |
| 391 *result.paths[result.best_result_index].get(); | 265 *result.paths[result.best_result_index].get(); |
| 392 | 266 |
| 393 if (partial_path.path.trust_anchor) { | 267 if (partial_path.path.trust_anchor) { |
| 394 verify_result->is_issued_by_known_root = | 268 verify_result->is_issued_by_known_root = |
| 395 trust_store->IsKnownRoot(partial_path.path.trust_anchor); | 269 ssl_trust_store->IsKnownRoot(partial_path.path.trust_anchor); |
| 396 | 270 |
| 397 verify_result->is_issued_by_additional_trust_anchor = | 271 verify_result->is_issued_by_additional_trust_anchor = |
| 398 trust_store->IsAdditionalTrustAnchor(partial_path.path.trust_anchor); | 272 ssl_trust_store->IsAdditionalTrustAnchor( |
| 273 partial_path.path.trust_anchor); |
| 399 } else { | 274 } else { |
| 400 // TODO(eroman): This shouldn't be necessary -- partial_path.errors should | 275 // TODO(eroman): This shouldn't be necessary -- partial_path.errors should |
| 401 // contain an error if it didn't chain to trust anchor. | 276 // contain an error if it didn't chain to trust anchor. |
| 402 verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID; | 277 verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID; |
| 403 } | 278 } |
| 404 | 279 |
| 405 verify_result->verified_cert = | 280 verify_result->verified_cert = |
| 406 CreateVerifiedCertChain(input_cert, partial_path); | 281 CreateVerifiedCertChain(input_cert, partial_path); |
| 407 | 282 |
| 408 AppendPublicKeyHashes(partial_path, &verify_result->public_key_hashes); | 283 AppendPublicKeyHashes(partial_path, &verify_result->public_key_hashes); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 436 : OK; | 311 : OK; |
| 437 } | 312 } |
| 438 | 313 |
| 439 } // namespace | 314 } // namespace |
| 440 | 315 |
| 441 scoped_refptr<CertVerifyProc> CreateCertVerifyProcBuiltin() { | 316 scoped_refptr<CertVerifyProc> CreateCertVerifyProcBuiltin() { |
| 442 return scoped_refptr<CertVerifyProc>(new CertVerifyProcBuiltin()); | 317 return scoped_refptr<CertVerifyProc>(new CertVerifyProcBuiltin()); |
| 443 } | 318 } |
| 444 | 319 |
| 445 } // namespace net | 320 } // namespace net |
| OLD | NEW |