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"
14 // This key was determined by inspecting userInfo dict of an SSL error.
15 NSString* const kNSErrorPeerCertificateChainKey =
16 @"NSErrorPeerCertificateChainKey";
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),
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]);
39 return CreateCertFromSubject(
40 error.userInfo[NSURLErrorFailingURLStringErrorKey]);
43 // Maps NSError code to net::CertStatus.
44 net::CertStatus GetCertStatusFromNSErrorCode(NSInteger 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;
68 scoped_refptr<net::X509Certificate> CreateCertFromChain(NSArray* certs) {
71 net::X509Certificate::OSCertHandles intermediates;
72 for (NSUInteger i = 1; i < certs.count; i++) {
73 intermediates.push_back(reinterpret_cast<SecCertificateRef>(certs[i]));
75 return net::X509Certificate::CreateFromHandle(
76 reinterpret_cast<SecCertificateRef>(certs[0]), intermediates);
79 scoped_refptr<net::X509Certificate> CreateCertFromTrust(SecTrustRef trust) {
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.
89 net::X509Certificate::OSCertHandles intermediates;
90 for (CFIndex i = 1; i < cert_count; i++) {
91 intermediates.push_back(SecTrustGetCertificateAtIndex(trust, i));
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);