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

Unified Diff: chrome/browser/extensions/api/enterprise_platform_keys/token_method_nss.cc

Issue 214863002: Extension API enterprise.platformKeys. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: @kalman only Created 6 years, 7 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
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..c0fa510e9241bc50bcc9e8dad180490ecd7a2862
--- /dev/null
+++ b/chrome/browser/extensions/api/enterprise_platform_keys/token_method_nss.cc
@@ -0,0 +1,407 @@
+// 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>
Ryan Sleevi 2014/05/08 20:52:04 style: newline
pneubeck (no reviews) 2014/05/14 15:01:49 Done.
+#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,
+ const TokenMethod::ErrorCallback& error_callback,
+ net::NSSCertDatabase* cert_db) {
+ if (!cert_db) {
+ LOG(ERROR) << "Couldn't get NSSCertDatabase.";
+ error_callback.Run(kErrorInternal);
+ return;
+ }
+
+ crypto::ScopedPK11Slot slot = cert_db->GetPrivateSlot();
+ if (!slot) {
+ LOG(ERROR) << "No private slot";
+ error_callback.Run(kErrorInternal);
+ return;
+ }
+ callback.Run(slot.Pass(), cert_db);
+}
+
+void GetCertDatabase(const std::string& token_id,
+ const GetCertDBCallback& callback,
+ const TokenMethod::ErrorCallback& error_callback,
+ Profile* profile) {
+ GetNSSCertDatabaseForProfile(
+ profile, base::Bind(&DidGetCertDB, callback, error_callback));
+}
+
+class GenerateKey : public TokenMethod {
+ public:
+ GenerateKey(scoped_ptr<api_epki::GenerateKey::Params> params,
+ const GenerateKeyCallback& callback,
+ const ErrorCallback& error_callback,
+ Profile* profile);
+ virtual ~GenerateKey() {}
+ virtual void Run() OVERRIDE;
+
+ void DidGetDB(crypto::ScopedPK11Slot slot, net::NSSCertDatabase* cert_db);
Ryan Sleevi 2014/05/08 20:52:04 Document
pneubeck (no reviews) 2014/05/14 15:01:49 Done.
+
+ private:
+ scoped_ptr<api_epki::GenerateKey::Params> params_;
+ GenerateKeyCallback callback_;
+ 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);
Ryan Sleevi 2014/05/08 20:52:04 Document
pneubeck (no reviews) 2014/05/14 15:01:49 Done.
+
+ 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);
Ryan Sleevi 2014/05/08 20:52:04 Document
pneubeck (no reviews) 2014/05/14 15:01:49 Done.
+ 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);
Ryan Sleevi 2014/05/08 20:52:04 Document
pneubeck (no reviews) 2014/05/14 15:01:49 Done.
+
+ 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);
Ryan Sleevi 2014/05/08 20:52:04 Document
pneubeck (no reviews) 2014/05/14 15:01:49 Done.
+
+ private:
+ scoped_ptr<api_epk::RemoveCertificate::Params> params_;
+ base::WeakPtrFactory<RemoveCertificate> weak_factory_;
+};
+
+GenerateKey::GenerateKey(scoped_ptr<api_epki::GenerateKey::Params> params,
+ const GenerateKeyCallback& callback,
+ const TokenMethod::ErrorCallback& error_callback,
+ Profile* profile)
+ : TokenMethod(error_callback, profile),
+ params_(params.Pass()),
+ callback_(callback),
+ weak_factory_(this) {
+}
+
+void GenerateKey::Run() {
+ GetCertDatabase(
+ params_->token_id,
+ base::Bind(&GenerateKey::DidGetDB, weak_factory_.GetWeakPtr()),
+ error_callback_,
+ profile_);
+}
+
+void GenerateKey::DidGetDB(crypto::ScopedPK11Slot slot,
+ net::NSSCertDatabase* cert_db) {
+ const int modulus_length = params_->modulus_length;
+ if (modulus_length > 2048) {
Ryan Sleevi 2014/05/08 20:52:04 Why do this check here? Is it because the TPM doe
pneubeck (no reviews) 2014/05/14 15:01:49 RSAPrivateKey seems to understand 'sensitive' as '
Ryan Sleevi 2014/05/15 19:57:13 Hrm. I really wish Chaps used separate slots then,
+ error_callback_.Run(kErrorAlgorithmNotSupported);
+ return;
+ }
+ scoped_ptr<crypto::RSAPrivateKey> rsa_key(
+ crypto::RSAPrivateKey::CreateSensitive(slot.get(), modulus_length));
Ryan Sleevi 2014/05/08 20:52:04 What thread will this run on? It will block whatev
pneubeck (no reviews) 2014/05/14 15:01:49 Yes, I still have to move that to another thread.
Ryan Sleevi 2014/05/15 19:57:13 I don't think we should enable this API until that
+ if (!rsa_key) {
+ LOG(ERROR) << "Couldn't create key.";
+ error_callback_.Run(kErrorInternal);
+ return;
+ }
+
+ std::vector<uint8> public_key_der;
+ if (!rsa_key->ExportPublicKey(&public_key_der)) {
Ryan Sleevi 2014/05/08 20:52:04 Don't use this function if you want this API to be
pneubeck (no reviews) 2014/05/14 15:01:49 Hm. I thought about this one too and stopped inves
Ryan Sleevi 2014/05/15 19:57:13 Yeah, I did. Thanks for digging in.
+ // TODO(pneubeck): Remove rsa_key from storage.
+ LOG(ERROR) << "Couldn't export public key.";
+ error_callback_.Run(kErrorInternal);
+ return;
+ }
+ std::string public_key_der_str(public_key_der.begin(), public_key_der.end());
+ callback_.Run(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,
Ryan Sleevi 2014/05/08 20:52:04 Should this class be "RSASign", since you've coupl
pneubeck (no reviews) 2014/05/14 15:01:49 Done.
+ 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);
Ryan Sleevi 2014/05/08 20:52:04 delete?
pneubeck (no reviews) 2014/05/14 15:01:49 Done.
+ 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);
Ryan Sleevi 2014/05/08 20:52:04 delete?
pneubeck (no reviews) 2014/05/14 15:01:49 Done.
+}
+
+ImportCertificate::ImportCertificate(
+ scoped_ptr<api_epk::ImportCertificate::Params> params,
+ EnterprisePlatformKeysTokenMethodExtensionFunction* func)
+ : TokenMethod(func), params_(params.Pass()), weak_factory_(this) {
Ryan Sleevi 2014/05/08 20:52:04 git cl format will show this is bad style.
pneubeck (no reviews) 2014/05/14 15:01:49 sorry to disappoint you, it doesn't. I can change
+}
+
+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,
+ const GenerateKeyCallback& callback,
+ const TokenMethod::ErrorCallback& error_callback,
+ Profile* profile) {
+ return scoped_ptr<TokenMethod>(
+ new GenerateKey(params.Pass(), callback, error_callback, profile));
+}
+
+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

Powered by Google App Engine
This is Rietveld 408576698