summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorbulach@chromium.org <bulach@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-08 14:33:11 +0000
committerbulach@chromium.org <bulach@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-08 14:33:11 +0000
commit1e5fead8aa598e7d834806f6f8eaef8302074f35 (patch)
tree27d865f1cbc3f810fd0ea0038228057e2dafd814 /net
parent2db58053f8e04deaf129724bdf8ec0b326fb65ac (diff)
downloadchromium_src-1e5fead8aa598e7d834806f6f8eaef8302074f35.zip
chromium_src-1e5fead8aa598e7d834806f6f8eaef8302074f35.tar.gz
chromium_src-1e5fead8aa598e7d834806f6f8eaef8302074f35.tar.bz2
Adds X509 certificates for OpenSSL.
Depends on http://codereview.chromium.org/3565006/show TEST=Existing *X509* tests should pass. Review URL: http://codereview.chromium.org/3529008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@61955 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/base/cert_database_openssl.cc52
-rw-r--r--net/base/cert_test_util.cc31
-rw-r--r--net/base/keygen_handler_openssl.cc18
-rw-r--r--net/base/openssl_util.cc61
-rw-r--r--net/base/openssl_util.h51
-rw-r--r--net/base/x509_certificate.cc37
-rw-r--r--net/base/x509_certificate.h9
-rw-r--r--net/base/x509_certificate_mac.cc15
-rw-r--r--net/base/x509_certificate_nss.cc10
-rw-r--r--net/base/x509_certificate_openssl.cc410
-rw-r--r--net/base/x509_certificate_unittest.cc13
-rw-r--r--net/base/x509_certificate_win.cc10
-rw-r--r--net/net.gyp34
13 files changed, 708 insertions, 43 deletions
diff --git a/net/base/cert_database_openssl.cc b/net/base/cert_database_openssl.cc
new file mode 100644
index 0000000..b56d8ba
--- /dev/null
+++ b/net/base/cert_database_openssl.cc
@@ -0,0 +1,52 @@
+// Copyright (c) 2010 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/base/cert_database.h"
+
+#include "net/base/net_errors.h"
+#include "net/base/x509_certificate.h"
+
+namespace net {
+
+CertDatabase::CertDatabase() {
+}
+
+int CertDatabase::CheckUserCert(X509Certificate* cert) {
+ if (!cert)
+ return ERR_CERT_INVALID;
+ if (cert->HasExpired())
+ return ERR_CERT_DATE_INVALID;
+
+ // TODO(bulach): implement me.
+ return ERR_NOT_IMPLEMENTED;
+}
+
+int CertDatabase::AddUserCert(X509Certificate* cert) {
+ // TODO(bulach): implement me.
+ return ERR_NOT_IMPLEMENTED;
+}
+
+void CertDatabase::ListCerts(CertificateList* certs) {
+ // TODO(bulach): implement me.
+}
+
+int CertDatabase::ImportFromPKCS12(const std::string& data,
+ const string16& password) {
+ // TODO(bulach): implement me.
+ return ERR_NOT_IMPLEMENTED;
+}
+
+int CertDatabase::ExportToPKCS12(const CertificateList& certs,
+ const string16& password,
+ std::string* output) const {
+ // TODO(bulach): implement me.
+ return 0;
+}
+
+bool CertDatabase::DeleteCertAndKey(const X509Certificate* cert) {
+ // TODO(bulach): implement me.
+ return false;
+}
+
+} // namespace net
diff --git a/net/base/cert_test_util.cc b/net/base/cert_test_util.cc
index 9fc6573..8815cd5 100644
--- a/net/base/cert_test_util.cc
+++ b/net/base/cert_test_util.cc
@@ -6,7 +6,11 @@
#include "build/build_config.h"
-#if defined(USE_NSS)
+#if defined(USE_OPENSSL)
+#include <openssl/err.h>
+#include <openssl/x509v3.h>
+#include "net/base/openssl_util.h"
+#elif defined(USE_NSS)
#include <cert.h>
#include "base/nss_util.h"
#elif defined(OS_MACOSX)
@@ -21,7 +25,30 @@
namespace net {
-#if defined(USE_NSS)
+#if defined(USE_OPENSSL)
+X509Certificate* LoadTemporaryRootCert(const FilePath& filename) {
+ OpenSSLInitSingleton* openssl_init = GetOpenSSLInitSingleton();
+
+ std::string rawcert;
+ if (!file_util::ReadFileToString(filename, &rawcert)) {
+ LOG(ERROR) << "Can't load certificate " << filename.value();
+ return NULL;
+ }
+
+ X509Certificate* certificate = X509Certificate::CreateFromBytes(
+ rawcert.c_str(), rawcert.length());
+
+ X509* x509_cert =
+ X509Certificate::DupOSCertHandle(certificate->os_cert_handle());
+ if (!X509_STORE_add_cert(openssl_init->x509_store(), x509_cert)) {
+ LOG(ERROR) << "X509_STORE_add_cert error: " << ERR_get_error();
+ X509_free(x509_cert);
+ return NULL;
+ }
+
+ return certificate;
+}
+#elif defined(USE_NSS)
X509Certificate* LoadTemporaryRootCert(const FilePath& filename) {
base::EnsureNSSInit();
diff --git a/net/base/keygen_handler_openssl.cc b/net/base/keygen_handler_openssl.cc
new file mode 100644
index 0000000..0f5d874
--- /dev/null
+++ b/net/base/keygen_handler_openssl.cc
@@ -0,0 +1,18 @@
+// Copyright (c) 2010 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/base/keygen_handler.h"
+
+#if defined(USE_OPENSSL)
+
+namespace net {
+
+std::string KeygenHandler::GenKeyAndSignChallenge() {
+ // TODO(bulach): implement me.
+ return "";
+}
+
+} // namespace net
+
+#endif // USE_OPENSSL
diff --git a/net/base/openssl_util.cc b/net/base/openssl_util.cc
new file mode 100644
index 0000000..54a3df4
--- /dev/null
+++ b/net/base/openssl_util.cc
@@ -0,0 +1,61 @@
+// Copyright (c) 2006-2008 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/base/openssl_util.h"
+
+#include <openssl/err.h>
+#include <openssl/x509v3.h>
+
+#include "base/logging.h"
+
+namespace net {
+
+X509_STORE* OpenSSLInitSingleton::x509_store() const {
+ return store_.get();
+}
+
+OpenSSLInitSingleton::OpenSSLInitSingleton()
+ : store_(X509_STORE_new()) {
+ CHECK(store_.get());
+ SSL_load_error_strings();
+ OpenSSL_add_all_algorithms();
+ X509_STORE_set_default_paths(store_.get());
+ // TODO(bulach): Enable CRL (see X509_STORE_set_flags(X509_V_FLAG_CRL_CHECK)).
+ int num_locks = CRYPTO_num_locks();
+ for (int i = 0; i < num_locks; ++i)
+ locks_.push_back(new Lock());
+ CRYPTO_set_locking_callback(LockingCallback);
+}
+
+OpenSSLInitSingleton::~OpenSSLInitSingleton() {
+ CRYPTO_set_locking_callback(NULL);
+ EVP_cleanup();
+ ERR_free_strings();
+}
+
+OpenSSLInitSingleton* GetOpenSSLInitSingleton() {
+ return Singleton<OpenSSLInitSingleton>::get();
+}
+
+// static
+void OpenSSLInitSingleton::LockingCallback(int mode,
+ int n,
+ const char* file,
+ int line) {
+ GetOpenSSLInitSingleton()->OnLockingCallback(mode, n, file, line);
+}
+
+void OpenSSLInitSingleton::OnLockingCallback(int mode,
+ int n,
+ const char* file,
+ int line) {
+ CHECK_LT(static_cast<size_t>(n), locks_.size());
+ if (mode & CRYPTO_LOCK)
+ locks_[n]->Acquire();
+ else
+ locks_[n]->Release();
+}
+
+} // namespace net
+
diff --git a/net/base/openssl_util.h b/net/base/openssl_util.h
new file mode 100644
index 0000000..8015917
--- /dev/null
+++ b/net/base/openssl_util.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2006-2008 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 <openssl/ssl.h>
+
+#include "base/lock.h"
+#include "base/scoped_vector.h"
+#include "base/singleton.h"
+
+namespace net {
+
+// A helper class that takes care of destroying OpenSSL objects when it goes out
+// of scope.
+template <typename T, void (*destructor)(T*)>
+class ScopedSSL {
+ public:
+ explicit ScopedSSL(T* ptr_) : ptr_(ptr_) { }
+ ~ScopedSSL() { if (ptr_) (*destructor)(ptr_); }
+
+ T* get() const { return ptr_; }
+
+ private:
+ T* ptr_;
+};
+
+// Singleton for initializing / cleaning up OpenSSL and holding a X509 store.
+// Access it via EnsureOpenSSLInit().
+class OpenSSLInitSingleton {
+ public:
+ X509_STORE* x509_store() const;
+
+ private:
+ friend struct DefaultSingletonTraits<OpenSSLInitSingleton>;
+ OpenSSLInitSingleton();
+ ~OpenSSLInitSingleton();
+
+ static void LockingCallback(int mode, int n, const char* file, int line);
+ void OnLockingCallback(int mode, int n, const char* file, int line);
+
+ ScopedSSL<X509_STORE, X509_STORE_free> store_;
+ // These locks are used and managed by OpenSSL via LockingCallback().
+ ScopedVector<Lock> locks_;
+
+ DISALLOW_COPY_AND_ASSIGN(OpenSSLInitSingleton);
+};
+
+OpenSSLInitSingleton* GetOpenSSLInitSingleton();
+
+} // namespace net
+
diff --git a/net/base/x509_certificate.cc b/net/base/x509_certificate.cc
index df62ec8..6395b97 100644
--- a/net/base/x509_certificate.cc
+++ b/net/base/x509_certificate.cc
@@ -4,12 +4,6 @@
#include "net/base/x509_certificate.h"
-#if defined(OS_MACOSX)
-#include <Security/Security.h>
-#elif defined(USE_NSS)
-#include <cert.h>
-#endif
-
#include <map>
#include "base/histogram.h"
@@ -47,33 +41,6 @@ const char kPKCS7Header[] = "PKCS7";
} // namespace
-// static
-bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a,
- X509Certificate::OSCertHandle b) {
- DCHECK(a && b);
- if (a == b)
- return true;
-#if defined(OS_WIN)
- return a->cbCertEncoded == b->cbCertEncoded &&
- memcmp(a->pbCertEncoded, b->pbCertEncoded, a->cbCertEncoded) == 0;
-#elif defined(OS_MACOSX)
- if (CFEqual(a, b))
- return true;
- CSSM_DATA a_data, b_data;
- return SecCertificateGetData(a, &a_data) == noErr &&
- SecCertificateGetData(b, &b_data) == noErr &&
- a_data.Length == b_data.Length &&
- memcmp(a_data.Data, b_data.Data, a_data.Length) == 0;
-#elif defined(USE_NSS)
- return a->derCert.len == b->derCert.len &&
- memcmp(a->derCert.data, b->derCert.data, a->derCert.len) == 0;
-#else
- // TODO(snej): not implemented
- UNREACHED();
- return false;
-#endif
-}
-
bool X509Certificate::LessThan::operator()(X509Certificate* lhs,
X509Certificate* rhs) const {
if (lhs == rhs)
@@ -282,7 +249,7 @@ X509Certificate::X509Certificate(OSCertHandle cert_handle,
const OSCertHandles& intermediates)
: cert_handle_(DupOSCertHandle(cert_handle)),
source_(source) {
-#if defined(OS_MACOSX) || defined(OS_WIN)
+#if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_OPENSSL)
// Copy/retain the intermediate cert handles.
for (size_t i = 0; i < intermediates.size(); ++i)
intermediate_ca_certs_.push_back(DupOSCertHandle(intermediates[i]));
@@ -320,7 +287,7 @@ bool X509Certificate::HasExpired() const {
}
bool X509Certificate::HasIntermediateCertificate(OSCertHandle cert) {
-#if defined(OS_MACOSX) || defined(OS_WIN)
+#if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_OPENSSL)
for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) {
if (IsSameOSCert(cert, intermediate_ca_certs_[i]))
return true;
diff --git a/net/base/x509_certificate.h b/net/base/x509_certificate.h
index 5a9e897..577de92 100644
--- a/net/base/x509_certificate.h
+++ b/net/base/x509_certificate.h
@@ -22,6 +22,9 @@
#elif defined(OS_MACOSX)
#include <CoreFoundation/CFArray.h>
#include <Security/SecBase.h>
+#elif defined(USE_OPENSSL)
+// Forward declaration; real one in <x509.h>
+struct x509_st;
#elif defined(USE_NSS)
// Forward declaration; real one in <cert.h>
struct CERTCertificateStr;
@@ -45,6 +48,8 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> {
typedef PCCERT_CONTEXT OSCertHandle;
#elif defined(OS_MACOSX)
typedef SecCertificateRef OSCertHandle;
+#elif defined(USE_OPENSSL)
+ typedef struct x509_st* OSCertHandle;
#elif defined(USE_NSS)
typedef struct CERTCertificateStr* OSCertHandle;
#else
@@ -168,7 +173,7 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> {
// now.
bool HasExpired() const;
-#if defined(OS_MACOSX) || defined(OS_WIN)
+#if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_OPENSSL)
// Returns intermediate certificates added via AddIntermediateCertificate().
// Ownership follows the "get" rule: it is the caller's responsibility to
// retain the elements of the result.
@@ -287,7 +292,7 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> {
// A handle to the certificate object in the underlying crypto library.
OSCertHandle cert_handle_;
-#if defined(OS_MACOSX) || defined(OS_WIN)
+#if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_OPENSSL)
// Untrusted intermediate certificates associated with this certificate
// that may be needed for chain building. (NSS impl does not need these.)
OSCertHandles intermediate_ca_certs_;
diff --git a/net/base/x509_certificate_mac.cc b/net/base/x509_certificate_mac.cc
index e4c5c7f..cd8a3ca 100644
--- a/net/base/x509_certificate_mac.cc
+++ b/net/base/x509_certificate_mac.cc
@@ -728,6 +728,21 @@ bool X509Certificate::VerifyEV() const {
}
// static
+bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a,
+ X509Certificate::OSCertHandle b) {
+ DCHECK(a && b);
+ if (a == b)
+ return true;
+ if (CFEqual(a, b))
+ return true;
+ CSSM_DATA a_data, b_data;
+ return SecCertificateGetData(a, &a_data) == noErr &&
+ SecCertificateGetData(b, &b_data) == noErr &&
+ a_data.Length == b_data.Length &&
+ memcmp(a_data.Data, b_data.Data, a_data.Length) == 0;
+}
+
+// static
X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
const char* data, int length) {
CSSM_DATA cert_data;
diff --git a/net/base/x509_certificate_nss.cc b/net/base/x509_certificate_nss.cc
index 00880022..5061238 100644
--- a/net/base/x509_certificate_nss.cc
+++ b/net/base/x509_certificate_nss.cc
@@ -725,6 +725,16 @@ bool X509Certificate::VerifyEV() const {
}
// static
+bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a,
+ X509Certificate::OSCertHandle b) {
+ DCHECK(a && b);
+ if (a == b)
+ return true;
+ return a->derCert.len == b->derCert.len &&
+ memcmp(a->derCert.data, b->derCert.data, a->derCert.len) == 0;
+}
+
+// static
X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
const char* data, int length) {
if (length < 0)
diff --git a/net/base/x509_certificate_openssl.cc b/net/base/x509_certificate_openssl.cc
new file mode 100644
index 0000000..afba382
--- /dev/null
+++ b/net/base/x509_certificate_openssl.cc
@@ -0,0 +1,410 @@
+// Copyright (c) 2006-2008 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/base/x509_certificate.h"
+
+#include <openssl/asn1.h>
+#include <openssl/obj_mac.h>
+#include <openssl/pem.h>
+#include <openssl/pkcs7.h>
+#include <openssl/sha.h>
+#include <openssl/ssl.h>
+#include <openssl/x509v3.h>
+
+#include "base/pickle.h"
+#include "base/string_number_conversions.h"
+#include "net/base/cert_status_flags.h"
+#include "net/base/cert_verify_result.h"
+#include "net/base/net_errors.h"
+#include "net/base/openssl_util.h"
+
+namespace net {
+
+namespace {
+
+void CreateOSCertHandlesFromPKCS7Bytes(
+ const char* data, int length,
+ X509Certificate::OSCertHandles* handles) {
+ const unsigned char* der_data = reinterpret_cast<const unsigned char*>(data);
+ ScopedSSL<PKCS7, PKCS7_free> pkcs7_cert(
+ d2i_PKCS7(NULL, &der_data, length));
+ if (!pkcs7_cert.get())
+ return;
+
+ STACK_OF(X509)* certs = NULL;
+ int nid = OBJ_obj2nid(pkcs7_cert.get()->type);
+ if (nid == NID_pkcs7_signed) {
+ certs = pkcs7_cert.get()->d.sign->cert;
+ } else if (nid == NID_pkcs7_signedAndEnveloped) {
+ certs = pkcs7_cert.get()->d.signed_and_enveloped->cert;
+ }
+
+ if (certs) {
+ for (int i = 0; i < sk_X509_num(certs); ++i) {
+ X509* x509_cert =
+ X509Certificate::DupOSCertHandle(sk_X509_value(certs, i));
+ handles->push_back(x509_cert);
+ }
+ }
+}
+
+bool ParsePrincipalFieldInternal(X509_NAME* name,
+ int index,
+ std::string* field) {
+ ASN1_STRING* data =
+ X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, index));
+ if (!data)
+ return false;
+
+ unsigned char* buf = NULL;
+ int len = ASN1_STRING_to_UTF8(&buf, data);
+ if (len <= 0)
+ return false;
+
+ field->assign(reinterpret_cast<const char*>(buf), len);
+ OPENSSL_free(buf);
+ return true;
+}
+
+void ParsePrincipalField(X509_NAME* name, int nid, std::string* field) {
+ int index = X509_NAME_get_index_by_NID(name, nid, -1);
+ if (index < 0)
+ return;
+
+ ParsePrincipalFieldInternal(name, index, field);
+}
+
+void ParsePrincipalFields(X509_NAME* name,
+ int nid,
+ std::vector<std::string>* fields) {
+ for (int index = -1;
+ (index = X509_NAME_get_index_by_NID(name, nid, index)) != -1;) {
+ std::string field;
+ if (!ParsePrincipalFieldInternal(name, index, &field))
+ break;
+ fields->push_back(field);
+ }
+}
+
+void ParsePrincipal(X509Certificate::OSCertHandle cert,
+ X509_NAME* x509_name,
+ CertPrincipal* principal) {
+ if (!x509_name)
+ return;
+
+ ParsePrincipalFields(x509_name, NID_streetAddress,
+ &principal->street_addresses);
+ ParsePrincipalFields(x509_name, NID_organizationName,
+ &principal->organization_names);
+ ParsePrincipalFields(x509_name, NID_organizationalUnitName,
+ &principal->organization_unit_names);
+ ParsePrincipalFields(x509_name, NID_domainComponent,
+ &principal->domain_components);
+
+ ParsePrincipalField(x509_name, NID_commonName, &principal->common_name);
+ ParsePrincipalField(x509_name, NID_localityName, &principal->locality_name);
+ ParsePrincipalField(x509_name, NID_stateOrProvinceName,
+ &principal->state_or_province_name);
+ ParsePrincipalField(x509_name, NID_countryName, &principal->country_name);
+}
+
+void ParseDate(ASN1_TIME* x509_time, base::Time* time) {
+ if (!x509_time ||
+ (x509_time->type != V_ASN1_UTCTIME &&
+ x509_time->type != V_ASN1_GENERALIZEDTIME))
+ return;
+
+ std::string str_date(reinterpret_cast<char*>(x509_time->data),
+ x509_time->length);
+ // UTCTime: YYMMDDHHMMSSZ
+ // GeneralizedTime: YYYYMMDDHHMMSSZ
+ size_t year_length = x509_time->type == V_ASN1_UTCTIME ? 2 : 4;
+ size_t fields_offset = x509_time->type == V_ASN1_UTCTIME ? 0 : 2;
+
+ if (str_date.length() < 11 + year_length)
+ return;
+
+ base::Time::Exploded exploded = {0};
+ bool valid = base::StringToInt(str_date.substr(0, year_length),
+ &exploded.year);
+ if (valid && year_length == 2)
+ exploded.year += exploded.year < 50 ? 2000 : 1900;
+
+ valid &= base::StringToInt(str_date.substr(2 + fields_offset, 2),
+ &exploded.month);
+ valid &= base::StringToInt(str_date.substr(4 + fields_offset, 2),
+ &exploded.day_of_month);
+ valid &= base::StringToInt(str_date.substr(6 + fields_offset, 2),
+ &exploded.hour);
+ valid &= base::StringToInt(str_date.substr(8 + fields_offset, 2),
+ &exploded.minute);
+ valid &= base::StringToInt(str_date.substr(10 + fields_offset, 2),
+ &exploded.second);
+
+ DCHECK(valid);
+
+ *time = base::Time::FromUTCExploded(exploded);
+}
+
+void ParseSubjectAltNames(X509Certificate::OSCertHandle cert,
+ std::vector<std::string>* dns_names) {
+ int index = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1);
+ X509_EXTENSION* alt_name_ext = X509_get_ext(cert, index);
+ if (!alt_name_ext)
+ return;
+
+ ScopedSSL<GENERAL_NAMES, GENERAL_NAMES_free> alt_names(
+ reinterpret_cast<GENERAL_NAMES*>(X509V3_EXT_d2i(alt_name_ext)));
+ if (!alt_names.get())
+ return;
+
+ for (int i = 0; i < sk_GENERAL_NAME_num(alt_names.get()); ++i) {
+ const GENERAL_NAME* name = sk_GENERAL_NAME_value(alt_names.get(), i);
+ if (name->type == GEN_DNS) {
+ unsigned char* dns_name = ASN1_STRING_data(name->d.dNSName);
+ if (!dns_name)
+ continue;
+ int dns_name_len = ASN1_STRING_length(name->d.dNSName);
+ dns_names->push_back(
+ std::string(reinterpret_cast<char*>(dns_name), dns_name_len));
+ }
+ }
+}
+
+// Maps X509_STORE_CTX_get_error() return values to our cert status flags.
+int MapCertErrorToCertStatus(int err) {
+ switch (err) {
+ case X509_V_ERR_SUBJECT_ISSUER_MISMATCH:
+ return CERT_STATUS_COMMON_NAME_INVALID;
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ case X509_V_ERR_CRL_NOT_YET_VALID:
+ case X509_V_ERR_CRL_HAS_EXPIRED:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+ case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
+ case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
+ return CERT_STATUS_DATE_INVALID;
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ case X509_V_ERR_UNABLE_TO_GET_CRL:
+ case X509_V_ERR_INVALID_CA:
+ case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
+ case X509_V_ERR_INVALID_NON_CA:
+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+ case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+ return CERT_STATUS_AUTHORITY_INVALID;
+#if 0
+// TODO(bulach): what should we map to these status?
+ return CERT_STATUS_NO_REVOCATION_MECHANISM;
+ return CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
+ return CERT_STATUS_NOT_IN_DNS;
+#endif
+ case X509_V_ERR_CERT_REVOKED:
+ return CERT_STATUS_REVOKED;
+ case X509_V_ERR_KEYUSAGE_NO_CERTSIGN:
+ return CERT_STATUS_WEAK_SIGNATURE_ALGORITHM;
+ // All these status are mapped to CERT_STATUS_INVALID.
+ case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
+ case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
+ case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
+ case X509_V_ERR_CERT_SIGNATURE_FAILURE:
+ case X509_V_ERR_CRL_SIGNATURE_FAILURE:
+ case X509_V_ERR_OUT_OF_MEM:
+ case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+ case X509_V_ERR_CERT_CHAIN_TOO_LONG:
+ case X509_V_ERR_PATH_LENGTH_EXCEEDED:
+ case X509_V_ERR_INVALID_PURPOSE:
+ case X509_V_ERR_CERT_UNTRUSTED:
+ case X509_V_ERR_CERT_REJECTED:
+ case X509_V_ERR_AKID_SKID_MISMATCH:
+ case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH:
+ case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION:
+ case X509_V_ERR_KEYUSAGE_NO_CRL_SIGN:
+ case X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION:
+ case X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED:
+ case X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE:
+ case X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED:
+ case X509_V_ERR_INVALID_EXTENSION:
+ case X509_V_ERR_INVALID_POLICY_EXTENSION:
+ case X509_V_ERR_NO_EXPLICIT_POLICY:
+ case X509_V_ERR_UNNESTED_RESOURCE:
+ case X509_V_ERR_APPLICATION_VERIFICATION:
+ return CERT_STATUS_INVALID;
+ default:
+ NOTREACHED() << "Invalid X509 err " << err;
+ return CERT_STATUS_INVALID;
+ }
+}
+
+// sk_X509_free is a function-style macro, so can't be used as a template
+// param directly.
+void sk_X509_free_fn(STACK_OF(X509)* st) {
+ sk_X509_free(st);
+}
+
+} // namespace
+
+// static
+X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle(
+ OSCertHandle cert_handle) {
+ return X509_dup(cert_handle);
+}
+
+// static
+void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) {
+ X509_free(cert_handle);
+}
+
+void X509Certificate::Initialize() {
+ fingerprint_ = CalculateFingerprint(cert_handle_);
+ ParsePrincipal(cert_handle_, X509_get_subject_name(cert_handle_), &subject_);
+ ParsePrincipal(cert_handle_, X509_get_issuer_name(cert_handle_), &issuer_);
+ ParseDate(X509_get_notBefore(cert_handle_), &valid_start_);
+ ParseDate(X509_get_notAfter(cert_handle_), &valid_expiry_);
+}
+
+SHA1Fingerprint X509Certificate::CalculateFingerprint(OSCertHandle cert) {
+ SHA1Fingerprint 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));
+ return sha1;
+}
+
+// static
+X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
+ const char* data, int length) {
+ if (length < 0)
+ return NULL;
+ const unsigned char* d2i_data =
+ reinterpret_cast<const unsigned char*>(data);
+ X509* cert = d2i_X509(NULL, &d2i_data, length);
+ return cert;
+}
+
+// static
+X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes(
+ const char* data, int length, Format format) {
+ OSCertHandles results;
+ if (length < 0)
+ return results;
+
+ switch (format) {
+ case FORMAT_SINGLE_CERTIFICATE: {
+ OSCertHandle handle = CreateOSCertHandleFromBytes(data, length);
+ if (handle)
+ results.push_back(handle);
+ break;
+ }
+ case FORMAT_PKCS7: {
+ CreateOSCertHandlesFromPKCS7Bytes(data, length, &results);
+ break;
+ }
+ default: {
+ NOTREACHED() << "Certificate format " << format << " unimplemented";
+ break;
+ }
+ }
+
+ return results;
+}
+
+X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle,
+ void** pickle_iter) {
+ const char* data;
+ int length;
+ if (!pickle.ReadData(pickle_iter, &data, &length))
+ return NULL;
+
+ return CreateFromBytes(data, length);
+}
+
+void X509Certificate::Persist(Pickle* pickle) {
+ unsigned char* data = NULL;
+ int data_length = i2d_X509(cert_handle_, &data);
+ if (data_length <= 0 || !data)
+ return;
+
+ pickle->WriteData(reinterpret_cast<const char*>(data), data_length);
+ OPENSSL_free(data);
+}
+
+void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const {
+ dns_names->clear();
+
+ ParseSubjectAltNames(cert_handle_, dns_names);
+
+ if (dns_names->empty())
+ dns_names->push_back(subject_.common_name);
+}
+
+int X509Certificate::Verify(const std::string& hostname,
+ int flags,
+ CertVerifyResult* verify_result) const {
+ verify_result->Reset();
+
+ ScopedSSL<X509_STORE_CTX, X509_STORE_CTX_free> ctx(X509_STORE_CTX_new());
+
+ ScopedSSL<STACK_OF(X509), sk_X509_free_fn> intermediates(sk_X509_new_null());
+ if (!intermediates.get())
+ return ERR_OUT_OF_MEMORY;
+
+ for (OSCertHandles::const_iterator it = intermediate_ca_certs_.begin();
+ it != intermediate_ca_certs_.end(); ++it) {
+ if (!sk_X509_push(intermediates.get(), *it))
+ return ERR_OUT_OF_MEMORY;
+ }
+ int rv = X509_STORE_CTX_init(ctx.get(),
+ GetOpenSSLInitSingleton()->x509_store(),
+ cert_handle_, intermediates.get());
+ CHECK_EQ(1, rv);
+
+ if (X509_verify_cert(ctx.get()) == 1) {
+ return OK;
+ }
+
+ int x509_error = X509_STORE_CTX_get_error(ctx.get());
+ int cert_status = MapCertErrorToCertStatus(x509_error);
+ LOG(ERROR) << "X509 Verification error "
+ << X509_verify_cert_error_string(x509_error)
+ << " : " << x509_error
+ << " : " << X509_STORE_CTX_get_error_depth(ctx.get())
+ << " : " << cert_status;
+ verify_result->cert_status |= cert_status;
+ return MapCertStatusToNetError(verify_result->cert_status);
+}
+
+// static
+bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a,
+ X509Certificate::OSCertHandle b) {
+ DCHECK(a && b);
+ if (a == b)
+ return true;
+
+ // TODO(bulach): re-encoding the certificate is an expensive operation.
+ // Consider 'tagging' each X509* we create using X509_set_ex_data, storing the
+ // original DER data in an index. Then, when comparing two handles, see if
+ // X509_get_ex_data() returns the DER form.
+ unsigned char* data_a = NULL;
+ int data_length_a = i2d_X509(a, &data_a);
+ if (data_length_a <= 0 || !data_a)
+ return false;
+
+ bool ret = true;
+ unsigned char* data_b = NULL;
+ int data_length_b = i2d_X509(b, &data_b);
+ if (data_length_b <= 0 || !data_b)
+ ret = false;
+
+ ret = ret && data_length_a == data_length_b;
+ ret = ret && memcmp(data_a, data_b, data_length_a) == 0;
+
+ OPENSSL_free(data_a);
+ OPENSSL_free(data_b);
+ return ret;
+}
+
+} // namespace net
diff --git a/net/base/x509_certificate_unittest.cc b/net/base/x509_certificate_unittest.cc
index e1319d7..9bb81cb 100644
--- a/net/base/x509_certificate_unittest.cc
+++ b/net/base/x509_certificate_unittest.cc
@@ -399,7 +399,7 @@ TEST(X509CertificateTest, PaypalNullCertParsing) {
// Either the system crypto library should correctly report a certificate
// name mismatch, or our certificate blacklist should cause us to report an
// invalid certificate.
-#if !defined(OS_MACOSX)
+#if !defined(OS_MACOSX) && !defined(USE_OPENSSL)
EXPECT_NE(0, verify_result.cert_status &
(CERT_STATUS_COMMON_NAME_INVALID | CERT_STATUS_INVALID));
#endif
@@ -427,7 +427,7 @@ TEST(X509CertificateTest, UnoSoftCertParsing) {
EXPECT_NE(0, verify_result.cert_status & CERT_STATUS_AUTHORITY_INVALID);
}
-#if defined(USE_NSS)
+#if defined(USE_NSS) || defined(USE_OPENSSL)
// A regression test for http://crbug.com/31497.
// This certificate will expire on 2012-04-08.
// TODO(wtc): we can't run this test on Mac because MacTrustedCertificates
@@ -452,9 +452,16 @@ TEST(X509CertificateTest, IntermediateCARequireExplicitPolicy) {
LoadTemporaryRootCert(root_cert_path);
ASSERT_NE(static_cast<X509Certificate*>(NULL), root_cert);
+ X509Certificate::OSCertHandles intermediates;
+ intermediates.push_back(intermediate_cert->os_cert_handle());
+ scoped_refptr<X509Certificate> cert_chain =
+ X509Certificate::CreateFromHandle(server_cert->os_cert_handle(),
+ X509Certificate::SOURCE_FROM_NETWORK,
+ intermediates);
+
int flags = 0;
CertVerifyResult verify_result;
- int error = server_cert->Verify("www.us.army.mil", flags, &verify_result);
+ int error = cert_chain->Verify("www.us.army.mil", flags, &verify_result);
EXPECT_EQ(OK, error);
EXPECT_EQ(0, verify_result.cert_status);
}
diff --git a/net/base/x509_certificate_win.cc b/net/base/x509_certificate_win.cc
index 03434bb..380ff3c 100644
--- a/net/base/x509_certificate_win.cc
+++ b/net/base/x509_certificate_win.cc
@@ -787,6 +787,16 @@ bool X509Certificate::VerifyEV() const {
}
// static
+bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a,
+ X509Certificate::OSCertHandle b) {
+ DCHECK(a && b);
+ if (a == b)
+ return true;
+ return a->cbCertEncoded == b->cbCertEncoded &&
+ memcmp(a->pbCertEncoded, b->pbCertEncoded, a->cbCertEncoded) == 0;
+}
+
+// static
X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
const char* data, int length) {
OSCertHandle cert_handle = NULL;
diff --git a/net/net.gyp b/net/net.gyp
index c4cef18..79f6c66 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -36,6 +36,7 @@
'base/cert_database.h',
'base/cert_database_mac.cc',
'base/cert_database_nss.cc',
+ 'base/cert_database_openssl.cc',
'base/cert_database_win.cc',
'base/cert_status_flags.cc',
'base/cert_status_flags.h',
@@ -98,6 +99,7 @@
'base/keygen_handler.h',
'base/keygen_handler_mac.cc',
'base/keygen_handler_nss.cc',
+ 'base/keygen_handler_openssl.cc',
'base/keygen_handler_win.cc',
'base/listen_socket.cc',
'base/listen_socket.h',
@@ -140,6 +142,8 @@
'base/network_config_watcher_mac.h',
'base/nss_memio.c',
'base/nss_memio.h',
+ 'base/openssl_util.cc',
+ 'base/openssl_util.h',
'base/pem_tokenizer.cc',
'base/pem_tokenizer.h',
'base/platform_mime_util.h',
@@ -187,6 +191,7 @@
'base/x509_certificate.h',
'base/x509_certificate_mac.cc',
'base/x509_certificate_nss.cc',
+ 'base/x509_certificate_openssl.cc',
'base/x509_certificate_win.cc',
'base/x509_cert_types.cc',
'base/x509_cert_types.h',
@@ -247,6 +252,33 @@
],
},
],
+ [ 'use_openssl == 1 and OS == "linux"', {
+ # When building for OpenSSL, we need to exclude some NSS files.
+ # TODO(bulach): remove once we fully support OpenSSL.
+ 'sources!': [
+ 'base/cert_database_nss.cc',
+ 'base/keygen_handler_nss.cc',
+ 'base/x509_certificate_nss.cc',
+ 'third_party/mozilla_security_manager/nsKeygenHandler.cpp',
+ 'third_party/mozilla_security_manager/nsKeygenHandler.h',
+ 'third_party/mozilla_security_manager/nsNSSCertificateDB.cpp',
+ 'third_party/mozilla_security_manager/nsNSSCertificateDB.h',
+ 'third_party/mozilla_security_manager/nsNSSCertTrust.cpp',
+ 'third_party/mozilla_security_manager/nsNSSCertTrust.h',
+ 'third_party/mozilla_security_manager/nsPKCS12Blob.cpp',
+ 'third_party/mozilla_security_manager/nsPKCS12Blob.h',
+ ],
+ },
+ { # else: not using openssl.
+ 'sources!': [
+ 'base/cert_database_openssl.cc',
+ 'base/keygen_handler_openssl.cc',
+ 'base/openssl_util.cc',
+ 'base/openssl_util.h',
+ 'base/x509_certificate_openssl.cc',
+ ],
+ },
+ ],
[ 'OS == "win"', {
'dependencies': [
'../third_party/nss/nss.gyp:nss',
@@ -1079,7 +1111,7 @@
}],
],
}],
- ['use_openssl==1 and OS == "linux"', {
+ ['use_openssl == 1 and OS == "linux"', {
'dependencies': [
'../build/linux/system.gyp:openssl',
]