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