Add ICU message format support
[chromium-blink-merge.git] / chrome / browser / chromeos / platform_keys / platform_keys_nss.cc
blobd6887d5f8152ef4bcec69804e27ac2da96f4d23d
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"
7 #include <cert.h>
8 #include <cryptohi.h>
9 #include <keyhi.h>
10 #include <secder.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/nss_key_util.h"
35 #include "crypto/scoped_nss_types.h"
36 #include "net/base/crypto_module.h"
37 #include "net/base/net_errors.h"
38 #include "net/cert/cert_database.h"
39 #include "net/cert/nss_cert_database.h"
40 #include "net/cert/x509_certificate.h"
41 #include "net/cert/x509_util_nss.h"
42 #include "net/ssl/client_cert_store_chromeos.h"
43 #include "net/ssl/ssl_cert_request_info.h"
45 using content::BrowserContext;
46 using content::BrowserThread;
48 namespace {
49 const char kErrorInternal[] = "Internal Error.";
50 const char kErrorKeyNotFound[] = "Key not found.";
51 const char kErrorCertificateNotFound[] = "Certificate could not be found.";
52 const char kErrorAlgorithmNotSupported[] = "Algorithm not supported.";
54 // The current maximal RSA modulus length that ChromeOS's TPM supports for key
55 // generation.
56 const unsigned int kMaxRSAModulusLengthBits = 2048;
59 namespace chromeos {
61 namespace platform_keys {
63 namespace {
65 // Base class to store state that is common to all NSS database operations and
66 // to provide convenience methods to call back.
67 // Keeps track of the originating task runner.
68 class NSSOperationState {
69 public:
70 NSSOperationState();
71 virtual ~NSSOperationState() {}
73 // Called if an error occurred during the execution of the NSS operation
74 // described by this object.
75 virtual void OnError(const tracked_objects::Location& from,
76 const std::string& error_message) = 0;
78 crypto::ScopedPK11Slot slot_;
80 // The task runner on which the NSS operation was called. Any reply must be
81 // posted to this runner.
82 scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
84 private:
85 DISALLOW_COPY_AND_ASSIGN(NSSOperationState);
88 typedef base::Callback<void(net::NSSCertDatabase* cert_db)> GetCertDBCallback;
90 // Used by GetCertDatabaseOnIOThread and called back with the requested
91 // NSSCertDatabase.
92 // If |token_id| is not empty, sets |slot_| of |state| accordingly and calls
93 // |callback| if the database was successfully retrieved.
94 void DidGetCertDBOnIOThread(const std::string& token_id,
95 const GetCertDBCallback& callback,
96 NSSOperationState* state,
97 net::NSSCertDatabase* cert_db) {
98 DCHECK_CURRENTLY_ON(BrowserThread::IO);
99 if (!cert_db) {
100 LOG(ERROR) << "Couldn't get NSSCertDatabase.";
101 state->OnError(FROM_HERE, kErrorInternal);
102 return;
105 if (!token_id.empty()) {
106 if (token_id == kTokenIdUser)
107 state->slot_ = cert_db->GetPrivateSlot();
108 else if (token_id == kTokenIdSystem)
109 state->slot_ = cert_db->GetSystemSlot();
111 if (!state->slot_) {
112 LOG(ERROR) << "Slot for token id '" << token_id << "' not available.";
113 state->OnError(FROM_HERE, kErrorInternal);
114 return;
118 callback.Run(cert_db);
121 // Retrieves the NSSCertDatabase from |context| and, if |token_id| is not empty,
122 // the slot for |token_id|.
123 // Must be called on the IO thread.
124 void GetCertDatabaseOnIOThread(const std::string& token_id,
125 const GetCertDBCallback& callback,
126 content::ResourceContext* context,
127 NSSOperationState* state) {
128 DCHECK_CURRENTLY_ON(BrowserThread::IO);
129 net::NSSCertDatabase* cert_db = GetNSSCertDatabaseForResourceContext(
130 context, base::Bind(&DidGetCertDBOnIOThread, token_id, callback, state));
132 if (cert_db)
133 DidGetCertDBOnIOThread(token_id, callback, state, cert_db);
136 // Asynchronously fetches the NSSCertDatabase for |browser_context| and, if
137 // |token_id| is not empty, the slot for |token_id|. Stores the slot in |state|
138 // and passes the database to |callback|. Will run |callback| on the IO thread.
139 void GetCertDatabase(const std::string& token_id,
140 const GetCertDBCallback& callback,
141 BrowserContext* browser_context,
142 NSSOperationState* state) {
143 BrowserThread::PostTask(BrowserThread::IO,
144 FROM_HERE,
145 base::Bind(&GetCertDatabaseOnIOThread,
146 token_id,
147 callback,
148 browser_context->GetResourceContext(),
149 state));
152 class GenerateRSAKeyState : public NSSOperationState {
153 public:
154 GenerateRSAKeyState(unsigned int modulus_length_bits,
155 const subtle::GenerateKeyCallback& callback);
156 ~GenerateRSAKeyState() override {}
158 void OnError(const tracked_objects::Location& from,
159 const std::string& error_message) override {
160 CallBack(from, std::string() /* no public key */, error_message);
163 void CallBack(const tracked_objects::Location& from,
164 const std::string& public_key_spki_der,
165 const std::string& error_message) {
166 origin_task_runner_->PostTask(
167 from, base::Bind(callback_, public_key_spki_der, error_message));
170 const unsigned int modulus_length_bits_;
172 private:
173 // Must be called on origin thread, therefore use CallBack().
174 subtle::GenerateKeyCallback callback_;
177 class SignRSAState : public NSSOperationState {
178 public:
179 SignRSAState(const std::string& data,
180 const std::string& public_key,
181 bool sign_direct_pkcs_padded,
182 HashAlgorithm hash_algorithm,
183 const subtle::SignCallback& callback);
184 ~SignRSAState() override {}
186 void OnError(const tracked_objects::Location& from,
187 const std::string& error_message) override {
188 CallBack(from, std::string() /* no signature */, error_message);
191 void CallBack(const tracked_objects::Location& from,
192 const std::string& signature,
193 const std::string& error_message) {
194 origin_task_runner_->PostTask(
195 from, base::Bind(callback_, signature, error_message));
198 // The data that will be signed.
199 const std::string data_;
201 // Must be the DER encoding of a SubjectPublicKeyInfo.
202 const std::string public_key_;
204 // If true, |data_| will not be hashed before signing. Only PKCS#1 v1.5
205 // padding will be applied before signing.
206 // If false, |hash_algorithm_| must be set to a value != NONE.
207 const bool sign_direct_pkcs_padded_;
209 // Determines the hash algorithm that is used to digest |data| before signing.
210 // Ignored if |sign_direct_pkcs_padded_| is true.
211 const HashAlgorithm hash_algorithm_;
213 private:
214 // Must be called on origin thread, therefore use CallBack().
215 subtle::SignCallback callback_;
218 class SelectCertificatesState : public NSSOperationState {
219 public:
220 explicit SelectCertificatesState(
221 const std::string& username_hash,
222 const bool use_system_key_slot,
223 const scoped_refptr<net::SSLCertRequestInfo>& request,
224 const subtle::SelectCertificatesCallback& callback);
225 ~SelectCertificatesState() override {}
227 void OnError(const tracked_objects::Location& from,
228 const std::string& error_message) override {
229 CallBack(from, scoped_ptr<net::CertificateList>() /* no matches */,
230 error_message);
233 void CallBack(const tracked_objects::Location& from,
234 scoped_ptr<net::CertificateList> matches,
235 const std::string& error_message) {
236 origin_task_runner_->PostTask(
237 from, base::Bind(callback_, base::Passed(&matches), error_message));
240 const std::string username_hash_;
241 const bool use_system_key_slot_;
242 scoped_refptr<net::SSLCertRequestInfo> cert_request_info_;
243 scoped_ptr<net::ClientCertStore> cert_store_;
244 scoped_ptr<net::CertificateList> certs_;
246 private:
247 // Must be called on origin thread, therefore use CallBack().
248 subtle::SelectCertificatesCallback callback_;
251 class GetCertificatesState : public NSSOperationState {
252 public:
253 explicit GetCertificatesState(const GetCertificatesCallback& callback);
254 ~GetCertificatesState() override {}
256 void OnError(const tracked_objects::Location& from,
257 const std::string& error_message) override {
258 CallBack(from,
259 scoped_ptr<net::CertificateList>() /* no certificates */,
260 error_message);
263 void CallBack(const tracked_objects::Location& from,
264 scoped_ptr<net::CertificateList> certs,
265 const std::string& error_message) {
266 origin_task_runner_->PostTask(
267 from, base::Bind(callback_, base::Passed(&certs), error_message));
270 scoped_ptr<net::CertificateList> certs_;
272 private:
273 // Must be called on origin thread, therefore use CallBack().
274 GetCertificatesCallback callback_;
277 class ImportCertificateState : public NSSOperationState {
278 public:
279 ImportCertificateState(const scoped_refptr<net::X509Certificate>& certificate,
280 const ImportCertificateCallback& callback);
281 ~ImportCertificateState() override {}
283 void OnError(const tracked_objects::Location& from,
284 const std::string& error_message) override {
285 CallBack(from, error_message);
288 void CallBack(const tracked_objects::Location& from,
289 const std::string& error_message) {
290 origin_task_runner_->PostTask(from, base::Bind(callback_, error_message));
293 scoped_refptr<net::X509Certificate> certificate_;
295 private:
296 // Must be called on origin thread, therefore use CallBack().
297 ImportCertificateCallback callback_;
300 class RemoveCertificateState : public NSSOperationState {
301 public:
302 RemoveCertificateState(const scoped_refptr<net::X509Certificate>& certificate,
303 const RemoveCertificateCallback& callback);
304 ~RemoveCertificateState() override {}
306 void OnError(const tracked_objects::Location& from,
307 const std::string& error_message) override {
308 CallBack(from, error_message);
311 void CallBack(const tracked_objects::Location& from,
312 const std::string& error_message) {
313 origin_task_runner_->PostTask(from, base::Bind(callback_, error_message));
316 scoped_refptr<net::X509Certificate> certificate_;
318 private:
319 // Must be called on origin thread, therefore use CallBack().
320 RemoveCertificateCallback callback_;
323 class GetTokensState : public NSSOperationState {
324 public:
325 explicit GetTokensState(const GetTokensCallback& callback);
326 ~GetTokensState() override {}
328 void OnError(const tracked_objects::Location& from,
329 const std::string& error_message) override {
330 CallBack(from,
331 scoped_ptr<std::vector<std::string> >() /* no token ids */,
332 error_message);
335 void CallBack(const tracked_objects::Location& from,
336 scoped_ptr<std::vector<std::string> > token_ids,
337 const std::string& error_message) {
338 origin_task_runner_->PostTask(
339 from, base::Bind(callback_, base::Passed(&token_ids), error_message));
342 private:
343 // Must be called on origin thread, therefore use CallBack().
344 GetTokensCallback callback_;
347 NSSOperationState::NSSOperationState()
348 : origin_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
351 GenerateRSAKeyState::GenerateRSAKeyState(
352 unsigned int modulus_length_bits,
353 const subtle::GenerateKeyCallback& callback)
354 : modulus_length_bits_(modulus_length_bits), callback_(callback) {
357 SignRSAState::SignRSAState(const std::string& data,
358 const std::string& public_key,
359 bool sign_direct_pkcs_padded,
360 HashAlgorithm hash_algorithm,
361 const subtle::SignCallback& callback)
362 : data_(data),
363 public_key_(public_key),
364 sign_direct_pkcs_padded_(sign_direct_pkcs_padded),
365 hash_algorithm_(hash_algorithm),
366 callback_(callback) {
369 SelectCertificatesState::SelectCertificatesState(
370 const std::string& username_hash,
371 const bool use_system_key_slot,
372 const scoped_refptr<net::SSLCertRequestInfo>& cert_request_info,
373 const subtle::SelectCertificatesCallback& callback)
374 : username_hash_(username_hash),
375 use_system_key_slot_(use_system_key_slot),
376 cert_request_info_(cert_request_info),
377 callback_(callback) {
380 GetCertificatesState::GetCertificatesState(
381 const GetCertificatesCallback& callback)
382 : callback_(callback) {
385 ImportCertificateState::ImportCertificateState(
386 const scoped_refptr<net::X509Certificate>& certificate,
387 const ImportCertificateCallback& callback)
388 : certificate_(certificate), callback_(callback) {
391 RemoveCertificateState::RemoveCertificateState(
392 const scoped_refptr<net::X509Certificate>& certificate,
393 const RemoveCertificateCallback& callback)
394 : certificate_(certificate), callback_(callback) {
397 GetTokensState::GetTokensState(const GetTokensCallback& callback)
398 : callback_(callback) {
401 // Does the actual key generation on a worker thread. Used by
402 // GenerateRSAKeyWithDB().
403 void GenerateRSAKeyOnWorkerThread(scoped_ptr<GenerateRSAKeyState> state) {
404 if (!state->slot_) {
405 LOG(ERROR) << "No slot.";
406 state->OnError(FROM_HERE, kErrorInternal);
407 return;
410 crypto::ScopedSECKEYPublicKey public_key;
411 crypto::ScopedSECKEYPrivateKey private_key;
412 if (!crypto::GenerateRSAKeyPairNSS(
413 state->slot_.get(), state->modulus_length_bits_, true /* permanent */,
414 &public_key, &private_key)) {
415 LOG(ERROR) << "Couldn't create key.";
416 state->OnError(FROM_HERE, kErrorInternal);
417 return;
420 crypto::ScopedSECItem public_key_der(
421 SECKEY_EncodeDERSubjectPublicKeyInfo(public_key.get()));
422 if (!public_key_der) {
423 // TODO(pneubeck): Remove private_key and public_key from storage.
424 LOG(ERROR) << "Couldn't export public key.";
425 state->OnError(FROM_HERE, kErrorInternal);
426 return;
428 state->CallBack(
429 FROM_HERE,
430 std::string(reinterpret_cast<const char*>(public_key_der->data),
431 public_key_der->len),
432 std::string() /* no error */);
435 // Continues generating a RSA key with the obtained NSSCertDatabase. Used by
436 // GenerateRSAKey().
437 void GenerateRSAKeyWithDB(scoped_ptr<GenerateRSAKeyState> state,
438 net::NSSCertDatabase* cert_db) {
439 DCHECK_CURRENTLY_ON(BrowserThread::IO);
440 // Only the slot and not the NSSCertDatabase is required. Ignore |cert_db|.
441 base::WorkerPool::PostTask(
442 FROM_HERE,
443 base::Bind(&GenerateRSAKeyOnWorkerThread, base::Passed(&state)),
444 true /*task is slow*/);
447 // Does the actual signing on a worker thread. Used by SignRSAWithDB().
448 void SignRSAOnWorkerThread(scoped_ptr<SignRSAState> state) {
449 const uint8* public_key_uint8 =
450 reinterpret_cast<const uint8*>(state->public_key_.data());
451 std::vector<uint8> public_key_vector(
452 public_key_uint8, public_key_uint8 + state->public_key_.size());
454 crypto::ScopedSECKEYPrivateKey rsa_key;
455 if (state->slot_) {
456 rsa_key = crypto::FindNSSKeyFromPublicKeyInfoInSlot(public_key_vector,
457 state->slot_.get());
458 } else {
459 rsa_key = crypto::FindNSSKeyFromPublicKeyInfo(public_key_vector);
462 // Fail if the key was not found or is of the wrong type.
463 if (!rsa_key || SECKEY_GetPrivateKeyType(rsa_key.get()) != rsaKey) {
464 state->OnError(FROM_HERE, kErrorKeyNotFound);
465 return;
468 std::string signature_str;
469 if (state->sign_direct_pkcs_padded_) {
470 static_assert(
471 sizeof(*state->data_.data()) == sizeof(char),
472 "Can't reinterpret data if it's characters are not 8 bit large.");
473 SECItem input = {siBuffer,
474 reinterpret_cast<unsigned char*>(
475 const_cast<char*>(state->data_.data())),
476 state->data_.size()};
478 // Compute signature of hash.
479 int signature_len = PK11_SignatureLen(rsa_key.get());
480 if (signature_len <= 0) {
481 state->OnError(FROM_HERE, kErrorInternal);
482 return;
485 std::vector<unsigned char> signature(signature_len);
486 SECItem signature_output = {
487 siBuffer, vector_as_array(&signature), signature.size()};
488 if (PK11_Sign(rsa_key.get(), &signature_output, &input) == SECSuccess)
489 signature_str.assign(signature.begin(), signature.end());
490 } else {
491 SECOidTag sign_alg_tag = SEC_OID_UNKNOWN;
492 switch (state->hash_algorithm_) {
493 case HASH_ALGORITHM_SHA1:
494 sign_alg_tag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
495 break;
496 case HASH_ALGORITHM_SHA256:
497 sign_alg_tag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
498 break;
499 case HASH_ALGORITHM_SHA384:
500 sign_alg_tag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
501 break;
502 case HASH_ALGORITHM_SHA512:
503 sign_alg_tag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
504 break;
505 case HASH_ALGORITHM_NONE:
506 NOTREACHED();
507 break;
510 SECItem sign_result = {siBuffer, nullptr, 0};
511 if (SEC_SignData(
512 &sign_result,
513 reinterpret_cast<const unsigned char*>(state->data_.data()),
514 state->data_.size(), rsa_key.get(), sign_alg_tag) == SECSuccess) {
515 signature_str.assign(sign_result.data,
516 sign_result.data + sign_result.len);
520 if (signature_str.empty()) {
521 LOG(ERROR) << "Couldn't sign.";
522 state->OnError(FROM_HERE, kErrorInternal);
523 return;
526 state->CallBack(FROM_HERE, signature_str, std::string() /* no error */);
529 // Continues signing with the obtained NSSCertDatabase. Used by Sign().
530 void SignRSAWithDB(scoped_ptr<SignRSAState> state,
531 net::NSSCertDatabase* cert_db) {
532 DCHECK_CURRENTLY_ON(BrowserThread::IO);
533 // Only the slot and not the NSSCertDatabase is required. Ignore |cert_db|.
534 base::WorkerPool::PostTask(
535 FROM_HERE, base::Bind(&SignRSAOnWorkerThread, base::Passed(&state)),
536 true /*task is slow*/);
539 // Called when ClientCertStoreChromeOS::GetClientCerts is done. Builds the list
540 // of net::CertificateList and calls back. Used by
541 // SelectCertificatesOnIOThread().
542 void DidSelectCertificatesOnIOThread(
543 scoped_ptr<SelectCertificatesState> state) {
544 DCHECK_CURRENTLY_ON(BrowserThread::IO);
545 state->CallBack(FROM_HERE, state->certs_.Pass(),
546 std::string() /* no error */);
549 // Continues selecting certificates on the IO thread. Used by
550 // SelectClientCertificates().
551 void SelectCertificatesOnIOThread(scoped_ptr<SelectCertificatesState> state) {
552 DCHECK_CURRENTLY_ON(BrowserThread::IO);
553 state->cert_store_.reset(new net::ClientCertStoreChromeOS(
554 make_scoped_ptr(new chromeos::ClientCertFilterChromeOS(
555 state->use_system_key_slot_, state->username_hash_)),
556 net::ClientCertStoreChromeOS::PasswordDelegateFactory()));
558 state->certs_.reset(new net::CertificateList);
560 SelectCertificatesState* state_ptr = state.get();
561 state_ptr->cert_store_->GetClientCerts(
562 *state_ptr->cert_request_info_, state_ptr->certs_.get(),
563 base::Bind(&DidSelectCertificatesOnIOThread, base::Passed(&state)));
566 // Filters the obtained certificates on a worker thread. Used by
567 // DidGetCertificates().
568 void FilterCertificatesOnWorkerThread(scoped_ptr<GetCertificatesState> state) {
569 scoped_ptr<net::CertificateList> client_certs(new net::CertificateList);
570 for (net::CertificateList::const_iterator it = state->certs_->begin();
571 it != state->certs_->end();
572 ++it) {
573 net::X509Certificate::OSCertHandle cert_handle = (*it)->os_cert_handle();
574 crypto::ScopedPK11Slot cert_slot(PK11_KeyForCertExists(cert_handle,
575 NULL, // keyPtr
576 NULL)); // wincx
578 // Keep only user certificates, i.e. certs for which the private key is
579 // present and stored in the queried slot.
580 if (cert_slot != state->slot_)
581 continue;
583 client_certs->push_back(*it);
586 state->CallBack(FROM_HERE, client_certs.Pass(), std::string() /* no error */);
589 // Passes the obtained certificates to the worker thread for filtering. Used by
590 // GetCertificatesWithDB().
591 void DidGetCertificates(scoped_ptr<GetCertificatesState> state,
592 scoped_ptr<net::CertificateList> all_certs) {
593 DCHECK_CURRENTLY_ON(BrowserThread::IO);
594 state->certs_ = all_certs.Pass();
595 base::WorkerPool::PostTask(
596 FROM_HERE,
597 base::Bind(&FilterCertificatesOnWorkerThread, base::Passed(&state)),
598 true /*task is slow*/);
601 // Continues getting certificates with the obtained NSSCertDatabase. Used by
602 // GetCertificates().
603 void GetCertificatesWithDB(scoped_ptr<GetCertificatesState> state,
604 net::NSSCertDatabase* cert_db) {
605 DCHECK_CURRENTLY_ON(BrowserThread::IO);
606 // Get the pointer to slot before base::Passed releases |state|.
607 PK11SlotInfo* slot = state->slot_.get();
608 cert_db->ListCertsInSlot(
609 base::Bind(&DidGetCertificates, base::Passed(&state)), slot);
612 // Does the actual certificate importing on the IO thread. Used by
613 // ImportCertificate().
614 void ImportCertificateWithDB(scoped_ptr<ImportCertificateState> state,
615 net::NSSCertDatabase* cert_db) {
616 DCHECK_CURRENTLY_ON(BrowserThread::IO);
617 // TODO(pneubeck): Use |state->slot_| to verify that we're really importing to
618 // the correct token.
619 // |cert_db| is not required, ignore it.
620 net::CertDatabase* db = net::CertDatabase::GetInstance();
622 const net::Error cert_status =
623 static_cast<net::Error>(db->CheckUserCert(state->certificate_.get()));
624 if (cert_status == net::ERR_NO_PRIVATE_KEY_FOR_CERT) {
625 state->OnError(FROM_HERE, kErrorKeyNotFound);
626 return;
627 } else if (cert_status != net::OK) {
628 state->OnError(FROM_HERE, net::ErrorToString(cert_status));
629 return;
632 // Check that the private key is in the correct slot.
633 PK11SlotInfo* slot =
634 PK11_KeyForCertExists(state->certificate_->os_cert_handle(), NULL, NULL);
635 if (slot != state->slot_) {
636 state->OnError(FROM_HERE, kErrorKeyNotFound);
637 return;
640 const net::Error import_status =
641 static_cast<net::Error>(db->AddUserCert(state->certificate_.get()));
642 if (import_status != net::OK) {
643 LOG(ERROR) << "Could not import certificate.";
644 state->OnError(FROM_HERE, net::ErrorToString(import_status));
645 return;
648 state->CallBack(FROM_HERE, std::string() /* no error */);
651 // Called on IO thread after the certificate removal is finished.
652 void DidRemoveCertificate(scoped_ptr<RemoveCertificateState> state,
653 bool certificate_found,
654 bool success) {
655 DCHECK_CURRENTLY_ON(BrowserThread::IO);
656 // CertificateNotFound error has precedence over an internal error.
657 if (!certificate_found) {
658 state->OnError(FROM_HERE, kErrorCertificateNotFound);
659 return;
661 if (!success) {
662 state->OnError(FROM_HERE, kErrorInternal);
663 return;
666 state->CallBack(FROM_HERE, std::string() /* no error */);
669 // Does the actual certificate removal on the IO thread. Used by
670 // RemoveCertificate().
671 void RemoveCertificateWithDB(scoped_ptr<RemoveCertificateState> state,
672 net::NSSCertDatabase* cert_db) {
673 DCHECK_CURRENTLY_ON(BrowserThread::IO);
674 // Get the pointer before base::Passed clears |state|.
675 scoped_refptr<net::X509Certificate> certificate = state->certificate_;
676 bool certificate_found = certificate->os_cert_handle()->isperm;
677 cert_db->DeleteCertAndKeyAsync(
678 certificate,
679 base::Bind(
680 &DidRemoveCertificate, base::Passed(&state), certificate_found));
683 // Does the actual work to determine which tokens are available.
684 void GetTokensWithDB(scoped_ptr<GetTokensState> state,
685 net::NSSCertDatabase* cert_db) {
686 DCHECK_CURRENTLY_ON(BrowserThread::IO);
687 scoped_ptr<std::vector<std::string> > token_ids(new std::vector<std::string>);
689 // The user's token is always available.
690 token_ids->push_back(kTokenIdUser);
691 if (cert_db->GetSystemSlot())
692 token_ids->push_back(kTokenIdSystem);
694 state->CallBack(FROM_HERE, token_ids.Pass(), std::string() /* no error */);
697 } // namespace
699 namespace subtle {
701 void GenerateRSAKey(const std::string& token_id,
702 unsigned int modulus_length_bits,
703 const GenerateKeyCallback& callback,
704 BrowserContext* browser_context) {
705 DCHECK_CURRENTLY_ON(BrowserThread::UI);
706 scoped_ptr<GenerateRSAKeyState> state(
707 new GenerateRSAKeyState(modulus_length_bits, callback));
709 if (modulus_length_bits > kMaxRSAModulusLengthBits) {
710 state->OnError(FROM_HERE, kErrorAlgorithmNotSupported);
711 return;
714 // Get the pointer to |state| before base::Passed releases |state|.
715 NSSOperationState* state_ptr = state.get();
716 GetCertDatabase(token_id,
717 base::Bind(&GenerateRSAKeyWithDB, base::Passed(&state)),
718 browser_context,
719 state_ptr);
722 void SignRSAPKCS1Digest(const std::string& token_id,
723 const std::string& data,
724 const std::string& public_key,
725 HashAlgorithm hash_algorithm,
726 const SignCallback& callback,
727 content::BrowserContext* browser_context) {
728 DCHECK_CURRENTLY_ON(BrowserThread::UI);
729 scoped_ptr<SignRSAState> state(
730 new SignRSAState(data, public_key, false /* digest before signing */,
731 hash_algorithm, callback));
732 // Get the pointer to |state| before base::Passed releases |state|.
733 NSSOperationState* state_ptr = state.get();
735 // The NSSCertDatabase object is not required. But in case it's not available
736 // we would get more informative error messages and we can double check that
737 // we use a key of the correct token.
738 GetCertDatabase(token_id, base::Bind(&SignRSAWithDB, base::Passed(&state)),
739 browser_context, state_ptr);
742 void SignRSAPKCS1Raw(const std::string& token_id,
743 const std::string& data,
744 const std::string& public_key,
745 const SignCallback& callback,
746 content::BrowserContext* browser_context) {
747 DCHECK_CURRENTLY_ON(BrowserThread::UI);
748 scoped_ptr<SignRSAState> state(new SignRSAState(
749 data, public_key, true /* sign directly without hashing */,
750 HASH_ALGORITHM_NONE, callback));
751 // Get the pointer to |state| before base::Passed releases |state|.
752 NSSOperationState* state_ptr = state.get();
754 // The NSSCertDatabase object is not required. But in case it's not available
755 // we would get more informative error messages and we can double check that
756 // we use a key of the correct token.
757 GetCertDatabase(token_id, base::Bind(&SignRSAWithDB, base::Passed(&state)),
758 browser_context, state_ptr);
761 void SelectClientCertificates(
762 const std::vector<std::string>& certificate_authorities,
763 const SelectCertificatesCallback& callback,
764 content::BrowserContext* browser_context) {
765 DCHECK_CURRENTLY_ON(BrowserThread::UI);
767 scoped_refptr<net::SSLCertRequestInfo> cert_request_info(
768 new net::SSLCertRequestInfo);
770 // Currently we do not pass down the requested certificate type to the net
771 // layer, as it does not support filtering certificates by type. Rather, we
772 // do not constrain the certificate type here, instead the caller has to apply
773 // filtering afterwards.
774 cert_request_info->cert_authorities = certificate_authorities;
776 const user_manager::User* user =
777 chromeos::ProfileHelper::Get()->GetUserByProfile(
778 Profile::FromBrowserContext(browser_context));
780 // Use the device-wide system key slot only if the user is of the same
781 // domain as the device is registered to.
782 policy::BrowserPolicyConnectorChromeOS* connector =
783 g_browser_process->platform_part()->browser_policy_connector_chromeos();
784 bool use_system_key_slot = connector->GetUserAffiliation(user->email()) ==
785 policy::USER_AFFILIATION_MANAGED;
787 scoped_ptr<SelectCertificatesState> state(new SelectCertificatesState(
788 user->username_hash(), use_system_key_slot, cert_request_info, callback));
790 BrowserThread::PostTask(
791 BrowserThread::IO, FROM_HERE,
792 base::Bind(&SelectCertificatesOnIOThread, base::Passed(&state)));
795 } // namespace subtle
797 std::string GetSubjectPublicKeyInfo(
798 const scoped_refptr<net::X509Certificate>& certificate) {
799 const SECItem& spki_der = certificate->os_cert_handle()->derPublicKey;
800 return std::string(spki_der.data, spki_der.data + spki_der.len);
803 bool GetPublicKey(const scoped_refptr<net::X509Certificate>& certificate,
804 net::X509Certificate::PublicKeyType* key_type,
805 size_t* key_size_bits) {
806 net::X509Certificate::PublicKeyType key_type_tmp =
807 net::X509Certificate::kPublicKeyTypeUnknown;
808 size_t key_size_bits_tmp = 0;
809 net::X509Certificate::GetPublicKeyInfo(certificate->os_cert_handle(),
810 &key_size_bits_tmp, &key_type_tmp);
812 if (key_type_tmp == net::X509Certificate::kPublicKeyTypeUnknown) {
813 LOG(WARNING) << "Could not extract public key of certificate.";
814 return false;
816 if (key_type_tmp != net::X509Certificate::kPublicKeyTypeRSA) {
817 LOG(WARNING) << "Keys of other type than RSA are not supported.";
818 return false;
821 crypto::ScopedSECKEYPublicKey public_key(
822 CERT_ExtractPublicKey(certificate->os_cert_handle()));
823 if (!public_key) {
824 LOG(WARNING) << "Could not extract public key of certificate.";
825 return false;
827 long public_exponent = DER_GetInteger(&public_key->u.rsa.publicExponent);
828 if (public_exponent != 65537L) {
829 LOG(ERROR) << "Rejecting RSA public exponent that is unequal 65537.";
830 return false;
833 *key_type = key_type_tmp;
834 *key_size_bits = key_size_bits_tmp;
835 return true;
838 void GetCertificates(const std::string& token_id,
839 const GetCertificatesCallback& callback,
840 BrowserContext* browser_context) {
841 DCHECK_CURRENTLY_ON(BrowserThread::UI);
842 scoped_ptr<GetCertificatesState> state(new GetCertificatesState(callback));
843 // Get the pointer to |state| before base::Passed releases |state|.
844 NSSOperationState* state_ptr = state.get();
845 GetCertDatabase(token_id,
846 base::Bind(&GetCertificatesWithDB, base::Passed(&state)),
847 browser_context,
848 state_ptr);
851 void ImportCertificate(const std::string& token_id,
852 const scoped_refptr<net::X509Certificate>& certificate,
853 const ImportCertificateCallback& callback,
854 BrowserContext* browser_context) {
855 DCHECK_CURRENTLY_ON(BrowserThread::UI);
856 scoped_ptr<ImportCertificateState> state(
857 new ImportCertificateState(certificate, callback));
858 // Get the pointer to |state| before base::Passed releases |state|.
859 NSSOperationState* state_ptr = state.get();
861 // The NSSCertDatabase object is not required. But in case it's not available
862 // we would get more informative error messages and we can double check that
863 // we use a key of the correct token.
864 GetCertDatabase(token_id,
865 base::Bind(&ImportCertificateWithDB, base::Passed(&state)),
866 browser_context,
867 state_ptr);
870 void RemoveCertificate(const std::string& token_id,
871 const scoped_refptr<net::X509Certificate>& certificate,
872 const RemoveCertificateCallback& callback,
873 BrowserContext* browser_context) {
874 DCHECK_CURRENTLY_ON(BrowserThread::UI);
875 scoped_ptr<RemoveCertificateState> state(
876 new RemoveCertificateState(certificate, callback));
877 // Get the pointer to |state| before base::Passed releases |state|.
878 NSSOperationState* state_ptr = state.get();
880 // The NSSCertDatabase object is not required. But in case it's not available
881 // we would get more informative error messages.
882 GetCertDatabase(token_id,
883 base::Bind(&RemoveCertificateWithDB, base::Passed(&state)),
884 browser_context,
885 state_ptr);
888 void GetTokens(const GetTokensCallback& callback,
889 content::BrowserContext* browser_context) {
890 DCHECK_CURRENTLY_ON(BrowserThread::UI);
891 scoped_ptr<GetTokensState> state(new GetTokensState(callback));
892 // Get the pointer to |state| before base::Passed releases |state|.
893 NSSOperationState* state_ptr = state.get();
894 GetCertDatabase(std::string() /* don't get any specific slot */,
895 base::Bind(&GetTokensWithDB, base::Passed(&state)),
896 browser_context,
897 state_ptr);
900 } // namespace platform_keys
902 } // namespace chromeos