Add ICU message format support
[chromium-blink-merge.git] / ios / web / navigation / crw_session_certificate_policy_manager.mm
blob3547536bc816307a8f4a3a248aefb547adea7697
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.
5 #import "ios/web/navigation/crw_session_certificate_policy_manager.h"
7 #include <map>
8 #include <set>
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"
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);
47 namespace {
49 NSString* const kAllowedCertificatesKey = @"allowedCertificates";
51 struct AllowedCertificate {
52   scoped_refptr<net::X509Certificate> certificate;
53   std::string host;
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_;
68 typedef std::map<AllowedCertificate, net::CertStatus, LessThan>
69     AllowedCertificates;
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()];
79 net::X509Certificate* NSDataToCertificate(NSData* data) {
80   return net::X509Certificate::CreateFromBytes((const char *)[data bytes],
81                                                [data length]);
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   }
95 }  // namespace
97 @implementation CRWSessionCertificatePolicyManager {
98  @private
99   AllowedCertificates allowed_;
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;
111 - (void)clearCertificates {
112   DCHECK([NSThread isMainThread]);
113   allowed_.clear();
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_));
126 #pragma mark -
127 #pragma mark NSCoding and NSCopying methods
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;
153 - (void)encodeWithCoder:(NSCoder*)aCoder {
154   if (allowed_.size() == 0)
155     return;
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];
175 - (id)copyWithZone:(NSZone*)zone {
176   DCHECK([NSThread isMainThread]);
177   CRWSessionCertificatePolicyManager* copy = [[[self class] alloc] init];
178   copy->allowed_ = allowed_;
179   return copy;
182 @end