OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/cros/cert_library.h" | 5 #include "chrome/browser/chromeos/cros/cert_library.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/chromeos/chromeos_version.h" | 9 #include "base/chromeos/chromeos_version.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
11 #include "base/memory/weak_ptr.h" | 11 #include "base/memory/weak_ptr.h" |
12 #include "base/observer_list_threadsafe.h" | 12 #include "base/observer_list_threadsafe.h" |
13 #include "base/string_util.h" | 13 #include "base/string_util.h" |
14 #include "base/strings/string_number_conversions.h" | 14 #include "base/strings/string_number_conversions.h" |
15 #include "base/utf_string_conversions.h" | 15 #include "base/utf_string_conversions.h" |
16 #include "chrome/browser/browser_process.h" // g_browser_process | 16 #include "chrome/browser/browser_process.h" // g_browser_process |
17 #include "chrome/browser/chromeos/cros/cros_library.h" | |
18 #include "chrome/browser/chromeos/cros/cryptohome_library.h" | |
19 #include "chrome/common/chrome_switches.h" | 17 #include "chrome/common/chrome_switches.h" |
20 #include "chrome/common/net/x509_certificate_model.h" | 18 #include "chrome/common/net/x509_certificate_model.h" |
21 #include "chromeos/dbus/cryptohome_client.h" | 19 #include "chromeos/dbus/cryptohome_client.h" |
22 #include "chromeos/dbus/dbus_thread_manager.h" | 20 #include "chromeos/dbus/dbus_thread_manager.h" |
23 #include "chromeos/login/login_state.h" | 21 #include "chromeos/login/login_state.h" |
24 #include "content/public/browser/browser_thread.h" | 22 #include "content/public/browser/browser_thread.h" |
25 #include "crypto/encryptor.h" | |
26 #include "crypto/nss_util.h" | 23 #include "crypto/nss_util.h" |
27 #include "crypto/sha2.h" | |
28 #include "crypto/symmetric_key.h" | |
29 #include "grit/generated_resources.h" | 24 #include "grit/generated_resources.h" |
30 #include "net/cert/cert_database.h" | 25 #include "net/cert/cert_database.h" |
31 #include "net/cert/nss_cert_database.h" | 26 #include "net/cert/nss_cert_database.h" |
32 #include "third_party/icu/public/i18n/unicode/coll.h" // icu::Collator | 27 #include "third_party/icu/public/i18n/unicode/coll.h" // icu::Collator |
33 #include "ui/base/l10n/l10n_util.h" | 28 #include "ui/base/l10n/l10n_util.h" |
34 #include "ui/base/l10n/l10n_util_collator.h" | 29 #include "ui/base/l10n/l10n_util_collator.h" |
35 | 30 |
36 using content::BrowserThread; | 31 using content::BrowserThread; |
37 | 32 |
38 namespace chromeos { | 33 namespace chromeos { |
39 | 34 |
40 namespace { | 35 namespace { |
41 | 36 |
42 // Root CA certificates that are built into Chrome use this token name. | 37 // Root CA certificates that are built into Chrome use this token name. |
43 const char kRootCertificateTokenName[] = "Builtin Object Token"; | 38 const char kRootCertificateTokenName[] = "Builtin Object Token"; |
44 | 39 |
45 // Delay between certificate requests while waiting for TPM/PKCS#11 init. | 40 // Delay between certificate requests while waiting for TPM/PKCS#11 init. |
46 const int kRequestDelayMs = 500; | 41 const int kRequestDelayMs = 500; |
47 | 42 |
48 const size_t kKeySize = 16; | |
49 | |
50 string16 GetDisplayString(net::X509Certificate* cert, bool hardware_backed) { | 43 string16 GetDisplayString(net::X509Certificate* cert, bool hardware_backed) { |
51 std::string org; | 44 std::string org; |
52 if (!cert->subject().organization_names.empty()) | 45 if (!cert->subject().organization_names.empty()) |
53 org = cert->subject().organization_names[0]; | 46 org = cert->subject().organization_names[0]; |
54 if (org.empty()) | 47 if (org.empty()) |
55 org = cert->subject().GetDisplayName(); | 48 org = cert->subject().GetDisplayName(); |
56 string16 issued_by = UTF8ToUTF16( | 49 string16 issued_by = UTF8ToUTF16( |
57 x509_certificate_model::GetIssuerCommonName(cert->os_cert_handle(), | 50 x509_certificate_model::GetIssuerCommonName(cert->os_cert_handle(), |
58 org)); // alternative text | 51 org)); // alternative text |
59 string16 issued_to = UTF8ToUTF16( | 52 string16 issued_to = UTF8ToUTF16( |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
159 virtual const CertList& GetServerCertificates() const OVERRIDE { | 152 virtual const CertList& GetServerCertificates() const OVERRIDE { |
160 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 153 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
161 return server_certs_; | 154 return server_certs_; |
162 } | 155 } |
163 | 156 |
164 virtual const CertList& GetCACertificates() const OVERRIDE { | 157 virtual const CertList& GetCACertificates() const OVERRIDE { |
165 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 158 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
166 return server_ca_certs_; | 159 return server_ca_certs_; |
167 } | 160 } |
168 | 161 |
169 virtual crypto::SymmetricKey* PassphraseToKey(const std::string& passprhase, | |
170 const std::string& salt) { | |
171 return crypto::SymmetricKey::DeriveKeyFromPassword( | |
172 crypto::SymmetricKey::AES, passprhase, salt, 1000, 256); | |
173 } | |
174 | |
175 virtual std::string EncryptWithSystemSalt(const std::string& token) OVERRIDE { | |
176 // Don't care about token encryption while debugging. | |
177 if (!base::chromeos::IsRunningOnChromeOS()) | |
178 return token; | |
179 | |
180 if (!LoadSystemSaltKey()) { | |
181 LOG(WARNING) << "System salt key is not available for encrypt."; | |
182 return std::string(); | |
183 } | |
184 return EncryptTokenWithKey( | |
185 system_salt_key_.get(), | |
186 CrosLibrary::Get()->GetCryptohomeLibrary()->GetSystemSalt(), | |
187 token); | |
188 } | |
189 | |
190 virtual std::string EncryptWithUserKey(const std::string& token) OVERRIDE { | |
191 // Don't care about token encryption while debugging. | |
192 if (!base::chromeos::IsRunningOnChromeOS()) | |
193 return token; | |
194 | |
195 if (!LoadSupplementalUserKey()) { | |
196 LOG(WARNING) << "Supplemental user key is not available for encrypt."; | |
197 return std::string(); | |
198 } | |
199 return EncryptTokenWithKey( | |
200 supplemental_user_key_.get(), | |
201 CrosLibrary::Get()->GetCryptohomeLibrary()->GetSystemSalt(), | |
202 token); | |
203 } | |
204 | |
205 // Encrypts (AES) the token given |key| and |salt|. | |
206 virtual std::string EncryptTokenWithKey(crypto::SymmetricKey* key, | |
207 const std::string& salt, | |
208 const std::string& token) { | |
209 crypto::Encryptor encryptor; | |
210 if (!encryptor.Init(key, crypto::Encryptor::CTR, std::string())) { | |
211 LOG(WARNING) << "Failed to initialize Encryptor."; | |
212 return std::string(); | |
213 } | |
214 std::string nonce = salt.substr(0, kKeySize); | |
215 std::string encoded_token; | |
216 CHECK(encryptor.SetCounter(nonce)); | |
217 if (!encryptor.Encrypt(token, &encoded_token)) { | |
218 LOG(WARNING) << "Failed to encrypt token."; | |
219 return std::string(); | |
220 } | |
221 | |
222 return StringToLowerASCII(base::HexEncode( | |
223 reinterpret_cast<const void*>(encoded_token.data()), | |
224 encoded_token.size())); | |
225 } | |
226 | |
227 virtual std::string DecryptWithSystemSalt( | |
228 const std::string& encrypted_token_hex) OVERRIDE { | |
229 // Don't care about token encryption while debugging. | |
230 if (!base::chromeos::IsRunningOnChromeOS()) | |
231 return encrypted_token_hex; | |
232 | |
233 if (!LoadSystemSaltKey()) { | |
234 LOG(WARNING) << "System salt key is not available for decrypt."; | |
235 return std::string(); | |
236 } | |
237 return DecryptTokenWithKey( | |
238 system_salt_key_.get(), | |
239 CrosLibrary::Get()->GetCryptohomeLibrary()->GetSystemSalt(), | |
240 encrypted_token_hex); | |
241 } | |
242 | |
243 virtual std::string DecryptWithUserKey( | |
244 const std::string& encrypted_token_hex) OVERRIDE { | |
245 // Don't care about token encryption while debugging. | |
246 if (!base::chromeos::IsRunningOnChromeOS()) | |
247 return encrypted_token_hex; | |
248 | |
249 if (!LoadSupplementalUserKey()) { | |
250 LOG(WARNING) << "Supplemental user key is not available for decrypt."; | |
251 return std::string(); | |
252 } | |
253 return DecryptTokenWithKey( | |
254 supplemental_user_key_.get(), | |
255 CrosLibrary::Get()->GetCryptohomeLibrary()->GetSystemSalt(), | |
256 encrypted_token_hex); | |
257 } | |
258 | |
259 // Decrypts (AES) hex encoded encrypted token given |key| and |salt|. | |
260 virtual std::string DecryptTokenWithKey( | |
261 crypto::SymmetricKey* key, | |
262 const std::string& salt, | |
263 const std::string& encrypted_token_hex) { | |
264 std::vector<uint8> encrypted_token_bytes; | |
265 if (!base::HexStringToBytes(encrypted_token_hex, &encrypted_token_bytes)) { | |
266 LOG(WARNING) << "Corrupt encrypted token found."; | |
267 return std::string(); | |
268 } | |
269 | |
270 std::string encrypted_token( | |
271 reinterpret_cast<char*>(encrypted_token_bytes.data()), | |
272 encrypted_token_bytes.size()); | |
273 crypto::Encryptor encryptor; | |
274 if (!encryptor.Init(key, crypto::Encryptor::CTR, std::string())) { | |
275 LOG(WARNING) << "Failed to initialize Encryptor."; | |
276 return std::string(); | |
277 } | |
278 | |
279 std::string nonce = salt.substr(0, kKeySize); | |
280 std::string token; | |
281 CHECK(encryptor.SetCounter(nonce)); | |
282 if (!encryptor.Decrypt(encrypted_token, &token)) { | |
283 LOG(WARNING) << "Failed to decrypt token."; | |
284 return std::string(); | |
285 } | |
286 return token; | |
287 } | |
288 | |
289 // net::CertDatabase::Observer implementation. Observer added on UI thread. | 162 // net::CertDatabase::Observer implementation. Observer added on UI thread. |
290 virtual void OnCertTrustChanged(const net::X509Certificate* cert) OVERRIDE { | 163 virtual void OnCertTrustChanged(const net::X509Certificate* cert) OVERRIDE { |
291 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 164 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
292 } | 165 } |
293 | 166 |
294 virtual void OnCertAdded(const net::X509Certificate* cert) OVERRIDE { | 167 virtual void OnCertAdded(const net::X509Certificate* cert) OVERRIDE { |
295 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 168 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
296 // Only load certificates if we have completed an initial request. | 169 // Only load certificates if we have completed an initial request. |
297 if (certificates_loaded_) { | 170 if (certificates_loaded_) { |
298 BrowserThread::PostTask( | 171 BrowserThread::PostTask( |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
415 | 288 |
416 // Set loaded state and notify observers. | 289 // Set loaded state and notify observers. |
417 if (!certificates_loaded_) { | 290 if (!certificates_loaded_) { |
418 certificates_loaded_ = true; | 291 certificates_loaded_ = true; |
419 NotifyCertificatesLoaded(true); | 292 NotifyCertificatesLoaded(true); |
420 } else { | 293 } else { |
421 NotifyCertificatesLoaded(false); | 294 NotifyCertificatesLoaded(false); |
422 } | 295 } |
423 } | 296 } |
424 | 297 |
425 bool LoadSupplementalUserKey() { | |
426 if (!user_logged_in_) { | |
427 // If we are not logged in, we cannot load any certificates. | |
428 // Set 'loaded' to true for the UI, since we are not waiting on loading. | |
429 LOG(WARNING) << "Requesting supplemental use key before login."; | |
430 return false; | |
431 } | |
432 if (!supplemental_user_key_.get()) { | |
433 supplemental_user_key_.reset(crypto::GetSupplementalUserKey()); | |
434 } | |
435 return supplemental_user_key_.get() != NULL; | |
436 } | |
437 | |
438 // TODO: should this use the system salt for both the password and the salt | |
439 // value, or should this use a separate salt value? | |
440 bool LoadSystemSaltKey() { | |
441 if (!system_salt_key_.get()) { | |
442 system_salt_key_.reset(PassphraseToKey( | |
443 CrosLibrary::Get()->GetCryptohomeLibrary()->GetSystemSalt(), | |
444 CrosLibrary::Get()->GetCryptohomeLibrary()->GetSystemSalt())); | |
445 } | |
446 return system_salt_key_.get() != NULL; | |
447 } | |
448 | |
449 // Call this to start the certificate list initialization process. | 298 // Call this to start the certificate list initialization process. |
450 // Must be called from the UI thread. | 299 // Must be called from the UI thread. |
451 void RequestCertificates() { | 300 void RequestCertificates() { |
452 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 301 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
453 | 302 |
454 certificates_requested_ = true; | 303 certificates_requested_ = true; |
455 | 304 |
456 if (!LoginState::Get()->IsUserLoggedIn()) { | 305 if (!LoginState::Get()->IsUserLoggedIn()) { |
457 // If we are not logged in, we cannot load any certificates. | 306 // If we are not logged in, we cannot load any certificates. |
458 // Set 'loaded' to true for the UI, since we are not waiting on loading. | 307 // Set 'loaded' to true for the UI, since we are not waiting on loading. |
459 LOG(WARNING) << "Requesting certificates before login."; | 308 LOG(WARNING) << "Requesting certificates before login."; |
460 certificates_loaded_ = true; | 309 certificates_loaded_ = true; |
461 supplemental_user_key_.reset(NULL); | |
462 return; | 310 return; |
463 } | 311 } |
464 | 312 |
465 if (!user_logged_in_) { | 313 if (!user_logged_in_) { |
466 user_logged_in_ = true; | 314 user_logged_in_ = true; |
467 certificates_loaded_ = false; | 315 certificates_loaded_ = false; |
468 supplemental_user_key_.reset(NULL); | |
469 } | 316 } |
470 | 317 |
471 VLOG(1) << "Requesting Certificates."; | 318 VLOG(1) << "Requesting Certificates."; |
472 DBusThreadManager::Get()->GetCryptohomeClient()->TpmIsEnabled( | 319 DBusThreadManager::Get()->GetCryptohomeClient()->TpmIsEnabled( |
473 base::Bind(&CertLibraryImpl::OnTpmIsEnabled, | 320 base::Bind(&CertLibraryImpl::OnTpmIsEnabled, |
474 weak_ptr_factory_.GetWeakPtr())); | 321 weak_ptr_factory_.GetWeakPtr())); |
475 } | 322 } |
476 | 323 |
477 // This method is used to implement RequestCertificates. | 324 // This method is used to implement RequestCertificates. |
478 void OnTpmIsEnabled(DBusMethodCallStatus call_status, bool tpm_is_enabled) { | 325 void OnTpmIsEnabled(DBusMethodCallStatus call_status, bool tpm_is_enabled) { |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
563 base::Closure request_task_; | 410 base::Closure request_task_; |
564 | 411 |
565 bool tpm_token_ready_; | 412 bool tpm_token_ready_; |
566 | 413 |
567 // Cached TPM token name. | 414 // Cached TPM token name. |
568 std::string tpm_token_name_; | 415 std::string tpm_token_name_; |
569 | 416 |
570 // Cached TPM user pin. | 417 // Cached TPM user pin. |
571 std::string tpm_user_pin_; | 418 std::string tpm_user_pin_; |
572 | 419 |
573 // Supplemental user key. | |
574 scoped_ptr<crypto::SymmetricKey> supplemental_user_key_; | |
575 | |
576 // A key based on the system salt. Useful for encrypting device-level | |
577 // data for which we have no additional credentials. | |
578 scoped_ptr<crypto::SymmetricKey> system_salt_key_; | |
579 | |
580 // Local state. | 420 // Local state. |
581 bool user_logged_in_; | 421 bool user_logged_in_; |
582 bool certificates_requested_; | 422 bool certificates_requested_; |
583 bool certificates_loaded_; | 423 bool certificates_loaded_; |
584 // The key store for the current user has been loaded. This flag is needed to | 424 // The key store for the current user has been loaded. This flag is needed to |
585 // ensure that the key store will not be loaded twice in the policy recovery | 425 // ensure that the key store will not be loaded twice in the policy recovery |
586 // "safe-mode". | 426 // "safe-mode". |
587 bool key_store_loaded_; | 427 bool key_store_loaded_; |
588 | 428 |
589 // Certificates. | 429 // Certificates. |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
627 } | 467 } |
628 virtual const CertList& GetUserCertificates() const { | 468 virtual const CertList& GetUserCertificates() const { |
629 return cert_list_; | 469 return cert_list_; |
630 } | 470 } |
631 virtual const CertList& GetServerCertificates() const { | 471 virtual const CertList& GetServerCertificates() const { |
632 return cert_list_; | 472 return cert_list_; |
633 } | 473 } |
634 virtual const CertList& GetCACertificates() const { | 474 virtual const CertList& GetCACertificates() const { |
635 return cert_list_; | 475 return cert_list_; |
636 } | 476 } |
637 virtual std::string EncryptWithSystemSalt(const std::string& token) { | |
638 return token; | |
639 } | |
640 virtual std::string DecryptWithSystemSalt( | |
641 const std::string& encrypted_token_hex) { | |
642 return encrypted_token_hex; | |
643 } | |
644 virtual std::string EncryptWithUserKey(const std::string& token) { | |
645 return token; | |
646 } | |
647 virtual std::string DecryptWithUserKey( | |
648 const std::string& encrypted_token_hex) { | |
649 return encrypted_token_hex; | |
650 } | |
651 | 477 |
652 private: | 478 private: |
653 std::string token_name_; | 479 std::string token_name_; |
654 CertList cert_list_; | 480 CertList cert_list_; |
655 | 481 |
656 DISALLOW_COPY_AND_ASSIGN(CertLibraryImplStub); | 482 DISALLOW_COPY_AND_ASSIGN(CertLibraryImplStub); |
657 }; | 483 }; |
658 | 484 |
659 ////////////////////////////////////////////////////////////////////////////// | 485 ////////////////////////////////////////////////////////////////////////////// |
660 | 486 |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
727 net::X509Certificate* cert = GetCertificateAt(index); | 553 net::X509Certificate* cert = GetCertificateAt(index); |
728 net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); | 554 net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); |
729 std::string id = x509_certificate_model::GetPkcs11Id(cert_handle); | 555 std::string id = x509_certificate_model::GetPkcs11Id(cert_handle); |
730 if (id == pkcs11_id) | 556 if (id == pkcs11_id) |
731 return index; | 557 return index; |
732 } | 558 } |
733 return -1; // Not found. | 559 return -1; // Not found. |
734 } | 560 } |
735 | 561 |
736 } // chromeos | 562 } // chromeos |
OLD | NEW |