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

Unified Diff: chrome/common/net/x509_certificate_model_nss.cc

Issue 3565006: Decouples certificates viewers from NSS to prepare support for OpenSSL. (Closed)
Patch Set: Comments / ProcessIDN Created 10 years, 2 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
« no previous file with comments | « chrome/common/net/x509_certificate_model.cc ('k') | chrome/common/net/x509_certificate_model_openssl.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « chrome/common/net/x509_certificate_model.cc ('k') | chrome/common/net/x509_certificate_model_openssl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698