Convert iOS to use X509CertificateBytes.
BUG=671420
Review-Url: https://codereview.chromium.org/2864133002
Cr-Commit-Position: refs/heads/master@{#472024}
diff --git a/chrome/browser/ui/certificate_viewer_mac.mm b/chrome/browser/ui/certificate_viewer_mac.mm
index 370ee6d..1697cd3 100644
--- a/chrome/browser/ui/certificate_viewer_mac.mm
+++ b/chrome/browser/ui/certificate_viewer_mac.mm
@@ -12,6 +12,7 @@
#import "base/mac/scoped_nsobject.h"
#include "content/public/browser/web_contents.h"
#include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util_ios_and_mac.h"
#include "net/cert/x509_util_mac.h"
namespace {
diff --git a/ios/web/net/crw_cert_verification_controller.mm b/ios/web/net/crw_cert_verification_controller.mm
index 587d92c9..bb7717e 100644
--- a/ios/web/net/crw_cert_verification_controller.mm
+++ b/ios/web/net/crw_cert_verification_controller.mm
@@ -17,6 +17,7 @@
#include "ios/web/public/web_thread.h"
#import "ios/web/web_state/wk_web_view_security_util.h"
#include "net/cert/cert_verify_proc_ios.h"
+#include "net/cert/x509_util_ios.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
@@ -224,9 +225,9 @@
// Check if user has decided to proceed with this bad cert.
scoped_refptr<net::X509Certificate> leafCert =
- net::X509Certificate::CreateFromHandle(
+ net::x509_util::CreateX509CertificateFromSecCertificate(
SecTrustGetCertificateAtIndex(trust, 0),
- net::X509Certificate::OSCertHandles());
+ std::vector<SecCertificateRef>());
if (!leafCert)
return web::CERT_ACCEPT_POLICY_NON_RECOVERABLE_ERROR;
diff --git a/ios/web/net/crw_cert_verification_controller_unittest.mm b/ios/web/net/crw_cert_verification_controller_unittest.mm
index aac4d43d..5414b54b 100644
--- a/ios/web/net/crw_cert_verification_controller_unittest.mm
+++ b/ios/web/net/crw_cert_verification_controller_unittest.mm
@@ -12,6 +12,7 @@
#include "ios/web/public/web_thread.h"
#import "ios/web/web_state/wk_web_view_security_util.h"
#include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util_ios_and_mac.h"
#include "net/test/cert_test_util.h"
#include "net/test/test_data_directory.h"
@@ -36,20 +37,15 @@
net::ImportCertFromFile(net::GetTestCertsDirectory(), kCertFileName);
ASSERT_TRUE(cert_);
- NSArray* chain = GetChain(cert_);
- valid_trust_ = web::CreateServerTrustFromChain(chain, kHostName);
+ base::ScopedCFTypeRef<CFMutableArrayRef> chain(
+ net::x509_util::CreateSecCertificateArrayForX509Certificate(
+ cert_.get()));
+ ASSERT_TRUE(chain);
+ valid_trust_ = web::CreateServerTrustFromChain(
+ static_cast<NSArray*>(chain.get()), kHostName);
web::EnsureFutureTrustEvaluationSucceeds(valid_trust_.get());
- invalid_trust_ = web::CreateServerTrustFromChain(chain, kHostName);
- }
-
- // Returns NSArray of SecCertificateRef objects for the given |cert|.
- NSArray* GetChain(const scoped_refptr<net::X509Certificate>& cert) const {
- NSMutableArray* result = [NSMutableArray
- arrayWithObject:static_cast<id>(cert->os_cert_handle())];
- for (SecCertificateRef intermediate : cert->GetIntermediateCertificates()) {
- [result addObject:static_cast<id>(intermediate)];
- }
- return result;
+ invalid_trust_ = web::CreateServerTrustFromChain(
+ static_cast<NSArray*>(chain.get()), kHostName);
}
// Synchronously returns result of
diff --git a/ios/web/net/crw_ssl_status_updater_unittest.mm b/ios/web/net/crw_ssl_status_updater_unittest.mm
index 96c7731..0beecd9 100644
--- a/ios/web/net/crw_ssl_status_updater_unittest.mm
+++ b/ios/web/net/crw_ssl_status_updater_unittest.mm
@@ -13,6 +13,7 @@
#include "ios/web/public/ssl_status.h"
#include "ios/web/public/test/web_test.h"
#import "ios/web/web_state/wk_web_view_security_util.h"
+#include "net/cert/x509_util_ios_and_mac.h"
#include "net/test/cert_test_util.h"
#include "net/test/test_data_directory.h"
#include "third_party/ocmock/OCMock/OCMock.h"
@@ -92,8 +93,12 @@
scoped_refptr<net::X509Certificate> cert =
net::ImportCertFromFile(net::GetTestCertsDirectory(), kCertFileName);
ASSERT_TRUE(cert);
- NSArray* chain = @[ static_cast<id>(cert->os_cert_handle()) ];
- trust_ = CreateServerTrustFromChain(chain, kHostName);
+ base::ScopedCFTypeRef<CFMutableArrayRef> chain(
+ net::x509_util::CreateSecCertificateArrayForX509Certificate(
+ cert.get()));
+ ASSERT_TRUE(chain);
+ trust_ = CreateServerTrustFromChain(static_cast<NSArray*>(chain.get()),
+ kHostName);
}
void TearDown() override {
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 3c446cd..8b17115f 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -100,6 +100,7 @@
#import "ios/web/webui/mojo_facade.h"
#import "net/base/mac/url_conversions.h"
#include "net/base/net_errors.h"
+#include "net/cert/x509_util_ios.h"
#include "net/ssl/ssl_info.h"
#include "ui/base/page_transition_types.h"
#include "url/gurl.h"
@@ -3196,9 +3197,9 @@
// |didFailProvisionalNavigation:| will differ (it is the server-supplied
// chain), thus if intermediates were considered, the keys would mismatch.
scoped_refptr<net::X509Certificate> leafCert =
- net::X509Certificate::CreateFromHandle(
+ net::x509_util::CreateX509CertificateFromSecCertificate(
SecTrustGetCertificateAtIndex(trust, 0),
- net::X509Certificate::OSCertHandles());
+ std::vector<SecCertificateRef>());
if (leafCert) {
BOOL is_recoverable =
policy == web::CERT_ACCEPT_POLICY_RECOVERABLE_ERROR_UNDECIDED_BY_USER;
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm
index 2f9a6c9..69a0c60 100644
--- a/ios/web/web_state/ui/crw_web_controller_unittest.mm
+++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -38,6 +38,7 @@
#import "ios/web/web_state/web_state_impl.h"
#import "ios/web/web_state/wk_web_view_security_util.h"
#import "net/base/mac/url_conversions.h"
+#include "net/cert/x509_util_ios_and_mac.h"
#include "net/ssl/ssl_info.h"
#include "net/test/cert_test_util.h"
#include "net/test/test_data_directory.h"
@@ -189,14 +190,18 @@
scoped_refptr<net::X509Certificate> cert =
net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
+ ASSERT_TRUE(cert);
+ base::ScopedCFTypeRef<CFMutableArrayRef> chain(
+ net::x509_util::CreateSecCertificateArrayForX509Certificate(cert.get()));
+ ASSERT_TRUE(chain);
- NSArray* chain = @[ static_cast<id>(cert->os_cert_handle()) ];
GURL url("https://chromium.test");
NSError* error =
[NSError errorWithDomain:NSURLErrorDomain
code:NSURLErrorServerCertificateHasUnknownRoot
userInfo:@{
- web::kNSErrorPeerCertificateChainKey : chain,
+ web::kNSErrorPeerCertificateChainKey :
+ static_cast<NSArray*>(chain.get()),
web::kNSErrorFailingURLKey : net::NSURLWithGURL(url),
}];
base::scoped_nsobject<NSObject> navigation([[NSObject alloc] init]);
diff --git a/ios/web/web_state/wk_web_view_security_util.mm b/ios/web/web_state/wk_web_view_security_util.mm
index 5836fab..5b7e446 100644
--- a/ios/web/web_state/wk_web_view_security_util.mm
+++ b/ios/web/web_state/wk_web_view_security_util.mm
@@ -7,6 +7,7 @@
#include "base/mac/scoped_cftyperef.h"
#include "base/strings/sys_string_conversions.h"
#include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util_ios.h"
#include "net/ssl/ssl_info.h"
namespace web {
@@ -47,11 +48,11 @@
scoped_refptr<net::X509Certificate> CreateCertFromChain(NSArray* certs) {
if (certs.count == 0)
return nullptr;
- net::X509Certificate::OSCertHandles intermediates;
+ std::vector<SecCertificateRef> intermediates;
for (NSUInteger i = 1; i < certs.count; i++) {
intermediates.push_back(reinterpret_cast<SecCertificateRef>(certs[i]));
}
- return net::X509Certificate::CreateFromHandle(
+ return net::x509_util::CreateX509CertificateFromSecCertificate(
reinterpret_cast<SecCertificateRef>(certs[0]), intermediates);
}
@@ -65,11 +66,11 @@
return nullptr;
}
- net::X509Certificate::OSCertHandles intermediates;
+ std::vector<SecCertificateRef> intermediates;
for (CFIndex i = 1; i < cert_count; i++) {
intermediates.push_back(SecTrustGetCertificateAtIndex(trust, i));
}
- return net::X509Certificate::CreateFromHandle(
+ return net::x509_util::CreateX509CertificateFromSecCertificate(
SecTrustGetCertificateAtIndex(trust, 0), intermediates);
}
diff --git a/ios/web/web_state/wk_web_view_security_util_unittest.mm b/ios/web/web_state/wk_web_view_security_util_unittest.mm
index d2eb9c0..d7d77d3 100644
--- a/ios/web/web_state/wk_web_view_security_util_unittest.mm
+++ b/ios/web/web_state/wk_web_view_security_util_unittest.mm
@@ -14,6 +14,7 @@
#include "net/cert/x509_cert_types.h"
#include "net/cert/x509_certificate.h"
#include "net/cert/x509_util.h"
+#include "net/cert/x509_util_ios.h"
#include "net/ssl/ssl_info.h"
#include "testing/gtest/include/gtest/gtest.h"
#import "testing/gtest_mac.h"
@@ -37,8 +38,10 @@
&der_cert);
base::ScopedCFTypeRef<SecCertificateRef> cert(
- net::X509Certificate::CreateOSCertHandleFromBytes(der_cert.data(),
- der_cert.size()));
+ net::x509_util::CreateSecCertificateFromBytes(
+ reinterpret_cast<const uint8_t*>(der_cert.data()), der_cert.size()));
+ if (!cert)
+ return nullptr;
NSArray* result = @[ reinterpret_cast<id>(cert.get()) ];
return result;
}
@@ -68,6 +71,7 @@
TEST_F(WKWebViewSecurityUtilTest, CreationCertFromChain) {
scoped_refptr<net::X509Certificate> cert =
CreateCertFromChain(MakeTestCertChain(kTestSubject));
+ ASSERT_TRUE(cert);
EXPECT_TRUE(cert->subject().GetDisplayName() == kTestSubject);
}
@@ -103,6 +107,7 @@
base::ScopedCFTypeRef<SecTrustRef> trust =
CreateTestTrust(MakeTestCertChain(kTestSubject));
scoped_refptr<net::X509Certificate> cert = CreateCertFromTrust(trust);
+ ASSERT_TRUE(cert);
EXPECT_TRUE(cert->subject().GetDisplayName() == kTestSubject);
}
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 27952a6..e67dc82 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -41,7 +41,7 @@
# in addition to use_openssl_certs or use_nss_certs, in that case byte certs
# are used internally but OpenSSL or NSS are used for certificate verification.
# TODO(mattm): crbug.com/671420: Implement and enable this for all platforms.
-use_byte_certs = is_mac || is_android || is_nacl
+use_byte_certs = is_mac || is_android || is_nacl || is_ios
buildflag_header("features") {
header = "net_features.h"
@@ -605,6 +605,8 @@
"cert/x509_util_android.h",
"cert/x509_util_ios.cc",
"cert/x509_util_ios.h",
+ "cert/x509_util_ios_and_mac.cc",
+ "cert/x509_util_ios_and_mac.h",
"cert/x509_util_mac.cc",
"cert/x509_util_mac.h",
"cert/x509_util_nss.cc",
@@ -1893,6 +1895,8 @@
"base/network_interfaces_mac.h",
"base/platform_mime_util_mac.mm",
"cert/test_root_certs_mac.cc",
+ "cert/x509_util_ios_and_mac.cc",
+ "cert/x509_util_ios_and_mac.h",
"proxy/proxy_resolver_mac.cc",
"proxy/proxy_resolver_mac.h",
"proxy/proxy_server_mac.cc",
@@ -4319,6 +4323,7 @@
"cert/test_root_certs_unittest.cc",
"cert/x509_cert_types_unittest.cc",
"cert/x509_certificate_unittest.cc",
+ "cert/x509_util_ios_and_mac_unittest.cc",
"cert/x509_util_unittest.cc",
"cert_net/cert_net_fetcher_impl_unittest.cc",
"cert_net/nss_ocsp_unittest.cc",
@@ -4905,6 +4910,7 @@
"url_request/url_request_unittest.cc",
"url_request/view_cache_helper_unittest.cc",
]
+ net_unfiltered_sources = []
configs += [
"//build/config:precompiled_headers",
@@ -5206,6 +5212,7 @@
"socket/unix_domain_client_socket_posix_unittest.cc",
"socket/unix_domain_server_socket_posix_unittest.cc",
]
+ net_unfiltered_sources += [ "cert/x509_util_ios_and_mac_unittest.cc" ]
bundle_deps = [ ":net_unittests_bundle_data" ]
}
@@ -5295,6 +5302,11 @@
if (host_toolchain == current_toolchain) {
deps += [ "//net/tools/transport_security_state_generator:transport_security_state_generator_test_sources" ]
}
+
+ # Add back some sources that were otherwise filtered out.
+ set_sources_assignment_filter([])
+ sources += net_unfiltered_sources
+ set_sources_assignment_filter(sources_assignment_filter)
}
# !is_android && !is_win && !is_mac
diff --git a/net/base/net_string_util_icu_alternatives_ios.mm b/net/base/net_string_util_icu_alternatives_ios.mm
index 7ea42808..5470437 100644
--- a/net/base/net_string_util_icu_alternatives_ios.mm
+++ b/net/base/net_string_util_icu_alternatives_ios.mm
@@ -2,13 +2,34 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <CoreFoundation/CoreFoundation.h>
+
#include "base/logging.h"
+#include "base/mac/scoped_cftyperef.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
+#include "base/strings/sys_string_conversions.h"
#include "net/base/net_string_util.h"
namespace net {
+namespace {
+
+bool CharsetToCFStringEncoding(const char* charset,
+ CFStringEncoding* encoding) {
+ if (charset == kCharsetLatin1 || strcmp(charset, kCharsetLatin1) == 0) {
+ *encoding = kCFStringEncodingISOLatin1;
+ return true;
+ }
+ // TODO(mattm): handle other charsets? See
+ // https://developer.apple.com/reference/corefoundation/cfstringbuiltinencodings?language=objc
+ // for list of standard CFStringEncodings.
+
+ return false;
+}
+
+} // namespace
+
// This constant cannot be defined as const char[] because it is initialized
// by base::kCodepageLatin1 (which is const char[]) in net_string_util_icu.cc.
const char* const kCharsetLatin1 = "ISO-8859-1";
@@ -16,8 +37,18 @@
bool ConvertToUtf8(const std::string& text,
const char* charset,
std::string* output) {
- DCHECK(false) << "Not implemented yet.";
- return false;
+ CFStringEncoding encoding;
+ if (!CharsetToCFStringEncoding(charset, &encoding))
+ return false;
+
+ base::ScopedCFTypeRef<CFStringRef> cfstring(CFStringCreateWithBytes(
+ kCFAllocatorDefault, reinterpret_cast<const UInt8*>(text.data()),
+ base::checked_cast<CFIndex>(text.length()), encoding,
+ false /* isExternalRepresentation */));
+ if (!cfstring)
+ return false;
+ *output = base::SysCFStringRefToUTF8(cfstring.get());
+ return true;
}
bool ConvertToUtf8AndNormalize(const std::string& text,
@@ -41,4 +72,4 @@
return false;
}
-} // namespace net
\ No newline at end of file
+} // namespace net
diff --git a/net/cert/cert_verify_proc_ios.cc b/net/cert/cert_verify_proc_ios.cc
index 527326e..ebb2960 100644
--- a/net/cert/cert_verify_proc_ios.cc
+++ b/net/cert/cert_verify_proc_ios.cc
@@ -14,6 +14,8 @@
#include "net/cert/cert_verify_result.h"
#include "net/cert/test_root_certs.h"
#include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util_ios.h"
+#include "net/cert/x509_util_ios_and_mac.h"
#include "net/ssl/openssl_ssl_util.h"
using base::ScopedCFTypeRef;
@@ -115,14 +117,19 @@
verified_chain.push_back(chain_cert);
}
- std::string der_bytes;
- if (!X509Certificate::GetDEREncoded(chain_cert, &der_bytes)) {
+ base::ScopedCFTypeRef<CFDataRef> der_data(
+ SecCertificateCopyData(chain_cert));
+ if (!der_data) {
verify_result->cert_status |= CERT_STATUS_INVALID;
return;
}
base::StringPiece spki_bytes;
- if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes)) {
+ if (!asn1::ExtractSPKIFromDERCert(
+ base::StringPiece(
+ reinterpret_cast<const char*>(CFDataGetBytePtr(der_data)),
+ CFDataGetLength(der_data)),
+ &spki_bytes)) {
verify_result->cert_status |= CERT_STATUS_INVALID;
return;
}
@@ -148,7 +155,8 @@
}
scoped_refptr<X509Certificate> verified_cert_with_chain =
- X509Certificate::CreateFromHandle(verified_cert, verified_chain);
+ x509_util::CreateX509CertificateFromSecCertificate(verified_cert,
+ verified_chain);
if (verified_cert_with_chain)
verify_result->verified_cert = std::move(verified_cert_with_chain);
else
@@ -248,7 +256,7 @@
return NetErrorFromOSStatus(status);
ScopedCFTypeRef<CFMutableArrayRef> cert_array(
- cert->CreateOSCertChainForCert());
+ x509_util::CreateSecCertificateArrayForX509Certificate(cert));
ScopedCFTypeRef<SecTrustRef> trust_ref;
SecTrustResultType trust_result = kSecTrustResultDeny;
ScopedCFTypeRef<CFArrayRef> final_chain;
diff --git a/net/cert/cert_verify_proc_ios_unittest.cc b/net/cert/cert_verify_proc_ios_unittest.cc
index b2191ce..e76b2b7 100644
--- a/net/cert/cert_verify_proc_ios_unittest.cc
+++ b/net/cert/cert_verify_proc_ios_unittest.cc
@@ -10,6 +10,7 @@
#include "base/mac/scoped_cftyperef.h"
#include "base/memory/ref_counted.h"
#include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util_ios_and_mac.h"
#include "net/test/cert_test_util.h"
#include "net/test/test_data_directory.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -23,14 +24,22 @@
scoped_refptr<net::X509Certificate> cert =
net::ImportCertFromFile(net::GetTestCertsDirectory(), cert_file);
+ if (!cert) {
+ ADD_FAILURE();
+ return scoped_result;
+ }
base::ScopedCFTypeRef<CFMutableArrayRef> certs(
- CFArrayCreateMutable(kCFAllocatorDefault, 1, &kCFTypeArrayCallBacks));
- CFArrayAppendValue(certs, cert->os_cert_handle());
+ net::x509_util::CreateSecCertificateArrayForX509Certificate(cert.get()));
+ if (!certs) {
+ ADD_FAILURE();
+ return scoped_result;
+ }
base::ScopedCFTypeRef<SecPolicyRef> policy(
SecPolicyCreateSSL(TRUE, CFSTR("chromium.org")));
SecTrustRef result = nullptr;
- if (SecTrustCreateWithCertificates(certs, policy, &result) == errSecSuccess) {
+ if (SecTrustCreateWithCertificates(certs.get(), policy, &result) ==
+ errSecSuccess) {
scoped_result.reset(result);
}
return scoped_result;
diff --git a/net/cert/cert_verify_proc_mac.cc b/net/cert/cert_verify_proc_mac.cc
index 4184294b..701587d 100644
--- a/net/cert/cert_verify_proc_mac.cc
+++ b/net/cert/cert_verify_proc_mac.cc
@@ -35,6 +35,7 @@
#include "net/cert/test_root_certs.h"
#include "net/cert/x509_certificate.h"
#include "net/cert/x509_util.h"
+#include "net/cert/x509_util_ios_and_mac.h"
#include "net/cert/x509_util_mac.h"
// CSSM functions are deprecated as of OSX 10.7, but have no replacement.
diff --git a/net/cert/x509_certificate.h b/net/cert/x509_certificate.h
index 0cb93b5a..4fb0b3e 100644
--- a/net/cert/x509_certificate.h
+++ b/net/cert/x509_certificate.h
@@ -231,15 +231,6 @@
return intermediate_ca_certs_;
}
-#if defined(OS_IOS)
- // Returns a new CFMutableArrayRef containing this certificate and its
- // intermediate certificates in the form expected by Security.framework
- // and Keychain Services, or NULL on failure.
- // The first item in the array will be this certificate, followed by its
- // intermediates, if any.
- CFMutableArrayRef CreateOSCertChainForCert() const;
-#endif
-
// Do any of the given issuer names appear in this cert's chain of trust?
// |valid_issuers| is a list of DER-encoded X.509 DistinguishedNames.
bool IsIssuedByEncoded(const std::vector<std::string>& valid_issuers);
diff --git a/net/cert/x509_certificate_ios.cc b/net/cert/x509_certificate_ios.cc
index df8482f..475de8f9 100644
--- a/net/cert/x509_certificate_ios.cc
+++ b/net/cert/x509_certificate_ios.cc
@@ -13,6 +13,7 @@
#include "base/strings/string_util.h"
#include "crypto/openssl_util.h"
#include "net/base/ip_address.h"
+#include "net/cert/x509_util_ios.h"
#include "net/cert/x509_util_openssl.h"
#include "net/ssl/openssl_ssl_util.h"
#include "third_party/boringssl/src/include/openssl/x509.h"
@@ -24,21 +25,6 @@
namespace {
-// Returns true if a given |cert_handle| is actually a valid X.509 certificate
-// handle.
-//
-// SecCertificateCreateFromData() does not always force the immediate parsing of
-// the certificate, and as such, may return a SecCertificateRef for an
-// invalid/unparsable certificate. Force parsing to occur to ensure that the
-// SecCertificateRef is correct. On later versions where
-// SecCertificateCreateFromData() immediately parses, rather than lazily, this
-// call is cheap, as the subject is cached.
-bool IsValidOSCertHandle(SecCertificateRef cert_handle) {
- ScopedCFTypeRef<CFStringRef> sanity_check(
- SecCertificateCopySubjectSummary(cert_handle));
- return sanity_check != nullptr;
-}
-
bssl::UniquePtr<X509> OSCertHandleToOpenSSL(
X509Certificate::OSCertHandle os_handle) {
std::string der_encoded;
@@ -245,19 +231,8 @@
X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
const char* data,
size_t length) {
- ScopedCFTypeRef<CFDataRef> cert_data(CFDataCreateWithBytesNoCopy(
- kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data),
- base::checked_cast<CFIndex>(length), kCFAllocatorNull));
- if (!cert_data)
- return nullptr;
- OSCertHandle cert_handle = SecCertificateCreateWithData(nullptr, cert_data);
- if (!cert_handle)
- return nullptr;
- if (!IsValidOSCertHandle(cert_handle)) {
- CFRelease(cert_handle);
- return nullptr;
- }
- return cert_handle;
+ return x509_util::CreateSecCertificateFromBytes(
+ reinterpret_cast<const uint8_t*>(data), length);
}
// static
@@ -375,19 +350,6 @@
*size_bits = EVP_PKEY_bits(key);
}
-CFMutableArrayRef X509Certificate::CreateOSCertChainForCert() const {
- CFMutableArrayRef cert_list =
- CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
- if (!cert_list)
- return nullptr;
-
- CFArrayAppendValue(cert_list, os_cert_handle());
- for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i)
- CFArrayAppendValue(cert_list, intermediate_ca_certs_[i]);
-
- return cert_list;
-}
-
bool X509Certificate::IsIssuedByEncoded(
const std::vector<std::string>& valid_issuers) {
if (valid_issuers.empty())
diff --git a/net/cert/x509_util_ios.cc b/net/cert/x509_util_ios.cc
index 9bf4185..18d33151 100644
--- a/net/cert/x509_util_ios.cc
+++ b/net/cert/x509_util_ios.cc
@@ -5,16 +5,101 @@
#include "net/cert/x509_util_ios.h"
#include "net/cert/x509_certificate.h"
+#include "third_party/boringssl/src/include/openssl/pool.h"
namespace net {
namespace x509_util {
+namespace {
+
+// Returns true if a given |cert_handle| is actually a valid X.509 certificate
+// handle.
+//
+// SecCertificateCreateFromData() does not always force the immediate parsing of
+// the certificate, and as such, may return a SecCertificateRef for an
+// invalid/unparsable certificate. Force parsing to occur to ensure that the
+// SecCertificateRef is correct. On later versions where
+// SecCertificateCreateFromData() immediately parses, rather than lazily, this
+// call is cheap, as the subject is cached.
+bool IsValidSecCertificate(SecCertificateRef cert_handle) {
+ base::ScopedCFTypeRef<CFStringRef> sanity_check(
+ SecCertificateCopySubjectSummary(cert_handle));
+ return sanity_check != nullptr;
+}
+
+} // namespace
+
+base::ScopedCFTypeRef<SecCertificateRef> CreateSecCertificateFromBytes(
+ const uint8_t* data,
+ size_t length) {
+ base::ScopedCFTypeRef<CFDataRef> cert_data(CFDataCreateWithBytesNoCopy(
+ kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data),
+ base::checked_cast<CFIndex>(length), kCFAllocatorNull));
+ if (!cert_data)
+ return base::ScopedCFTypeRef<SecCertificateRef>();
+
+ base::ScopedCFTypeRef<SecCertificateRef> cert_handle(
+ SecCertificateCreateWithData(nullptr, cert_data));
+ if (!cert_handle)
+ return base::ScopedCFTypeRef<SecCertificateRef>();
+
+ if (!IsValidSecCertificate(cert_handle.get()))
+ return base::ScopedCFTypeRef<SecCertificateRef>();
+ return cert_handle;
+}
+
base::ScopedCFTypeRef<SecCertificateRef>
CreateSecCertificateFromX509Certificate(const X509Certificate* cert) {
+#if BUILDFLAG(USE_BYTE_CERTS)
+ return CreateSecCertificateFromBytes(
+ CRYPTO_BUFFER_data(cert->os_cert_handle()),
+ CRYPTO_BUFFER_len(cert->os_cert_handle()));
+#else
return base::ScopedCFTypeRef<SecCertificateRef>(
reinterpret_cast<SecCertificateRef>(
const_cast<void*>(CFRetain(cert->os_cert_handle()))));
+#endif
+}
+
+scoped_refptr<X509Certificate> CreateX509CertificateFromSecCertificate(
+ SecCertificateRef sec_cert,
+ const std::vector<SecCertificateRef>& sec_chain) {
+#if BUILDFLAG(USE_BYTE_CERTS)
+ if (!sec_cert)
+ return nullptr;
+ base::ScopedCFTypeRef<CFDataRef> der_data(SecCertificateCopyData(sec_cert));
+ if (!der_data)
+ return nullptr;
+ bssl::UniquePtr<CRYPTO_BUFFER> cert_handle(
+ X509Certificate::CreateOSCertHandleFromBytes(
+ reinterpret_cast<const char*>(CFDataGetBytePtr(der_data)),
+ CFDataGetLength(der_data)));
+ if (!cert_handle)
+ return nullptr;
+ std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
+ X509Certificate::OSCertHandles intermediates_raw;
+ for (const SecCertificateRef& sec_intermediate : sec_chain) {
+ if (!sec_intermediate)
+ return nullptr;
+ der_data.reset(SecCertificateCopyData(sec_intermediate));
+ if (!der_data)
+ return nullptr;
+ bssl::UniquePtr<CRYPTO_BUFFER> intermediate_cert_handle(
+ X509Certificate::CreateOSCertHandleFromBytes(
+ reinterpret_cast<const char*>(CFDataGetBytePtr(der_data)),
+ CFDataGetLength(der_data)));
+ if (!intermediate_cert_handle)
+ return nullptr;
+ intermediates_raw.push_back(intermediate_cert_handle.get());
+ intermediates.push_back(std::move(intermediate_cert_handle));
+ }
+ scoped_refptr<X509Certificate> result(
+ X509Certificate::CreateFromHandle(cert_handle.get(), intermediates_raw));
+ return result;
+#else
+ return X509Certificate::CreateFromHandle(sec_cert, sec_chain);
+#endif
}
} // namespace x509_util
diff --git a/net/cert/x509_util_ios.h b/net/cert/x509_util_ios.h
index bf3473f..cfc9827 100644
--- a/net/cert/x509_util_ios.h
+++ b/net/cert/x509_util_ios.h
@@ -7,7 +7,10 @@
#include <Security/Security.h>
+#include <vector>
+
#include "base/mac/scoped_cftyperef.h"
+#include "base/memory/ref_counted.h"
#include "net/base/net_export.h"
namespace net {
@@ -16,10 +19,22 @@
namespace x509_util {
+// Creates a SecCertificate handle from the DER-encoded representation.
+// Returns NULL on failure.
+NET_EXPORT base::ScopedCFTypeRef<SecCertificateRef>
+CreateSecCertificateFromBytes(const uint8_t* data, size_t length);
+
// Returns a SecCertificate representing |cert|, or NULL on failure.
NET_EXPORT base::ScopedCFTypeRef<SecCertificateRef>
CreateSecCertificateFromX509Certificate(const X509Certificate* cert);
+// Creates an X509Certificate representing |sec_cert| with intermediates
+// |sec_chain|.
+NET_EXPORT scoped_refptr<X509Certificate>
+CreateX509CertificateFromSecCertificate(
+ SecCertificateRef sec_cert,
+ const std::vector<SecCertificateRef>& sec_chain);
+
} // namespace x509_util
} // namespace net
diff --git a/net/cert/x509_util_ios_and_mac.cc b/net/cert/x509_util_ios_and_mac.cc
new file mode 100644
index 0000000..ff8faaf
--- /dev/null
+++ b/net/cert/x509_util_ios_and_mac.cc
@@ -0,0 +1,54 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/x509_util_ios_and_mac.h"
+
+#include "net/cert/x509_certificate.h"
+#if defined(OS_IOS)
+#include "net/cert/x509_util_ios.h"
+#else
+#include "net/cert/x509_util_mac.h"
+#endif
+#include "third_party/boringssl/src/include/openssl/pool.h"
+
+namespace net {
+
+namespace x509_util {
+
+base::ScopedCFTypeRef<CFMutableArrayRef>
+CreateSecCertificateArrayForX509Certificate(X509Certificate* cert) {
+ base::ScopedCFTypeRef<CFMutableArrayRef> cert_list(
+ CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));
+ if (!cert_list)
+ return base::ScopedCFTypeRef<CFMutableArrayRef>();
+#if BUILDFLAG(USE_BYTE_CERTS)
+ std::string bytes;
+ base::ScopedCFTypeRef<SecCertificateRef> sec_cert(
+ CreateSecCertificateFromBytes(CRYPTO_BUFFER_data(cert->os_cert_handle()),
+ CRYPTO_BUFFER_len(cert->os_cert_handle())));
+ if (!sec_cert)
+ return base::ScopedCFTypeRef<CFMutableArrayRef>();
+ CFArrayAppendValue(cert_list, sec_cert);
+ for (X509Certificate::OSCertHandle intermediate :
+ cert->GetIntermediateCertificates()) {
+ base::ScopedCFTypeRef<SecCertificateRef> sec_cert(
+ CreateSecCertificateFromBytes(CRYPTO_BUFFER_data(intermediate),
+ CRYPTO_BUFFER_len(intermediate)));
+ if (!sec_cert)
+ return base::ScopedCFTypeRef<CFMutableArrayRef>();
+ CFArrayAppendValue(cert_list, sec_cert);
+ }
+#else
+ X509Certificate::OSCertHandles intermediate_ca_certs =
+ cert->GetIntermediateCertificates();
+ CFArrayAppendValue(cert_list, cert->os_cert_handle());
+ for (size_t i = 0; i < intermediate_ca_certs.size(); ++i)
+ CFArrayAppendValue(cert_list, intermediate_ca_certs[i]);
+#endif
+ return cert_list;
+}
+
+} // namespace x509_util
+
+} // namespace net
diff --git a/net/cert/x509_util_ios_and_mac.h b/net/cert/x509_util_ios_and_mac.h
new file mode 100644
index 0000000..4cc9183
--- /dev/null
+++ b/net/cert/x509_util_ios_and_mac.h
@@ -0,0 +1,32 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_CERT_X509_UTIL_IOS_AND_MAC_H_
+#define NET_CERT_X509_UTIL_IOS_AND_MAC_H_
+
+#include <CoreFoundation/CFArray.h>
+#include <Security/Security.h>
+
+#include "base/mac/scoped_cftyperef.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+class X509Certificate;
+
+namespace x509_util {
+
+// Returns a new CFMutableArrayRef containing this certificate and its
+// intermediate certificates in the form expected by Security.framework
+// and Keychain Services, or NULL on failure.
+// The first item in the array will be this certificate, followed by its
+// intermediates, if any.
+NET_EXPORT base::ScopedCFTypeRef<CFMutableArrayRef>
+CreateSecCertificateArrayForX509Certificate(X509Certificate* cert);
+
+} // namespace x509_util
+
+} // namespace net
+
+#endif // NET_CERT_X509_UTIL_IOS_AND_MAC_H_
diff --git a/net/cert/x509_util_ios_and_mac_unittest.cc b/net/cert/x509_util_ios_and_mac_unittest.cc
new file mode 100644
index 0000000..bab2923
--- /dev/null
+++ b/net/cert/x509_util_ios_and_mac_unittest.cc
@@ -0,0 +1,152 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/cert/x509_util_ios_and_mac.h"
+
+#include "net/cert/x509_certificate.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/test_data_directory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_IOS)
+#include "net/cert/x509_util_ios.h"
+#else
+#include "net/cert/x509_util_mac.h"
+#endif
+
+namespace net {
+
+namespace x509_util {
+
+namespace {
+
+std::string BytesForSecCert(SecCertificateRef sec_cert) {
+ std::string result;
+ base::ScopedCFTypeRef<CFDataRef> der_data(SecCertificateCopyData(sec_cert));
+ if (!der_data) {
+ ADD_FAILURE();
+ return result;
+ }
+ result.assign(reinterpret_cast<const char*>(CFDataGetBytePtr(der_data)),
+ CFDataGetLength(der_data));
+ return result;
+}
+
+std::string BytesForSecCert(const void* sec_cert) {
+ return BytesForSecCert(
+ reinterpret_cast<SecCertificateRef>(const_cast<void*>(sec_cert)));
+}
+
+std::string BytesForX509CertHandle(X509Certificate::OSCertHandle handle) {
+ std::string result;
+ if (!X509Certificate::GetDEREncoded(handle, &result))
+ ADD_FAILURE();
+ return result;
+}
+
+std::string BytesForX509Cert(X509Certificate* cert) {
+ return BytesForX509CertHandle(cert->os_cert_handle());
+}
+
+} // namespace
+
+TEST(X509UtilTest, CreateSecCertificateArrayForX509Certificate) {
+ scoped_refptr<X509Certificate> cert = CreateCertificateChainFromFile(
+ GetTestCertsDirectory(), "multi-root-chain1.pem",
+ X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
+ ASSERT_TRUE(cert);
+ EXPECT_EQ(3U, cert->GetIntermediateCertificates().size());
+
+ base::ScopedCFTypeRef<CFMutableArrayRef> sec_certs(
+ CreateSecCertificateArrayForX509Certificate(cert.get()));
+ ASSERT_TRUE(sec_certs);
+ ASSERT_EQ(4, CFArrayGetCount(sec_certs.get()));
+ for (int i = 0; i < 4; ++i)
+ ASSERT_TRUE(CFArrayGetValueAtIndex(sec_certs.get(), i));
+
+ EXPECT_EQ(BytesForX509Cert(cert.get()),
+ BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 0)));
+ EXPECT_EQ(BytesForX509CertHandle(cert->GetIntermediateCertificates()[0]),
+ BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 1)));
+ EXPECT_EQ(BytesForX509CertHandle(cert->GetIntermediateCertificates()[1]),
+ BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 2)));
+ EXPECT_EQ(BytesForX509CertHandle(cert->GetIntermediateCertificates()[2]),
+ BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 3)));
+}
+
+TEST(X509UtilTest,
+ CreateSecCertificateFromBytesAndCreateX509CertificateFromSecCertificate) {
+ CertificateList certs = CreateCertificateListFromFile(
+ GetTestCertsDirectory(), "multi-root-chain1.pem",
+ X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
+ ASSERT_EQ(4u, certs.size());
+
+ std::string bytes_cert0 = BytesForX509CertHandle(certs[0]->os_cert_handle());
+ std::string bytes_cert1 = BytesForX509CertHandle(certs[1]->os_cert_handle());
+ std::string bytes_cert2 = BytesForX509CertHandle(certs[2]->os_cert_handle());
+ std::string bytes_cert3 = BytesForX509CertHandle(certs[3]->os_cert_handle());
+
+ base::ScopedCFTypeRef<SecCertificateRef> sec_cert0(
+ CreateSecCertificateFromBytes(
+ reinterpret_cast<const uint8_t*>(bytes_cert0.data()),
+ bytes_cert0.length()));
+ ASSERT_TRUE(sec_cert0);
+ EXPECT_EQ(bytes_cert0, BytesForSecCert(sec_cert0));
+
+ base::ScopedCFTypeRef<SecCertificateRef> sec_cert1(
+ CreateSecCertificateFromBytes(
+ reinterpret_cast<const uint8_t*>(bytes_cert1.data()),
+ bytes_cert1.length()));
+ ASSERT_TRUE(sec_cert1);
+ EXPECT_EQ(bytes_cert1, BytesForSecCert(sec_cert1));
+
+ base::ScopedCFTypeRef<SecCertificateRef> sec_cert2(
+ CreateSecCertificateFromX509Certificate(certs[2].get()));
+ ASSERT_TRUE(sec_cert2);
+ EXPECT_EQ(bytes_cert2, BytesForSecCert(sec_cert2));
+
+ base::ScopedCFTypeRef<SecCertificateRef> sec_cert3(
+ CreateSecCertificateFromX509Certificate(certs[3].get()));
+ ASSERT_TRUE(sec_cert3);
+ EXPECT_EQ(bytes_cert3, BytesForSecCert(sec_cert3));
+
+ scoped_refptr<X509Certificate> x509_cert_no_intermediates =
+ CreateX509CertificateFromSecCertificate(sec_cert0.get(), {});
+ ASSERT_TRUE(x509_cert_no_intermediates);
+ EXPECT_EQ(0U,
+ x509_cert_no_intermediates->GetIntermediateCertificates().size());
+ EXPECT_EQ(bytes_cert0, BytesForX509CertHandle(
+ x509_cert_no_intermediates->os_cert_handle()));
+
+ scoped_refptr<X509Certificate> x509_cert_one_intermediate =
+ CreateX509CertificateFromSecCertificate(sec_cert0.get(),
+ {sec_cert1.get()});
+ ASSERT_TRUE(x509_cert_one_intermediate);
+ EXPECT_EQ(bytes_cert0, BytesForX509CertHandle(
+ x509_cert_one_intermediate->os_cert_handle()));
+ ASSERT_EQ(1U,
+ x509_cert_one_intermediate->GetIntermediateCertificates().size());
+ EXPECT_EQ(bytes_cert1,
+ BytesForX509CertHandle(
+ x509_cert_one_intermediate->GetIntermediateCertificates()[0]));
+
+ scoped_refptr<X509Certificate> x509_cert_two_intermediates =
+ CreateX509CertificateFromSecCertificate(
+ sec_cert0.get(), {sec_cert1.get(), sec_cert2.get()});
+ ASSERT_TRUE(x509_cert_two_intermediates);
+ EXPECT_EQ(bytes_cert0, BytesForX509CertHandle(
+ x509_cert_two_intermediates->os_cert_handle()));
+ ASSERT_EQ(2U,
+ x509_cert_two_intermediates->GetIntermediateCertificates().size());
+ EXPECT_EQ(bytes_cert1,
+ BytesForX509CertHandle(
+ x509_cert_two_intermediates->GetIntermediateCertificates()[0]));
+ EXPECT_EQ(bytes_cert2,
+ BytesForX509CertHandle(
+ x509_cert_two_intermediates->GetIntermediateCertificates()[1]));
+}
+
+} // namespace x509_util
+
+} // namespace net
diff --git a/net/cert/x509_util_mac.cc b/net/cert/x509_util_mac.cc
index c8f6a2f..d533588 100644
--- a/net/cert/x509_util_mac.cc
+++ b/net/cert/x509_util_mac.cc
@@ -92,39 +92,6 @@
#endif
}
-base::ScopedCFTypeRef<CFMutableArrayRef>
-CreateSecCertificateArrayForX509Certificate(X509Certificate* cert) {
- base::ScopedCFTypeRef<CFMutableArrayRef> cert_list(
- CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));
- if (!cert_list)
- return base::ScopedCFTypeRef<CFMutableArrayRef>();
-#if BUILDFLAG(USE_BYTE_CERTS)
- std::string bytes;
- base::ScopedCFTypeRef<SecCertificateRef> sec_cert(
- CreateSecCertificateFromBytes(CRYPTO_BUFFER_data(cert->os_cert_handle()),
- CRYPTO_BUFFER_len(cert->os_cert_handle())));
- if (!sec_cert)
- return base::ScopedCFTypeRef<CFMutableArrayRef>();
- CFArrayAppendValue(cert_list, sec_cert);
- for (X509Certificate::OSCertHandle intermediate :
- cert->GetIntermediateCertificates()) {
- base::ScopedCFTypeRef<SecCertificateRef> sec_cert(
- CreateSecCertificateFromBytes(CRYPTO_BUFFER_data(intermediate),
- CRYPTO_BUFFER_len(intermediate)));
- if (!sec_cert)
- return base::ScopedCFTypeRef<CFMutableArrayRef>();
- CFArrayAppendValue(cert_list, sec_cert);
- }
-#else
- X509Certificate::OSCertHandles intermediate_ca_certs =
- cert->GetIntermediateCertificates();
- CFArrayAppendValue(cert_list, cert->os_cert_handle());
- for (size_t i = 0; i < intermediate_ca_certs.size(); ++i)
- CFArrayAppendValue(cert_list, intermediate_ca_certs[i]);
-#endif
- return cert_list;
-}
-
scoped_refptr<X509Certificate> CreateX509CertificateFromSecCertificate(
SecCertificateRef sec_cert,
const std::vector<SecCertificateRef>& sec_chain) {
diff --git a/net/cert/x509_util_mac.h b/net/cert/x509_util_mac.h
index 1700a6cc..4368613 100644
--- a/net/cert/x509_util_mac.h
+++ b/net/cert/x509_util_mac.h
@@ -44,14 +44,6 @@
NET_EXPORT base::ScopedCFTypeRef<SecCertificateRef>
CreateSecCertificateFromX509Certificate(const X509Certificate* cert);
-// Returns a new CFMutableArrayRef containing this certificate and its
-// intermediate certificates in the form expected by Security.framework
-// and Keychain Services, or NULL on failure.
-// The first item in the array will be this certificate, followed by its
-// intermediates, if any.
-NET_EXPORT base::ScopedCFTypeRef<CFMutableArrayRef>
-CreateSecCertificateArrayForX509Certificate(X509Certificate* cert);
-
// Creates an X509Certificate representing |sec_cert| with intermediates
// |sec_chain|.
NET_EXPORT scoped_refptr<X509Certificate>
diff --git a/net/ssl/client_cert_store_mac.cc b/net/ssl/client_cert_store_mac.cc
index 8003524..7fadb33 100644
--- a/net/ssl/client_cert_store_mac.cc
+++ b/net/ssl/client_cert_store_mac.cc
@@ -22,6 +22,7 @@
#include "crypto/mac_security_services_lock.h"
#include "net/base/host_port_pair.h"
#include "net/cert/x509_util.h"
+#include "net/cert/x509_util_ios_and_mac.h"
#include "net/cert/x509_util_mac.h"
using base::ScopedCFTypeRef;