| OLD | NEW |
| (Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "net/cert/cert_verify_proc_builtin.h" |
| 6 |
| 7 #include <string> |
| 8 #include <vector> |
| 9 |
| 10 #if defined(USE_NSS_CERTS) |
| 11 #include <cert.h> |
| 12 #include <pk11pub.h> |
| 13 #endif |
| 14 |
| 15 #include "base/logging.h" |
| 16 #include "base/memory/ptr_util.h" |
| 17 #include "base/sha1.h" |
| 18 #include "base/strings/string_piece.h" |
| 19 #include "crypto/sha2.h" |
| 20 #include "net/base/net_errors.h" |
| 21 #include "net/cert/asn1_util.h" |
| 22 #include "net/cert/cert_status_flags.h" |
| 23 #include "net/cert/cert_verify_proc.h" |
| 24 #include "net/cert/cert_verify_result.h" |
| 25 #include "net/cert/internal/cert_errors.h" |
| 26 #include "net/cert/internal/cert_issuer_source_static.h" |
| 27 #include "net/cert/internal/parsed_certificate.h" |
| 28 #include "net/cert/internal/path_builder.h" |
| 29 #include "net/cert/internal/signature_policy.h" |
| 30 #include "net/cert/internal/trust_store_collection.h" |
| 31 #include "net/cert/internal/trust_store_in_memory.h" |
| 32 #include "net/cert/internal/verify_certificate_chain.h" |
| 33 #include "net/cert/x509_certificate.h" |
| 34 #include "net/cert/x509_util.h" |
| 35 #include "net/der/encode_values.h" |
| 36 |
| 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 { |
| 45 |
| 46 namespace { |
| 47 |
| 48 class CertVerifyProcBuiltin : public CertVerifyProc { |
| 49 public: |
| 50 CertVerifyProcBuiltin(); |
| 51 |
| 52 bool SupportsAdditionalTrustAnchors() const override; |
| 53 bool SupportsOCSPStapling() const override; |
| 54 |
| 55 protected: |
| 56 ~CertVerifyProcBuiltin() override; |
| 57 |
| 58 private: |
| 59 int VerifyInternal(X509Certificate* cert, |
| 60 const std::string& hostname, |
| 61 const std::string& ocsp_response, |
| 62 int flags, |
| 63 CRLSet* crl_set, |
| 64 const CertificateList& additional_trust_anchors, |
| 65 CertVerifyResult* verify_result) override; |
| 66 }; |
| 67 |
| 68 CertVerifyProcBuiltin::CertVerifyProcBuiltin() {} |
| 69 |
| 70 CertVerifyProcBuiltin::~CertVerifyProcBuiltin() {} |
| 71 |
| 72 bool CertVerifyProcBuiltin::SupportsAdditionalTrustAnchors() const { |
| 73 return true; |
| 74 } |
| 75 |
| 76 bool CertVerifyProcBuiltin::SupportsOCSPStapling() const { |
| 77 // TODO(crbug.com/649017): Implement. |
| 78 return false; |
| 79 } |
| 80 |
| 81 scoped_refptr<ParsedCertificate> ParseCertificateFromOSHandle( |
| 82 X509Certificate::OSCertHandle cert_handle, |
| 83 CertErrors* errors) { |
| 84 std::string cert_bytes; |
| 85 if (!X509Certificate::GetDEREncoded(cert_handle, &cert_bytes)) |
| 86 return nullptr; |
| 87 return ParsedCertificate::Create(x509_util::CreateCryptoBuffer(cert_bytes), |
| 88 {}, errors); |
| 89 } |
| 90 |
| 91 void AddIntermediatesToIssuerSource(X509Certificate* x509_cert, |
| 92 CertIssuerSourceStatic* intermediates) { |
| 93 const X509Certificate::OSCertHandles& cert_handles = |
| 94 x509_cert->GetIntermediateCertificates(); |
| 95 CertErrors errors; |
| 96 for (auto it = cert_handles.begin(); it != cert_handles.end(); ++it) { |
| 97 scoped_refptr<ParsedCertificate> cert = |
| 98 ParseCertificateFromOSHandle(*it, &errors); |
| 99 if (cert) |
| 100 intermediates->AddCert(std::move(cert)); |
| 101 // TODO(crbug.com/634443): Surface these parsing errors? |
| 102 } |
| 103 } |
| 104 |
| 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|. |
| 229 void AppendPublicKeyHashes(const der::Input& spki_bytes, |
| 230 HashValueVector* hashes) { |
| 231 HashValue sha1(HASH_VALUE_SHA1); |
| 232 base::SHA1HashBytes(spki_bytes.UnsafeData(), spki_bytes.Length(), |
| 233 sha1.data()); |
| 234 hashes->push_back(sha1); |
| 235 |
| 236 HashValue sha256(HASH_VALUE_SHA256); |
| 237 crypto::SHA256HashString(spki_bytes.AsStringPiece(), sha256.data(), |
| 238 crypto::kSHA256Length); |
| 239 hashes->push_back(sha256); |
| 240 } |
| 241 |
| 242 // Appends the SubjectPublicKeyInfo hashes for all certificates (and trust |
| 243 // anchor) in |partial_path| to |*hashes|. |
| 244 void AppendPublicKeyHashes(const CertPathBuilder::ResultPath& partial_path, |
| 245 HashValueVector* hashes) { |
| 246 for (const scoped_refptr<ParsedCertificate>& cert : partial_path.path.certs) |
| 247 AppendPublicKeyHashes(cert->tbs().spki_tlv, hashes); |
| 248 |
| 249 if (partial_path.path.trust_anchor) |
| 250 AppendPublicKeyHashes(partial_path.path.trust_anchor->spki(), hashes); |
| 251 } |
| 252 |
| 253 // Sets the bits on |cert_status| for all the errors encountered during the path |
| 254 // building of |partial_path|. |
| 255 void MapPathBuilderErrorsToCertStatus( |
| 256 const CertPathBuilder::ResultPath& partial_path, |
| 257 const std::string& hostname, |
| 258 CertStatus* cert_status) { |
| 259 // If path building was successful, there are no errors to map (there may have |
| 260 // been warnings but they do not map to CertStatus). |
| 261 if (partial_path.valid) |
| 262 return; |
| 263 |
| 264 LOG(ERROR) << "CertVerifyProcBuiltin for " << hostname << " failed:\n" |
| 265 << partial_path.errors.ToDebugString(); |
| 266 |
| 267 if (partial_path.errors.ContainsError(kRsaModulusTooSmall)) |
| 268 *cert_status |= CERT_STATUS_WEAK_KEY; |
| 269 |
| 270 if (partial_path.errors.ContainsError(kValidityFailedNotAfter) || |
| 271 partial_path.errors.ContainsError(kValidityFailedNotBefore)) { |
| 272 *cert_status |= CERT_STATUS_DATE_INVALID; |
| 273 } |
| 274 |
| 275 // IMPORTANT: If the path was invalid for a reason that was not |
| 276 // explicity checked above, set a general error. This is important as |
| 277 // |cert_status| is what ultimately indicates whether verification was |
| 278 // successful or not (absense of errors implies success). |
| 279 if (!IsCertStatusError(*cert_status)) |
| 280 *cert_status |= CERT_STATUS_INVALID; |
| 281 } |
| 282 |
| 283 X509Certificate::OSCertHandle CreateOSCertHandle( |
| 284 const scoped_refptr<ParsedCertificate>& certificate) { |
| 285 return X509Certificate::CreateOSCertHandleFromBytes( |
| 286 reinterpret_cast<const char*>(certificate->der_cert().UnsafeData()), |
| 287 certificate->der_cert().Length()); |
| 288 } |
| 289 |
| 290 // Creates a X509Certificate (chain) to return as the verified result. |
| 291 // |
| 292 // * |target_cert|: The original X509Certificate that was passed in to |
| 293 // VerifyInternal() |
| 294 // * |path|: The result (possibly failed) from path building. |
| 295 scoped_refptr<X509Certificate> CreateVerifiedCertChain( |
| 296 X509Certificate* target_cert, |
| 297 const CertPathBuilder::ResultPath& path) { |
| 298 X509Certificate::OSCertHandles intermediates; |
| 299 |
| 300 // Skip the first certificate in the path as that is the target certificate |
| 301 for (size_t i = 1; i < path.path.certs.size(); ++i) |
| 302 intermediates.push_back(CreateOSCertHandle(path.path.certs[i])); |
| 303 |
| 304 if (path.path.trust_anchor) { |
| 305 // TODO(eroman): This assumes that TrustAnchor::cert() cannot be null, |
| 306 // which disagrees with the documentation. |
| 307 intermediates.push_back(CreateOSCertHandle(path.path.trust_anchor->cert())); |
| 308 } |
| 309 |
| 310 scoped_refptr<X509Certificate> result = X509Certificate::CreateFromHandle( |
| 311 target_cert->os_cert_handle(), intermediates); |
| 312 |
| 313 for (const X509Certificate::OSCertHandle handle : intermediates) |
| 314 X509Certificate::FreeOSCertHandle(handle); |
| 315 |
| 316 return result; |
| 317 } |
| 318 |
| 319 // TODO(crbug.com/649017): Make use of |flags|, |crl_set|, and |ocsp_response|. |
| 320 // Also handle key usages, policies and EV. |
| 321 // |
| 322 // Any failure short-circuits from the function must set |
| 323 // |verify_result->cert_status|. |
| 324 void DoVerify(X509Certificate* input_cert, |
| 325 const std::string& hostname, |
| 326 const std::string& ocsp_response, |
| 327 int flags, |
| 328 CRLSet* crl_set, |
| 329 const CertificateList& additional_trust_anchors, |
| 330 CertVerifyResult* verify_result) { |
| 331 CertErrors errors; |
| 332 |
| 333 // Parse the target certificate. |
| 334 scoped_refptr<ParsedCertificate> target = |
| 335 ParseCertificateFromOSHandle(input_cert->os_cert_handle(), &errors); |
| 336 if (!target) { |
| 337 // TODO(crbug.com/634443): Surface these parsing errors? |
| 338 verify_result->cert_status |= CERT_STATUS_INVALID; |
| 339 return; |
| 340 } |
| 341 |
| 342 std::unique_ptr<SystemTrustStore> trust_store = |
| 343 CreateSystemTrustStore(additional_trust_anchors); |
| 344 |
| 345 // TODO(eroman): The path building code in this file enforces its idea of weak |
| 346 // keys, and separately cert_verify_proc.cc also checks the chains with its |
| 347 // own policy. These policies should be aligned, to give path building the |
| 348 // best chance of finding a good path. |
| 349 // Another difference to resolve is the path building here does not check the |
| 350 // target certificate's key strength, whereas cert_verify_proc.cc does. |
| 351 SimpleSignaturePolicy signature_policy(1024); |
| 352 |
| 353 // Use the current time. |
| 354 der::GeneralizedTime verification_time; |
| 355 if (!der::EncodeTimeAsGeneralizedTime(base::Time::Now(), |
| 356 &verification_time)) { |
| 357 // This really shouldn't be possible unless Time::Now() returned |
| 358 // something crazy. |
| 359 verify_result->cert_status |= CERT_STATUS_DATE_INVALID; |
| 360 return; |
| 361 } |
| 362 |
| 363 // Initialize the path builder. |
| 364 CertPathBuilder::Result result; |
| 365 CertPathBuilder path_builder(target, trust_store->GetTrustStore(), |
| 366 &signature_policy, verification_time, &result); |
| 367 |
| 368 // Allow the path builder to discover intermediates from the trust store. |
| 369 if (trust_store->GetCertIssuerSource()) |
| 370 path_builder.AddCertIssuerSource(trust_store->GetCertIssuerSource()); |
| 371 |
| 372 // Allow the path builder to discover the explicitly provided intermediates in |
| 373 // |input_cert|. |
| 374 CertIssuerSourceStatic intermediates; |
| 375 AddIntermediatesToIssuerSource(input_cert, &intermediates); |
| 376 path_builder.AddCertIssuerSource(&intermediates); |
| 377 |
| 378 // TODO(crbug.com/649017): Allow the path builder to discover intermediates |
| 379 // through AIA fetching. |
| 380 |
| 381 path_builder.Run(); |
| 382 |
| 383 if (result.best_result_index >= result.paths.size()) { |
| 384 // TODO(crbug.com/634443): What errors to communicate? Maybe the path |
| 385 // builder should always return some partial path (even if just containing |
| 386 // the target), then there is a CertErrors to test. |
| 387 verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID; |
| 388 return; |
| 389 } |
| 390 |
| 391 // Use the best path that was built. This could be a partial path, or it could |
| 392 // be a valid complete path. |
| 393 const CertPathBuilder::ResultPath& partial_path = |
| 394 *result.paths[result.best_result_index].get(); |
| 395 |
| 396 if (partial_path.path.trust_anchor) { |
| 397 verify_result->is_issued_by_known_root = |
| 398 trust_store->IsKnownRoot(partial_path.path.trust_anchor); |
| 399 |
| 400 verify_result->is_issued_by_additional_trust_anchor = |
| 401 trust_store->IsAdditionalTrustAnchor(partial_path.path.trust_anchor); |
| 402 } else { |
| 403 verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID; |
| 404 } |
| 405 |
| 406 verify_result->verified_cert = |
| 407 CreateVerifiedCertChain(input_cert, partial_path); |
| 408 |
| 409 AppendPublicKeyHashes(partial_path, &verify_result->public_key_hashes); |
| 410 MapPathBuilderErrorsToCertStatus(partial_path, hostname, |
| 411 &verify_result->cert_status); |
| 412 } |
| 413 |
| 414 int CertVerifyProcBuiltin::VerifyInternal( |
| 415 X509Certificate* input_cert, |
| 416 const std::string& hostname, |
| 417 const std::string& ocsp_response, |
| 418 int flags, |
| 419 CRLSet* crl_set, |
| 420 const CertificateList& additional_trust_anchors, |
| 421 CertVerifyResult* verify_result) { |
| 422 DoVerify(input_cert, hostname, ocsp_response, flags, crl_set, |
| 423 additional_trust_anchors, verify_result); |
| 424 |
| 425 return IsCertStatusError(verify_result->cert_status) |
| 426 ? MapCertStatusToNetError(verify_result->cert_status) |
| 427 : OK; |
| 428 } |
| 429 |
| 430 } // namespace |
| 431 |
| 432 scoped_refptr<CertVerifyProc> CreateCertVerifyProcBuiltin() { |
| 433 return scoped_refptr<CertVerifyProc>(new CertVerifyProcBuiltin()); |
| 434 } |
| 435 |
| 436 } // namespace net |
| OLD | NEW |