Chromium Code Reviews| 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..ee167b6e6856b151639434bbb22e7bb821e22a4c 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,11 @@ 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(scoped_ptr<SignRSAParams> params, |
| + const subtle::SignCallback& callback); |
| + ~SignRSAState() override {} |
| void OnError(const tracked_objects::Location& from, |
| const std::string& error_message) override { |
| @@ -188,9 +191,7 @@ class SignState : public NSSOperationState { |
| from, base::Bind(callback_, signature, error_message)); |
| } |
| - const std::string public_key_; |
| - HashAlgorithm hash_algorithm_; |
| - const std::string data_; |
| + scoped_ptr<SignRSAParams> params_; |
| private: |
| // Must be called on origin thread, therefore use CallBack(). |
| @@ -336,14 +337,9 @@ 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), |
| - hash_algorithm_(hash_algorithm), |
| - data_(data), |
| - callback_(callback) { |
| +SignRSAState::SignRSAState(scoped_ptr<SignRSAParams> params, |
| + const subtle::SignCallback& callback) |
| + : params_(params.Pass()), callback_(callback) { |
| } |
| SelectCertificatesState::SelectCertificatesState( |
| @@ -415,60 +411,87 @@ 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 SignRSAParams& params = *state->params_; |
| const uint8* public_key_uint8 = |
| - reinterpret_cast<const uint8*>(state->public_key_.data()); |
| + reinterpret_cast<const uint8*>(params.public_key.data()); |
| std::vector<uint8> public_key_vector( |
| - public_key_uint8, public_key_uint8 + state->public_key_.size()); |
| + public_key_uint8, public_key_uint8 + params.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 || 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; |
| + std::vector<unsigned char> data_vec(params.data.begin(), params.data.end()); |
| + std::string signature_str; |
| + if (params.sign_direct_pkcs_padded) { |
| + SECItem input = {siBuffer, vector_as_array(&data_vec), data_vec.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 (params.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: |
|
Ryan Sleevi
2015/02/07 02:09:40
Add a default? Or are we relying on the compiler t
pneubeck (no reviews)
2015/02/08 10:52:00
yes it will.
'default' prevents the completeness c
|
| + NOTREACHED(); |
| + break; |
| + } |
| + |
| + SECItem sign_result = {siBuffer, nullptr, 0}; |
| + if (SEC_SignData(&sign_result, vector_as_array(&data_vec), data_vec.size(), |
| + rsa_key->key(), sign_alg_tag) == SECSuccess) { |
| + signature_str.assign(sign_result.data, |
| + sign_result.data + sign_result.len); |
| + } |
| } |
| - 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) { |
| + 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 +678,20 @@ 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 SignRSA(const std::string& token_id, |
| + scoped_ptr<SignRSAParams> params, |
| + const SignCallback& callback, |
| + 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(params.Pass(), 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 SelectClientCertificates(const ClientCertificateRequest& request, |
| @@ -706,6 +724,38 @@ void SelectClientCertificates(const ClientCertificateRequest& request, |
| } // namespace subtle |
| +bool GetPublicKey(scoped_refptr<net::X509Certificate> certificate, |
| + SubjectPublicKeyInfo* info) { |
| + const SECItem& spki_der = certificate->os_cert_handle()->derPublicKey; |
| + |
| + *info = SubjectPublicKeyInfo(); |
| + info->public_key_spki_der.assign(spki_der.data, spki_der.data + spki_der.len); |
| + |
| + net::X509Certificate::GetPublicKeyInfo(certificate->os_cert_handle(), |
| + &info->key_size_bits, &info->key_type); |
| + |
| + if (info->key_type == net::X509Certificate::kPublicKeyTypeUnknown) { |
| + LOG(WARNING) << "Could not extract public key of certificate."; |
| + return false; |
| + } |
| + if (info->key_type == net::X509Certificate::kPublicKeyTypeRSA) { |
| + // TODO(pneubeck): Verify that the public exponent equals 65537. |
| + |
| + 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; |
| + } |
| + } |
| + return true; |
| +} |
| + |
| void GetCertificates(const std::string& token_id, |
| const GetCertificatesCallback& callback, |
| BrowserContext* browser_context) { |