summaryrefslogtreecommitdiffstats
path: root/net/cert/x509_certificate_nss.cc
diff options
context:
space:
mode:
authorphajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-29 21:48:11 +0000
committerphajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-29 21:48:11 +0000
commit6e7845aed4759ab35d722ce0551b5a90d21e7640 (patch)
treef29a3f007f7ded842d2096446ff7ecaf186cb362 /net/cert/x509_certificate_nss.cc
parenta6b4f91d970aa2b71b0f3552dbc11e94f7650fd5 (diff)
downloadchromium_src-6e7845aed4759ab35d722ce0551b5a90d21e7640.zip
chromium_src-6e7845aed4759ab35d722ce0551b5a90d21e7640.tar.gz
chromium_src-6e7845aed4759ab35d722ce0551b5a90d21e7640.tar.bz2
net: extract net/cert out of net/base
This introduces the following dependency of net/base on things outside: net/base/openssl_client_key_store.cc:#include "net/cert/x509_certificate.h" BUG=70818 Review URL: https://codereview.chromium.org/13006020 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@191450 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/cert/x509_certificate_nss.cc')
-rw-r--r--net/cert/x509_certificate_nss.cc306
1 files changed, 306 insertions, 0 deletions
diff --git a/net/cert/x509_certificate_nss.cc b/net/cert/x509_certificate_nss.cc
new file mode 100644
index 0000000..f6fdd94
--- /dev/null
+++ b/net/cert/x509_certificate_nss.cc
@@ -0,0 +1,306 @@
+// Copyright (c) 2012 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/cert/x509_certificate.h"
+
+#include <cert.h>
+#include <cryptohi.h>
+#include <keyhi.h>
+#include <nss.h>
+#include <pk11pub.h>
+#include <prtime.h>
+#include <seccomon.h>
+#include <secder.h>
+#include <sechash.h>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/pickle.h"
+#include "base/time.h"
+#include "crypto/nss_util.h"
+#include "crypto/rsa_private_key.h"
+#include "crypto/scoped_nss_types.h"
+#include "net/cert/x509_util_nss.h"
+
+namespace net {
+
+void X509Certificate::Initialize() {
+ x509_util::ParsePrincipal(&cert_handle_->subject, &subject_);
+ x509_util::ParsePrincipal(&cert_handle_->issuer, &issuer_);
+
+ x509_util::ParseDate(&cert_handle_->validity.notBefore, &valid_start_);
+ x509_util::ParseDate(&cert_handle_->validity.notAfter, &valid_expiry_);
+
+ fingerprint_ = CalculateFingerprint(cert_handle_);
+ ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_);
+
+ serial_number_ = x509_util::ParseSerialNumber(cert_handle_);
+}
+
+// static
+X509Certificate* X509Certificate::CreateFromBytesWithNickname(
+ const char* data,
+ int length,
+ const char* nickname) {
+ OSCertHandle cert_handle = CreateOSCertHandleFromBytesWithNickname(data,
+ length,
+ nickname);
+ if (!cert_handle)
+ return NULL;
+
+ X509Certificate* cert = CreateFromHandle(cert_handle, OSCertHandles());
+ FreeOSCertHandle(cert_handle);
+
+ if (nickname)
+ cert->default_nickname_ = nickname;
+
+ return cert;
+}
+
+std::string X509Certificate::GetDefaultNickname(CertType type) const {
+ if (!default_nickname_.empty())
+ return default_nickname_;
+
+ std::string result;
+ if (type == USER_CERT && cert_handle_->slot) {
+ // Find the private key for this certificate and see if it has a
+ // nickname. If there is a private key, and it has a nickname, then
+ // we return that nickname.
+ SECKEYPrivateKey* private_key = PK11_FindPrivateKeyFromCert(
+ cert_handle_->slot,
+ cert_handle_,
+ NULL); // wincx
+ if (private_key) {
+ char* private_key_nickname = PK11_GetPrivateKeyNickname(private_key);
+ if (private_key_nickname) {
+ result = private_key_nickname;
+ PORT_Free(private_key_nickname);
+ SECKEY_DestroyPrivateKey(private_key);
+ return result;
+ }
+ SECKEY_DestroyPrivateKey(private_key);
+ }
+ }
+
+ switch (type) {
+ case CA_CERT: {
+ char* nickname = CERT_MakeCANickname(cert_handle_);
+ result = nickname;
+ PORT_Free(nickname);
+ break;
+ }
+ case USER_CERT: {
+ // Create a nickname for a user certificate.
+ // We use the scheme used by Firefox:
+ // --> <subject's common name>'s <issuer's common name> ID.
+ // TODO(gspencer): internationalize this: it's wrong to
+ // hard code English.
+
+ std::string username, ca_name;
+ char* temp_username = CERT_GetCommonName(
+ &cert_handle_->subject);
+ char* temp_ca_name = CERT_GetCommonName(&cert_handle_->issuer);
+ if (temp_username) {
+ username = temp_username;
+ PORT_Free(temp_username);
+ }
+ if (temp_ca_name) {
+ ca_name = temp_ca_name;
+ PORT_Free(temp_ca_name);
+ }
+ result = username + "'s " + ca_name + " ID";
+ break;
+ }
+ case SERVER_CERT:
+ result = subject_.GetDisplayName();
+ break;
+ case UNKNOWN_CERT:
+ default:
+ break;
+ }
+ return result;
+}
+
+// static
+X509Certificate* X509Certificate::CreateSelfSigned(
+ crypto::RSAPrivateKey* key,
+ const std::string& subject,
+ uint32 serial_number,
+ base::TimeDelta valid_duration) {
+ DCHECK(key);
+ base::Time not_valid_before = base::Time::Now();
+ base::Time not_valid_after = not_valid_before + valid_duration;
+ CERTCertificate* cert = x509_util::CreateSelfSignedCert(key->public_key(),
+ key->key(),
+ subject,
+ serial_number,
+ not_valid_before,
+ not_valid_after);
+ if (!cert)
+ return NULL;
+
+ X509Certificate* x509_cert = X509Certificate::CreateFromHandle(
+ cert, X509Certificate::OSCertHandles());
+ CERT_DestroyCertificate(cert);
+ return x509_cert;
+}
+
+void X509Certificate::GetSubjectAltName(
+ std::vector<std::string>* dns_names,
+ std::vector<std::string>* ip_addrs) const {
+ x509_util::GetSubjectAltName(cert_handle_, dns_names, ip_addrs);
+}
+
+bool X509Certificate::VerifyNameMatch(const std::string& hostname) const {
+ return CERT_VerifyCertName(cert_handle_, hostname.c_str()) == SECSuccess;
+}
+
+bool X509Certificate::IsIssuedByEncoded(
+ const std::vector<std::string>& valid_issuers) {
+ // Get certificate chain as scoped list of CERTCertificate objects.
+ std::vector<CERTCertificate*> cert_chain;
+ cert_chain.push_back(cert_handle_);
+ for (size_t n = 0; n < intermediate_ca_certs_.size(); ++n) {
+ cert_chain.push_back(intermediate_ca_certs_[n]);
+ }
+ // Convert encoded issuers to scoped CERTName* list.
+ std::vector<CERTName*> issuers;
+ crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
+ if (!x509_util::GetIssuersFromEncodedList(valid_issuers,
+ arena.get(),
+ &issuers)) {
+ return false;
+ }
+ return x509_util::IsCertificateIssuedBy(cert_chain, issuers);
+}
+
+// static
+bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle,
+ std::string* encoded) {
+ if (!cert_handle->derCert.len)
+ return false;
+ encoded->assign(reinterpret_cast<char*>(cert_handle->derCert.data),
+ cert_handle->derCert.len);
+ return true;
+}
+
+// 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) {
+ return CreateOSCertHandleFromBytesWithNickname(data, length, NULL);
+}
+
+// static
+X509Certificate::OSCertHandle
+X509Certificate::CreateOSCertHandleFromBytesWithNickname(
+ const char* data,
+ int length,
+ const char* nickname) {
+ if (length < 0)
+ return NULL;
+
+ crypto::EnsureNSSInit();
+
+ if (!NSS_IsInitialized())
+ return NULL;
+
+ SECItem der_cert;
+ der_cert.data = reinterpret_cast<unsigned char*>(const_cast<char*>(data));
+ der_cert.len = length;
+ der_cert.type = siDERCertBuffer;
+
+ // Parse into a certificate structure.
+ return CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &der_cert,
+ const_cast<char*>(nickname),
+ PR_FALSE, PR_TRUE);
+}
+
+// static
+X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes(
+ const char* data,
+ int length,
+ Format format) {
+ return x509_util::CreateOSCertHandlesFromBytes(data, length, format);
+}
+
+// static
+X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle(
+ OSCertHandle cert_handle) {
+ return CERT_DupCertificate(cert_handle);
+}
+
+// static
+void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) {
+ CERT_DestroyCertificate(cert_handle);
+}
+
+// static
+SHA1HashValue X509Certificate::CalculateFingerprint(
+ OSCertHandle cert) {
+ SHA1HashValue sha1;
+ memset(sha1.data, 0, sizeof(sha1.data));
+
+ DCHECK(NULL != cert->derCert.data);
+ DCHECK_NE(0U, cert->derCert.len);
+
+ SECStatus rv = HASH_HashBuf(HASH_AlgSHA1, sha1.data,
+ cert->derCert.data, cert->derCert.len);
+ DCHECK_EQ(SECSuccess, rv);
+
+ return sha1;
+}
+
+// static
+SHA1HashValue X509Certificate::CalculateCAFingerprint(
+ const OSCertHandles& intermediates) {
+ SHA1HashValue sha1;
+ memset(sha1.data, 0, sizeof(sha1.data));
+
+ HASHContext* sha1_ctx = HASH_Create(HASH_AlgSHA1);
+ if (!sha1_ctx)
+ return sha1;
+ HASH_Begin(sha1_ctx);
+ for (size_t i = 0; i < intermediates.size(); ++i) {
+ CERTCertificate* ca_cert = intermediates[i];
+ HASH_Update(sha1_ctx, ca_cert->derCert.data, ca_cert->derCert.len);
+ }
+ unsigned int result_len;
+ HASH_End(sha1_ctx, sha1.data, &result_len, HASH_ResultLenContext(sha1_ctx));
+ HASH_Destroy(sha1_ctx);
+
+ return sha1;
+}
+
+// static
+X509Certificate::OSCertHandle
+X509Certificate::ReadOSCertHandleFromPickle(PickleIterator* pickle_iter) {
+ return x509_util::ReadOSCertHandleFromPickle(pickle_iter);
+}
+
+// static
+bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle,
+ Pickle* pickle) {
+ return pickle->WriteData(
+ reinterpret_cast<const char*>(cert_handle->derCert.data),
+ cert_handle->derCert.len);
+}
+
+// static
+void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle,
+ size_t* size_bits,
+ PublicKeyType* type) {
+ x509_util::GetPublicKeyInfo(cert_handle, size_bits, type);
+}
+
+} // namespace net