| Index: chrome/common/net/x509_certificate_model_nss.cc
 | 
| diff --git a/chrome/common/net/x509_certificate_model_nss.cc b/chrome/common/net/x509_certificate_model_nss.cc
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..da17a602591a6107f50cf222391fdcd955f09a95
 | 
| --- /dev/null
 | 
| +++ b/chrome/common/net/x509_certificate_model_nss.cc
 | 
| @@ -0,0 +1,381 @@
 | 
| +// 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 "chrome/common/net/x509_certificate_model.h"
 | 
| +
 | 
| +#include <cert.h>
 | 
| +#include <cms.h>
 | 
| +#include <hasht.h>
 | 
| +#include <pk11pub.h>
 | 
| +#include <sechash.h>
 | 
| +
 | 
| +#include <pk11pub.h>
 | 
| +
 | 
| +#include "base/logging.h"
 | 
| +#include "base/nss_util.h"
 | 
| +#include "base/string_number_conversions.h"
 | 
| +#include "net/base/x509_certificate.h"
 | 
| +#include "chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h"
 | 
| +#include "chrome/third_party/mozilla_security_manager/nsNSSCertificate.h"
 | 
| +#include "chrome/third_party/mozilla_security_manager/nsUsageArrayHelper.h"
 | 
| +
 | 
| +namespace psm = mozilla_security_manager;
 | 
| +
 | 
| +namespace {
 | 
| +
 | 
| +// Convert a char* return value from NSS into a std::string and free the NSS
 | 
| +// memory.  If the arg is NULL, an empty string will be returned instead.
 | 
| +std::string Stringize(char* nss_text, const std::string& alternative_text) {
 | 
| +  if (!nss_text)
 | 
| +    return alternative_text;
 | 
| +
 | 
| +  std::string s = nss_text;
 | 
| +  PORT_Free(nss_text);
 | 
| +  return s;
 | 
| +}
 | 
| +
 | 
| +// Hash a certificate using the given algorithm, return the result as a
 | 
| +// colon-seperated hex string.  The len specified is the number of bytes
 | 
| +// required for storing the raw fingerprint.
 | 
| +// (It's a bit redundant that the caller needs to specify len in addition to the
 | 
| +// algorithm, but given the limited uses, not worth fixing.)
 | 
| +std::string HashCert(CERTCertificate* cert, HASH_HashType algorithm, int len) {
 | 
| +  unsigned char fingerprint[HASH_LENGTH_MAX];
 | 
| +  SECItem fingerprint_item;
 | 
| +
 | 
| +  DCHECK(NULL != cert->derCert.data);
 | 
| +  DCHECK_NE(0U, cert->derCert.len);
 | 
| +  DCHECK_LE(len, HASH_LENGTH_MAX);
 | 
| +  memset(fingerprint, 0, len);
 | 
| +  SECStatus rv = HASH_HashBuf(algorithm, fingerprint, cert->derCert.data,
 | 
| +                              cert->derCert.len);
 | 
| +  DCHECK_EQ(rv, SECSuccess);
 | 
| +  fingerprint_item.data = fingerprint;
 | 
| +  fingerprint_item.len = len;
 | 
| +  return psm::ProcessRawBytes(&fingerprint_item);
 | 
| +}
 | 
| +
 | 
| +std::string ProcessSecAlgorithmInternal(SECAlgorithmID* algorithm_id) {
 | 
| +  return psm::GetOIDText(&algorithm_id->algorithm);
 | 
| +}
 | 
| +
 | 
| +std::string ProcessExtension(
 | 
| +    const std::string& critical_label,
 | 
| +    const std::string& non_critical_label,
 | 
| +    CERTCertExtension* extension) {
 | 
| +  std::string criticality =
 | 
| +      extension->critical.data && extension->critical.data[0] ?
 | 
| +          critical_label : non_critical_label;
 | 
| +  return criticality + "\n" +
 | 
| +      psm::ProcessExtensionData(SECOID_FindOIDTag(&extension->id),
 | 
| +                                &extension->value);
 | 
| +}
 | 
| +
 | 
| +////////////////////////////////////////////////////////////////////////////////
 | 
| +// NSS certificate export functions.
 | 
| +
 | 
| +class FreeNSSCMSMessage {
 | 
| + public:
 | 
| +  inline void operator()(NSSCMSMessage* x) const {
 | 
| +    NSS_CMSMessage_Destroy(x);
 | 
| +  }
 | 
| +};
 | 
| +typedef scoped_ptr_malloc<NSSCMSMessage, FreeNSSCMSMessage>
 | 
| +    ScopedNSSCMSMessage;
 | 
| +
 | 
| +class FreeNSSCMSSignedData {
 | 
| + public:
 | 
| +  inline void operator()(NSSCMSSignedData* x) const {
 | 
| +    NSS_CMSSignedData_Destroy(x);
 | 
| +  }
 | 
| +};
 | 
| +typedef scoped_ptr_malloc<NSSCMSSignedData, FreeNSSCMSSignedData>
 | 
| +    ScopedNSSCMSSignedData;
 | 
| +
 | 
| +}  // namespace
 | 
| +
 | 
| +namespace x509_certificate_model {
 | 
| +
 | 
| +using net::X509Certificate;
 | 
| +using std::string;
 | 
| +
 | 
| +string GetCertNameOrNickname(X509Certificate::OSCertHandle cert_handle) {
 | 
| +  string name = ProcessIDN(Stringize(CERT_GetCommonName(&cert_handle->subject),
 | 
| +                                     ""));
 | 
| +  if (name.empty() && cert_handle->nickname) {
 | 
| +    name = cert_handle->nickname;
 | 
| +    // Hack copied from mozilla: Cut off text before first :, which seems to
 | 
| +    // just be the token name.
 | 
| +    size_t colon_pos = name.find(':');
 | 
| +    if (colon_pos != string::npos)
 | 
| +      name = name.substr(colon_pos + 1);
 | 
| +  }
 | 
| +  return name;
 | 
| +}
 | 
| +
 | 
| +string GetTokenName(X509Certificate::OSCertHandle cert_handle) {
 | 
| +  return psm::GetCertTokenName(cert_handle);
 | 
| +}
 | 
| +
 | 
| +string GetVersion(X509Certificate::OSCertHandle cert_handle) {
 | 
| +  unsigned long version = ULONG_MAX;
 | 
| +  if (SEC_ASN1DecodeInteger(&cert_handle->version, &version) == SECSuccess &&
 | 
| +      version != ULONG_MAX)
 | 
| +    return base::UintToString(version + 1);
 | 
| +  return "";
 | 
| +}
 | 
| +
 | 
| +net::CertType GetType(X509Certificate::OSCertHandle cert_handle) {
 | 
| +    return psm::GetCertType(cert_handle);
 | 
| +}
 | 
| +
 | 
| +string GetEmailAddress(X509Certificate::OSCertHandle cert_handle) {
 | 
| +  if (cert_handle->emailAddr)
 | 
| +    return cert_handle->emailAddr;
 | 
| +  return "";
 | 
| +}
 | 
| +
 | 
| +void GetUsageStrings(X509Certificate::OSCertHandle cert_handle,
 | 
| +                     std::vector<string>* usages) {
 | 
| +  psm::GetCertUsageStrings(cert_handle, usages);
 | 
| +}
 | 
| +
 | 
| +string GetKeyUsageString(X509Certificate::OSCertHandle cert_handle) {
 | 
| +  SECItem key_usage;
 | 
| +  key_usage.data = NULL;
 | 
| +  string key_usage_str;
 | 
| +  if (CERT_FindKeyUsageExtension(cert_handle, &key_usage) == SECSuccess) {
 | 
| +    key_usage_str = psm::ProcessKeyUsageBitString(&key_usage, ',');
 | 
| +    PORT_Free(key_usage.data);
 | 
| +  }
 | 
| +  return key_usage_str;
 | 
| +}
 | 
| +
 | 
| +string GetSerialNumberHexified(X509Certificate::OSCertHandle cert_handle,
 | 
| +                               const string& alternative_text) {
 | 
| +  return Stringize(CERT_Hexify(&cert_handle->serialNumber, true),
 | 
| +                   alternative_text);
 | 
| +}
 | 
| +
 | 
| +string GetIssuerCommonName(X509Certificate::OSCertHandle cert_handle,
 | 
| +                           const string& alternative_text) {
 | 
| +  return Stringize(CERT_GetCommonName(&cert_handle->issuer), alternative_text);
 | 
| +}
 | 
| +
 | 
| +string GetIssuerOrgName(X509Certificate::OSCertHandle cert_handle,
 | 
| +                        const string& alternative_text) {
 | 
| +  return Stringize(CERT_GetOrgName(&cert_handle->issuer), alternative_text);
 | 
| +}
 | 
| +
 | 
| +string GetIssuerOrgUnitName(X509Certificate::OSCertHandle cert_handle,
 | 
| +                            const string& alternative_text) {
 | 
| +  return Stringize(CERT_GetOrgUnitName(&cert_handle->issuer), alternative_text);
 | 
| +}
 | 
| +
 | 
| +string GetSubjectOrgName(X509Certificate::OSCertHandle cert_handle,
 | 
| +                         const string& alternative_text) {
 | 
| +  return Stringize(CERT_GetOrgName(&cert_handle->subject), alternative_text);
 | 
| +}
 | 
| +
 | 
| +string GetSubjectOrgUnitName(X509Certificate::OSCertHandle cert_handle,
 | 
| +                             const string& alternative_text) {
 | 
| +  return Stringize(CERT_GetOrgUnitName(&cert_handle->subject),
 | 
| +                   alternative_text);
 | 
| +}
 | 
| +
 | 
| +string GetSubjectCommonName(X509Certificate::OSCertHandle cert_handle,
 | 
| +                            const string& alternative_text) {
 | 
| +  return Stringize(CERT_GetCommonName(&cert_handle->subject), alternative_text);
 | 
| +}
 | 
| +
 | 
| +bool GetTimes(X509Certificate::OSCertHandle cert_handle,
 | 
| +              base::Time* issued, base::Time* expires) {
 | 
| +  PRTime pr_issued, pr_expires;
 | 
| +  if (CERT_GetCertTimes(cert_handle, &pr_issued, &pr_expires) == SECSuccess) {
 | 
| +    *issued = base::PRTimeToBaseTime(pr_issued);
 | 
| +    *expires = base::PRTimeToBaseTime(pr_expires);
 | 
| +    return true;
 | 
| +  }
 | 
| +  return false;
 | 
| +}
 | 
| +
 | 
| +string GetTitle(X509Certificate::OSCertHandle cert_handle) {
 | 
| +  return psm::GetCertTitle(cert_handle);
 | 
| +}
 | 
| +
 | 
| +string GetIssuerName(X509Certificate::OSCertHandle cert_handle) {
 | 
| +  return psm::ProcessName(&cert_handle->issuer);
 | 
| +}
 | 
| +
 | 
| +string GetSubjectName(X509Certificate::OSCertHandle cert_handle) {
 | 
| +  return psm::ProcessName(&cert_handle->subject);
 | 
| +}
 | 
| +
 | 
| +void GetEmailAddresses(X509Certificate::OSCertHandle cert_handle,
 | 
| +                       std::vector<string>* email_addresses) {
 | 
| +  for (const char* addr = CERT_GetFirstEmailAddress(cert_handle);
 | 
| +       addr; addr = CERT_GetNextEmailAddress(cert_handle, addr)) {
 | 
| +    // The first email addr (from Subject) may be duplicated in Subject
 | 
| +    // Alternative Name, so check subsequent addresses are not equal to the
 | 
| +    // first one before adding to the list.
 | 
| +    if (!email_addresses->size() || (*email_addresses)[0] != addr)
 | 
| +      email_addresses->push_back(addr);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +void GetNicknameStringsFromCertList(
 | 
| +    const std::vector<scoped_refptr<X509Certificate> >& certs,
 | 
| +    const string& cert_expired,
 | 
| +    const string& cert_not_yet_valid,
 | 
| +    std::vector<string>* nick_names) {
 | 
| +  CERTCertList* cert_list = CERT_NewCertList();
 | 
| +  for (size_t i = 0; i < certs.size(); ++i) {
 | 
| +    CERT_AddCertToListTail(
 | 
| +        cert_list,
 | 
| +        CERT_DupCertificate(certs[i]->os_cert_handle()));
 | 
| +  }
 | 
| +  // Would like to use CERT_GetCertNicknameWithValidity on each cert
 | 
| +  // individually instead of having to build a CERTCertList for this, but that
 | 
| +  // function is not exported.
 | 
| +  CERTCertNicknames* cert_nicknames = CERT_NicknameStringsFromCertList(
 | 
| +      cert_list,
 | 
| +      const_cast<char*>(cert_expired.c_str()),
 | 
| +      const_cast<char*>(cert_not_yet_valid.c_str()));
 | 
| +  DCHECK_EQ(cert_nicknames->numnicknames,
 | 
| +            static_cast<int>(certs.size()));
 | 
| +
 | 
| +  for (int i = 0; i < cert_nicknames->numnicknames; ++i)
 | 
| +    nick_names->push_back(cert_nicknames->nicknames[i]);
 | 
| +
 | 
| +  CERT_FreeNicknames(cert_nicknames);
 | 
| +  CERT_DestroyCertList(cert_list);
 | 
| +}
 | 
| +
 | 
| +void GetExtensions(
 | 
| +    const string& critical_label,
 | 
| +    const string& non_critical_label,
 | 
| +    X509Certificate::OSCertHandle cert_handle,
 | 
| +    Extensions* extensions) {
 | 
| +  if (cert_handle->extensions) {
 | 
| +    for (size_t i = 0; cert_handle->extensions[i] != NULL; ++i) {
 | 
| +      Extension extension;
 | 
| +      extension.name = psm::GetOIDText(&cert_handle->extensions[i]->id);
 | 
| +      extension.value = ProcessExtension(
 | 
| +          critical_label, non_critical_label, cert_handle->extensions[i]);
 | 
| +      extensions->push_back(extension);
 | 
| +    }
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +string HashCertSHA256(X509Certificate::OSCertHandle cert_handle) {
 | 
| +  return HashCert(cert_handle, HASH_AlgSHA256, SHA256_LENGTH);
 | 
| +}
 | 
| +
 | 
| +string HashCertSHA1(X509Certificate::OSCertHandle cert_handle) {
 | 
| +  return HashCert(cert_handle, HASH_AlgSHA1, SHA1_LENGTH);
 | 
| +}
 | 
| +
 | 
| +void GetCertChainFromCert(X509Certificate::OSCertHandle cert_handle,
 | 
| +                          X509Certificate::OSCertHandles* cert_handles) {
 | 
| +  CERTCertList* cert_list =
 | 
| +      CERT_GetCertChainFromCert(cert_handle, PR_Now(), certUsageSSLServer);
 | 
| +  CERTCertListNode* node;
 | 
| +  for (node = CERT_LIST_HEAD(cert_list);
 | 
| +       !CERT_LIST_END(node, cert_list);
 | 
| +       node = CERT_LIST_NEXT(node)) {
 | 
| +    cert_handles->push_back(CERT_DupCertificate(node->cert));
 | 
| +  }
 | 
| +  CERT_DestroyCertList(cert_list);
 | 
| +}
 | 
| +
 | 
| +void DestroyCertChain(X509Certificate::OSCertHandles* cert_handles) {
 | 
| +  for (X509Certificate::OSCertHandles::iterator i(cert_handles->begin());
 | 
| +       i != cert_handles->end(); ++i)
 | 
| +    CERT_DestroyCertificate(*i);
 | 
| +}
 | 
| +
 | 
| +string GetDerString(X509Certificate::OSCertHandle cert_handle) {
 | 
| +  return string(reinterpret_cast<const char*>(cert_handle->derCert.data),
 | 
| +                cert_handle->derCert.len);
 | 
| +}
 | 
| +
 | 
| +string GetCMSString(const X509Certificate::OSCertHandles& cert_chain,
 | 
| +                    size_t start, size_t end) {
 | 
| +  ScopedPRArenaPool arena(PORT_NewArena(1024));
 | 
| +  CHECK(arena.get());
 | 
| +
 | 
| +  ScopedNSSCMSMessage message(NSS_CMSMessage_Create(arena.get()));
 | 
| +  CHECK(message.get());
 | 
| +
 | 
| +  // First, create SignedData with the certificate only (no chain).
 | 
| +  ScopedNSSCMSSignedData signed_data(NSS_CMSSignedData_CreateCertsOnly(
 | 
| +      message.get(), cert_chain[start], PR_FALSE));
 | 
| +  if (!signed_data.get()) {
 | 
| +    LOG(ERROR) << "NSS_CMSSignedData_Create failed";
 | 
| +    return "";
 | 
| +  }
 | 
| +  // Add the rest of the chain (if any).
 | 
| +  for (size_t i = start + 1; i < end; ++i) {
 | 
| +    if (NSS_CMSSignedData_AddCertificate(signed_data.get(), cert_chain[i]) !=
 | 
| +        SECSuccess) {
 | 
| +      LOG(ERROR) << "NSS_CMSSignedData_AddCertificate failed on " << i;
 | 
| +      return "";
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  NSSCMSContentInfo *cinfo = NSS_CMSMessage_GetContentInfo(message.get());
 | 
| +  if (NSS_CMSContentInfo_SetContent_SignedData(
 | 
| +      message.get(), cinfo, signed_data.get()) == SECSuccess) {
 | 
| +    ignore_result(signed_data.release());
 | 
| +  } else {
 | 
| +    LOG(ERROR) << "NSS_CMSMessage_GetContentInfo failed";
 | 
| +    return "";
 | 
| +  }
 | 
| +
 | 
| +  SECItem cert_p7 = { siBuffer, NULL, 0 };
 | 
| +  NSSCMSEncoderContext *ecx = NSS_CMSEncoder_Start(message.get(), NULL, NULL,
 | 
| +                                                   &cert_p7, arena.get(), NULL,
 | 
| +                                                   NULL, NULL, NULL, NULL,
 | 
| +                                                   NULL);
 | 
| +  if (!ecx) {
 | 
| +    LOG(ERROR) << "NSS_CMSEncoder_Start failed";
 | 
| +    return "";
 | 
| +  }
 | 
| +
 | 
| +  if (NSS_CMSEncoder_Finish(ecx) != SECSuccess) {
 | 
| +    LOG(ERROR) << "NSS_CMSEncoder_Finish failed";
 | 
| +    return "";
 | 
| +  }
 | 
| +
 | 
| +  return string(reinterpret_cast<const char*>(cert_p7.data), cert_p7.len);
 | 
| +}
 | 
| +
 | 
| +string ProcessSecAlgorithmSignature(X509Certificate::OSCertHandle cert_handle) {
 | 
| +  return ProcessSecAlgorithmInternal(&cert_handle->signature);
 | 
| +}
 | 
| +
 | 
| +string ProcessSecAlgorithmSubjectPublicKey(
 | 
| +    X509Certificate::OSCertHandle cert_handle) {
 | 
| +  return ProcessSecAlgorithmInternal(
 | 
| +      &cert_handle->subjectPublicKeyInfo.algorithm);
 | 
| +}
 | 
| +
 | 
| +string ProcessSecAlgorithmSignatureWrap(
 | 
| +    X509Certificate::OSCertHandle cert_handle) {
 | 
| +  return ProcessSecAlgorithmInternal(
 | 
| +      &cert_handle->signatureWrap.signatureAlgorithm);
 | 
| +}
 | 
| +
 | 
| +string ProcessSubjectPublicKeyInfo(X509Certificate::OSCertHandle cert_handle) {
 | 
| +  return psm::ProcessSubjectPublicKeyInfo(&cert_handle->subjectPublicKeyInfo);
 | 
| +}
 | 
| +
 | 
| +string ProcessRawBitsSignatureWrap(X509Certificate::OSCertHandle cert_handle) {
 | 
| +  return psm::ProcessRawBits(&cert_handle->signatureWrap.signature);
 | 
| +}
 | 
| +
 | 
| +void RegisterDynamicOids() {
 | 
| +}
 | 
| +
 | 
| +}  // namespace x509_certificate_model
 | 
| 
 |