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

Unified Diff: chrome/browser/chromeos/platform_keys/platform_keys_nss.cc

Issue 884073002: Implement chrome.platformKeys.getKeyPair(). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@cert_impl2
Patch Set: Rebased. Created 5 years, 10 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/chromeos/platform_keys/platform_keys_nss.cc
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc b/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc
index e9e32558b2818ee555c57f4988ac945b1ae05177..978f1159a37f207e3f423299d7f192ba427e5813 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc
@@ -4,7 +4,10 @@
#include "chrome/browser/chromeos/platform_keys/platform_keys.h"
+#include <cert.h>
#include <cryptohi.h>
+#include <keyhi.h>
+#include <secder.h>
#include "base/bind.h"
#include "base/bind_helpers.h"
@@ -14,6 +17,7 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
#include "base/thread_task_runner_handle.h"
#include "base/threading/worker_pool.h"
#include "chrome/browser/browser_process.h"
@@ -33,6 +37,7 @@
#include "net/cert/cert_database.h"
#include "net/cert/nss_cert_database.h"
#include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util_nss.h"
#include "net/ssl/client_cert_store_chromeos.h"
#include "net/ssl/ssl_cert_request_info.h"
@@ -168,13 +173,14 @@ class GenerateRSAKeyState : public NSSOperationState {
subtle::GenerateKeyCallback callback_;
};
-class SignState : public NSSOperationState {
+class SignRSAState : public NSSOperationState {
public:
- SignState(const std::string& public_key,
- HashAlgorithm hash_algorithm,
- const std::string& data,
- const subtle::SignCallback& callback);
- ~SignState() override {}
+ SignRSAState(const std::string& data,
+ const std::string& public_key,
+ bool sign_direct_pkcs_padded,
+ HashAlgorithm hash_algorithm,
+ const subtle::SignCallback& callback);
+ ~SignRSAState() override {}
void OnError(const tracked_objects::Location& from,
const std::string& error_message) override {
@@ -188,10 +194,21 @@ class SignState : public NSSOperationState {
from, base::Bind(callback_, signature, error_message));
}
- const std::string public_key_;
- HashAlgorithm hash_algorithm_;
+ // The data that will be signed.
const std::string data_;
+ // Must be the DER encoding of a SubjectPublicKeyInfo.
+ const std::string public_key_;
+
+ // If true, |data_| will not be hashed before signing. Only PKCS#1 v1.5
+ // padding will be applied before signing.
+ // If false, |hash_algorithm_| must be set to a value != NONE.
+ const bool sign_direct_pkcs_padded_;
+
+ // Determines the hash algorithm that is used to digest |data| before signing.
+ // Ignored if |sign_direct_pkcs_padded_| is true.
+ const HashAlgorithm hash_algorithm_;
+
private:
// Must be called on origin thread, therefore use CallBack().
subtle::SignCallback callback_;
@@ -202,7 +219,7 @@ class SelectCertificatesState : public NSSOperationState {
explicit SelectCertificatesState(
const std::string& username_hash,
const bool use_system_key_slot,
- scoped_refptr<net::SSLCertRequestInfo> request,
+ const scoped_refptr<net::SSLCertRequestInfo>& request,
const subtle::SelectCertificatesCallback& callback);
~SelectCertificatesState() override {}
@@ -258,7 +275,7 @@ class GetCertificatesState : public NSSOperationState {
class ImportCertificateState : public NSSOperationState {
public:
- ImportCertificateState(scoped_refptr<net::X509Certificate> certificate,
+ ImportCertificateState(const scoped_refptr<net::X509Certificate>& certificate,
const ImportCertificateCallback& callback);
~ImportCertificateState() override {}
@@ -281,7 +298,7 @@ class ImportCertificateState : public NSSOperationState {
class RemoveCertificateState : public NSSOperationState {
public:
- RemoveCertificateState(scoped_refptr<net::X509Certificate> certificate,
+ RemoveCertificateState(const scoped_refptr<net::X509Certificate>& certificate,
const RemoveCertificateCallback& callback);
~RemoveCertificateState() override {}
@@ -336,20 +353,22 @@ GenerateRSAKeyState::GenerateRSAKeyState(
: modulus_length_bits_(modulus_length_bits), callback_(callback) {
}
-SignState::SignState(const std::string& public_key,
- HashAlgorithm hash_algorithm,
- const std::string& data,
- const subtle::SignCallback& callback)
- : public_key_(public_key),
+SignRSAState::SignRSAState(const std::string& data,
+ const std::string& public_key,
+ bool sign_direct_pkcs_padded,
+ HashAlgorithm hash_algorithm,
+ const subtle::SignCallback& callback)
+ : data_(data),
+ public_key_(public_key),
+ sign_direct_pkcs_padded_(sign_direct_pkcs_padded),
hash_algorithm_(hash_algorithm),
- data_(data),
callback_(callback) {
}
SelectCertificatesState::SelectCertificatesState(
const std::string& username_hash,
const bool use_system_key_slot,
- scoped_refptr<net::SSLCertRequestInfo> cert_request_info,
+ const scoped_refptr<net::SSLCertRequestInfo>& cert_request_info,
const subtle::SelectCertificatesCallback& callback)
: username_hash_(username_hash),
use_system_key_slot_(use_system_key_slot),
@@ -363,13 +382,13 @@ GetCertificatesState::GetCertificatesState(
}
ImportCertificateState::ImportCertificateState(
- scoped_refptr<net::X509Certificate> certificate,
+ const scoped_refptr<net::X509Certificate>& certificate,
const ImportCertificateCallback& callback)
: certificate_(certificate), callback_(callback) {
}
RemoveCertificateState::RemoveCertificateState(
- scoped_refptr<net::X509Certificate> certificate,
+ const scoped_refptr<net::X509Certificate>& certificate,
const RemoveCertificateCallback& callback)
: certificate_(certificate), callback_(callback) {
}
@@ -415,8 +434,8 @@ void GenerateRSAKeyWithDB(scoped_ptr<GenerateRSAKeyState> state,
true /*task is slow*/);
}
-// Does the actual signing on a worker thread. Used by RSASignWithDB().
-void RSASignOnWorkerThread(scoped_ptr<SignState> state) {
+// Does the actual signing on a worker thread. Used by SignRSAWithDB().
+void SignRSAOnWorkerThread(scoped_ptr<SignRSAState> state) {
const uint8* public_key_uint8 =
reinterpret_cast<const uint8*>(state->public_key_.data());
std::vector<uint8> public_key_vector(
@@ -425,50 +444,83 @@ void RSASignOnWorkerThread(scoped_ptr<SignState> state) {
// 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 || rsa_key->key()->pkcs11Slot != state->slot_) {
+
+ // Fail if the key was not found. If a specific slot was requested, also fail
+ // if the key was found in the wrong slot.
+ if (!rsa_key ||
+ (state->slot_ && rsa_key->key()->pkcs11Slot != state->slot_)) {
state->OnError(FROM_HERE, kErrorKeyNotFound);
return;
}
- SECOidTag sign_alg_tag = SEC_OID_UNKNOWN;
- switch (state->hash_algorithm_) {
- case HASH_ALGORITHM_SHA1:
- sign_alg_tag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
- break;
- case HASH_ALGORITHM_SHA256:
- sign_alg_tag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
- break;
- case HASH_ALGORITHM_SHA384:
- sign_alg_tag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
- break;
- case HASH_ALGORITHM_SHA512:
- sign_alg_tag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
- break;
- }
-
- crypto::ScopedSECItem sign_result(SECITEM_AllocItem(NULL, NULL, 0));
- if (SEC_SignData(sign_result.get(),
- reinterpret_cast<const unsigned char*>(state->data_.data()),
- state->data_.size(),
- rsa_key->key(),
- sign_alg_tag) != SECSuccess) {
+ std::string signature_str;
+ if (state->sign_direct_pkcs_padded_) {
+ static_assert(
+ sizeof(*state->data_.data()) == sizeof(char),
+ "Can't reinterpret data if it's characters are not 8 bit large.");
+ SECItem input = {siBuffer,
+ reinterpret_cast<unsigned char*>(
+ const_cast<char*>(state->data_.data())),
+ state->data_.size()};
+
+ // Compute signature of hash.
+ int signature_len = PK11_SignatureLen(rsa_key->key());
+ if (signature_len <= 0) {
+ state->OnError(FROM_HERE, kErrorInternal);
+ return;
+ }
+
+ std::vector<unsigned char> signature(signature_len);
+ SECItem signature_output = {
+ siBuffer, vector_as_array(&signature), signature.size()};
+ if (PK11_Sign(rsa_key->key(), &signature_output, &input) == SECSuccess)
+ signature_str.assign(signature.begin(), signature.end());
+ } else {
+ SECOidTag sign_alg_tag = SEC_OID_UNKNOWN;
+ switch (state->hash_algorithm_) {
+ case HASH_ALGORITHM_SHA1:
+ sign_alg_tag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
+ break;
+ case HASH_ALGORITHM_SHA256:
+ sign_alg_tag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
+ break;
+ case HASH_ALGORITHM_SHA384:
+ sign_alg_tag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
+ break;
+ case HASH_ALGORITHM_SHA512:
+ sign_alg_tag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
+ break;
+ case HASH_ALGORITHM_NONE:
+ NOTREACHED();
+ break;
+ }
+
+ SECItem sign_result = {siBuffer, nullptr, 0};
+ if (SEC_SignData(
+ &sign_result,
+ reinterpret_cast<const unsigned char*>(state->data_.data()),
+ state->data_.size(), rsa_key->key(), sign_alg_tag) == SECSuccess) {
+ signature_str.assign(sign_result.data,
+ sign_result.data + sign_result.len);
+ }
+ }
+
+ if (signature_str.empty()) {
LOG(ERROR) << "Couldn't sign.";
state->OnError(FROM_HERE, kErrorInternal);
return;
}
- std::string signature(reinterpret_cast<const char*>(sign_result->data),
- sign_result->len);
- state->CallBack(FROM_HERE, signature, std::string() /* no error */);
+ state->CallBack(FROM_HERE, signature_str, std::string() /* no error */);
}
// Continues signing with the obtained NSSCertDatabase. Used by Sign().
-void RSASignWithDB(scoped_ptr<SignState> state, net::NSSCertDatabase* cert_db) {
+void SignRSAWithDB(scoped_ptr<SignRSAState> state,
+ net::NSSCertDatabase* cert_db) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
// Only the slot and not the NSSCertDatabase is required. Ignore |cert_db|.
base::WorkerPool::PostTask(
- FROM_HERE,
- base::Bind(&RSASignOnWorkerThread, base::Passed(&state)),
+ FROM_HERE, base::Bind(&SignRSAOnWorkerThread, base::Passed(&state)),
true /*task is slow*/);
}
@@ -655,25 +707,43 @@ void GenerateRSAKey(const std::string& token_id,
state_ptr);
}
-void Sign(const std::string& token_id,
- const std::string& public_key,
- HashAlgorithm hash_algorithm,
- const std::string& data,
- const SignCallback& callback,
- BrowserContext* browser_context) {
+void SignRSAPKCS1Digest(const std::string& token_id,
+ const std::string& data,
+ const std::string& public_key,
+ HashAlgorithm hash_algorithm,
+ const SignCallback& callback,
+ content::BrowserContext* browser_context) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- scoped_ptr<SignState> state(
- new SignState(public_key, hash_algorithm, data, callback));
+ scoped_ptr<SignRSAState> state(
+ new SignRSAState(data, public_key, false /* digest before signing */,
+ hash_algorithm, callback));
// Get the pointer to |state| before base::Passed releases |state|.
NSSOperationState* state_ptr = state.get();
// The NSSCertDatabase object is not required. But in case it's not available
// we would get more informative error messages and we can double check that
// we use a key of the correct token.
- GetCertDatabase(token_id,
- base::Bind(&RSASignWithDB, base::Passed(&state)),
- browser_context,
- state_ptr);
+ GetCertDatabase(token_id, base::Bind(&SignRSAWithDB, base::Passed(&state)),
+ browser_context, state_ptr);
+}
+
+void SignRSAPKCS1Raw(const std::string& token_id,
+ const std::string& data,
+ const std::string& public_key,
+ const SignCallback& callback,
+ content::BrowserContext* browser_context) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ scoped_ptr<SignRSAState> state(new SignRSAState(
+ data, public_key, true /* sign directly without hashing */,
+ HASH_ALGORITHM_NONE, callback));
+ // Get the pointer to |state| before base::Passed releases |state|.
+ NSSOperationState* state_ptr = state.get();
+
+ // The NSSCertDatabase object is not required. But in case it's not available
+ // we would get more informative error messages and we can double check that
+ // we use a key of the correct token.
+ GetCertDatabase(token_id, base::Bind(&SignRSAWithDB, base::Passed(&state)),
+ browser_context, state_ptr);
}
void SelectClientCertificates(const ClientCertificateRequest& request,
@@ -706,6 +776,46 @@ void SelectClientCertificates(const ClientCertificateRequest& request,
} // namespace subtle
+bool GetPublicKey(const scoped_refptr<net::X509Certificate>& certificate,
+ std::string* public_key_spki_der,
+ net::X509Certificate::PublicKeyType* key_type,
+ size_t* key_size_bits) {
+ const SECItem& spki_der = certificate->os_cert_handle()->derPublicKey;
+
+ net::X509Certificate::PublicKeyType key_type_tmp =
+ net::X509Certificate::kPublicKeyTypeUnknown;
+ size_t key_size_bits_tmp = 0;
+ net::X509Certificate::GetPublicKeyInfo(certificate->os_cert_handle(),
+ &key_size_bits_tmp, &key_type_tmp);
+
+ if (key_type_tmp == net::X509Certificate::kPublicKeyTypeUnknown) {
+ LOG(WARNING) << "Could not extract public key of certificate.";
+ return false;
+ }
+ if (key_type_tmp != net::X509Certificate::kPublicKeyTypeRSA) {
+ LOG(WARNING) << "Keys of other type than RSA are not supported.";
+ return false;
+ }
+
+ crypto::ScopedSECKEYPublicKey public_key(
+ CERT_ExtractPublicKey(certificate->os_cert_handle()));
+ if (!public_key) {
+ LOG(WARNING) << "Could not extract public key of certificate.";
+ return false;
+ }
+ long public_exponent = DER_GetInteger(&public_key->u.rsa.publicExponent);
+ if (public_exponent != 65537L) {
+ LOG(ERROR) << "Rejecting RSA public exponent that is unequal 65537.";
+ return false;
+ }
+
+ public_key_spki_der->assign(spki_der.data, spki_der.data + spki_der.len);
+ *key_type = key_type_tmp;
+ *key_size_bits = key_size_bits_tmp;
+
+ return true;
+}
+
void GetCertificates(const std::string& token_id,
const GetCertificatesCallback& callback,
BrowserContext* browser_context) {
@@ -720,7 +830,7 @@ void GetCertificates(const std::string& token_id,
}
void ImportCertificate(const std::string& token_id,
- scoped_refptr<net::X509Certificate> certificate,
+ const scoped_refptr<net::X509Certificate>& certificate,
const ImportCertificateCallback& callback,
BrowserContext* browser_context) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -739,7 +849,7 @@ void ImportCertificate(const std::string& token_id,
}
void RemoveCertificate(const std::string& token_id,
- scoped_refptr<net::X509Certificate> certificate,
+ const scoped_refptr<net::X509Certificate>& certificate,
const RemoveCertificateCallback& callback,
BrowserContext* browser_context) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
« no previous file with comments | « chrome/browser/chromeos/platform_keys/platform_keys.h ('k') | chrome/browser/chromeos/platform_keys/platform_keys_service.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698