Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3132)

Unified Diff: net/cert/x509_certificate_openssl_ios.cc

Issue 1810153002: Adding iOS OpenSSL Implementation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixing more nits. Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: net/cert/x509_certificate_openssl_ios.cc
diff --git a/net/cert/x509_certificate_openssl.cc b/net/cert/x509_certificate_openssl_ios.cc
similarity index 60%
copy from net/cert/x509_certificate_openssl.cc
copy to net/cert/x509_certificate_openssl_ios.cc
index ec31e6e371b98b0ebfba80a80cbe7f28312b4d70..49a88d72af6ff83ea80dc89bef01f5b4eeef2d38 100644
--- a/net/cert/x509_certificate_openssl.cc
+++ b/net/cert/x509_certificate_openssl_ios.cc
@@ -1,36 +1,26 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright (c) 2016 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_certificate.h"
-#include <openssl/asn1.h>
-#include <openssl/bytestring.h>
-#include <openssl/crypto.h>
-#include <openssl/obj_mac.h>
-#include <openssl/pem.h>
-#include <openssl/sha.h>
-#include <openssl/ssl.h>
+#include <CommonCrypto/CommonDigest.h>
+#include <Security/Security.h>
+
+#include <openssl/x509.h>
#include <openssl/x509v3.h>
-#include "base/macros.h"
-#include "base/memory/singleton.h"
-#include "base/numerics/safe_conversions.h"
+#include "base/mac/scoped_cftyperef.h"
#include "base/pickle.h"
-#include "base/sha1.h"
-#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "crypto/openssl_util.h"
#include "crypto/scoped_openssl_types.h"
#include "net/base/ip_address_number.h"
-#include "net/base/net_errors.h"
#include "net/cert/x509_util_openssl.h"
+#include "net/ssl/openssl_ssl_util.h"
-#if defined(OS_ANDROID)
-#include "base/logging.h"
-#include "net/android/network_library.h"
-#endif
+using base::ScopedCFTypeRef;
namespace net {
@@ -39,6 +29,21 @@ namespace {
using ScopedGENERAL_NAMES =
crypto::ScopedOpenSSL<GENERAL_NAMES, GENERAL_NAMES_free>;
+// 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;
+}
+
void CreateOSCertHandlesFromPKCS7Bytes(
const char* data,
size_t length,
@@ -52,9 +57,12 @@ void CreateOSCertHandlesFromPKCS7Bytes(
if (PKCS7_get_certificates(certs, &der_data)) {
for (size_t i = 0; i < sk_X509_num(certs); ++i) {
- X509* x509_cert =
- X509Certificate::DupOSCertHandle(sk_X509_value(certs, i));
- handles->push_back(x509_cert);
+ X509* x509_cert = sk_X509_value(certs, i);
+ base::StringPiece der;
+ if (!x509_util::GetDER(x509_cert, &der))
+ return;
+ handles->push_back(X509Certificate::CreateOSCertHandleFromBytes(
+ der.data(), der.length()));
}
}
sk_X509_pop_free(certs, X509_free);
@@ -72,7 +80,7 @@ void ParsePrincipalValues(X509_NAME* name,
}
}
-void ParsePrincipal(X509Certificate::OSCertHandle cert,
+void ParsePrincipal(X509Certificate::OSCertHandle os_cert,
X509_NAME* x509_name,
CertPrincipal* principal) {
if (!x509_name)
@@ -97,12 +105,15 @@ void ParsePrincipal(X509Certificate::OSCertHandle cert,
&principal->country_name);
}
-void ParseSubjectAltName(X509Certificate::OSCertHandle cert,
+void ParseSubjectAltName(X509Certificate::OSCertHandle os_cert,
std::vector<std::string>* dns_names,
std::vector<std::string>* ip_addresses) {
DCHECK(dns_names || ip_addresses);
- int index = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1);
- X509_EXTENSION* alt_name_ext = X509_get_ext(cert, index);
+ ScopedX509 cert = OSCertHandleToOpenSSL(os_cert);
+ if (!cert.get())
+ return;
+ int index = X509_get_ext_by_NID(cert.get(), NID_subject_alt_name, -1);
+ X509_EXTENSION* alt_name_ext = X509_get_ext(cert.get(), index);
if (!alt_name_ext)
return;
@@ -139,38 +150,8 @@ void ParseSubjectAltName(X509Certificate::OSCertHandle cert,
}
}
-class X509InitSingleton {
- public:
- static X509InitSingleton* GetInstance() {
- // We allow the X509 store to leak, because it is used from a non-joinable
- // worker that is not stopped on shutdown, hence may still be using
- // OpenSSL library after the AtExit runner has completed.
- return base::Singleton<X509InitSingleton, base::LeakySingletonTraits<
- X509InitSingleton>>::get();
- }
- X509_STORE* store() const { return store_.get(); }
-
- void ResetCertStore() {
- store_.reset(X509_STORE_new());
- DCHECK(store_.get());
- X509_STORE_set_default_paths(store_.get());
- // TODO(joth): Enable CRL (see X509_STORE_set_flags(X509_V_FLAG_CRL_CHECK)).
- }
-
- private:
- friend struct base::DefaultSingletonTraits<X509InitSingleton>;
- X509InitSingleton() {
- crypto::EnsureOpenSSLInit();
- ResetCertStore();
- }
-
- crypto::ScopedOpenSSL<X509_STORE, X509_STORE_free> store_;
-
- DISALLOW_COPY_AND_ASSIGN(X509InitSingleton);
-};
-
// Used to free a list of X509_NAMEs and the objects it points to.
-void sk_X509_NAME_free_all(STACK_OF(X509_NAME)* sk) {
+void sk_X509_NAME_free_all(STACK_OF(X509_NAME) * sk) {
sk_X509_NAME_pop_free(sk, X509_NAME_free);
}
@@ -178,25 +159,26 @@ void sk_X509_NAME_free_all(STACK_OF(X509_NAME)* sk) {
// static
X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle(
- OSCertHandle cert_handle) {
- DCHECK(cert_handle);
- return X509_up_ref(cert_handle);
+ OSCertHandle handle) {
+ if (!handle)
+ return nullptr;
+ return reinterpret_cast<OSCertHandle>(const_cast<void*>(CFRetain(handle)));
}
// static
void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) {
- // Decrement the ref-count for the cert and, if all references are gone,
- // free the memory and any application-specific data associated with the
- // certificate.
- X509_free(cert_handle);
+ if (cert_handle)
+ CFRelease(cert_handle);
}
void X509Certificate::Initialize() {
crypto::EnsureOpenSSLInit();
fingerprint_ = CalculateFingerprint(cert_handle_);
ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_);
-
- ASN1_INTEGER* serial_num = X509_get_serialNumber(cert_handle_);
+ ScopedX509 x509_cert = OSCertHandleToOpenSSL(cert_handle_);
+ if (!x509_cert)
+ return;
+ ASN1_INTEGER* serial_num = X509_get_serialNumber(x509_cert.get());
if (serial_num) {
// ASN1_INTEGERS represent the decoded number, in a format internal to
// OpenSSL. Most notably, this may have leading zeroes stripped off for
@@ -204,41 +186,48 @@ void X509Certificate::Initialize() {
// re-encoded the integer back into DER, which is what the interface
// of X509Certificate exposes, to ensure callers get the proper (DER)
// value.
- int bytes_required = i2c_ASN1_INTEGER(serial_num, NULL);
+ int bytes_required = i2c_ASN1_INTEGER(serial_num, nullptr);
unsigned char* buffer = reinterpret_cast<unsigned char*>(
base::WriteInto(&serial_number_, bytes_required + 1));
int bytes_written = i2c_ASN1_INTEGER(serial_num, &buffer);
DCHECK_EQ(static_cast<size_t>(bytes_written), serial_number_.size());
}
- ParsePrincipal(cert_handle_, X509_get_subject_name(cert_handle_), &subject_);
- ParsePrincipal(cert_handle_, X509_get_issuer_name(cert_handle_), &issuer_);
- x509_util::ParseDate(X509_get_notBefore(cert_handle_), &valid_start_);
- x509_util::ParseDate(X509_get_notAfter(cert_handle_), &valid_expiry_);
-}
-
-// static
-void X509Certificate::ResetCertStore() {
- X509InitSingleton::GetInstance()->ResetCertStore();
+ ParsePrincipal(cert_handle_, X509_get_subject_name(x509_cert.get()),
+ &subject_);
+ ParsePrincipal(cert_handle_, X509_get_issuer_name(x509_cert.get()), &issuer_);
+ x509_util::ParseDate(X509_get_notBefore(x509_cert.get()), &valid_start_);
+ x509_util::ParseDate(X509_get_notAfter(x509_cert.get()), &valid_expiry_);
}
// static
SHA1HashValue X509Certificate::CalculateFingerprint(OSCertHandle cert) {
SHA1HashValue sha1;
- unsigned int sha1_size = static_cast<unsigned int>(sizeof(sha1.data));
- int ret = X509_digest(cert, EVP_sha1(), sha1.data, &sha1_size);
- CHECK(ret);
- CHECK_EQ(sha1_size, sizeof(sha1.data));
+ memset(sha1.data, 0, sizeof(sha1.data));
+
+ ScopedCFTypeRef<CFDataRef> cert_data(SecCertificateCopyData(cert));
+ if (!cert_data)
+ return sha1;
+ DCHECK(CFDataGetBytePtr(cert_data));
+ DCHECK_NE(0, CFDataGetLength(cert_data));
+ CC_SHA1(CFDataGetBytePtr(cert_data), CFDataGetLength(cert_data), sha1.data);
+
return sha1;
}
// static
SHA256HashValue X509Certificate::CalculateFingerprint256(OSCertHandle cert) {
SHA256HashValue sha256;
- unsigned int sha256_size = static_cast<unsigned int>(sizeof(sha256.data));
- int ret = X509_digest(cert, EVP_sha256(), sha256.data, &sha256_size);
- CHECK(ret);
- CHECK_EQ(sha256_size, sizeof(sha256.data));
+ memset(sha256.data, 0, sizeof(sha256.data));
+
+ ScopedCFTypeRef<CFDataRef> cert_data(SecCertificateCopyData(cert));
+ if (!cert_data)
+ return sha256;
+ DCHECK(CFDataGetBytePtr(cert_data));
+ DCHECK_NE(0, CFDataGetLength(cert_data));
+ CC_SHA256(CFDataGetBytePtr(cert_data), CFDataGetLength(cert_data),
+ sha256.data);
+
return sha256;
}
@@ -248,16 +237,17 @@ SHA1HashValue X509Certificate::CalculateCAFingerprint(
SHA1HashValue sha1;
memset(sha1.data, 0, sizeof(sha1.data));
- SHA_CTX sha1_ctx;
- SHA1_Init(&sha1_ctx);
- base::StringPiece der;
+ CC_SHA1_CTX sha1_ctx;
+ CC_SHA1_Init(&sha1_ctx);
for (size_t i = 0; i < intermediates.size(); ++i) {
- if (!x509_util::GetDER(intermediates[i], &der))
+ ScopedCFTypeRef<CFDataRef> cert_data(
+ SecCertificateCopyData(intermediates[i]));
+ if (!cert_data)
return sha1;
- SHA1_Update(&sha1_ctx, der.data(), der.length());
+ CC_SHA1_Update(&sha1_ctx, CFDataGetBytePtr(cert_data),
+ CFDataGetLength(cert_data));
}
- SHA1_Final(sha1.data, &sha1_ctx);
-
+ CC_SHA1_Final(sha1.data, &sha1_ctx);
return sha1;
}
@@ -265,13 +255,19 @@ SHA1HashValue X509Certificate::CalculateCAFingerprint(
X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
const char* data,
size_t length) {
- crypto::EnsureOpenSSLInit();
- const unsigned char* d2i_data =
- reinterpret_cast<const unsigned char*>(data);
- // Don't cache this data for x509_util::GetDER as this wire format
- // may be not be identical from the i2d_X509 roundtrip.
- X509* cert = d2i_X509(NULL, &d2i_data, base::checked_cast<long>(length));
- return cert;
+ 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;
}
// static
@@ -283,7 +279,8 @@ X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes(
switch (format) {
case FORMAT_SINGLE_CERTIFICATE: {
- OSCertHandle handle = CreateOSCertHandleFromBytes(data, length);
+ OSCertHandle handle =
+ X509Certificate::CreateOSCertHandleFromBytes(data, length);
if (handle)
results.push_back(handle);
break;
@@ -313,17 +310,16 @@ void X509Certificate::GetSubjectAltName(
}
// static
-X509_STORE* X509Certificate::cert_store() {
- return X509InitSingleton::GetInstance()->store();
-}
-
-// static
bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle,
std::string* encoded) {
base::StringPiece der;
- if (!cert_handle || !x509_util::GetDER(cert_handle, &der))
+ if (!cert_handle)
return false;
- encoded->assign(der.data(), der.length());
+ ScopedCFTypeRef<CFDataRef> der_data(SecCertificateCopyData(cert_handle));
+ if (!der_data)
+ return false;
+ encoded->assign(reinterpret_cast<const char*>(CFDataGetBytePtr(der_data)),
+ CFDataGetLength(der_data));
return true;
}
@@ -331,17 +327,7 @@ bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle,
bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a,
X509Certificate::OSCertHandle b) {
DCHECK(a && b);
- if (a == b)
- return true;
-
- // X509_cmp only checks the fingerprint, but we want to compare the whole
- // DER data. Encoding it from OSCertHandle is an expensive operation, so we
- // cache the DER (if not already cached via X509_set_ex_data).
- base::StringPiece der_a, der_b;
-
- return x509_util::GetDER(a, &der_a) &&
- x509_util::GetDER(b, &der_b) &&
- der_a == der_b;
+ return CFEqual(a, b);
}
// static
@@ -350,53 +336,70 @@ X509Certificate::OSCertHandle X509Certificate::ReadOSCertHandleFromPickle(
const char* data;
int length;
if (!pickle_iter->ReadData(&data, &length))
- return NULL;
+ return nullptr;
- return CreateOSCertHandleFromBytes(data, length);
+ return X509Certificate::CreateOSCertHandleFromBytes(data, length);
}
// static
bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle,
base::Pickle* pickle) {
- base::StringPiece der;
- if (!x509_util::GetDER(cert_handle, &der))
+ ScopedCFTypeRef<CFDataRef> cert_data(SecCertificateCopyData(cert_handle));
+ if (!cert_data)
return false;
- return pickle->WriteData(der.data(), der.length());
+ return pickle->WriteData(
+ reinterpret_cast<const char*>(CFDataGetBytePtr(cert_data)),
+ CFDataGetLength(cert_data));
}
// static
-void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle,
+void X509Certificate::GetPublicKeyInfo(OSCertHandle os_cert,
size_t* size_bits,
PublicKeyType* type) {
*type = kPublicKeyTypeUnknown;
*size_bits = 0;
-
- crypto::ScopedEVP_PKEY scoped_key(X509_get_pubkey(cert_handle));
- if (!scoped_key.get())
+ ScopedX509 cert = OSCertHandleToOpenSSL(os_cert);
+ if (!cert)
+ return;
+ crypto::ScopedEVP_PKEY scoped_key(X509_get_pubkey(cert.get()));
+ if (!scoped_key)
return;
- CHECK(scoped_key.get());
EVP_PKEY* key = scoped_key.get();
switch (key->type) {
case EVP_PKEY_RSA:
*type = kPublicKeyTypeRSA;
- *size_bits = EVP_PKEY_size(key) * 8;
break;
case EVP_PKEY_DSA:
*type = kPublicKeyTypeDSA;
- *size_bits = EVP_PKEY_size(key) * 8;
break;
case EVP_PKEY_EC:
*type = kPublicKeyTypeECDSA;
- *size_bits = EVP_PKEY_bits(key);
break;
case EVP_PKEY_DH:
*type = kPublicKeyTypeDH;
- *size_bits = EVP_PKEY_size(key) * 8;
break;
}
+ *size_bits = EVP_PKEY_bits(key);
+}
+
+bool X509Certificate::SupportsSSLClientAuth() const {
+ return false;
+}
+
+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(
@@ -408,16 +411,15 @@ bool X509Certificate::IsIssuedByEncoded(
// It will own the objects it points to.
crypto::ScopedOpenSSL<STACK_OF(X509_NAME), sk_X509_NAME_free_all>
issuer_names(sk_X509_NAME_new_null());
- if (!issuer_names.get())
+ if (!issuer_names)
return false;
for (std::vector<std::string>::const_iterator it = valid_issuers.begin();
- it != valid_issuers.end(); ++it) {
- const unsigned char* p =
- reinterpret_cast<const unsigned char*>(it->data());
+ it != valid_issuers.end(); ++it) {
+ const unsigned char* p = reinterpret_cast<const unsigned char*>(it->data());
long len = static_cast<long>(it->length());
- X509_NAME* ca_name = d2i_X509_NAME(NULL, &p, len);
- if (ca_name == NULL)
+ X509_NAME* ca_name = d2i_X509_NAME(nullptr, &p, len);
+ if (ca_name == nullptr)
return false;
sk_X509_NAME_push(issuer_names.get(), ca_name);
}
@@ -425,15 +427,21 @@ bool X509Certificate::IsIssuedByEncoded(
// Create a temporary list of X509_NAME objects corresponding
// to the certificate chain. It doesn't own the object it points to.
std::vector<X509_NAME*> cert_names;
- X509_NAME* issuer = X509_get_issuer_name(cert_handle_);
- if (issuer == NULL)
+ ScopedX509 x509_cert = OSCertHandleToOpenSSL(cert_handle_);
+ if (!x509_cert)
+ return false;
+ X509_NAME* issuer = X509_get_issuer_name(x509_cert.get());
+ if (issuer == nullptr)
return false;
cert_names.push_back(issuer);
for (OSCertHandles::iterator it = intermediate_ca_certs_.begin();
- it != intermediate_ca_certs_.end(); ++it) {
- issuer = X509_get_issuer_name(*it);
- if (issuer == NULL)
+ it != intermediate_ca_certs_.end(); ++it) {
+ ScopedX509 intermediate_cert = OSCertHandleToOpenSSL(*it);
+ if (!intermediate_cert)
+ return false;
+ issuer = X509_get_issuer_name(intermediate_cert.get());
+ if (issuer == nullptr)
return false;
cert_names.push_back(issuer);
}
@@ -452,13 +460,16 @@ bool X509Certificate::IsIssuedByEncoded(
}
// static
-bool X509Certificate::IsSelfSigned(OSCertHandle cert_handle) {
- crypto::ScopedEVP_PKEY scoped_key(X509_get_pubkey(cert_handle));
+bool X509Certificate::IsSelfSigned(OSCertHandle os_cert) {
+ ScopedX509 cert = OSCertHandleToOpenSSL(os_cert);
+ if (!cert)
+ return false;
+ crypto::ScopedEVP_PKEY scoped_key(X509_get_pubkey(cert.get()));
if (!scoped_key)
return false;
// NOTE: X509_verify() returns 1 in case of success, 0 or -1 on error.
- return X509_verify(cert_handle, scoped_key.get()) == 1;
+ return X509_verify(cert.get(), scoped_key.get()) == 1;
}
} // namespace net
« net/BUILD.gn ('K') | « net/cert/cert_verify_proc_ios.cc ('k') | net/net.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698