OLD | NEW |
---|---|
(Empty) | |
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. | |
4 | |
5 #include "chrome/browser/chromeos/platform_keys/platform_keys.h" | |
6 | |
7 #include <cryptohi.h> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/bind_helpers.h" | |
11 #include "base/callback.h" | |
12 #include "base/compiler_specific.h" | |
13 #include "base/location.h" | |
14 #include "base/logging.h" | |
15 #include "base/macros.h" | |
16 #include "base/single_thread_task_runner.h" | |
17 #include "base/thread_task_runner_handle.h" | |
18 #include "base/threading/worker_pool.h" | |
19 #include "chrome/browser/extensions/api/enterprise_platform_keys/enterprise_plat form_keys_api.h" | |
20 #include "chrome/browser/net/nss_context.h" | |
21 #include "chrome/browser/profiles/profile.h" | |
22 #include "content/public/browser/browser_thread.h" | |
23 #include "crypto/rsa_private_key.h" | |
24 #include "net/base/crypto_module.h" | |
25 #include "net/base/net_errors.h" | |
26 #include "net/cert/cert_database.h" | |
27 #include "net/cert/nss_cert_database.h" | |
28 #include "net/cert/x509_certificate.h" | |
29 | |
30 using content::BrowserThread; | |
31 | |
32 namespace { | |
33 const char kErrorInternal[] = "Internal Error."; | |
34 const char kErrorKeyNotFound[] = "Key not found."; | |
35 const char kErrorCertificateNotFound[] = "Certificate could not be found."; | |
36 const char kErrorAlgorithmNotSupported[] = "Algorithm not supported."; | |
37 | |
38 // The current maximal RSA modulus length that ChromeOS's TPM supports for key | |
39 // generation. | |
40 const unsigned int kMaxRSAModulusLength = 2048; | |
41 } | |
42 | |
43 namespace chromeos { | |
44 | |
45 namespace platform_keys { | |
46 | |
47 namespace { | |
48 | |
49 // Base class to store state that is common to all NSS database operations and | |
50 // to provide convenience methods to call back. | |
51 // Keeps track of the originating task runner. | |
52 class NSSOperationState { | |
53 public: | |
54 explicit NSSOperationState(Profile* profile); | |
55 virtual ~NSSOperationState() {} | |
56 | |
57 // Called if an error occurred during the execution of the NSS operation | |
58 // described by this object. | |
59 virtual void OnError(const tracked_objects::Location& from, | |
60 const std::string& error_message) = 0; | |
61 | |
62 Profile* profile_; | |
63 crypto::ScopedPK11Slot slot_; | |
64 | |
65 // The task runner on which the NSS operation was called. Any reply must be | |
66 // posted to this runner. | |
67 scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_; | |
68 | |
69 private: | |
70 DISALLOW_COPY_AND_ASSIGN(NSSOperationState); | |
71 }; | |
72 | |
73 typedef base::Callback<void(net::NSSCertDatabase* cert_db)> GetCertDBCallback; | |
74 | |
75 // Called back with the NSSCertDatabase associated to the given |token_id|. | |
76 // Calls |callback| if the database was successfully retrieved. Used by | |
77 // GetCertDatabaseOnIOThread. | |
78 void DidGetCertDBOnIOThread(const GetCertDBCallback& callback, | |
79 NSSOperationState* state, | |
80 net::NSSCertDatabase* cert_db) { | |
81 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
82 if (!cert_db) { | |
83 LOG(ERROR) << "Couldn't get NSSCertDatabase."; | |
84 state->OnError(FROM_HERE, kErrorInternal); | |
85 return; | |
86 } | |
87 | |
88 state->slot_ = cert_db->GetPrivateSlot(); | |
89 if (!state->slot_) { | |
90 LOG(ERROR) << "No private slot"; | |
91 state->OnError(FROM_HERE, kErrorInternal); | |
92 return; | |
93 } | |
94 | |
95 callback.Run(cert_db); | |
96 } | |
97 | |
98 // Retrieves the NSSCertDatabase from |context|. Must be called on the IO | |
99 // thread. | |
100 void GetCertDatabaseOnIOThread(content::ResourceContext* context, | |
101 const GetCertDBCallback& callback, | |
102 NSSOperationState* state) { | |
103 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
104 net::NSSCertDatabase* cert_db = GetNSSCertDatabaseForResourceContext( | |
105 context, | |
106 base::Bind(&DidGetCertDBOnIOThread, callback, state)); | |
107 | |
108 if (cert_db) | |
109 DidGetCertDBOnIOThread(callback, state, cert_db); | |
110 } | |
111 | |
112 // Asynchronously fetches the NSSCertDatabase for |token_id| and passes it to | |
113 // |callback|. Will run |callback| on the IO thread. | |
114 void GetCertDatabase(const std::string& token_id, | |
115 const GetCertDBCallback& callback, | |
116 NSSOperationState* state) { | |
117 // TODO(pneubeck): Decide which DB to retrieve depending on |token_id|. | |
118 BrowserThread::PostTask(BrowserThread::IO, | |
119 FROM_HERE, | |
120 base::Bind(&GetCertDatabaseOnIOThread, | |
121 state->profile_->GetResourceContext(), | |
122 callback, | |
123 state)); | |
124 } | |
125 | |
126 class GenerateRSAKeyState : public NSSOperationState { | |
127 public: | |
128 GenerateRSAKeyState(unsigned int modulus_length, | |
129 const GenerateKeyCallback& callback, | |
130 Profile* profile); | |
131 virtual ~GenerateRSAKeyState() {} | |
132 | |
133 virtual void OnError(const tracked_objects::Location& from, | |
134 const std::string& error_message) OVERRIDE { | |
135 CallBack(from, std::string() /* no public key */, error_message); | |
136 } | |
137 | |
138 void CallBack(const tracked_objects::Location& from, | |
139 const std::string& public_key_spki_der, | |
140 const std::string& error_message) { | |
141 origin_task_runner_->PostTask( | |
142 from, base::Bind(callback_, public_key_spki_der, error_message)); | |
143 } | |
144 | |
145 unsigned int modulus_length_; | |
146 | |
147 private: | |
148 // Must be called on origin thread, use CallBack() therefore. | |
149 GenerateKeyCallback callback_; | |
150 }; | |
151 | |
152 class SignState : public NSSOperationState { | |
153 public: | |
154 SignState(const std::string& public_key, | |
155 const std::string& data, | |
156 const SignCallback& callback, | |
157 Profile* profile); | |
158 virtual ~SignState() {} | |
159 | |
160 virtual void OnError(const tracked_objects::Location& from, | |
161 const std::string& error_message) OVERRIDE { | |
162 CallBack(from, std::string() /* no signature */, error_message); | |
163 } | |
164 | |
165 void CallBack(const tracked_objects::Location& from, | |
166 const std::string& signature, | |
167 const std::string& error_message) { | |
168 origin_task_runner_->PostTask( | |
169 from, base::Bind(callback_, signature, error_message)); | |
170 } | |
171 | |
172 std::string public_key_; | |
173 std::string data_; | |
174 | |
175 private: | |
176 // Must be called on origin thread, use CallBack() therefore. | |
177 SignCallback callback_; | |
178 }; | |
179 | |
180 class GetCertificatesState : public NSSOperationState { | |
181 public: | |
182 GetCertificatesState(const GetCertificatesCallback& callback, | |
183 Profile* profile); | |
184 virtual ~GetCertificatesState() {} | |
185 | |
186 virtual void OnError(const tracked_objects::Location& from, | |
187 const std::string& error_message) OVERRIDE { | |
188 CallBack(from, | |
189 scoped_ptr<net::CertificateList>() /* no certificates */, | |
190 error_message); | |
191 } | |
192 | |
193 void CallBack(const tracked_objects::Location& from, | |
194 scoped_ptr<net::CertificateList> certs, | |
195 const std::string& error_message) { | |
196 origin_task_runner_->PostTask( | |
197 from, base::Bind(callback_, base::Passed(&certs), error_message)); | |
198 } | |
199 | |
200 scoped_ptr<net::CertificateList> certs_; | |
201 | |
202 private: | |
203 // Must be called on origin thread, use CallBack() therefore. | |
204 GetCertificatesCallback callback_; | |
205 }; | |
206 | |
207 class ImportCertificateState : public NSSOperationState { | |
208 public: | |
209 ImportCertificateState(scoped_refptr<net::X509Certificate> certificate, | |
210 const ImportCertificateCallback& callback, | |
211 Profile* profile); | |
212 virtual ~ImportCertificateState() {} | |
213 | |
214 virtual void OnError(const tracked_objects::Location& from, | |
215 const std::string& error_message) OVERRIDE { | |
216 CallBack(from, error_message); | |
217 } | |
218 | |
219 void CallBack(const tracked_objects::Location& from, | |
220 const std::string& error_message) { | |
221 origin_task_runner_->PostTask(from, base::Bind(callback_, error_message)); | |
222 } | |
223 | |
224 scoped_refptr<net::X509Certificate> certificate_; | |
225 | |
226 private: | |
227 // Must be called on origin thread, use CallBack() therefore. | |
228 ImportCertificateCallback callback_; | |
229 }; | |
230 | |
231 class RemoveCertificateState : public NSSOperationState { | |
232 public: | |
233 RemoveCertificateState(scoped_refptr<net::X509Certificate> certificate, | |
234 const RemoveCertificateCallback& callback, | |
235 Profile* profile); | |
236 virtual ~RemoveCertificateState() {} | |
237 | |
238 virtual void OnError(const tracked_objects::Location& from, | |
239 const std::string& error_message) OVERRIDE { | |
240 CallBack(from, error_message); | |
241 } | |
242 | |
243 void CallBack(const tracked_objects::Location& from, | |
244 const std::string& error_message) { | |
245 origin_task_runner_->PostTask(from, base::Bind(callback_, error_message)); | |
246 } | |
247 | |
248 scoped_refptr<net::X509Certificate> certificate_; | |
249 | |
250 private: | |
251 // Must be called on origin thread, use CallBack() therefore. | |
252 RemoveCertificateCallback callback_; | |
253 }; | |
254 | |
255 NSSOperationState::NSSOperationState(Profile* profile) | |
256 : profile_(profile), | |
257 origin_task_runner_(base::ThreadTaskRunnerHandle::Get()) { | |
258 } | |
259 | |
260 GenerateRSAKeyState::GenerateRSAKeyState(unsigned int modulus_length, | |
261 const GenerateKeyCallback& callback, | |
262 Profile* profile) | |
263 : NSSOperationState(profile), | |
264 modulus_length_(modulus_length), | |
265 callback_(callback) { | |
266 } | |
267 | |
268 SignState::SignState(const std::string& public_key, | |
269 const std::string& data, | |
270 const SignCallback& callback, | |
271 Profile* profile) | |
272 : NSSOperationState(profile), | |
273 public_key_(public_key), | |
274 data_(data), | |
275 callback_(callback) { | |
276 } | |
277 | |
278 GetCertificatesState::GetCertificatesState( | |
279 const GetCertificatesCallback& callback, | |
280 Profile* profile) | |
281 : NSSOperationState(profile), callback_(callback) { | |
282 } | |
283 | |
284 ImportCertificateState::ImportCertificateState( | |
285 scoped_refptr<net::X509Certificate> certificate, | |
286 const ImportCertificateCallback& callback, | |
287 Profile* profile) | |
eroman
2014/05/19 23:27:45
The ownership model here seems ill defined.
There
pneubeck (no reviews)
2014/05/20 09:29:21
I fixed Profile*, by passing it explicitly. It's n
| |
288 : NSSOperationState(profile), | |
289 certificate_(certificate), | |
290 callback_(callback) { | |
291 } | |
292 | |
293 RemoveCertificateState::RemoveCertificateState( | |
294 scoped_refptr<net::X509Certificate> certificate, | |
295 const RemoveCertificateCallback& callback, | |
296 Profile* profile) | |
297 : NSSOperationState(profile), | |
298 certificate_(certificate), | |
299 callback_(callback) { | |
300 } | |
301 | |
302 // Does the actual key generation on a worker thread. Used by | |
303 // GenerateRSAKeyWithDB(). | |
304 void GenerateRSAKeyOnWorkerThread(scoped_ptr<GenerateRSAKeyState> state) { | |
305 scoped_ptr<crypto::RSAPrivateKey> rsa_key( | |
306 crypto::RSAPrivateKey::CreateSensitive(state->slot_.get(), | |
307 state->modulus_length_)); | |
308 if (!rsa_key) { | |
309 LOG(ERROR) << "Couldn't create key."; | |
310 state->OnError(FROM_HERE, kErrorInternal); | |
311 return; | |
312 } | |
313 | |
314 std::vector<uint8> public_key_spki_der; | |
315 if (!rsa_key->ExportPublicKey(&public_key_spki_der)) { | |
316 // TODO(pneubeck): Remove rsa_key from storage. | |
317 LOG(ERROR) << "Couldn't export public key."; | |
318 state->OnError(FROM_HERE, kErrorInternal); | |
319 return; | |
320 } | |
321 state->CallBack( | |
322 FROM_HERE, | |
323 std::string(public_key_spki_der.begin(), public_key_spki_der.end()), | |
324 std::string() /* no error */); | |
325 } | |
326 | |
327 // Continues generating a RSA key with the obtained NSSCertDatabase. Used by | |
328 // GenerateRSAKey(). | |
329 void GenerateRSAKeyWithDB(scoped_ptr<GenerateRSAKeyState> state, | |
330 net::NSSCertDatabase* cert_db) { | |
331 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
332 // Only the slot and not the NSSCertDatabase is required. Ignore |cert_db|. | |
333 base::WorkerPool::PostTask( | |
334 FROM_HERE, | |
335 base::Bind(&GenerateRSAKeyOnWorkerThread, base::Passed(&state)), | |
336 true /*task is slow*/); | |
337 } | |
338 | |
339 // Does the actual signing on a worker thread. Used by RSASignWithDB(). | |
340 void RSASignOnWorkerThread(scoped_ptr<SignState> state) { | |
341 const uint8* public_key_uint8 = | |
342 reinterpret_cast<const uint8*>(state->public_key_.data()); | |
343 std::vector<uint8> public_key_vector( | |
344 public_key_uint8, public_key_uint8 + state->public_key_.size()); | |
345 | |
346 // TODO(pneubeck): This searches all slots. Change to look only at |slot_|. | |
347 scoped_ptr<crypto::RSAPrivateKey> rsa_key( | |
348 crypto::RSAPrivateKey::FindFromPublicKeyInfo(public_key_vector)); | |
349 if (!rsa_key || rsa_key->key()->pkcs11Slot != state->slot_) { | |
350 state->OnError(FROM_HERE, kErrorKeyNotFound); | |
351 return; | |
352 } | |
353 | |
354 SECItem sign_result = {siBuffer, NULL, 0}; | |
355 if (SEC_SignData(&sign_result, | |
356 reinterpret_cast<const unsigned char*>(state->data_.data()), | |
357 state->data_.size(), | |
358 rsa_key->key(), | |
359 SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION) != SECSuccess) { | |
360 LOG(ERROR) << "Couldn't sign."; | |
361 state->OnError(FROM_HERE, kErrorInternal); | |
362 return; | |
363 } | |
364 | |
365 std::string signature(reinterpret_cast<const char*>(sign_result.data), | |
366 sign_result.len); | |
367 state->CallBack(FROM_HERE, signature, std::string() /* no error */); | |
368 } | |
369 | |
370 // Continues signing with the obtained NSSCertDatabase. Used by Sign(). | |
371 void RSASignWithDB(scoped_ptr<SignState> state, net::NSSCertDatabase* cert_db) { | |
372 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
373 // Only the slot and not the NSSCertDatabase is required. Ignore |cert_db|. | |
374 base::WorkerPool::PostTask( | |
375 FROM_HERE, | |
376 base::Bind(&RSASignOnWorkerThread, base::Passed(&state)), | |
377 true /*task is slow*/); | |
378 } | |
379 | |
380 // Filters the obtained certificates on a worker thread. Used by | |
381 // DidGetCertificates(). | |
382 void FilterCertificatesOnWorkerThread(scoped_ptr<GetCertificatesState> state) { | |
383 scoped_ptr<net::CertificateList> client_certs(new net::CertificateList); | |
384 for (net::CertificateList::const_iterator it = state->certs_->begin(); | |
385 it != state->certs_->end(); | |
386 ++it) { | |
387 net::X509Certificate::OSCertHandle cert_handle = (*it)->os_cert_handle(); | |
388 crypto::ScopedPK11Slot cert_slot(PK11_KeyForCertExists(cert_handle, | |
389 NULL, // keyPtr | |
390 NULL)); // wincx | |
391 | |
392 // Keep only user certificates, i.e. certs for which the private key is | |
393 // present and stored in the queried slot. | |
394 if (cert_slot != state->slot_) | |
395 continue; | |
396 | |
397 client_certs->push_back(*it); | |
398 } | |
399 | |
400 state->CallBack(FROM_HERE, client_certs.Pass(), std::string() /* no error */); | |
401 } | |
402 | |
403 // Passes the obtained certificates to the worker thread for filtering. Used by | |
404 // GetCertificatesWithDB(). | |
405 void DidGetCertificates(scoped_ptr<GetCertificatesState> state, | |
406 scoped_ptr<net::CertificateList> all_certs) { | |
407 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
408 state->certs_ = all_certs.Pass(); | |
409 base::WorkerPool::PostTask( | |
410 FROM_HERE, | |
411 base::Bind(&FilterCertificatesOnWorkerThread, base::Passed(&state)), | |
412 true /*task is slow*/); | |
413 } | |
414 | |
415 // Continues getting certificates with the obtained NSSCertDatabase. Used by | |
416 // GetCertificates(). | |
417 void GetCertificatesWithDB(scoped_ptr<GetCertificatesState> state, | |
418 net::NSSCertDatabase* cert_db) { | |
419 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
420 // Get the pointer to slot before base::Passed releases |state|. | |
421 PK11SlotInfo* slot = state->slot_.get(); | |
422 cert_db->ListCertsInSlot( | |
423 base::Bind(&DidGetCertificates, base::Passed(&state)), slot); | |
424 } | |
425 | |
426 // Does the actual certificate importing on the IO thread. Used by | |
427 // ImportCertificate(). | |
428 void ImportCertificateWithDB(scoped_ptr<ImportCertificateState> state, | |
429 net::NSSCertDatabase* cert_db) { | |
430 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
431 // TODO(pneubeck): Use |state->slot_| to verify that we're really importing to | |
432 // the correct token. | |
433 // |cert_db| is not required, ignore it. | |
434 net::CertDatabase* db = net::CertDatabase::GetInstance(); | |
435 | |
436 const net::Error cert_status = db->CheckUserCert(state->certificate_); | |
437 if (cert_status == net::ERR_NO_PRIVATE_KEY_FOR_CERT) { | |
438 state->OnError(FROM_HERE, kErrorKeyNotFound); | |
439 return; | |
440 } else if (cert_status != net::OK) { | |
441 state->OnError(FROM_HERE, net::ErrorToString(cert_status)); | |
442 return; | |
443 } | |
444 | |
445 const net::Error import_status = db->AddUserCert(state->certificate_.get()); | |
446 if (import_status != net::OK) { | |
447 LOG(ERROR) << "Could not import certificate."; | |
448 state->OnError(FROM_HERE, net::ErrorToString(import_status)); | |
449 return; | |
450 } | |
451 | |
452 state->CallBack(FROM_HERE, std::string() /* no error */); | |
453 } | |
454 | |
455 // Called on IO thread after the certificate removal is finished. | |
456 void DidRemoveCertificate(scoped_ptr<RemoveCertificateState> state, | |
457 bool certificate_found, | |
458 bool success) { | |
459 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
460 // CertificateNotFound error has precedence over an internal error. | |
461 if (!certificate_found) { | |
462 state->OnError(FROM_HERE, kErrorCertificateNotFound); | |
463 return; | |
464 } | |
465 if (!success) { | |
466 state->OnError(FROM_HERE, kErrorInternal); | |
467 return; | |
468 } | |
469 | |
470 state->CallBack(FROM_HERE, std::string() /* no error */); | |
471 } | |
472 | |
473 // Does the actual certificate removal on the IO thread. Used by | |
474 // RemoveCertificate(). | |
475 void RemoveCertificateWithDB(scoped_ptr<RemoveCertificateState> state, | |
476 net::NSSCertDatabase* cert_db) { | |
477 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
478 // Get the pointer before base::Passed clears |state|. | |
479 scoped_refptr<net::X509Certificate> certificate = state->certificate_; | |
480 bool certificate_found = certificate->os_cert_handle()->isperm; | |
481 cert_db->DeleteCertAndKeyAsync( | |
482 certificate, | |
483 base::Bind( | |
484 &DidRemoveCertificate, base::Passed(&state), certificate_found)); | |
485 } | |
486 | |
487 } // namespace | |
488 | |
489 void GenerateRSAKey(const std::string& token_id, | |
490 unsigned int modulus_length, | |
491 const GenerateKeyCallback& callback, | |
492 Profile* profile) { | |
493 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
494 scoped_ptr<GenerateRSAKeyState> state( | |
495 new GenerateRSAKeyState(modulus_length, callback, profile)); | |
496 | |
497 if (modulus_length > kMaxRSAModulusLength) { | |
498 state->OnError(FROM_HERE, kErrorAlgorithmNotSupported); | |
499 return; | |
500 } | |
501 | |
502 // Get the pointer to |state| before base::Passed releases |state|. | |
503 NSSOperationState* state_ptr = state.get(); | |
504 GetCertDatabase(token_id, | |
505 base::Bind(&GenerateRSAKeyWithDB, base::Passed(&state)), | |
506 state_ptr); | |
507 } | |
508 | |
509 void Sign(const std::string& token_id, | |
510 const std::string& public_key, | |
511 const std::string& data, | |
512 const SignCallback& callback, | |
513 Profile* profile) { | |
514 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
515 scoped_ptr<SignState> state( | |
516 new SignState(public_key, data, callback, profile)); | |
517 // Get the pointer to |state| before base::Passed releases |state|. | |
518 NSSOperationState* state_ptr = state.get(); | |
519 | |
520 // The NSSCertDatabase object is not required. But in case it's not available | |
521 // we would get more informative error messages and we can double check that | |
522 // we use a key of the correct token. | |
523 GetCertDatabase( | |
524 token_id, base::Bind(&RSASignWithDB, base::Passed(&state)), state_ptr); | |
525 } | |
526 | |
527 void GetCertificates(const std::string& token_id, | |
528 const GetCertificatesCallback& callback, | |
529 Profile* profile) { | |
530 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
531 scoped_ptr<GetCertificatesState> state( | |
532 new GetCertificatesState(callback, profile)); | |
533 // Get the pointer to |state| before base::Passed releases |state|. | |
534 NSSOperationState* state_ptr = state.get(); | |
535 GetCertDatabase(token_id, | |
536 base::Bind(&GetCertificatesWithDB, base::Passed(&state)), | |
537 state_ptr); | |
538 } | |
539 | |
540 void ImportCertificate(const std::string& token_id, | |
541 scoped_refptr<net::X509Certificate> certificate, | |
542 const ImportCertificateCallback& callback, | |
543 Profile* profile) { | |
544 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
545 scoped_ptr<ImportCertificateState> state( | |
546 new ImportCertificateState(certificate, callback, profile)); | |
547 // Get the pointer to |state| before base::Passed releases |state|. | |
548 NSSOperationState* state_ptr = state.get(); | |
549 | |
550 // The NSSCertDatabase object is not required. But in case it's not available | |
551 // we would get more informative error messages and we can double check that | |
552 // we use a key of the correct token. | |
553 GetCertDatabase(token_id, | |
554 base::Bind(&ImportCertificateWithDB, base::Passed(&state)), | |
555 state_ptr); | |
556 } | |
557 | |
558 void RemoveCertificate(const std::string& token_id, | |
559 scoped_refptr<net::X509Certificate> certificate, | |
560 const RemoveCertificateCallback& callback, | |
561 Profile* profile) { | |
562 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
563 scoped_ptr<RemoveCertificateState> state( | |
564 new RemoveCertificateState(certificate, callback, profile)); | |
565 // Get the pointer to |state| before base::Passed releases |state|. | |
566 NSSOperationState* state_ptr = state.get(); | |
567 | |
568 // The NSSCertDatabase object is not required. But in case it's not available | |
569 // we would get more informative error messages. | |
570 GetCertDatabase(token_id, | |
571 base::Bind(&RemoveCertificateWithDB, base::Passed(&state)), | |
572 state_ptr); | |
573 } | |
574 | |
575 } // namespace platform_keys | |
576 | |
577 } // namespace chromeos | |
OLD | NEW |