diff options
author | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-26 13:27:09 +0000 |
---|---|---|
committer | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-26 13:27:09 +0000 |
commit | 670dca99f9c8615c544d6fefaace29208c9223d2 (patch) | |
tree | 50a34ebd350701d916d0d35ec795e1e82d084a66 /net/base | |
parent | cf408d77cc83210061573b507574974bf86289fa (diff) | |
download | chromium_src-670dca99f9c8615c544d6fefaace29208c9223d2.zip chromium_src-670dca99f9c8615c544d6fefaace29208c9223d2.tar.gz chromium_src-670dca99f9c8615c544d6fefaace29208c9223d2.tar.bz2 |
net: move importing a DER certificate chain into X509Certificate.
This is a prelude to having SSLHostInfo be able to kick off
certificate validations.
The vector of intermediate certificates is added on Linux because,
otherwise, nothing is holding a reference to them. Previously, the
nss_fd_ was holding a reference. However, without the vector holding
references, CreateFromDERChain deletes them all at the end and NSS has
to AIA chase up the chain.
BUG=none
TEST=net_unittests
http://codereview.chromium.org/3920001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@63881 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/base')
-rw-r--r-- | net/base/x509_certificate.cc | 98 | ||||
-rw-r--r-- | net/base/x509_certificate.h | 28 | ||||
-rw-r--r-- | net/base/x509_certificate_win.cc | 27 |
3 files changed, 143 insertions, 10 deletions
diff --git a/net/base/x509_certificate.cc b/net/base/x509_certificate.cc index e21a3bc..ad49f18 100644 --- a/net/base/x509_certificate.cc +++ b/net/base/x509_certificate.cc @@ -153,6 +153,100 @@ X509Certificate* X509Certificate::CreateFromHandle( return cert; } +#if defined(OS_WIN) +// See IsProblematicComodoEVCACert, below. +// Issuer: +// CN = AddTrust External CA Root +// OU = AddTrust External TTP Network +// O = AddTrust AB +// C = SE +// +// This is the first 308 bytes of the certificate, which covers the serial +// number, issuer and subject. It stops just short of the public key. +static const uint8 kProblematicComodoEVCACert[] = { + 0x30, 0x82, 0x04, 0xd5, 0x30, 0x82, 0x03, 0xbd, 0xa0, 0x03, 0x02, 0x01, 0x02, + 0x02, 0x10, 0x79, 0x0a, 0x83, 0x4d, 0x48, 0x40, 0x6b, 0xab, 0x6c, 0x35, 0x2a, + 0xd5, 0x1f, 0x42, 0x83, 0xfe, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x6f, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x53, 0x45, 0x31, 0x14, 0x30, 0x12, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0b, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, + 0x73, 0x74, 0x20, 0x41, 0x42, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x13, 0x1d, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, 0x45, + 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x54, 0x54, 0x50, 0x20, 0x4e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x19, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x20, + 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x43, 0x41, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x37, 0x30, 0x31, 0x30, 0x31, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x30, 0x30, 0x35, + 0x33, 0x30, 0x31, 0x30, 0x34, 0x38, 0x33, 0x38, 0x5a, 0x30, 0x73, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x1b, + 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x12, 0x47, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x72, 0x20, 0x4d, 0x61, 0x6e, 0x63, 0x68, 0x65, 0x73, 0x74, 0x65, + 0x72, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x53, + 0x61, 0x6c, 0x66, 0x6f, 0x72, 0x64, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x13, 0x11, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, 0x43, 0x41, + 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x19, 0x30, 0x17, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, 0x43, 0x4f, 0x4d, 0x4f, 0x44, 0x4f, 0x20, + 0x45, 0x56, 0x20, 0x53, 0x47, 0x43, 0x20, 0x43, 0x41, +}; + +// A certificate for COMODO EV SGC CA, issued by AddTrust External CA Root, +// causes CertGetCertificateChain to report CERT_TRUST_IS_NOT_VALID_FOR_USAGE. +// It seems to be caused by the szOID_APPLICATION_CERT_POLICIES extension in +// that certificate. +// +// This function is used in the workaround for http://crbug.com/43538 +static bool IsProblematicComodoEVCACert(base::StringPiece der_cert) { + return der_cert.size() >= sizeof(kProblematicComodoEVCACert) && + memcmp(der_cert.data(), kProblematicComodoEVCACert, + sizeof(kProblematicComodoEVCACert)) == 0; +} +#endif + +#if defined(OS_WIN) +static X509Certificate::OSCertHandle CreateOSCert(base::StringPiece der_cert) { + X509Certificate::OSCertHandle cert_handle = NULL; + BOOL ok = CertAddEncodedCertificateToStore( + X509Certificate::cert_store(), X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + reinterpret_cast<const BYTE*>(der_cert.data()), der_cert.size(), + CERT_STORE_ADD_USE_EXISTING, &cert_handle); + return ok ? cert_handle : NULL; +} +#else +static X509Certificate::OSCertHandle CreateOSCert(base::StringPiece der_cert) { + return X509Certificate::CreateOSCertHandleFromBytes( + const_cast<char*>(der_cert.data()), der_cert.size()); +} +#endif + +// static +X509Certificate* X509Certificate::CreateFromDERCertChain( + const std::vector<base::StringPiece>& der_certs) { + if (der_certs.size() == 0) + return NULL; + + X509Certificate::OSCertHandles intermediate_ca_certs; + for (size_t i = 1; i < der_certs.size(); i++) { +#if defined(OS_WIN) + if (IsProblematicComodoEVCACert(der_certs[i])) + continue; +#endif + OSCertHandle handle = CreateOSCert(der_certs[i]); + DCHECK(handle); + intermediate_ca_certs.push_back(handle); + } + + OSCertHandle handle = CreateOSCert(der_certs[0]); + DCHECK(handle); + X509Certificate* cert = + CreateFromHandle(handle, SOURCE_FROM_NETWORK, intermediate_ca_certs); + FreeOSCertHandle(handle); + for (size_t i = 0; i < intermediate_ca_certs.size(); i++) + FreeOSCertHandle(intermediate_ca_certs[i]); + + return cert; +} + // static X509Certificate* X509Certificate::CreateFromBytes(const char* data, int length) { @@ -249,11 +343,9 @@ X509Certificate::X509Certificate(OSCertHandle cert_handle, const OSCertHandles& intermediates) : cert_handle_(DupOSCertHandle(cert_handle)), source_(source) { -#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])); -#endif // Platform-specific initialization. Initialize(); } @@ -276,10 +368,8 @@ X509Certificate::~X509Certificate() { X509Certificate::Cache::GetInstance()->Remove(this); if (cert_handle_) FreeOSCertHandle(cert_handle_); -#if defined(OS_MACOSX) || defined(OS_WIN) for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) FreeOSCertHandle(intermediate_ca_certs_[i]); -#endif } bool X509Certificate::HasExpired() const { diff --git a/net/base/x509_certificate.h b/net/base/x509_certificate.h index 577de92..a7eef9d 100644 --- a/net/base/x509_certificate.h +++ b/net/base/x509_certificate.h @@ -13,6 +13,7 @@ #include "base/gtest_prod_util.h" #include "base/ref_counted.h" +#include "base/string_piece.h" #include "base/time.h" #include "net/base/x509_cert_types.h" @@ -107,12 +108,20 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { // certificate cache prefers the handle from the network because our HTTP // cache isn't caching the corresponding intermediate CA certificates yet // (http://crbug.com/7065). - // The list of intermediate certificates is ignored under NSS (i.e. Linux.) // The returned pointer must be stored in a scoped_refptr<X509Certificate>. static X509Certificate* CreateFromHandle(OSCertHandle cert_handle, Source source, const OSCertHandles& intermediates); + // Create an X509Certificate from a chain of DER encoded certificates. The + // first certificate in the chain is the end-entity certificate to which a + // handle is returned. The other certificates in the chain are intermediate + // certificates. See the comment for |CreateFromHandle| about the |source| + // argument. + // The returned pointer must be stored in a scoped_refptr<X509Certificate>. + static X509Certificate* CreateFromDERCertChain( + const std::vector<base::StringPiece>& der_certs); + // Create an X509Certificate from the DER-encoded representation. // Returns NULL on failure. // @@ -173,14 +182,12 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { // now. bool HasExpired() const; -#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. const OSCertHandles& GetIntermediateCertificates() const { return intermediate_ca_certs_; } -#endif // Returns true if I already contain the given intermediate cert. bool HasIntermediateCertificate(OSCertHandle cert); @@ -213,6 +220,17 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { CFArrayRef CreateClientCertificateChain() const; #endif +#if defined(OS_WIN) + // Returns a handle to a global, in-memory certificate store. We use it for + // two purposes: + // 1. Import server certificates into this store so that we can verify and + // display the certificates using CryptoAPI. + // 2. Copy client certificates from the "MY" system certificate store into + // this store so that we can close the system store when we finish + // searching for client certificates. + static HCERTSTORE cert_store(); +#endif + // Verifies the certificate against the given hostname. Returns OK if // successful or an error code upon failure. // @@ -292,11 +310,9 @@ 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) || defined(USE_OPENSSL) // Untrusted intermediate certificates associated with this certificate - // that may be needed for chain building. (NSS impl does not need these.) + // that may be needed for chain building. OSCertHandles intermediate_ca_certs_; -#endif #if defined(OS_MACOSX) // Blocks multiple threads from verifying the cert simultaneously. diff --git a/net/base/x509_certificate_win.cc b/net/base/x509_certificate_win.cc index 380ff3c..1236f85 100644 --- a/net/base/x509_certificate_win.cc +++ b/net/base/x509_certificate_win.cc @@ -575,6 +575,33 @@ void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const { dns_names->push_back(subject_.common_name); } +class GlobalCertStore { + public: + HCERTSTORE cert_store() { + return cert_store_; + } + + private: + friend struct DefaultSingletonTraits<GlobalCertStore>; + + GlobalCertStore() + : cert_store_(CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, 0, NULL)) { + } + + ~GlobalCertStore() { + CertCloseStore(cert_store_, 0 /* flags */); + } + + const HCERTSTORE cert_store_; + + DISALLOW_COPY_AND_ASSIGN(GlobalCertStore); +}; + +// static +HCERTSTORE X509Certificate::cert_store() { + return Singleton<GlobalCertStore>::get()->cert_store(); +} + int X509Certificate::Verify(const std::string& hostname, int flags, CertVerifyResult* verify_result) const { |