Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ios / web / web_state / wk_web_view_security_util.mm
blob0cc3ba913b30403492a42e8b196d854bccb05cbb
1 // Copyright 2014 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/web_state/wk_web_view_security_util.h"
7 #include "base/mac/scoped_cftyperef.h"
8 #include "base/strings/sys_string_conversions.h"
9 #include "net/cert/x509_certificate.h"
10 #include "net/ssl/ssl_info.h"
12 namespace web {
14 // This key was determined by inspecting userInfo dict of an SSL error.
15 NSString* const kNSErrorPeerCertificateChainKey =
16     @"NSErrorPeerCertificateChainKey";
20 namespace {
22 // Creates certificate from subject string.
23 net::X509Certificate* CreateCertFromSubject(NSString* subject) {
24   std::string issuer = "";
25   base::Time start_date;
26   base::Time expiration_date;
27   return new net::X509Certificate(base::SysNSStringToUTF8(subject),
28                                   issuer,
29                                   start_date,
30                                   expiration_date);
33 // Creates certificate using information extracted from NSError.
34 scoped_refptr<net::X509Certificate> CreateCertFromSSLError(NSError* error) {
35   scoped_refptr<net::X509Certificate> cert = web::CreateCertFromChain(
36       error.userInfo[web::kNSErrorPeerCertificateChainKey]);
37   if (cert)
38     return cert;
39   return CreateCertFromSubject(
40       error.userInfo[NSURLErrorFailingURLStringErrorKey]);
43 // Maps NSError code to net::CertStatus.
44 net::CertStatus GetCertStatusFromNSErrorCode(NSInteger code) {
45   switch (code) {
46     // Regardless of real certificate problem the system always returns
47     // NSURLErrorServerCertificateUntrusted. The mapping is done in case this
48     // bug is fixed (rdar://18517043).
49     case NSURLErrorServerCertificateUntrusted:
50     case NSURLErrorSecureConnectionFailed:
51     case NSURLErrorServerCertificateHasUnknownRoot:
52     case NSURLErrorClientCertificateRejected:
53     case NSURLErrorClientCertificateRequired:
54       return net::CERT_STATUS_INVALID;
55     case NSURLErrorServerCertificateHasBadDate:
56     case NSURLErrorServerCertificateNotYetValid:
57       return net::CERT_STATUS_DATE_INVALID;
58   }
59   NOTREACHED();
60   return 0;
63 }  // namespace
66 namespace web {
68 scoped_refptr<net::X509Certificate> CreateCertFromChain(NSArray* certs) {
69   if (certs.count == 0)
70     return nullptr;
71   net::X509Certificate::OSCertHandles intermediates;
72   for (NSUInteger i = 1; i < certs.count; i++) {
73     intermediates.push_back(reinterpret_cast<SecCertificateRef>(certs[i]));
74   }
75   return net::X509Certificate::CreateFromHandle(
76       reinterpret_cast<SecCertificateRef>(certs[0]), intermediates);
79 scoped_refptr<net::X509Certificate> CreateCertFromTrust(SecTrustRef trust) {
80   if (!trust)
81     return nullptr;
83   CFIndex cert_count = SecTrustGetCertificateCount(trust);
84   if (cert_count == 0) {
85     // At the moment there is no API which allows trust creation w/o certs.
86     return nullptr;
87   }
89   net::X509Certificate::OSCertHandles intermediates;
90   for (CFIndex i = 1; i < cert_count; i++) {
91     intermediates.push_back(SecTrustGetCertificateAtIndex(trust, i));
92   }
93   return net::X509Certificate::CreateFromHandle(
94       SecTrustGetCertificateAtIndex(trust, 0), intermediates);
97 void EnsureFutureTrustEvaluationSucceeds(SecTrustRef trust) {
98   base::ScopedCFTypeRef<CFDataRef> exceptions(SecTrustCopyExceptions(trust));
99   SecTrustSetExceptions(trust, exceptions);
102 BOOL IsWKWebViewSSLError(NSError* error) {
103   // SSL errors range is (-2000..-1200], represented by kCFURLError constants:
104   // (kCFURLErrorCannotLoadFromNetwork..kCFURLErrorSecureConnectionFailed].
105   // It's reasonable to expect that all SSL errors will have the error code
106   // less or equal to NSURLErrorSecureConnectionFailed but greater than
107   // NSURLErrorCannotLoadFromNetwork.
108   return [error.domain isEqualToString:NSURLErrorDomain] &&
109          (error.code <= NSURLErrorSecureConnectionFailed &&
110           NSURLErrorCannotLoadFromNetwork < error.code);
113 void GetSSLInfoFromWKWebViewSSLError(NSError* error, net::SSLInfo* ssl_info) {
114   DCHECK(IsWKWebViewSSLError(error));
115   ssl_info->cert_status = GetCertStatusFromNSErrorCode(error.code);
116   ssl_info->cert = CreateCertFromSSLError(error);
119 }  // namespace web