1 // Copyright (c) 2011 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/ui/webui/options/certificate_manager_handler.h" 6 7 #include "base/file_util.h" // for FileAccessProvider 8 #include "base/memory/scoped_vector.h" 9 #include "base/safe_strerror_posix.h" 10 #include "base/string_number_conversions.h" 11 #include "base/values.h" 12 #include "chrome/browser/browser_process.h" 13 #include "chrome/browser/ui/crypto_module_password_dialog.h" 14 #include "chrome/browser/ui/gtk/certificate_dialogs.h" 15 #include "content/browser/browser_thread.h" // for FileAccessProvider 16 #include "content/browser/certificate_viewer.h" 17 #include "content/browser/tab_contents/tab_contents.h" 18 #include "content/browser/tab_contents/tab_contents_view.h" 19 #include "grit/generated_resources.h" 20 #include "net/base/crypto_module.h" 21 #include "net/base/x509_certificate.h" 22 #include "ui/base/l10n/l10n_util.h" 23 #include "ui/base/l10n/l10n_util_collator.h" 24 25 #if defined(OS_CHROMEOS) 26 #include "chrome/browser/chromeos/cros/cros_library.h" 27 #include "chrome/browser/chromeos/cros/cryptohome_library.h" 28 #endif 29 30 namespace { 31 32 static const char kKeyId[] = "id"; 33 static const char kSubNodesId[] = "subnodes"; 34 static const char kNameId[] = "name"; 35 static const char kReadOnlyId[] = "readonly"; 36 static const char kIconId[] = "icon"; 37 static const char kSecurityDeviceId[] = "device"; 38 static const char kErrorId[] = "error"; 39 40 // Enumeration of different callers of SelectFile. (Start counting at 1 so 41 // if SelectFile is accidentally called with params=NULL it won't match any.) 42 enum { 43 EXPORT_PERSONAL_FILE_SELECTED = 1, 44 IMPORT_PERSONAL_FILE_SELECTED, 45 IMPORT_SERVER_FILE_SELECTED, 46 IMPORT_CA_FILE_SELECTED, 47 }; 48 49 // TODO(mattm): These are duplicated from cookies_view_handler.cc 50 // Encodes a pointer value into a hex string. 51 std::string PointerToHexString(const void* pointer) { 52 return base::HexEncode(&pointer, sizeof(pointer)); 53 } 54 55 // Decodes a pointer from a hex string. 56 void* HexStringToPointer(const std::string& str) { 57 std::vector<uint8> buffer; 58 if (!base::HexStringToBytes(str, &buffer) || 59 buffer.size() != sizeof(void*)) { 60 return NULL; 61 } 62 63 return *reinterpret_cast<void**>(&buffer[0]); 64 } 65 66 std::string OrgNameToId(const std::string& org) { 67 return "org-" + org; 68 } 69 70 std::string CertToId(const net::X509Certificate& cert) { 71 return "cert-" + PointerToHexString(&cert); 72 } 73 74 net::X509Certificate* IdToCert(const std::string& id) { 75 if (!StartsWithASCII(id, "cert-", true)) 76 return NULL; 77 return reinterpret_cast<net::X509Certificate*>( 78 HexStringToPointer(id.substr(5))); 79 } 80 81 net::X509Certificate* CallbackArgsToCert(const ListValue* args) { 82 std::string node_id; 83 if (!args->GetString(0, &node_id)){ 84 return NULL; 85 } 86 net::X509Certificate* cert = IdToCert(node_id); 87 if (!cert) { 88 NOTREACHED(); 89 return NULL; 90 } 91 return cert; 92 } 93 94 bool CallbackArgsToBool(const ListValue* args, int index, bool* result) { 95 std::string string_value; 96 if (!args->GetString(index, &string_value)) 97 return false; 98 99 *result = string_value[0] == 't'; 100 return true; 101 } 102 103 struct DictionaryIdComparator { 104 explicit DictionaryIdComparator(icu::Collator* collator) 105 : collator_(collator) { 106 } 107 108 bool operator()(const Value* a, 109 const Value* b) const { 110 DCHECK(a->GetType() == Value::TYPE_DICTIONARY); 111 DCHECK(b->GetType() == Value::TYPE_DICTIONARY); 112 const DictionaryValue* a_dict = reinterpret_cast<const DictionaryValue*>(a); 113 const DictionaryValue* b_dict = reinterpret_cast<const DictionaryValue*>(b); 114 string16 a_str; 115 string16 b_str; 116 a_dict->GetString(kNameId, &a_str); 117 b_dict->GetString(kNameId, &b_str); 118 if (collator_ == NULL) 119 return a_str < b_str; 120 return l10n_util::CompareString16WithCollator( 121 collator_, a_str, b_str) == UCOL_LESS; 122 } 123 124 icu::Collator* collator_; 125 }; 126 127 std::string NetErrorToString(int net_error) { 128 switch (net_error) { 129 // TODO(mattm): handle more cases. 130 case net::ERR_IMPORT_CA_CERT_NOT_CA: 131 return l10n_util::GetStringUTF8(IDS_CERT_MANAGER_ERROR_NOT_CA); 132 default: 133 return l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR); 134 } 135 } 136 137 } // namespace 138 139 /////////////////////////////////////////////////////////////////////////////// 140 // FileAccessProvider 141 142 // TODO(mattm): Move to some shared location? 143 class FileAccessProvider 144 : public base::RefCountedThreadSafe<FileAccessProvider>, 145 public CancelableRequestProvider { 146 public: 147 // Reports 0 on success or errno on failure, and the data of the file upon 148 // success. 149 // TODO(mattm): don't pass std::string by value.. could use RefCountedBytes 150 // but it's a vector. Maybe do the derive from CancelableRequest thing 151 // described in cancelable_request.h? 152 typedef Callback2<int, std::string>::Type ReadCallback; 153 154 // Reports 0 on success or errno on failure, and the number of bytes written, 155 // on success. 156 typedef Callback2<int, int>::Type WriteCallback; 157 158 Handle StartRead(const FilePath& path, 159 CancelableRequestConsumerBase* consumer, 160 ReadCallback* callback); 161 Handle StartWrite(const FilePath& path, 162 const std::string& data, 163 CancelableRequestConsumerBase* consumer, 164 WriteCallback* callback); 165 166 private: 167 void DoRead(scoped_refptr<CancelableRequest<ReadCallback> > request, 168 FilePath path); 169 void DoWrite(scoped_refptr<CancelableRequest<WriteCallback> > request, 170 FilePath path, 171 std::string data); 172 }; 173 174 CancelableRequestProvider::Handle FileAccessProvider::StartRead( 175 const FilePath& path, 176 CancelableRequestConsumerBase* consumer, 177 FileAccessProvider::ReadCallback* callback) { 178 scoped_refptr<CancelableRequest<ReadCallback> > request( 179 new CancelableRequest<ReadCallback>(callback)); 180 AddRequest(request, consumer); 181 182 // Send the parameters and the request to the file thread. 183 BrowserThread::PostTask( 184 BrowserThread::FILE, FROM_HERE, 185 NewRunnableMethod(this, &FileAccessProvider::DoRead, request, path)); 186 187 // The handle will have been set by AddRequest. 188 return request->handle(); 189 } 190 191 CancelableRequestProvider::Handle FileAccessProvider::StartWrite( 192 const FilePath& path, 193 const std::string& data, 194 CancelableRequestConsumerBase* consumer, 195 WriteCallback* callback) { 196 scoped_refptr<CancelableRequest<WriteCallback> > request( 197 new CancelableRequest<WriteCallback>(callback)); 198 AddRequest(request, consumer); 199 200 // Send the parameters and the request to the file thWrite. 201 BrowserThread::PostTask( 202 BrowserThread::FILE, FROM_HERE, 203 NewRunnableMethod( 204 this, &FileAccessProvider::DoWrite, request, path, data)); 205 206 // The handle will have been set by AddRequest. 207 return request->handle(); 208 } 209 210 void FileAccessProvider::DoRead( 211 scoped_refptr<CancelableRequest<ReadCallback> > request, 212 FilePath path) { 213 if (request->canceled()) 214 return; 215 216 std::string data; 217 VLOG(1) << "DoRead starting read"; 218 bool success = file_util::ReadFileToString(path, &data); 219 int saved_errno = success ? 0 : errno; 220 VLOG(1) << "DoRead done read: " << success << " " << data.size(); 221 request->ForwardResult(ReadCallback::TupleType(saved_errno, data)); 222 } 223 224 void FileAccessProvider::DoWrite( 225 scoped_refptr<CancelableRequest<WriteCallback> > request, 226 FilePath path, 227 std::string data) { 228 VLOG(1) << "DoWrite starting write"; 229 int bytes_written = file_util::WriteFile(path, data.data(), data.size()); 230 int saved_errno = bytes_written >= 0 ? 0 : errno; 231 VLOG(1) << "DoWrite done write " << bytes_written; 232 233 if (request->canceled()) 234 return; 235 236 request->ForwardResult(WriteCallback::TupleType(saved_errno, bytes_written)); 237 } 238 239 /////////////////////////////////////////////////////////////////////////////// 240 // CertificateManagerHandler 241 242 CertificateManagerHandler::CertificateManagerHandler() 243 : file_access_provider_(new FileAccessProvider) { 244 certificate_manager_model_.reset(new CertificateManagerModel(this)); 245 } 246 247 CertificateManagerHandler::~CertificateManagerHandler() { 248 } 249 250 void CertificateManagerHandler::GetLocalizedValues( 251 DictionaryValue* localized_strings) { 252 DCHECK(localized_strings); 253 254 RegisterTitle(localized_strings, "certificateManagerPage", 255 IDS_CERTIFICATE_MANAGER_TITLE); 256 257 // Tabs. 258 localized_strings->SetString("personalCertsTabTitle", 259 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PERSONAL_CERTS_TAB_LABEL)); 260 localized_strings->SetString("serverCertsTabTitle", 261 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_SERVER_CERTS_TAB_LABEL)); 262 localized_strings->SetString("caCertsTabTitle", 263 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_CERT_AUTHORITIES_TAB_LABEL)); 264 localized_strings->SetString("unknownCertsTabTitle", 265 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_UNKNOWN_TAB_LABEL)); 266 267 // Tab descriptions. 268 localized_strings->SetString("personalCertsTabDescription", 269 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_USER_TREE_DESCRIPTION)); 270 localized_strings->SetString("serverCertsTabDescription", 271 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_SERVER_TREE_DESCRIPTION)); 272 localized_strings->SetString("caCertsTabDescription", 273 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_AUTHORITIES_TREE_DESCRIPTION)); 274 localized_strings->SetString("unknownCertsTabDescription", 275 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_UNKNOWN_TREE_DESCRIPTION)); 276 277 // Tree columns. 278 localized_strings->SetString("certNameColumn", 279 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_NAME_COLUMN_LABEL)); 280 localized_strings->SetString("certDeviceColumn", 281 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DEVICE_COLUMN_LABEL)); 282 localized_strings->SetString("certSerialColumn", 283 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_SERIAL_NUMBER_COLUMN_LABEL)); 284 localized_strings->SetString("certExpiresColumn", 285 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPIRES_COLUMN_LABEL)); 286 287 // Buttons. 288 localized_strings->SetString("view_certificate", 289 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_VIEW_CERT_BUTTON)); 290 localized_strings->SetString("import_certificate", 291 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_IMPORT_BUTTON)); 292 localized_strings->SetString("export_certificate", 293 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_BUTTON)); 294 localized_strings->SetString("export_all_certificates", 295 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_ALL_BUTTON)); 296 localized_strings->SetString("edit_certificate", 297 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_BUTTON)); 298 localized_strings->SetString("delete_certificate", 299 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_BUTTON)); 300 301 // Certificate Delete overlay strings. 302 localized_strings->SetString("personalCertsTabDeleteConfirm", 303 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_USER_FORMAT)); 304 localized_strings->SetString("personalCertsTabDeleteImpact", 305 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_USER_DESCRIPTION)); 306 localized_strings->SetString("serverCertsTabDeleteConfirm", 307 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_SERVER_FORMAT)); 308 localized_strings->SetString("serverCertsTabDeleteImpact", 309 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_SERVER_DESCRIPTION)); 310 localized_strings->SetString("caCertsTabDeleteConfirm", 311 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_CA_FORMAT)); 312 localized_strings->SetString("caCertsTabDeleteImpact", 313 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_CA_DESCRIPTION)); 314 localized_strings->SetString("unknownCertsTabDeleteConfirm", 315 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_UNKNOWN_FORMAT)); 316 localized_strings->SetString("unknownCertsTabDeleteImpact", ""); 317 318 // Certificate Restore overlay strings. 319 localized_strings->SetString("certificateRestorePasswordDescription", 320 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_RESTORE_PASSWORD_DESC)); 321 localized_strings->SetString("certificatePasswordLabel", 322 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PASSWORD_LABEL)); 323 324 // Personal Certificate Export overlay strings. 325 localized_strings->SetString("certificateExportPasswordDescription", 326 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_PASSWORD_DESC)); 327 localized_strings->SetString("certificateExportPasswordHelp", 328 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_PASSWORD_HELP)); 329 localized_strings->SetString("certificateConfirmPasswordLabel", 330 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_CONFIRM_PASSWORD_LABEL)); 331 332 // Edit CA Trust & Import CA overlay strings. 333 localized_strings->SetString("certificateEditTrustLabel", 334 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_TRUST_LABEL)); 335 localized_strings->SetString("certificateEditCaTrustDescriptionFormat", 336 l10n_util::GetStringUTF16( 337 IDS_CERT_MANAGER_EDIT_CA_TRUST_DESCRIPTION_FORMAT)); 338 localized_strings->SetString("certificateImportCaDescriptionFormat", 339 l10n_util::GetStringUTF16( 340 IDS_CERT_MANAGER_IMPORT_CA_DESCRIPTION_FORMAT)); 341 localized_strings->SetString("certificateCaTrustSSLLabel", 342 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_CA_TRUST_SSL_LABEL)); 343 localized_strings->SetString("certificateCaTrustEmailLabel", 344 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_CA_TRUST_EMAIL_LABEL)); 345 localized_strings->SetString("certificateCaTrustObjSignLabel", 346 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_CA_TRUST_OBJSIGN_LABEL)); 347 localized_strings->SetString("certificateImportErrorFormat", 348 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_IMPORT_ERROR_FORMAT)); 349 350 #if defined(OS_CHROMEOS) 351 localized_strings->SetString("importAndBindCertificate", 352 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_IMPORT_AND_BIND_BUTTON)); 353 localized_strings->SetString("hardwareBackedKeyFormat", 354 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_HARDWARE_BACKED_KEY_FORMAT)); 355 localized_strings->SetString("chromeOSDeviceName", 356 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_HARDWARE_BACKED)); 357 #endif // defined(OS_CHROMEOS) 358 } 359 360 void CertificateManagerHandler::RegisterMessages() { 361 web_ui_->RegisterMessageCallback("viewCertificate", 362 NewCallback(this, &CertificateManagerHandler::View)); 363 364 web_ui_->RegisterMessageCallback("getCaCertificateTrust", 365 NewCallback(this, &CertificateManagerHandler::GetCATrust)); 366 web_ui_->RegisterMessageCallback("editCaCertificateTrust", 367 NewCallback(this, &CertificateManagerHandler::EditCATrust)); 368 369 web_ui_->RegisterMessageCallback("editServerCertificate", 370 NewCallback(this, &CertificateManagerHandler::EditServer)); 371 372 web_ui_->RegisterMessageCallback("cancelImportExportCertificate", 373 NewCallback(this, &CertificateManagerHandler::CancelImportExportProcess)); 374 375 web_ui_->RegisterMessageCallback("exportPersonalCertificate", 376 NewCallback(this, &CertificateManagerHandler::ExportPersonal)); 377 web_ui_->RegisterMessageCallback("exportAllPersonalCertificates", 378 NewCallback(this, &CertificateManagerHandler::ExportAllPersonal)); 379 web_ui_->RegisterMessageCallback("exportPersonalCertificatePasswordSelected", 380 NewCallback(this, 381 &CertificateManagerHandler::ExportPersonalPasswordSelected)); 382 383 web_ui_->RegisterMessageCallback("importPersonalCertificate", 384 NewCallback(this, &CertificateManagerHandler::StartImportPersonal)); 385 web_ui_->RegisterMessageCallback("importPersonalCertificatePasswordSelected", 386 NewCallback(this, 387 &CertificateManagerHandler::ImportPersonalPasswordSelected)); 388 389 web_ui_->RegisterMessageCallback("importCaCertificate", 390 NewCallback(this, &CertificateManagerHandler::ImportCA)); 391 web_ui_->RegisterMessageCallback("importCaCertificateTrustSelected", 392 NewCallback(this, &CertificateManagerHandler::ImportCATrustSelected)); 393 394 web_ui_->RegisterMessageCallback("importServerCertificate", 395 NewCallback(this, &CertificateManagerHandler::ImportServer)); 396 397 web_ui_->RegisterMessageCallback("exportCertificate", 398 NewCallback(this, &CertificateManagerHandler::Export)); 399 400 web_ui_->RegisterMessageCallback("deleteCertificate", 401 NewCallback(this, &CertificateManagerHandler::Delete)); 402 403 web_ui_->RegisterMessageCallback("populateCertificateManager", 404 NewCallback(this, &CertificateManagerHandler::Populate)); 405 406 #if defined(OS_CHROMEOS) 407 web_ui_->RegisterMessageCallback("checkTpmTokenReady", 408 NewCallback(this, &CertificateManagerHandler::CheckTpmTokenReady)); 409 #endif 410 } 411 412 void CertificateManagerHandler::CertificatesRefreshed() { 413 PopulateTree("personalCertsTab", net::USER_CERT); 414 PopulateTree("serverCertsTab", net::SERVER_CERT); 415 PopulateTree("caCertsTab", net::CA_CERT); 416 PopulateTree("otherCertsTab", net::UNKNOWN_CERT); 417 VLOG(1) << "populating finished"; 418 } 419 420 void CertificateManagerHandler::FileSelected(const FilePath& path, int index, 421 void* params) { 422 switch (reinterpret_cast<intptr_t>(params)) { 423 case EXPORT_PERSONAL_FILE_SELECTED: 424 ExportPersonalFileSelected(path); 425 break; 426 case IMPORT_PERSONAL_FILE_SELECTED: 427 ImportPersonalFileSelected(path); 428 break; 429 case IMPORT_SERVER_FILE_SELECTED: 430 ImportServerFileSelected(path); 431 break; 432 case IMPORT_CA_FILE_SELECTED: 433 ImportCAFileSelected(path); 434 break; 435 default: 436 NOTREACHED(); 437 } 438 } 439 440 void CertificateManagerHandler::FileSelectionCanceled(void* params) { 441 switch (reinterpret_cast<intptr_t>(params)) { 442 case EXPORT_PERSONAL_FILE_SELECTED: 443 case IMPORT_PERSONAL_FILE_SELECTED: 444 case IMPORT_SERVER_FILE_SELECTED: 445 case IMPORT_CA_FILE_SELECTED: 446 ImportExportCleanup(); 447 break; 448 default: 449 NOTREACHED(); 450 } 451 } 452 453 void CertificateManagerHandler::View(const ListValue* args) { 454 net::X509Certificate* cert = CallbackArgsToCert(args); 455 if (!cert) 456 return; 457 ShowCertificateViewer(GetParentWindow(), cert); 458 } 459 460 void CertificateManagerHandler::GetCATrust(const ListValue* args) { 461 net::X509Certificate* cert = CallbackArgsToCert(args); 462 if (!cert) { 463 web_ui_->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss"); 464 return; 465 } 466 467 int trust = certificate_manager_model_->cert_db().GetCertTrust( 468 cert, net::CA_CERT); 469 FundamentalValue ssl_value(bool(trust & net::CertDatabase::TRUSTED_SSL)); 470 FundamentalValue email_value(bool(trust & net::CertDatabase::TRUSTED_EMAIL)); 471 FundamentalValue obj_sign_value( 472 bool(trust & net::CertDatabase::TRUSTED_OBJ_SIGN)); 473 web_ui_->CallJavascriptFunction( 474 "CertificateEditCaTrustOverlay.populateTrust", 475 ssl_value, email_value, obj_sign_value); 476 } 477 478 void CertificateManagerHandler::EditCATrust(const ListValue* args) { 479 net::X509Certificate* cert = CallbackArgsToCert(args); 480 bool fail = !cert; 481 bool trust_ssl = false; 482 bool trust_email = false; 483 bool trust_obj_sign = false; 484 fail |= !CallbackArgsToBool(args, 1, &trust_ssl); 485 fail |= !CallbackArgsToBool(args, 2, &trust_email); 486 fail |= !CallbackArgsToBool(args, 3, &trust_obj_sign); 487 if (fail) { 488 LOG(ERROR) << "EditCATrust args fail"; 489 web_ui_->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss"); 490 return; 491 } 492 493 bool result = certificate_manager_model_->SetCertTrust( 494 cert, 495 net::CA_CERT, 496 trust_ssl * net::CertDatabase::TRUSTED_SSL + 497 trust_email * net::CertDatabase::TRUSTED_EMAIL + 498 trust_obj_sign * net::CertDatabase::TRUSTED_OBJ_SIGN); 499 web_ui_->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss"); 500 if (!result) { 501 // TODO(mattm): better error messages? 502 ShowError( 503 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SET_TRUST_ERROR_TITLE), 504 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR)); 505 } 506 } 507 508 void CertificateManagerHandler::EditServer(const ListValue* args) { 509 NOTIMPLEMENTED(); 510 } 511 512 void CertificateManagerHandler::ExportPersonal(const ListValue* args) { 513 net::X509Certificate* cert = CallbackArgsToCert(args); 514 if (!cert) 515 return; 516 517 selected_cert_list_.push_back(cert); 518 519 SelectFileDialog::FileTypeInfo file_type_info; 520 file_type_info.extensions.resize(1); 521 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("p12")); 522 file_type_info.extension_description_overrides.push_back( 523 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PKCS12_FILES)); 524 file_type_info.include_all_files = true; 525 select_file_dialog_ = SelectFileDialog::Create(this); 526 select_file_dialog_->SelectFile( 527 SelectFileDialog::SELECT_SAVEAS_FILE, string16(), 528 FilePath(), &file_type_info, 1, FILE_PATH_LITERAL("p12"), 529 web_ui_->tab_contents(), GetParentWindow(), 530 reinterpret_cast<void*>(EXPORT_PERSONAL_FILE_SELECTED)); 531 } 532 533 void CertificateManagerHandler::ExportAllPersonal(const ListValue* args) { 534 NOTIMPLEMENTED(); 535 } 536 537 void CertificateManagerHandler::ExportPersonalFileSelected( 538 const FilePath& path) { 539 file_path_ = path; 540 web_ui_->CallJavascriptFunction( 541 "CertificateManager.exportPersonalAskPassword"); 542 } 543 544 void CertificateManagerHandler::ExportPersonalPasswordSelected( 545 const ListValue* args) { 546 if (!args->GetString(0, &password_)){ 547 web_ui_->CallJavascriptFunction("CertificateRestoreOverlay.dismiss"); 548 ImportExportCleanup(); 549 return; 550 } 551 552 // Currently, we don't support exporting more than one at a time. If we do, 553 // this would need to either change this to use UnlockSlotsIfNecessary or 554 // change UnlockCertSlotIfNecessary to take a CertificateList. 555 DCHECK_EQ(selected_cert_list_.size(), 1U); 556 557 // TODO(mattm): do something smarter about non-extractable keys 558 browser::UnlockCertSlotIfNecessary( 559 selected_cert_list_[0].get(), 560 browser::kCryptoModulePasswordCertExport, 561 "", // unused. 562 NewCallback(this, 563 &CertificateManagerHandler::ExportPersonalSlotsUnlocked)); 564 } 565 566 void CertificateManagerHandler::ExportPersonalSlotsUnlocked() { 567 std::string output; 568 int num_exported = certificate_manager_model_->cert_db().ExportToPKCS12( 569 selected_cert_list_, 570 password_, 571 &output); 572 if (!num_exported) { 573 web_ui_->CallJavascriptFunction("CertificateRestoreOverlay.dismiss"); 574 ShowError( 575 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_EXPORT_ERROR_TITLE), 576 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR)); 577 ImportExportCleanup(); 578 return; 579 } 580 file_access_provider_->StartWrite( 581 file_path_, 582 output, 583 &consumer_, 584 NewCallback(this, &CertificateManagerHandler::ExportPersonalFileWritten)); 585 } 586 587 void CertificateManagerHandler::ExportPersonalFileWritten(int write_errno, 588 int bytes_written) { 589 web_ui_->CallJavascriptFunction("CertificateRestoreOverlay.dismiss"); 590 ImportExportCleanup(); 591 if (write_errno) { 592 ShowError( 593 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_EXPORT_ERROR_TITLE), 594 l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_WRITE_ERROR_FORMAT, 595 UTF8ToUTF16(safe_strerror(write_errno)))); 596 } 597 } 598 599 void CertificateManagerHandler::StartImportPersonal(const ListValue* args) { 600 SelectFileDialog::FileTypeInfo file_type_info; 601 if (!args->GetBoolean(0, &use_hardware_backed_)){ 602 // Unable to retrieve the hardware backed attribute from the args, 603 // so bail. 604 web_ui_->CallJavascriptFunction("CertificateRestoreOverlay.dismiss"); 605 ImportExportCleanup(); 606 return; 607 } 608 file_type_info.extensions.resize(1); 609 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("p12")); 610 file_type_info.extension_description_overrides.push_back( 611 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PKCS12_FILES)); 612 file_type_info.include_all_files = true; 613 select_file_dialog_ = SelectFileDialog::Create(this); 614 select_file_dialog_->SelectFile( 615 SelectFileDialog::SELECT_OPEN_FILE, string16(), 616 FilePath(), &file_type_info, 1, FILE_PATH_LITERAL("p12"), 617 web_ui_->tab_contents(), GetParentWindow(), 618 reinterpret_cast<void*>(IMPORT_PERSONAL_FILE_SELECTED)); 619 } 620 621 void CertificateManagerHandler::ImportPersonalFileSelected( 622 const FilePath& path) { 623 file_path_ = path; 624 web_ui_->CallJavascriptFunction( 625 "CertificateManager.importPersonalAskPassword"); 626 } 627 628 void CertificateManagerHandler::ImportPersonalPasswordSelected( 629 const ListValue* args) { 630 if (!args->GetString(0, &password_)){ 631 web_ui_->CallJavascriptFunction("CertificateRestoreOverlay.dismiss"); 632 ImportExportCleanup(); 633 return; 634 } 635 file_access_provider_->StartRead( 636 file_path_, 637 &consumer_, 638 NewCallback(this, &CertificateManagerHandler::ImportPersonalFileRead)); 639 } 640 641 void CertificateManagerHandler::ImportPersonalFileRead( 642 int read_errno, std::string data) { 643 if (read_errno) { 644 ImportExportCleanup(); 645 web_ui_->CallJavascriptFunction("CertificateRestoreOverlay.dismiss"); 646 ShowError( 647 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_IMPORT_ERROR_TITLE), 648 l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT, 649 UTF8ToUTF16(safe_strerror(read_errno)))); 650 return; 651 } 652 653 file_data_ = data; 654 655 if (use_hardware_backed_) { 656 module_ = certificate_manager_model_->cert_db().GetPrivateModule(); 657 } else { 658 module_ = certificate_manager_model_->cert_db().GetPublicModule(); 659 } 660 661 net::CryptoModuleList modules; 662 modules.push_back(module_); 663 browser::UnlockSlotsIfNecessary( 664 modules, 665 browser::kCryptoModulePasswordCertImport, 666 "", // unused. 667 NewCallback(this, 668 &CertificateManagerHandler::ImportPersonalSlotUnlocked)); 669 } 670 671 void CertificateManagerHandler::ImportPersonalSlotUnlocked() { 672 int result = certificate_manager_model_->ImportFromPKCS12( 673 module_, file_data_, password_); 674 ImportExportCleanup(); 675 web_ui_->CallJavascriptFunction("CertificateRestoreOverlay.dismiss"); 676 switch (result) { 677 case net::OK: 678 break; 679 case net::ERR_PKCS12_IMPORT_BAD_PASSWORD: 680 ShowError( 681 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_IMPORT_ERROR_TITLE), 682 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_BAD_PASSWORD)); 683 // TODO(mattm): if the error was a bad password, we should reshow the 684 // password dialog after the user dismisses the error dialog. 685 break; 686 default: 687 ShowError( 688 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_IMPORT_ERROR_TITLE), 689 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR)); 690 break; 691 } 692 } 693 694 void CertificateManagerHandler::CancelImportExportProcess( 695 const ListValue* args) { 696 ImportExportCleanup(); 697 } 698 699 void CertificateManagerHandler::ImportExportCleanup() { 700 file_path_.clear(); 701 password_.clear(); 702 file_data_.clear(); 703 use_hardware_backed_ = false; 704 selected_cert_list_.clear(); 705 module_ = NULL; 706 707 // There may be pending file dialogs, we need to tell them that we've gone 708 // away so they don't try and call back to us. 709 if (select_file_dialog_.get()) 710 select_file_dialog_->ListenerDestroyed(); 711 select_file_dialog_ = NULL; 712 } 713 714 void CertificateManagerHandler::ImportServer(const ListValue* args) { 715 select_file_dialog_ = SelectFileDialog::Create(this); 716 ShowCertSelectFileDialog( 717 select_file_dialog_.get(), 718 SelectFileDialog::SELECT_OPEN_FILE, 719 FilePath(), 720 web_ui_->tab_contents(), 721 GetParentWindow(), 722 reinterpret_cast<void*>(IMPORT_SERVER_FILE_SELECTED)); 723 } 724 725 void CertificateManagerHandler::ImportServerFileSelected(const FilePath& path) { 726 file_path_ = path; 727 file_access_provider_->StartRead( 728 file_path_, 729 &consumer_, 730 NewCallback(this, &CertificateManagerHandler::ImportServerFileRead)); 731 } 732 733 void CertificateManagerHandler::ImportServerFileRead(int read_errno, 734 std::string data) { 735 if (read_errno) { 736 ImportExportCleanup(); 737 ShowError( 738 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE), 739 l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT, 740 UTF8ToUTF16(safe_strerror(read_errno)))); 741 return; 742 } 743 744 selected_cert_list_ = net::X509Certificate::CreateCertificateListFromBytes( 745 data.data(), data.size(), net::X509Certificate::FORMAT_AUTO); 746 if (selected_cert_list_.empty()) { 747 ImportExportCleanup(); 748 ShowError( 749 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE), 750 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CERT_PARSE_ERROR)); 751 return; 752 } 753 754 net::CertDatabase::ImportCertFailureList not_imported; 755 bool result = certificate_manager_model_->ImportServerCert( 756 selected_cert_list_, 757 ¬_imported); 758 if (!result) { 759 ShowError( 760 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE), 761 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR)); 762 } else if (!not_imported.empty()) { 763 ShowImportErrors( 764 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE), 765 not_imported); 766 } 767 ImportExportCleanup(); 768 } 769 770 void CertificateManagerHandler::ImportCA(const ListValue* args) { 771 select_file_dialog_ = SelectFileDialog::Create(this); 772 ShowCertSelectFileDialog(select_file_dialog_.get(), 773 SelectFileDialog::SELECT_OPEN_FILE, 774 FilePath(), 775 web_ui_->tab_contents(), 776 GetParentWindow(), 777 reinterpret_cast<void*>(IMPORT_CA_FILE_SELECTED)); 778 } 779 780 void CertificateManagerHandler::ImportCAFileSelected(const FilePath& path) { 781 file_path_ = path; 782 file_access_provider_->StartRead( 783 file_path_, 784 &consumer_, 785 NewCallback(this, &CertificateManagerHandler::ImportCAFileRead)); 786 } 787 788 void CertificateManagerHandler::ImportCAFileRead(int read_errno, 789 std::string data) { 790 if (read_errno) { 791 ImportExportCleanup(); 792 ShowError( 793 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE), 794 l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT, 795 UTF8ToUTF16(safe_strerror(read_errno)))); 796 return; 797 } 798 799 selected_cert_list_ = net::X509Certificate::CreateCertificateListFromBytes( 800 data.data(), data.size(), net::X509Certificate::FORMAT_AUTO); 801 if (selected_cert_list_.empty()) { 802 ImportExportCleanup(); 803 ShowError( 804 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE), 805 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CERT_PARSE_ERROR)); 806 return; 807 } 808 809 scoped_refptr<net::X509Certificate> root_cert = 810 certificate_manager_model_->cert_db().FindRootInList(selected_cert_list_); 811 812 // TODO(mattm): check here if root_cert is not a CA cert and show error. 813 814 StringValue cert_name(root_cert->subject().GetDisplayName()); 815 web_ui_->CallJavascriptFunction("CertificateEditCaTrustOverlay.showImport", 816 cert_name); 817 } 818 819 void CertificateManagerHandler::ImportCATrustSelected(const ListValue* args) { 820 bool fail = false; 821 bool trust_ssl = false; 822 bool trust_email = false; 823 bool trust_obj_sign = false; 824 fail |= !CallbackArgsToBool(args, 0, &trust_ssl); 825 fail |= !CallbackArgsToBool(args, 1, &trust_email); 826 fail |= !CallbackArgsToBool(args, 2, &trust_obj_sign); 827 if (fail) { 828 LOG(ERROR) << "ImportCATrustSelected args fail"; 829 ImportExportCleanup(); 830 web_ui_->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss"); 831 return; 832 } 833 834 net::CertDatabase::ImportCertFailureList not_imported; 835 bool result = certificate_manager_model_->ImportCACerts( 836 selected_cert_list_, 837 trust_ssl * net::CertDatabase::TRUSTED_SSL + 838 trust_email * net::CertDatabase::TRUSTED_EMAIL + 839 trust_obj_sign * net::CertDatabase::TRUSTED_OBJ_SIGN, 840 ¬_imported); 841 web_ui_->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss"); 842 if (!result) { 843 ShowError( 844 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE), 845 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR)); 846 } else if (!not_imported.empty()) { 847 ShowImportErrors( 848 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE), 849 not_imported); 850 } 851 ImportExportCleanup(); 852 } 853 854 void CertificateManagerHandler::Export(const ListValue* args) { 855 net::X509Certificate* cert = CallbackArgsToCert(args); 856 if (!cert) 857 return; 858 ShowCertExportDialog(web_ui_->tab_contents(), GetParentWindow(), 859 cert->os_cert_handle()); 860 } 861 862 void CertificateManagerHandler::Delete(const ListValue* args) { 863 net::X509Certificate* cert = CallbackArgsToCert(args); 864 if (!cert) 865 return; 866 bool result = certificate_manager_model_->Delete(cert); 867 if (!result) { 868 // TODO(mattm): better error messages? 869 ShowError( 870 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_DELETE_CERT_ERROR_TITLE), 871 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR)); 872 } 873 } 874 875 void CertificateManagerHandler::Populate(const ListValue* args) { 876 certificate_manager_model_->Refresh(); 877 } 878 879 void CertificateManagerHandler::PopulateTree(const std::string& tab_name, 880 net::CertType type) { 881 const std::string tree_name = tab_name + "-tree"; 882 883 scoped_ptr<icu::Collator> collator; 884 UErrorCode error = U_ZERO_ERROR; 885 collator.reset( 886 icu::Collator::createInstance( 887 icu::Locale(g_browser_process->GetApplicationLocale().c_str()), 888 error)); 889 if (U_FAILURE(error)) 890 collator.reset(NULL); 891 DictionaryIdComparator comparator(collator.get()); 892 CertificateManagerModel::OrgGroupingMap map; 893 894 certificate_manager_model_->FilterAndBuildOrgGroupingMap(type, &map); 895 896 { 897 ListValue* nodes = new ListValue; 898 for (CertificateManagerModel::OrgGroupingMap::iterator i = map.begin(); 899 i != map.end(); ++i) { 900 // Populate first level (org name). 901 DictionaryValue* dict = new DictionaryValue; 902 dict->SetString(kKeyId, OrgNameToId(i->first)); 903 dict->SetString(kNameId, i->first); 904 905 // Populate second level (certs). 906 ListValue* subnodes = new ListValue; 907 for (net::CertificateList::const_iterator org_cert_it = i->second.begin(); 908 org_cert_it != i->second.end(); ++org_cert_it) { 909 DictionaryValue* cert_dict = new DictionaryValue; 910 net::X509Certificate* cert = org_cert_it->get(); 911 cert_dict->SetString(kKeyId, CertToId(*cert)); 912 cert_dict->SetString(kNameId, certificate_manager_model_->GetColumnText( 913 *cert, CertificateManagerModel::COL_SUBJECT_NAME)); 914 cert_dict->SetBoolean( 915 kReadOnlyId, 916 certificate_manager_model_->cert_db().IsReadOnly(cert)); 917 // TODO(mattm): Other columns. 918 cert_dict->SetString(kIconId, "none"); 919 subnodes->Append(cert_dict); 920 } 921 std::sort(subnodes->begin(), subnodes->end(), comparator); 922 923 dict->Set(kSubNodesId, subnodes); 924 nodes->Append(dict); 925 } 926 std::sort(nodes->begin(), nodes->end(), comparator); 927 928 ListValue args; 929 args.Append(Value::CreateStringValue(tree_name)); 930 args.Append(nodes); 931 web_ui_->CallJavascriptFunction("CertificateManager.onPopulateTree", args); 932 } 933 } 934 935 void CertificateManagerHandler::ShowError(const std::string& title, 936 const std::string& error) const { 937 ScopedVector<const Value> args; 938 args.push_back(Value::CreateStringValue(title)); 939 args.push_back(Value::CreateStringValue(error)); 940 args.push_back(Value::CreateStringValue(l10n_util::GetStringUTF8(IDS_OK))); 941 args.push_back(Value::CreateNullValue()); // cancelTitle 942 args.push_back(Value::CreateNullValue()); // okCallback 943 args.push_back(Value::CreateNullValue()); // cancelCallback 944 web_ui_->CallJavascriptFunction("AlertOverlay.show", args.get()); 945 } 946 947 void CertificateManagerHandler::ShowImportErrors( 948 const std::string& title, 949 const net::CertDatabase::ImportCertFailureList& not_imported) const { 950 std::string error; 951 if (selected_cert_list_.size() == 1) 952 error = l10n_util::GetStringUTF8( 953 IDS_CERT_MANAGER_IMPORT_SINGLE_NOT_IMPORTED); 954 else if (not_imported.size() == selected_cert_list_.size()) 955 error = l10n_util::GetStringUTF8(IDS_CERT_MANAGER_IMPORT_ALL_NOT_IMPORTED); 956 else 957 error = l10n_util::GetStringUTF8(IDS_CERT_MANAGER_IMPORT_SOME_NOT_IMPORTED); 958 959 ListValue cert_error_list; 960 for (size_t i = 0; i < not_imported.size(); ++i) { 961 const net::CertDatabase::ImportCertFailure& failure = not_imported[i]; 962 DictionaryValue* dict = new DictionaryValue; 963 dict->SetString(kNameId, failure.certificate->subject().GetDisplayName()); 964 dict->SetString(kErrorId, NetErrorToString(failure.net_error)); 965 cert_error_list.Append(dict); 966 } 967 968 StringValue title_value(title); 969 StringValue error_value(error); 970 web_ui_->CallJavascriptFunction("CertificateImportErrorOverlay.show", 971 title_value, 972 error_value, 973 cert_error_list); 974 } 975 976 #if defined(OS_CHROMEOS) 977 void CertificateManagerHandler::CheckTpmTokenReady(const ListValue* args) { 978 chromeos::CryptohomeLibrary* cryptohome = 979 chromeos::CrosLibrary::Get()->GetCryptohomeLibrary(); 980 981 // TODO(xiyuan): Use async way when underlying supports it. 982 FundamentalValue ready(cryptohome->Pkcs11IsTpmTokenReady()); 983 web_ui_->CallJavascriptFunction("CertificateManager.onCheckTpmTokenReady", 984 ready); 985 } 986 #endif 987 988 gfx::NativeWindow CertificateManagerHandler::GetParentWindow() const { 989 return web_ui_->tab_contents()->view()->GetTopLevelNativeWindow(); 990 } 991