1// Copyright 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#import "ios/web/session/session_certificate_policy_cache_impl.h" 6 7#include "base/bind.h" 8#include "base/task/post_task.h" 9#include "ios/web/public/browser_state.h" 10#include "ios/web/public/security/certificate_policy_cache.h" 11#import "ios/web/public/session/crw_session_certificate_policy_cache_storage.h" 12#include "ios/web/public/thread/web_task_traits.h" 13#include "ios/web/public/thread/web_thread.h" 14#include "net/cert/x509_util.h" 15#include "net/cert/x509_util_ios.h" 16 17#if !defined(__has_feature) || !__has_feature(objc_arc) 18#error "This file requires ARC support." 19#endif 20 21// Break if CertStatus values changed, as they are persisted on disk and thus 22// must be consistent. 23static_assert(net::CERT_STATUS_ALL_ERRORS == 0xFF00FFFF, 24 "The value of CERT_STATUS_ALL_ERRORS changed!"); 25static_assert(net::CERT_STATUS_COMMON_NAME_INVALID == 1 << 0, 26 "The value of CERT_STATUS_COMMON_NAME_INVALID changed!"); 27static_assert(net::CERT_STATUS_DATE_INVALID == 1 << 1, 28 "The value of CERT_STATUS_DATE_INVALID changed!"); 29static_assert(net::CERT_STATUS_AUTHORITY_INVALID == 1 << 2, 30 "The value of CERT_STATUS_AUTHORITY_INVALID changed!"); 31static_assert(net::CERT_STATUS_NO_REVOCATION_MECHANISM == 1 << 4, 32 "The value of CERT_STATUS_NO_REVOCATION_MECHANISM changed!"); 33static_assert(net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION == 1 << 5, 34 "The value of CERT_STATUS_UNABLE_TO_CHECK_REVOCATION changed!"); 35static_assert(net::CERT_STATUS_REVOKED == 1 << 6, 36 "The value of CERT_STATUS_REVOKED changed!"); 37static_assert(net::CERT_STATUS_INVALID == 1 << 7, 38 "The value of CERT_STATUS_INVALID changed!"); 39static_assert(net::CERT_STATUS_WEAK_SIGNATURE_ALGORITHM == 1 << 8, 40 "The value of CERT_STATUS_WEAK_SIGNATURE_ALGORITHM changed!"); 41static_assert(net::CERT_STATUS_NON_UNIQUE_NAME == 1 << 10, 42 "The value of CERT_STATUS_NON_UNIQUE_NAME changed!"); 43static_assert(net::CERT_STATUS_WEAK_KEY == 1 << 11, 44 "The value of CERT_STATUS_WEAK_KEY changed!"); 45static_assert(net::CERT_STATUS_IS_EV == 1 << 16, 46 "The value of CERT_STATUS_IS_EV changed!"); 47static_assert(net::CERT_STATUS_REV_CHECKING_ENABLED == 1 << 17, 48 "The value of CERT_STATUS_REV_CHECKING_ENABLED changed!"); 49 50namespace web { 51 52SessionCertificatePolicyCacheImpl::SessionCertificatePolicyCacheImpl( 53 BrowserState* browser_state) 54 : SessionCertificatePolicyCache(browser_state), 55 allowed_certs_([[NSMutableSet alloc] init]) {} 56 57SessionCertificatePolicyCacheImpl::~SessionCertificatePolicyCacheImpl() {} 58 59void SessionCertificatePolicyCacheImpl::UpdateCertificatePolicyCache( 60 const scoped_refptr<web::CertificatePolicyCache>& cache) const { 61 DCHECK_CURRENTLY_ON(WebThread::UI); 62 DCHECK(cache.get()); 63 NSSet* allowed_certs = [NSSet setWithSet:allowed_certs_]; 64 const scoped_refptr<CertificatePolicyCache> cache_copy = cache; 65 base::PostTask(FROM_HERE, {WebThread::IO}, base::BindOnce(^{ 66 for (CRWSessionCertificateStorage* cert in allowed_certs) { 67 cache_copy->AllowCertForHost(cert.certificate, cert.host, 68 cert.status); 69 } 70 })); 71} 72 73void SessionCertificatePolicyCacheImpl::RegisterAllowedCertificate( 74 scoped_refptr<net::X509Certificate> certificate, 75 const std::string& host, 76 net::CertStatus status) { 77 DCHECK_CURRENTLY_ON(WebThread::UI); 78 // Store user decisions with the leaf cert, ignoring any intermediates. 79 // This is because WKWebView returns the verified certificate chain in 80 // |webView:didReceiveAuthenticationChallenge:completionHandler:|, 81 // but the server-supplied chain in 82 // |webView:didFailProvisionalNavigation:withError:|. 83 if (!certificate->intermediate_buffers().empty()) { 84 certificate = net::X509Certificate::CreateFromBuffer( 85 bssl::UpRef(certificate->cert_buffer()), {}); 86 DCHECK(certificate); 87 } 88 DCHECK(certificate->intermediate_buffers().empty()); 89 90 [allowed_certs_ addObject:[[CRWSessionCertificateStorage alloc] 91 initWithCertificate:certificate 92 host:host 93 status:status]]; 94 const scoped_refptr<CertificatePolicyCache> cache = 95 GetCertificatePolicyCache(); 96 base::PostTask( 97 FROM_HERE, {WebThread::IO}, 98 base::BindOnce(&CertificatePolicyCache::AllowCertForHost, cache, 99 base::RetainedRef(certificate.get()), host, status)); 100} 101 102void SessionCertificatePolicyCacheImpl::SetAllowedCerts(NSSet* allowed_certs) { 103 allowed_certs_ = [allowed_certs mutableCopy]; 104} 105 106NSSet* SessionCertificatePolicyCacheImpl::GetAllowedCerts() const { 107 return allowed_certs_; 108} 109 110} // namespace web 111