diff options
Diffstat (limited to 'net/base/x509_certificate_nss.cc')
-rw-r--r-- | net/base/x509_certificate_nss.cc | 108 |
1 files changed, 70 insertions, 38 deletions
diff --git a/net/base/x509_certificate_nss.cc b/net/base/x509_certificate_nss.cc index 2ca1255..ef4b8cd 100644 --- a/net/base/x509_certificate_nss.cc +++ b/net/base/x509_certificate_nss.cc @@ -13,12 +13,30 @@ #include <sechash.h> #undef Lock +#include "base/histogram.h" #include "base/logging.h" #include "base/time.h" #include "base/nss_init.h" namespace net { +// Calculates the SHA-1 fingerprint of the certificate. Returns an empty +// (all zero) fingerprint on failure. +X509Certificate::Fingerprint CalculateFingerprint( + X509Certificate::OSCertHandle cert) { + X509Certificate::Fingerprint sha1; + memset(sha1.data, 0, sizeof(sha1.data)); + + DCHECK(NULL != cert->derCert.data); + DCHECK(0 != cert->derCert.len); + + SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, sha1.data, + cert->derCert.data, cert->derCert.len); + DCHECK(rv == SECSuccess); + + return sha1; +} + namespace { // TODO(port): Implement this more simply, and put it in the right place @@ -39,11 +57,11 @@ base::Time PRTimeToBaseTime(PRTime prtime) { return base::Time::FromUTCExploded(exploded); } -void ParsePrincipal(SECItem* der_name, +void ParsePrincipal(SECItem *der_name, X509Certificate::Principal* principal) { CERTName name; - PRArenaPool* arena = NULL; + PRArenaPool *arena = NULL; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); DCHECK(arena != NULL); @@ -92,7 +110,7 @@ void ParsePrincipal(SECItem* der_name, SECItem* decode_item = CERT_DecodeAVAValue(&avas[pair]->value); if (!decode_item) break; - std::string value(reinterpret_cast<char*>(decode_item->data), + std::string value(reinterpret_cast<char *>(decode_item->data), decode_item->len); values[oid]->push_back(value); SECITEM_FreeItem(decode_item, PR_TRUE); @@ -147,9 +165,9 @@ void GetCertSubjectAltNamesOfType(X509Certificate::OSCertHandle cert_handle, name->type == certDNSName || name->type == certURI); if (name->type == name_type) { - unsigned char* p = name->name.other.data; + unsigned char *p = name->name.other.data; int len = name->name.other.len; - std::string value = std::string(reinterpret_cast<char*>(p), len); + std::string value = std::string(reinterpret_cast<char *>(p), len); result->push_back(value); } name = CERT_GetNextGeneralName(name); @@ -175,16 +193,63 @@ void X509Certificate::Initialize() { } // static +X509Certificate* X509Certificate::CreateFromHandle(OSCertHandle cert_handle) { + DCHECK(cert_handle); + + // Check if we already have this certificate in memory. + X509Certificate::Cache* cache = X509Certificate::Cache::GetInstance(); + X509Certificate* cert = cache->Find(CalculateFingerprint(cert_handle)); + if (cert) { + // We've found a certificate with the same fingerprint in our cache. We own + // the |cert_handle|, which makes it our job to free it. + CERT_DestroyCertificate(cert_handle); + DHISTOGRAM_COUNTS(L"X509CertificateReuseCount", 1); + return cert; + } + // Otherwise, allocate a new object. + return new X509Certificate(cert_handle); +} + +// static +X509Certificate* X509Certificate::CreateFromBytes(const char* data, + int length) { + base::EnsureNSSInit(); + + SECItem der_cert; + der_cert.data = reinterpret_cast<unsigned char *>(const_cast<char *>(data)); + der_cert.len = length; + OSCertHandle cert_handle = + CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &der_cert, + NULL, PR_FALSE, PR_TRUE); + if (!cert_handle) + return NULL; + + return CreateFromHandle(cert_handle); +} + +// static X509Certificate* X509Certificate::CreateFromPickle(const Pickle& pickle, void** pickle_iter) { NOTIMPLEMENTED(); return NULL; } +X509Certificate::X509Certificate(OSCertHandle cert_handle) + : cert_handle_(cert_handle) { + Initialize(); +} + void X509Certificate::Persist(Pickle* pickle) { NOTIMPLEMENTED(); } +X509Certificate::~X509Certificate() { + // We might not be in the cache, but it is safe to remove ourselves anyway. + X509Certificate::Cache::GetInstance()->Remove(this); + if (cert_handle_) + CERT_DestroyCertificate(cert_handle_); +} + void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const { dns_names->clear(); @@ -198,39 +263,6 @@ void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const { if (dns_names->empty()) dns_names->push_back(subject_.common_name); } - -// static -X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( - const char* data, int length) { - base::EnsureNSSInit(); - - SECItem der_cert; - der_cert.data = reinterpret_cast<unsigned char*>(const_cast<char*>(data)); - der_cert.len = length; - return CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &der_cert, - NULL, PR_FALSE, PR_TRUE); -} - -// static -void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { - CERT_DestroyCertificate(cert_handle); -} - -// static -X509Certificate::Fingerprint X509Certificate::CalculateFingerprint( - OSCertHandle cert) { - Fingerprint sha1; - memset(sha1.data, 0, sizeof(sha1.data)); - - DCHECK(NULL != cert->derCert.data); - DCHECK(0 != cert->derCert.len); - - SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, sha1.data, - cert->derCert.data, cert->derCert.len); - DCHECK(rv == SECSuccess); - - return sha1; -} } // namespace net |