OLD | NEW |
(Empty) | |
| 1 // Copyright 2012 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/navigation/crw_session_certificate_policy_manager.h" |
| 6 |
| 7 #include <map> |
| 8 #include <set> |
| 9 |
| 10 #include "base/bind.h" |
| 11 #include "base/location.h" |
| 12 #include "base/logging.h" |
| 13 #include "base/strings/sys_string_conversions.h" |
| 14 #include "ios/web/public/certificate_policy_cache.h" |
| 15 #include "ios/web/public/web_thread.h" |
| 16 #include "net/cert/x509_certificate.h" |
| 17 |
| 18 // Break if we detect that CertStatus values changed, because we persist them on |
| 19 // disk and thus require them to be consistent. |
| 20 COMPILE_ASSERT(net::CERT_STATUS_ALL_ERRORS == 0xFFFF, |
| 21 cert_status_value_changed); |
| 22 COMPILE_ASSERT(net::CERT_STATUS_COMMON_NAME_INVALID == 1 << 0, |
| 23 cert_status_value_changed); |
| 24 COMPILE_ASSERT(net::CERT_STATUS_DATE_INVALID == 1 << 1, |
| 25 cert_status_value_changed); |
| 26 COMPILE_ASSERT(net::CERT_STATUS_AUTHORITY_INVALID == 1 << 2, |
| 27 cert_status_value_changed); |
| 28 COMPILE_ASSERT(net::CERT_STATUS_NO_REVOCATION_MECHANISM == 1 << 4, |
| 29 cert_status_value_changed); |
| 30 COMPILE_ASSERT(net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION == 1 << 5, |
| 31 cert_status_value_changed); |
| 32 COMPILE_ASSERT(net::CERT_STATUS_REVOKED == 1 << 6, |
| 33 cert_status_value_changed); |
| 34 COMPILE_ASSERT(net::CERT_STATUS_INVALID == 1 << 7, |
| 35 cert_status_value_changed); |
| 36 COMPILE_ASSERT(net::CERT_STATUS_WEAK_SIGNATURE_ALGORITHM == 1 << 8, |
| 37 cert_status_value_changed); |
| 38 COMPILE_ASSERT(net::CERT_STATUS_NON_UNIQUE_NAME == 1 << 10, |
| 39 cert_status_value_changed); |
| 40 COMPILE_ASSERT(net::CERT_STATUS_WEAK_KEY == 1 << 11, |
| 41 cert_status_value_changed); |
| 42 COMPILE_ASSERT(net::CERT_STATUS_IS_EV == 1 << 16, |
| 43 cert_status_value_changed); |
| 44 COMPILE_ASSERT(net::CERT_STATUS_REV_CHECKING_ENABLED == 1 << 17, |
| 45 cert_status_value_changed); |
| 46 |
| 47 namespace { |
| 48 |
| 49 NSString* const kAllowedCertificatesKey = @"allowedCertificates"; |
| 50 |
| 51 struct AllowedCertificate { |
| 52 scoped_refptr<net::X509Certificate> certificate; |
| 53 std::string host; |
| 54 }; |
| 55 |
| 56 class LessThan { |
| 57 public: |
| 58 bool operator() (const AllowedCertificate& lhs, |
| 59 const AllowedCertificate& rhs) const { |
| 60 if (lhs.host != rhs.host) |
| 61 return lhs.host < rhs.host; |
| 62 return certificateCompare_(lhs.certificate, rhs.certificate); |
| 63 } |
| 64 private: |
| 65 net::X509Certificate::LessThan certificateCompare_; |
| 66 }; |
| 67 |
| 68 typedef std::map<AllowedCertificate, net::CertStatus, LessThan> |
| 69 AllowedCertificates; |
| 70 |
| 71 NSData* CertificateToNSData(net::X509Certificate* certificate) { |
| 72 std::string s; |
| 73 bool success = |
| 74 net::X509Certificate::GetDEREncoded(certificate->os_cert_handle(), &s); |
| 75 DCHECK(success); |
| 76 return [NSData dataWithBytes:s.c_str() length:s.length()]; |
| 77 } |
| 78 |
| 79 net::X509Certificate* NSDataToCertificate(NSData* data) { |
| 80 return net::X509Certificate::CreateFromBytes((const char *)[data bytes], |
| 81 [data length]); |
| 82 } |
| 83 |
| 84 void AddToCertificatePolicyCache( |
| 85 scoped_refptr<web::CertificatePolicyCache> policy_cache, |
| 86 AllowedCertificates certs) { |
| 87 DCHECK(policy_cache); |
| 88 AllowedCertificates::iterator it; |
| 89 for (it = certs.begin(); it != certs.end(); ++it) { |
| 90 policy_cache->AllowCertForHost( |
| 91 it->first.certificate.get(), it->first.host, it->second); |
| 92 } |
| 93 } |
| 94 |
| 95 } // namespace |
| 96 |
| 97 @implementation CRWSessionCertificatePolicyManager { |
| 98 @private |
| 99 AllowedCertificates allowed_; |
| 100 } |
| 101 |
| 102 - (void)registerAllowedCertificate:(net::X509Certificate*)certificate |
| 103 forHost:(const std::string&)host |
| 104 status:(net::CertStatus)status { |
| 105 DCHECK([NSThread isMainThread]); |
| 106 DCHECK(certificate); |
| 107 AllowedCertificate allowedCertificate = {certificate, host}; |
| 108 allowed_[allowedCertificate] = status; |
| 109 } |
| 110 |
| 111 - (void)clearCertificates { |
| 112 DCHECK([NSThread isMainThread]); |
| 113 allowed_.clear(); |
| 114 } |
| 115 |
| 116 - (void)updateCertificatePolicyCache: |
| 117 (const scoped_refptr<web::CertificatePolicyCache>&)cache { |
| 118 DCHECK([NSThread isMainThread]); |
| 119 DCHECK(cache); |
| 120 // Make a copy of allowed_ and access the policy cache from the IOThread. |
| 121 web::WebThread::PostTask( |
| 122 web::WebThread::IO, FROM_HERE, |
| 123 base::Bind(&AddToCertificatePolicyCache, cache, allowed_)); |
| 124 } |
| 125 |
| 126 #pragma mark - |
| 127 #pragma mark NSCoding and NSCopying methods |
| 128 |
| 129 - (id)initWithCoder:(NSCoder*)aDecoder { |
| 130 DCHECK([NSThread isMainThread]); |
| 131 self = [super init]; |
| 132 if (self) { |
| 133 NSMutableSet* allowed = [aDecoder |
| 134 decodeObjectForKey:kAllowedCertificatesKey]; |
| 135 for (NSArray* fields in allowed) { |
| 136 if ([fields count] == 2) { |
| 137 DVLOG(2) << "Dropping cached certificate policy (old format)."; |
| 138 continue; |
| 139 } else if ([fields count] != 3) { |
| 140 NOTREACHED(); |
| 141 continue; |
| 142 } |
| 143 net::X509Certificate* c = NSDataToCertificate([fields objectAtIndex:0]); |
| 144 std::string host = base::SysNSStringToUTF8([fields objectAtIndex:1]); |
| 145 net::CertStatus status = (net::CertStatus)[[fields objectAtIndex:2] |
| 146 unsignedIntegerValue]; |
| 147 [self registerAllowedCertificate:c forHost:host status:status]; |
| 148 } |
| 149 } |
| 150 return self; |
| 151 } |
| 152 |
| 153 - (void)encodeWithCoder:(NSCoder*)aCoder { |
| 154 if (allowed_.size() == 0) |
| 155 return; |
| 156 |
| 157 // Simple serialization of the set. If a same certificate is duplicated in the |
| 158 // set (for a different host), the serialization will be duplicated as well. |
| 159 NSMutableSet* allowedToEncode = [NSMutableSet set]; |
| 160 AllowedCertificates::iterator it; |
| 161 for (it = allowed_.begin(); it != allowed_.end(); ++it) { |
| 162 NSData* c = CertificateToNSData(it->first.certificate.get()); |
| 163 NSString* h = base::SysUTF8ToNSString(it->first.host); |
| 164 DCHECK(c); |
| 165 DCHECK(h); |
| 166 if (!c || !h) |
| 167 continue; |
| 168 const NSUInteger status = (NSUInteger)it->second; |
| 169 NSArray* fields = [NSArray arrayWithObjects:c, h, @(status), nil]; |
| 170 [allowedToEncode addObject:fields]; |
| 171 } |
| 172 [aCoder encodeObject:allowedToEncode forKey:kAllowedCertificatesKey]; |
| 173 } |
| 174 |
| 175 - (id)copyWithZone:(NSZone*)zone { |
| 176 DCHECK([NSThread isMainThread]); |
| 177 CRWSessionCertificatePolicyManager* copy = [[[self class] alloc] init]; |
| 178 copy->allowed_ = allowed_; |
| 179 return copy; |
| 180 } |
| 181 |
| 182 @end |
OLD | NEW |