1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/chromeos/platform_keys/platform_keys.h"
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/callback.h"
15 #include "base/compiler_specific.h"
16 #include "base/location.h"
17 #include "base/logging.h"
18 #include "base/macros.h"
19 #include "base/single_thread_task_runner.h"
20 #include "base/stl_util.h"
21 #include "base/thread_task_runner_handle.h"
22 #include "base/threading/worker_pool.h"
23 #include "chrome/browser/browser_process.h"
24 #include "chrome/browser/browser_process_platform_part_chromeos.h"
25 #include "chrome/browser/chromeos/net/client_cert_filter_chromeos.h"
26 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
27 #include "chrome/browser/chromeos/profiles/profile_helper.h"
28 #include "chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.h"
29 #include "chrome/browser/net/nss_context.h"
30 #include "chrome/browser/profiles/profile.h"
31 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
32 #include "content/public/browser/browser_context.h"
33 #include "content/public/browser/browser_thread.h"
34 #include "crypto/rsa_private_key.h"
35 #include "net/base/crypto_module.h"
36 #include "net/base/net_errors.h"
37 #include "net/cert/cert_database.h"
38 #include "net/cert/nss_cert_database.h"
39 #include "net/cert/x509_certificate.h"
40 #include "net/cert/x509_util_nss.h"
41 #include "net/ssl/client_cert_store_chromeos.h"
42 #include "net/ssl/ssl_cert_request_info.h"
44 using content::BrowserContext
;
45 using content::BrowserThread
;
48 const char kErrorInternal
[] = "Internal Error.";
49 const char kErrorKeyNotFound
[] = "Key not found.";
50 const char kErrorCertificateNotFound
[] = "Certificate could not be found.";
51 const char kErrorAlgorithmNotSupported
[] = "Algorithm not supported.";
53 // The current maximal RSA modulus length that ChromeOS's TPM supports for key
55 const unsigned int kMaxRSAModulusLengthBits
= 2048;
60 namespace platform_keys
{
64 // Base class to store state that is common to all NSS database operations and
65 // to provide convenience methods to call back.
66 // Keeps track of the originating task runner.
67 class NSSOperationState
{
70 virtual ~NSSOperationState() {}
72 // Called if an error occurred during the execution of the NSS operation
73 // described by this object.
74 virtual void OnError(const tracked_objects::Location
& from
,
75 const std::string
& error_message
) = 0;
77 crypto::ScopedPK11Slot slot_
;
79 // The task runner on which the NSS operation was called. Any reply must be
80 // posted to this runner.
81 scoped_refptr
<base::SingleThreadTaskRunner
> origin_task_runner_
;
84 DISALLOW_COPY_AND_ASSIGN(NSSOperationState
);
87 typedef base::Callback
<void(net::NSSCertDatabase
* cert_db
)> GetCertDBCallback
;
89 // Used by GetCertDatabaseOnIOThread and called back with the requested
91 // If |token_id| is not empty, sets |slot_| of |state| accordingly and calls
92 // |callback| if the database was successfully retrieved.
93 void DidGetCertDBOnIOThread(const std::string
& token_id
,
94 const GetCertDBCallback
& callback
,
95 NSSOperationState
* state
,
96 net::NSSCertDatabase
* cert_db
) {
97 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
99 LOG(ERROR
) << "Couldn't get NSSCertDatabase.";
100 state
->OnError(FROM_HERE
, kErrorInternal
);
104 if (!token_id
.empty()) {
105 if (token_id
== kTokenIdUser
)
106 state
->slot_
= cert_db
->GetPrivateSlot();
107 else if (token_id
== kTokenIdSystem
)
108 state
->slot_
= cert_db
->GetSystemSlot();
111 LOG(ERROR
) << "Slot for token id '" << token_id
<< "' not available.";
112 state
->OnError(FROM_HERE
, kErrorInternal
);
117 callback
.Run(cert_db
);
120 // Retrieves the NSSCertDatabase from |context| and, if |token_id| is not empty,
121 // the slot for |token_id|.
122 // Must be called on the IO thread.
123 void GetCertDatabaseOnIOThread(const std::string
& token_id
,
124 const GetCertDBCallback
& callback
,
125 content::ResourceContext
* context
,
126 NSSOperationState
* state
) {
127 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
128 net::NSSCertDatabase
* cert_db
= GetNSSCertDatabaseForResourceContext(
129 context
, base::Bind(&DidGetCertDBOnIOThread
, token_id
, callback
, state
));
132 DidGetCertDBOnIOThread(token_id
, callback
, state
, cert_db
);
135 // Asynchronously fetches the NSSCertDatabase for |browser_context| and, if
136 // |token_id| is not empty, the slot for |token_id|. Stores the slot in |state|
137 // and passes the database to |callback|. Will run |callback| on the IO thread.
138 void GetCertDatabase(const std::string
& token_id
,
139 const GetCertDBCallback
& callback
,
140 BrowserContext
* browser_context
,
141 NSSOperationState
* state
) {
142 BrowserThread::PostTask(BrowserThread::IO
,
144 base::Bind(&GetCertDatabaseOnIOThread
,
147 browser_context
->GetResourceContext(),
151 class GenerateRSAKeyState
: public NSSOperationState
{
153 GenerateRSAKeyState(unsigned int modulus_length_bits
,
154 const subtle::GenerateKeyCallback
& callback
);
155 ~GenerateRSAKeyState() override
{}
157 void OnError(const tracked_objects::Location
& from
,
158 const std::string
& error_message
) override
{
159 CallBack(from
, std::string() /* no public key */, error_message
);
162 void CallBack(const tracked_objects::Location
& from
,
163 const std::string
& public_key_spki_der
,
164 const std::string
& error_message
) {
165 origin_task_runner_
->PostTask(
166 from
, base::Bind(callback_
, public_key_spki_der
, error_message
));
169 const unsigned int modulus_length_bits_
;
172 // Must be called on origin thread, therefore use CallBack().
173 subtle::GenerateKeyCallback callback_
;
176 class SignRSAState
: public NSSOperationState
{
178 SignRSAState(const std::string
& data
,
179 const std::string
& public_key
,
180 bool sign_direct_pkcs_padded
,
181 HashAlgorithm hash_algorithm
,
182 const subtle::SignCallback
& callback
);
183 ~SignRSAState() override
{}
185 void OnError(const tracked_objects::Location
& from
,
186 const std::string
& error_message
) override
{
187 CallBack(from
, std::string() /* no signature */, error_message
);
190 void CallBack(const tracked_objects::Location
& from
,
191 const std::string
& signature
,
192 const std::string
& error_message
) {
193 origin_task_runner_
->PostTask(
194 from
, base::Bind(callback_
, signature
, error_message
));
197 // The data that will be signed.
198 const std::string data_
;
200 // Must be the DER encoding of a SubjectPublicKeyInfo.
201 const std::string public_key_
;
203 // If true, |data_| will not be hashed before signing. Only PKCS#1 v1.5
204 // padding will be applied before signing.
205 // If false, |hash_algorithm_| must be set to a value != NONE.
206 const bool sign_direct_pkcs_padded_
;
208 // Determines the hash algorithm that is used to digest |data| before signing.
209 // Ignored if |sign_direct_pkcs_padded_| is true.
210 const HashAlgorithm hash_algorithm_
;
213 // Must be called on origin thread, therefore use CallBack().
214 subtle::SignCallback callback_
;
217 class SelectCertificatesState
: public NSSOperationState
{
219 explicit SelectCertificatesState(
220 const std::string
& username_hash
,
221 const bool use_system_key_slot
,
222 const scoped_refptr
<net::SSLCertRequestInfo
>& request
,
223 const subtle::SelectCertificatesCallback
& callback
);
224 ~SelectCertificatesState() override
{}
226 void OnError(const tracked_objects::Location
& from
,
227 const std::string
& error_message
) override
{
228 CallBack(from
, scoped_ptr
<net::CertificateList
>() /* no matches */,
232 void CallBack(const tracked_objects::Location
& from
,
233 scoped_ptr
<net::CertificateList
> matches
,
234 const std::string
& error_message
) {
235 origin_task_runner_
->PostTask(
236 from
, base::Bind(callback_
, base::Passed(&matches
), error_message
));
239 const std::string username_hash_
;
240 const bool use_system_key_slot_
;
241 scoped_refptr
<net::SSLCertRequestInfo
> cert_request_info_
;
242 scoped_ptr
<net::ClientCertStore
> cert_store_
;
243 scoped_ptr
<net::CertificateList
> certs_
;
246 // Must be called on origin thread, therefore use CallBack().
247 subtle::SelectCertificatesCallback callback_
;
250 class GetCertificatesState
: public NSSOperationState
{
252 explicit GetCertificatesState(const GetCertificatesCallback
& callback
);
253 ~GetCertificatesState() override
{}
255 void OnError(const tracked_objects::Location
& from
,
256 const std::string
& error_message
) override
{
258 scoped_ptr
<net::CertificateList
>() /* no certificates */,
262 void CallBack(const tracked_objects::Location
& from
,
263 scoped_ptr
<net::CertificateList
> certs
,
264 const std::string
& error_message
) {
265 origin_task_runner_
->PostTask(
266 from
, base::Bind(callback_
, base::Passed(&certs
), error_message
));
269 scoped_ptr
<net::CertificateList
> certs_
;
272 // Must be called on origin thread, therefore use CallBack().
273 GetCertificatesCallback callback_
;
276 class ImportCertificateState
: public NSSOperationState
{
278 ImportCertificateState(const scoped_refptr
<net::X509Certificate
>& certificate
,
279 const ImportCertificateCallback
& callback
);
280 ~ImportCertificateState() override
{}
282 void OnError(const tracked_objects::Location
& from
,
283 const std::string
& error_message
) override
{
284 CallBack(from
, error_message
);
287 void CallBack(const tracked_objects::Location
& from
,
288 const std::string
& error_message
) {
289 origin_task_runner_
->PostTask(from
, base::Bind(callback_
, error_message
));
292 scoped_refptr
<net::X509Certificate
> certificate_
;
295 // Must be called on origin thread, therefore use CallBack().
296 ImportCertificateCallback callback_
;
299 class RemoveCertificateState
: public NSSOperationState
{
301 RemoveCertificateState(const scoped_refptr
<net::X509Certificate
>& certificate
,
302 const RemoveCertificateCallback
& callback
);
303 ~RemoveCertificateState() override
{}
305 void OnError(const tracked_objects::Location
& from
,
306 const std::string
& error_message
) override
{
307 CallBack(from
, error_message
);
310 void CallBack(const tracked_objects::Location
& from
,
311 const std::string
& error_message
) {
312 origin_task_runner_
->PostTask(from
, base::Bind(callback_
, error_message
));
315 scoped_refptr
<net::X509Certificate
> certificate_
;
318 // Must be called on origin thread, therefore use CallBack().
319 RemoveCertificateCallback callback_
;
322 class GetTokensState
: public NSSOperationState
{
324 explicit GetTokensState(const GetTokensCallback
& callback
);
325 ~GetTokensState() override
{}
327 void OnError(const tracked_objects::Location
& from
,
328 const std::string
& error_message
) override
{
330 scoped_ptr
<std::vector
<std::string
> >() /* no token ids */,
334 void CallBack(const tracked_objects::Location
& from
,
335 scoped_ptr
<std::vector
<std::string
> > token_ids
,
336 const std::string
& error_message
) {
337 origin_task_runner_
->PostTask(
338 from
, base::Bind(callback_
, base::Passed(&token_ids
), error_message
));
342 // Must be called on origin thread, therefore use CallBack().
343 GetTokensCallback callback_
;
346 NSSOperationState::NSSOperationState()
347 : origin_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
350 GenerateRSAKeyState::GenerateRSAKeyState(
351 unsigned int modulus_length_bits
,
352 const subtle::GenerateKeyCallback
& callback
)
353 : modulus_length_bits_(modulus_length_bits
), callback_(callback
) {
356 SignRSAState::SignRSAState(const std::string
& data
,
357 const std::string
& public_key
,
358 bool sign_direct_pkcs_padded
,
359 HashAlgorithm hash_algorithm
,
360 const subtle::SignCallback
& callback
)
362 public_key_(public_key
),
363 sign_direct_pkcs_padded_(sign_direct_pkcs_padded
),
364 hash_algorithm_(hash_algorithm
),
365 callback_(callback
) {
368 SelectCertificatesState::SelectCertificatesState(
369 const std::string
& username_hash
,
370 const bool use_system_key_slot
,
371 const scoped_refptr
<net::SSLCertRequestInfo
>& cert_request_info
,
372 const subtle::SelectCertificatesCallback
& callback
)
373 : username_hash_(username_hash
),
374 use_system_key_slot_(use_system_key_slot
),
375 cert_request_info_(cert_request_info
),
376 callback_(callback
) {
379 GetCertificatesState::GetCertificatesState(
380 const GetCertificatesCallback
& callback
)
381 : callback_(callback
) {
384 ImportCertificateState::ImportCertificateState(
385 const scoped_refptr
<net::X509Certificate
>& certificate
,
386 const ImportCertificateCallback
& callback
)
387 : certificate_(certificate
), callback_(callback
) {
390 RemoveCertificateState::RemoveCertificateState(
391 const scoped_refptr
<net::X509Certificate
>& certificate
,
392 const RemoveCertificateCallback
& callback
)
393 : certificate_(certificate
), callback_(callback
) {
396 GetTokensState::GetTokensState(const GetTokensCallback
& callback
)
397 : callback_(callback
) {
400 // Does the actual key generation on a worker thread. Used by
401 // GenerateRSAKeyWithDB().
402 void GenerateRSAKeyOnWorkerThread(scoped_ptr
<GenerateRSAKeyState
> state
) {
403 scoped_ptr
<crypto::RSAPrivateKey
> rsa_key(
404 crypto::RSAPrivateKey::CreateSensitive(state
->slot_
.get(),
405 state
->modulus_length_bits_
));
407 LOG(ERROR
) << "Couldn't create key.";
408 state
->OnError(FROM_HERE
, kErrorInternal
);
412 std::vector
<uint8
> public_key_spki_der
;
413 if (!rsa_key
->ExportPublicKey(&public_key_spki_der
)) {
414 // TODO(pneubeck): Remove rsa_key from storage.
415 LOG(ERROR
) << "Couldn't export public key.";
416 state
->OnError(FROM_HERE
, kErrorInternal
);
421 std::string(public_key_spki_der
.begin(), public_key_spki_der
.end()),
422 std::string() /* no error */);
425 // Continues generating a RSA key with the obtained NSSCertDatabase. Used by
427 void GenerateRSAKeyWithDB(scoped_ptr
<GenerateRSAKeyState
> state
,
428 net::NSSCertDatabase
* cert_db
) {
429 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
430 // Only the slot and not the NSSCertDatabase is required. Ignore |cert_db|.
431 base::WorkerPool::PostTask(
433 base::Bind(&GenerateRSAKeyOnWorkerThread
, base::Passed(&state
)),
434 true /*task is slow*/);
437 // Does the actual signing on a worker thread. Used by SignRSAWithDB().
438 void SignRSAOnWorkerThread(scoped_ptr
<SignRSAState
> state
) {
439 const uint8
* public_key_uint8
=
440 reinterpret_cast<const uint8
*>(state
->public_key_
.data());
441 std::vector
<uint8
> public_key_vector(
442 public_key_uint8
, public_key_uint8
+ state
->public_key_
.size());
444 // TODO(pneubeck): This searches all slots. Change to look only at |slot_|.
445 scoped_ptr
<crypto::RSAPrivateKey
> rsa_key(
446 crypto::RSAPrivateKey::FindFromPublicKeyInfo(public_key_vector
));
448 // Fail if the key was not found. If a specific slot was requested, also fail
449 // if the key was found in the wrong slot.
451 (state
->slot_
&& rsa_key
->key()->pkcs11Slot
!= state
->slot_
)) {
452 state
->OnError(FROM_HERE
, kErrorKeyNotFound
);
456 std::string signature_str
;
457 if (state
->sign_direct_pkcs_padded_
) {
459 sizeof(*state
->data_
.data()) == sizeof(char),
460 "Can't reinterpret data if it's characters are not 8 bit large.");
461 SECItem input
= {siBuffer
,
462 reinterpret_cast<unsigned char*>(
463 const_cast<char*>(state
->data_
.data())),
464 state
->data_
.size()};
466 // Compute signature of hash.
467 int signature_len
= PK11_SignatureLen(rsa_key
->key());
468 if (signature_len
<= 0) {
469 state
->OnError(FROM_HERE
, kErrorInternal
);
473 std::vector
<unsigned char> signature(signature_len
);
474 SECItem signature_output
= {
475 siBuffer
, vector_as_array(&signature
), signature
.size()};
476 if (PK11_Sign(rsa_key
->key(), &signature_output
, &input
) == SECSuccess
)
477 signature_str
.assign(signature
.begin(), signature
.end());
479 SECOidTag sign_alg_tag
= SEC_OID_UNKNOWN
;
480 switch (state
->hash_algorithm_
) {
481 case HASH_ALGORITHM_SHA1
:
482 sign_alg_tag
= SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION
;
484 case HASH_ALGORITHM_SHA256
:
485 sign_alg_tag
= SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION
;
487 case HASH_ALGORITHM_SHA384
:
488 sign_alg_tag
= SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION
;
490 case HASH_ALGORITHM_SHA512
:
491 sign_alg_tag
= SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION
;
493 case HASH_ALGORITHM_NONE
:
498 SECItem sign_result
= {siBuffer
, nullptr, 0};
501 reinterpret_cast<const unsigned char*>(state
->data_
.data()),
502 state
->data_
.size(), rsa_key
->key(), sign_alg_tag
) == SECSuccess
) {
503 signature_str
.assign(sign_result
.data
,
504 sign_result
.data
+ sign_result
.len
);
508 if (signature_str
.empty()) {
509 LOG(ERROR
) << "Couldn't sign.";
510 state
->OnError(FROM_HERE
, kErrorInternal
);
514 state
->CallBack(FROM_HERE
, signature_str
, std::string() /* no error */);
517 // Continues signing with the obtained NSSCertDatabase. Used by Sign().
518 void SignRSAWithDB(scoped_ptr
<SignRSAState
> state
,
519 net::NSSCertDatabase
* cert_db
) {
520 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
521 // Only the slot and not the NSSCertDatabase is required. Ignore |cert_db|.
522 base::WorkerPool::PostTask(
523 FROM_HERE
, base::Bind(&SignRSAOnWorkerThread
, base::Passed(&state
)),
524 true /*task is slow*/);
527 // Called when ClientCertStoreChromeOS::GetClientCerts is done. Builds the list
528 // of net::CertificateList and calls back. Used by
529 // SelectCertificatesOnIOThread().
530 void DidSelectCertificatesOnIOThread(
531 scoped_ptr
<SelectCertificatesState
> state
) {
532 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
533 state
->CallBack(FROM_HERE
, state
->certs_
.Pass(),
534 std::string() /* no error */);
537 // Continues selecting certificates on the IO thread. Used by
538 // SelectClientCertificates().
539 void SelectCertificatesOnIOThread(scoped_ptr
<SelectCertificatesState
> state
) {
540 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
541 state
->cert_store_
.reset(new net::ClientCertStoreChromeOS(
542 make_scoped_ptr(new chromeos::ClientCertFilterChromeOS(
543 state
->use_system_key_slot_
, state
->username_hash_
)),
544 net::ClientCertStoreChromeOS::PasswordDelegateFactory()));
546 state
->certs_
.reset(new net::CertificateList
);
548 SelectCertificatesState
* state_ptr
= state
.get();
549 state_ptr
->cert_store_
->GetClientCerts(
550 *state_ptr
->cert_request_info_
, state_ptr
->certs_
.get(),
551 base::Bind(&DidSelectCertificatesOnIOThread
, base::Passed(&state
)));
554 // Filters the obtained certificates on a worker thread. Used by
555 // DidGetCertificates().
556 void FilterCertificatesOnWorkerThread(scoped_ptr
<GetCertificatesState
> state
) {
557 scoped_ptr
<net::CertificateList
> client_certs(new net::CertificateList
);
558 for (net::CertificateList::const_iterator it
= state
->certs_
->begin();
559 it
!= state
->certs_
->end();
561 net::X509Certificate::OSCertHandle cert_handle
= (*it
)->os_cert_handle();
562 crypto::ScopedPK11Slot
cert_slot(PK11_KeyForCertExists(cert_handle
,
566 // Keep only user certificates, i.e. certs for which the private key is
567 // present and stored in the queried slot.
568 if (cert_slot
!= state
->slot_
)
571 client_certs
->push_back(*it
);
574 state
->CallBack(FROM_HERE
, client_certs
.Pass(), std::string() /* no error */);
577 // Passes the obtained certificates to the worker thread for filtering. Used by
578 // GetCertificatesWithDB().
579 void DidGetCertificates(scoped_ptr
<GetCertificatesState
> state
,
580 scoped_ptr
<net::CertificateList
> all_certs
) {
581 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
582 state
->certs_
= all_certs
.Pass();
583 base::WorkerPool::PostTask(
585 base::Bind(&FilterCertificatesOnWorkerThread
, base::Passed(&state
)),
586 true /*task is slow*/);
589 // Continues getting certificates with the obtained NSSCertDatabase. Used by
590 // GetCertificates().
591 void GetCertificatesWithDB(scoped_ptr
<GetCertificatesState
> state
,
592 net::NSSCertDatabase
* cert_db
) {
593 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
594 // Get the pointer to slot before base::Passed releases |state|.
595 PK11SlotInfo
* slot
= state
->slot_
.get();
596 cert_db
->ListCertsInSlot(
597 base::Bind(&DidGetCertificates
, base::Passed(&state
)), slot
);
600 // Does the actual certificate importing on the IO thread. Used by
601 // ImportCertificate().
602 void ImportCertificateWithDB(scoped_ptr
<ImportCertificateState
> state
,
603 net::NSSCertDatabase
* cert_db
) {
604 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
605 // TODO(pneubeck): Use |state->slot_| to verify that we're really importing to
606 // the correct token.
607 // |cert_db| is not required, ignore it.
608 net::CertDatabase
* db
= net::CertDatabase::GetInstance();
610 const net::Error cert_status
=
611 static_cast<net::Error
>(db
->CheckUserCert(state
->certificate_
.get()));
612 if (cert_status
== net::ERR_NO_PRIVATE_KEY_FOR_CERT
) {
613 state
->OnError(FROM_HERE
, kErrorKeyNotFound
);
615 } else if (cert_status
!= net::OK
) {
616 state
->OnError(FROM_HERE
, net::ErrorToString(cert_status
));
620 // Check that the private key is in the correct slot.
622 PK11_KeyForCertExists(state
->certificate_
->os_cert_handle(), NULL
, NULL
);
623 if (slot
!= state
->slot_
) {
624 state
->OnError(FROM_HERE
, kErrorKeyNotFound
);
628 const net::Error import_status
=
629 static_cast<net::Error
>(db
->AddUserCert(state
->certificate_
.get()));
630 if (import_status
!= net::OK
) {
631 LOG(ERROR
) << "Could not import certificate.";
632 state
->OnError(FROM_HERE
, net::ErrorToString(import_status
));
636 state
->CallBack(FROM_HERE
, std::string() /* no error */);
639 // Called on IO thread after the certificate removal is finished.
640 void DidRemoveCertificate(scoped_ptr
<RemoveCertificateState
> state
,
641 bool certificate_found
,
643 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
644 // CertificateNotFound error has precedence over an internal error.
645 if (!certificate_found
) {
646 state
->OnError(FROM_HERE
, kErrorCertificateNotFound
);
650 state
->OnError(FROM_HERE
, kErrorInternal
);
654 state
->CallBack(FROM_HERE
, std::string() /* no error */);
657 // Does the actual certificate removal on the IO thread. Used by
658 // RemoveCertificate().
659 void RemoveCertificateWithDB(scoped_ptr
<RemoveCertificateState
> state
,
660 net::NSSCertDatabase
* cert_db
) {
661 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
662 // Get the pointer before base::Passed clears |state|.
663 scoped_refptr
<net::X509Certificate
> certificate
= state
->certificate_
;
664 bool certificate_found
= certificate
->os_cert_handle()->isperm
;
665 cert_db
->DeleteCertAndKeyAsync(
668 &DidRemoveCertificate
, base::Passed(&state
), certificate_found
));
671 // Does the actual work to determine which tokens are available.
672 void GetTokensWithDB(scoped_ptr
<GetTokensState
> state
,
673 net::NSSCertDatabase
* cert_db
) {
674 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
675 scoped_ptr
<std::vector
<std::string
> > token_ids(new std::vector
<std::string
>);
677 // The user's token is always available.
678 token_ids
->push_back(kTokenIdUser
);
679 if (cert_db
->GetSystemSlot())
680 token_ids
->push_back(kTokenIdSystem
);
682 state
->CallBack(FROM_HERE
, token_ids
.Pass(), std::string() /* no error */);
689 void GenerateRSAKey(const std::string
& token_id
,
690 unsigned int modulus_length_bits
,
691 const GenerateKeyCallback
& callback
,
692 BrowserContext
* browser_context
) {
693 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
694 scoped_ptr
<GenerateRSAKeyState
> state(
695 new GenerateRSAKeyState(modulus_length_bits
, callback
));
697 if (modulus_length_bits
> kMaxRSAModulusLengthBits
) {
698 state
->OnError(FROM_HERE
, kErrorAlgorithmNotSupported
);
702 // Get the pointer to |state| before base::Passed releases |state|.
703 NSSOperationState
* state_ptr
= state
.get();
704 GetCertDatabase(token_id
,
705 base::Bind(&GenerateRSAKeyWithDB
, base::Passed(&state
)),
710 void SignRSAPKCS1Digest(const std::string
& token_id
,
711 const std::string
& data
,
712 const std::string
& public_key
,
713 HashAlgorithm hash_algorithm
,
714 const SignCallback
& callback
,
715 content::BrowserContext
* browser_context
) {
716 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
717 scoped_ptr
<SignRSAState
> state(
718 new SignRSAState(data
, public_key
, false /* digest before signing */,
719 hash_algorithm
, callback
));
720 // Get the pointer to |state| before base::Passed releases |state|.
721 NSSOperationState
* state_ptr
= state
.get();
723 // The NSSCertDatabase object is not required. But in case it's not available
724 // we would get more informative error messages and we can double check that
725 // we use a key of the correct token.
726 GetCertDatabase(token_id
, base::Bind(&SignRSAWithDB
, base::Passed(&state
)),
727 browser_context
, state_ptr
);
730 void SignRSAPKCS1Raw(const std::string
& token_id
,
731 const std::string
& data
,
732 const std::string
& public_key
,
733 const SignCallback
& callback
,
734 content::BrowserContext
* browser_context
) {
735 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
736 scoped_ptr
<SignRSAState
> state(new SignRSAState(
737 data
, public_key
, true /* sign directly without hashing */,
738 HASH_ALGORITHM_NONE
, callback
));
739 // Get the pointer to |state| before base::Passed releases |state|.
740 NSSOperationState
* state_ptr
= state
.get();
742 // The NSSCertDatabase object is not required. But in case it's not available
743 // we would get more informative error messages and we can double check that
744 // we use a key of the correct token.
745 GetCertDatabase(token_id
, base::Bind(&SignRSAWithDB
, base::Passed(&state
)),
746 browser_context
, state_ptr
);
749 void SelectClientCertificates(const ClientCertificateRequest
& request
,
750 const SelectCertificatesCallback
& callback
,
751 content::BrowserContext
* browser_context
) {
752 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
754 scoped_refptr
<net::SSLCertRequestInfo
> cert_request_info(
755 new net::SSLCertRequestInfo
);
756 cert_request_info
->cert_key_types
= request
.certificate_key_types
;
757 cert_request_info
->cert_authorities
= request
.certificate_authorities
;
759 const user_manager::User
* user
=
760 chromeos::ProfileHelper::Get()->GetUserByProfile(
761 Profile::FromBrowserContext(browser_context
));
763 // Use the device-wide system key slot only if the user is of the same
764 // domain as the device is registered to.
765 policy::BrowserPolicyConnectorChromeOS
* connector
=
766 g_browser_process
->platform_part()->browser_policy_connector_chromeos();
767 bool use_system_key_slot
= connector
->GetUserAffiliation(user
->email()) ==
768 policy::USER_AFFILIATION_MANAGED
;
770 scoped_ptr
<SelectCertificatesState
> state(new SelectCertificatesState(
771 user
->username_hash(), use_system_key_slot
, cert_request_info
, callback
));
773 BrowserThread::PostTask(
774 BrowserThread::IO
, FROM_HERE
,
775 base::Bind(&SelectCertificatesOnIOThread
, base::Passed(&state
)));
778 } // namespace subtle
780 std::string
GetSubjectPublicKeyInfo(
781 const scoped_refptr
<net::X509Certificate
>& certificate
) {
782 const SECItem
& spki_der
= certificate
->os_cert_handle()->derPublicKey
;
783 return std::string(spki_der
.data
, spki_der
.data
+ spki_der
.len
);
786 bool GetPublicKey(const scoped_refptr
<net::X509Certificate
>& certificate
,
787 net::X509Certificate::PublicKeyType
* key_type
,
788 size_t* key_size_bits
) {
789 net::X509Certificate::PublicKeyType key_type_tmp
=
790 net::X509Certificate::kPublicKeyTypeUnknown
;
791 size_t key_size_bits_tmp
= 0;
792 net::X509Certificate::GetPublicKeyInfo(certificate
->os_cert_handle(),
793 &key_size_bits_tmp
, &key_type_tmp
);
795 if (key_type_tmp
== net::X509Certificate::kPublicKeyTypeUnknown
) {
796 LOG(WARNING
) << "Could not extract public key of certificate.";
799 if (key_type_tmp
!= net::X509Certificate::kPublicKeyTypeRSA
) {
800 LOG(WARNING
) << "Keys of other type than RSA are not supported.";
804 crypto::ScopedSECKEYPublicKey
public_key(
805 CERT_ExtractPublicKey(certificate
->os_cert_handle()));
807 LOG(WARNING
) << "Could not extract public key of certificate.";
810 long public_exponent
= DER_GetInteger(&public_key
->u
.rsa
.publicExponent
);
811 if (public_exponent
!= 65537L) {
812 LOG(ERROR
) << "Rejecting RSA public exponent that is unequal 65537.";
816 *key_type
= key_type_tmp
;
817 *key_size_bits
= key_size_bits_tmp
;
821 void GetCertificates(const std::string
& token_id
,
822 const GetCertificatesCallback
& callback
,
823 BrowserContext
* browser_context
) {
824 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
825 scoped_ptr
<GetCertificatesState
> state(new GetCertificatesState(callback
));
826 // Get the pointer to |state| before base::Passed releases |state|.
827 NSSOperationState
* state_ptr
= state
.get();
828 GetCertDatabase(token_id
,
829 base::Bind(&GetCertificatesWithDB
, base::Passed(&state
)),
834 void ImportCertificate(const std::string
& token_id
,
835 const scoped_refptr
<net::X509Certificate
>& certificate
,
836 const ImportCertificateCallback
& callback
,
837 BrowserContext
* browser_context
) {
838 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
839 scoped_ptr
<ImportCertificateState
> state(
840 new ImportCertificateState(certificate
, callback
));
841 // Get the pointer to |state| before base::Passed releases |state|.
842 NSSOperationState
* state_ptr
= state
.get();
844 // The NSSCertDatabase object is not required. But in case it's not available
845 // we would get more informative error messages and we can double check that
846 // we use a key of the correct token.
847 GetCertDatabase(token_id
,
848 base::Bind(&ImportCertificateWithDB
, base::Passed(&state
)),
853 void RemoveCertificate(const std::string
& token_id
,
854 const scoped_refptr
<net::X509Certificate
>& certificate
,
855 const RemoveCertificateCallback
& callback
,
856 BrowserContext
* browser_context
) {
857 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
858 scoped_ptr
<RemoveCertificateState
> state(
859 new RemoveCertificateState(certificate
, callback
));
860 // Get the pointer to |state| before base::Passed releases |state|.
861 NSSOperationState
* state_ptr
= state
.get();
863 // The NSSCertDatabase object is not required. But in case it's not available
864 // we would get more informative error messages.
865 GetCertDatabase(token_id
,
866 base::Bind(&RemoveCertificateWithDB
, base::Passed(&state
)),
871 void GetTokens(const GetTokensCallback
& callback
,
872 content::BrowserContext
* browser_context
) {
873 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
874 scoped_ptr
<GetTokensState
> state(new GetTokensState(callback
));
875 // Get the pointer to |state| before base::Passed releases |state|.
876 NSSOperationState
* state_ptr
= state
.get();
877 GetCertDatabase(std::string() /* don't get any specific slot */,
878 base::Bind(&GetTokensWithDB
, base::Passed(&state
)),
883 } // namespace platform_keys
885 } // namespace chromeos