| Index: chrome/browser/extensions/api/enterprise_platform_keys/token_method_nss.cc
|
| diff --git a/chrome/browser/extensions/api/enterprise_platform_keys/token_method_nss.cc b/chrome/browser/extensions/api/enterprise_platform_keys/token_method_nss.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d19a3efc865cdc2c2a2975bd442ca9fa3d0f0a85
|
| --- /dev/null
|
| +++ b/chrome/browser/extensions/api/enterprise_platform_keys/token_method_nss.cc
|
| @@ -0,0 +1,396 @@
|
| +// Copyright 2014 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/browser/extensions/api/enterprise_platform_keys/token_method.h"
|
| +
|
| +#include <cryptohi.h>
|
| +#include "base/bind.h"
|
| +#include "base/bind_helpers.h"
|
| +#include "base/callback.h"
|
| +#include "base/compiler_specific.h"
|
| +#include "base/logging.h"
|
| +#include "base/memory/weak_ptr.h"
|
| +#include "chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.h"
|
| +#include "chrome/browser/net/nss_context.h"
|
| +#include "crypto/rsa_private_key.h"
|
| +#include "net/base/crypto_module.h"
|
| +#include "net/base/net_errors.h"
|
| +#include "net/cert/cert_database.h"
|
| +#include "net/cert/nss_cert_database.h"
|
| +#include "net/cert/x509_certificate.h"
|
| +
|
| +namespace {
|
| +const char kErrorInternal[] = "Internal Error";
|
| +const char kErrorKeyNotFound[] = "Key not found.";
|
| +const char kErrorInvalidX509Cert[] =
|
| + "Certificate is not a valid X.509 certificate.";
|
| +const char kErrorCertificateNotFound[] = "Certificate could not be found.";
|
| +const char kErrorAlgorithmNotSupported[] = "Algorithm not supported.";
|
| +}
|
| +
|
| +namespace extensions {
|
| +
|
| +namespace enterprise_platform_keys_details {
|
| +
|
| +namespace {
|
| +
|
| +namespace api_epk = api::enterprise_platform_keys;
|
| +namespace api_epki = api::enterprise_platform_keys_internal;
|
| +
|
| +typedef base::Callback<void(crypto::ScopedPK11Slot slot,
|
| + net::NSSCertDatabase* cert_db)> GetCertDBCallback;
|
| +
|
| +void DidGetCertDB(const GetCertDBCallback& callback,
|
| + EnterprisePlatformKeysTokenMethodExtensionFunction* func,
|
| + net::NSSCertDatabase* cert_db) {
|
| + if (!cert_db) {
|
| + LOG(ERROR) << "Couldn't get NSSCertDatabase.";
|
| + func->RespondWithError(kErrorInternal);
|
| + return;
|
| + }
|
| +
|
| + crypto::ScopedPK11Slot slot = cert_db->GetPrivateSlot();
|
| + if (!slot) {
|
| + LOG(ERROR) << "No private slot";
|
| + func->RespondWithError(kErrorInternal);
|
| + return;
|
| + }
|
| + callback.Run(slot.Pass(), cert_db);
|
| +}
|
| +
|
| +void GetCertDatabase(const std::string& token_id,
|
| + const GetCertDBCallback& callback,
|
| + EnterprisePlatformKeysTokenMethodExtensionFunction* func) {
|
| + GetNSSCertDatabaseForProfile(
|
| + func->GetProfile(),
|
| + base::Bind(&DidGetCertDB, callback, base::Unretained(func)));
|
| +}
|
| +
|
| +class GenerateKey : public TokenMethod {
|
| + public:
|
| + GenerateKey(scoped_ptr<api_epki::GenerateKey::Params> params,
|
| + EnterprisePlatformKeysTokenMethodExtensionFunction* func);
|
| + virtual ~GenerateKey() {}
|
| + virtual void Run() OVERRIDE;
|
| +
|
| + void DidGetDB(crypto::ScopedPK11Slot slot, net::NSSCertDatabase* cert_db);
|
| +
|
| + private:
|
| + scoped_ptr<api_epki::GenerateKey::Params> params_;
|
| + base::WeakPtrFactory<GenerateKey> weak_factory_;
|
| +};
|
| +
|
| +class Sign : public TokenMethod {
|
| + public:
|
| + Sign(scoped_ptr<api_epki::Sign::Params> params,
|
| + EnterprisePlatformKeysTokenMethodExtensionFunction* func);
|
| + virtual ~Sign() {}
|
| + virtual void Run() OVERRIDE;
|
| +
|
| + void DidGetDB(crypto::ScopedPK11Slot slot, net::NSSCertDatabase* cert_db);
|
| +
|
| + private:
|
| + scoped_ptr<api_epki::Sign::Params> params_;
|
| + base::WeakPtrFactory<Sign> weak_factory_;
|
| +};
|
| +
|
| +class GetCertificates : public TokenMethod {
|
| + public:
|
| + GetCertificates(scoped_ptr<api_epk::GetCertificates::Params> params,
|
| + EnterprisePlatformKeysTokenMethodExtensionFunction* func);
|
| + virtual ~GetCertificates() {}
|
| + virtual void Run() OVERRIDE;
|
| +
|
| + void DidGetDB(crypto::ScopedPK11Slot slot, net::NSSCertDatabase* cert_db);
|
| + void DidGetCertificates(scoped_ptr<net::CertificateList> certs);
|
| +
|
| + private:
|
| + scoped_ptr<api_epk::GetCertificates::Params> params_;
|
| + crypto::ScopedPK11Slot slot_;
|
| + base::WeakPtrFactory<GetCertificates> weak_factory_;
|
| +};
|
| +
|
| +class ImportCertificate : public TokenMethod {
|
| + public:
|
| + ImportCertificate(scoped_ptr<api_epk::ImportCertificate::Params> params,
|
| + EnterprisePlatformKeysTokenMethodExtensionFunction* func);
|
| + virtual ~ImportCertificate() {}
|
| + virtual void Run() OVERRIDE;
|
| +
|
| + void DidGetDB(crypto::ScopedPK11Slot slot, net::NSSCertDatabase* cert_db);
|
| +
|
| + private:
|
| + scoped_ptr<api_epk::ImportCertificate::Params> params_;
|
| + base::WeakPtrFactory<ImportCertificate> weak_factory_;
|
| +};
|
| +
|
| +class RemoveCertificate : public TokenMethod {
|
| + public:
|
| + RemoveCertificate(scoped_ptr<api_epk::RemoveCertificate::Params> params,
|
| + EnterprisePlatformKeysTokenMethodExtensionFunction* func);
|
| + virtual ~RemoveCertificate() {}
|
| + virtual void Run() OVERRIDE;
|
| +
|
| + void DidGetDB(crypto::ScopedPK11Slot slot, net::NSSCertDatabase* cert_db);
|
| +
|
| + private:
|
| + scoped_ptr<api_epk::RemoveCertificate::Params> params_;
|
| + base::WeakPtrFactory<RemoveCertificate> weak_factory_;
|
| +};
|
| +
|
| +GenerateKey::GenerateKey(
|
| + scoped_ptr<api_epki::GenerateKey::Params> params,
|
| + EnterprisePlatformKeysTokenMethodExtensionFunction* func)
|
| + : TokenMethod(func), params_(params.Pass()), weak_factory_(this) {
|
| +}
|
| +
|
| +void GenerateKey::Run() {
|
| + GetCertDatabase(
|
| + params_->token_id,
|
| + base::Bind(&GenerateKey::DidGetDB, weak_factory_.GetWeakPtr()),
|
| + func_);
|
| +}
|
| +
|
| +void GenerateKey::DidGetDB(crypto::ScopedPK11Slot slot,
|
| + net::NSSCertDatabase* cert_db) {
|
| + const int modulus_length = params_->modulus_length;
|
| + if (modulus_length > 2048) {
|
| + func_->RespondWithError(kErrorAlgorithmNotSupported);
|
| + return;
|
| + }
|
| + scoped_ptr<crypto::RSAPrivateKey> rsa_key(
|
| + crypto::RSAPrivateKey::CreateSensitive(slot.get(), modulus_length));
|
| + if (!rsa_key) {
|
| + LOG(ERROR) << "Couldn't create key.";
|
| + func_->RespondWithError(kErrorInternal);
|
| + return;
|
| + }
|
| +
|
| + std::vector<uint8> public_key_der;
|
| + if (!rsa_key->ExportPublicKey(&public_key_der)) {
|
| + // TODO(pneubeck): Remove rsa_key from storage.
|
| + LOG(ERROR) << "Couldn't export public key.";
|
| + func_->RespondWithError(kErrorInternal);
|
| + return;
|
| + }
|
| + std::string public_key_der_str(public_key_der.begin(), public_key_der.end());
|
| +
|
| + func_->RespondWithResults(
|
| + api_epki::GenerateKey::Results::Create(public_key_der_str));
|
| +}
|
| +
|
| +Sign::Sign(scoped_ptr<api_epki::Sign::Params> params,
|
| + EnterprisePlatformKeysTokenMethodExtensionFunction* func)
|
| + : TokenMethod(func), params_(params.Pass()), weak_factory_(this) {
|
| +}
|
| +
|
| +void Sign::Run() {
|
| + GetCertDatabase(params_->token_id,
|
| + base::Bind(&Sign::DidGetDB, weak_factory_.GetWeakPtr()),
|
| + func_);
|
| +}
|
| +
|
| +void Sign::DidGetDB(crypto::ScopedPK11Slot slot,
|
| + net::NSSCertDatabase* cert_db) {
|
| + const std::string& public_key = params_->public_key;
|
| + const uint8* public_key_uint8 =
|
| + reinterpret_cast<const uint8*>(public_key.data());
|
| + std::vector<uint8> public_key_vector(public_key_uint8,
|
| + public_key_uint8 + public_key.size());
|
| +
|
| + // TODO(pneubeck): This searches all slots. Change to look only at |slot_|.
|
| + scoped_ptr<crypto::RSAPrivateKey> rsa_key(
|
| + crypto::RSAPrivateKey::FindFromPublicKeyInfo(public_key_vector));
|
| + if (!rsa_key) {
|
| + func_->RespondWithError(kErrorKeyNotFound);
|
| + return;
|
| + }
|
| +
|
| + const std::string& data = params_->data;
|
| + SECItem sign_result = {siBuffer, NULL, 0};
|
| + if (SEC_SignData(&sign_result,
|
| + reinterpret_cast<const unsigned char*>(data.data()),
|
| + data.size(),
|
| + rsa_key->key(),
|
| + SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION) != SECSuccess) {
|
| + LOG(ERROR) << "Couldn't sign.";
|
| + func_->RespondWithError(kErrorInternal);
|
| + return;
|
| + }
|
| +
|
| + std::string signature(reinterpret_cast<const char*>(sign_result.data),
|
| + sign_result.len);
|
| + func_->RespondWithResults(api_epki::Sign::Results::Create(signature));
|
| +}
|
| +
|
| +GetCertificates::GetCertificates(
|
| + scoped_ptr<api_epk::GetCertificates::Params> params,
|
| + EnterprisePlatformKeysTokenMethodExtensionFunction* func)
|
| + : TokenMethod(func), params_(params.Pass()), weak_factory_(this) {
|
| +}
|
| +
|
| +void GetCertificates::Run() {
|
| + GetCertDatabase(
|
| + params_->token_id,
|
| + base::Bind(&GetCertificates::DidGetDB, weak_factory_.GetWeakPtr()),
|
| + func_);
|
| +}
|
| +
|
| +void GetCertificates::DidGetDB(crypto::ScopedPK11Slot slot,
|
| + net::NSSCertDatabase* cert_db) {
|
| + slot_ = slot.Pass();
|
| + cert_db->ListCertsInSlot(base::Bind(&GetCertificates::DidGetCertificates,
|
| + weak_factory_.GetWeakPtr()),
|
| + slot_.get());
|
| +}
|
| +
|
| +void GetCertificates::DidGetCertificates(
|
| + scoped_ptr<net::CertificateList> certs) {
|
| + // std::vector<std::string> client_certs;
|
| + scoped_ptr<base::ListValue> client_certs(new base::ListValue());
|
| + for (net::CertificateList::const_iterator it = certs->begin();
|
| + it != certs->end();
|
| + ++it) {
|
| + net::X509Certificate::OSCertHandle cert_handle = (*it)->os_cert_handle();
|
| + crypto::ScopedPK11Slot cert_slot(PK11_KeyForCertExists(cert_handle,
|
| + NULL, // keyPtr
|
| + NULL)); // wincx
|
| +
|
| + // Keep only user certificate, i.e. certs for which the private key is
|
| + // present, and certs where the private key is stored in the queried slot.
|
| + if (cert_slot != slot_)
|
| + continue;
|
| +
|
| + std::string der_encoding;
|
| + net::X509Certificate::GetDEREncoded(cert_handle, &der_encoding);
|
| + // client_certs.push_back(der_encoding);
|
| + client_certs->Append(base::BinaryValue::CreateWithCopiedBuffer(
|
| + der_encoding.data(), der_encoding.size()));
|
| + }
|
| + scoped_ptr<base::ListValue> results(new base::ListValue());
|
| + results->Append(client_certs.release());
|
| + func_->RespondWithResults(results.Pass());
|
| + // results_ = api_eci::GetClientCertificates::Results::Create(client_certs);
|
| +}
|
| +
|
| +ImportCertificate::ImportCertificate(
|
| + scoped_ptr<api_epk::ImportCertificate::Params> params,
|
| + EnterprisePlatformKeysTokenMethodExtensionFunction* func)
|
| + : TokenMethod(func), params_(params.Pass()), weak_factory_(this) {
|
| +}
|
| +
|
| +void ImportCertificate::Run() {
|
| + GetCertDatabase(
|
| + params_->token_id,
|
| + base::Bind(&ImportCertificate::DidGetDB, weak_factory_.GetWeakPtr()),
|
| + func_);
|
| +}
|
| +
|
| +void ImportCertificate::DidGetDB(crypto::ScopedPK11Slot slot,
|
| + net::NSSCertDatabase* cert_db) {
|
| + const std::string& certificate = params_->certificate;
|
| + scoped_refptr<net::X509Certificate> cert_x509 =
|
| + net::X509Certificate::CreateFromBytes(certificate.data(),
|
| + certificate.size());
|
| + if (!cert_x509) {
|
| + func_->RespondWithError(kErrorInvalidX509Cert);
|
| + return;
|
| + }
|
| +
|
| + net::CertDatabase* db = net::CertDatabase::GetInstance();
|
| +
|
| + const net::Error cert_status = db->CheckUserCert(cert_x509);
|
| + if (cert_status == net::ERR_NO_PRIVATE_KEY_FOR_CERT) {
|
| + func_->RespondWithError(kErrorKeyNotFound);
|
| + return;
|
| + } else if (cert_status != net::OK) {
|
| + func_->RespondWithError(net::ErrorToString(cert_status));
|
| + return;
|
| + }
|
| +
|
| + const net::Error import_status = db->AddUserCert(cert_x509.get());
|
| + if (import_status != net::OK) {
|
| + LOG(ERROR) << "Could not import certificate.";
|
| + func_->RespondWithError(net::ErrorToString(import_status));
|
| + return;
|
| + }
|
| +
|
| + func_->RespondWithoutResult();
|
| +}
|
| +
|
| +RemoveCertificate::RemoveCertificate(
|
| + scoped_ptr<api_epk::RemoveCertificate::Params> params,
|
| + EnterprisePlatformKeysTokenMethodExtensionFunction* func)
|
| + : TokenMethod(func), params_(params.Pass()), weak_factory_(this) {
|
| +}
|
| +
|
| +void RemoveCertificate::Run() {
|
| + GetCertDatabase(
|
| + params_->token_id,
|
| + base::Bind(&RemoveCertificate::DidGetDB, weak_factory_.GetWeakPtr()),
|
| + func_);
|
| +}
|
| +
|
| +void RemoveCertificate::DidGetDB(crypto::ScopedPK11Slot slot,
|
| + net::NSSCertDatabase* cert_db) {
|
| + const std::string& certificate = params_->certificate;
|
| + scoped_refptr<net::X509Certificate> cert_x509 =
|
| + net::X509Certificate::CreateFromBytes(certificate.data(),
|
| + certificate.size());
|
| + if (!cert_x509) {
|
| + func_->RespondWithError(kErrorInvalidX509Cert);
|
| + return;
|
| + }
|
| +
|
| + bool certificate_found = cert_x509->os_cert_handle()->isperm;
|
| + bool success = cert_db->DeleteCertAndKey(cert_x509);
|
| +
|
| + // CertificateNotFound error has precedence over an internal error.
|
| + if (!certificate_found) {
|
| + func_->RespondWithError(kErrorCertificateNotFound);
|
| + return;
|
| + }
|
| + if (!success) {
|
| + func_->RespondWithError(kErrorInternal);
|
| + return;
|
| + }
|
| +
|
| + func_->RespondWithoutResult();
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +scoped_ptr<TokenMethod> CreateGenerateKey(
|
| + scoped_ptr<api_epki::GenerateKey::Params> params,
|
| + EnterprisePlatformKeysTokenMethodExtensionFunction* func) {
|
| + return scoped_ptr<TokenMethod>(new GenerateKey(params.Pass(), func));
|
| +}
|
| +
|
| +scoped_ptr<TokenMethod> CreateSign(
|
| + scoped_ptr<api_epki::Sign::Params> params,
|
| + EnterprisePlatformKeysTokenMethodExtensionFunction* func) {
|
| + return scoped_ptr<TokenMethod>(new Sign(params.Pass(), func));
|
| +}
|
| +
|
| +scoped_ptr<TokenMethod> CreateGetCertificates(
|
| + scoped_ptr<api_epk::GetCertificates::Params> params,
|
| + EnterprisePlatformKeysTokenMethodExtensionFunction* func) {
|
| + return scoped_ptr<TokenMethod>(new GetCertificates(params.Pass(), func));
|
| +}
|
| +
|
| +scoped_ptr<TokenMethod> CreateImportCertificate(
|
| + scoped_ptr<api_epk::ImportCertificate::Params> params,
|
| + EnterprisePlatformKeysTokenMethodExtensionFunction* func) {
|
| + return scoped_ptr<TokenMethod>(new ImportCertificate(params.Pass(), func));
|
| +}
|
| +
|
| +scoped_ptr<TokenMethod> CreateRemoveCertificate(
|
| + scoped_ptr<api_epk::RemoveCertificate::Params> params,
|
| + EnterprisePlatformKeysTokenMethodExtensionFunction* func) {
|
| + return scoped_ptr<TokenMethod>(new RemoveCertificate(params.Pass(), func));
|
| +}
|
| +
|
| +} // namespace enterprise_platform_keys_details
|
| +
|
| +} // namespace extensions
|
|
|