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 3// found in the LICENSE file. 4 5#include "chrome/browser/ui/certificate_dialogs.h" 6 7 8#include <vector> 9 10#include "base/base64.h" 11#include "base/bind.h" 12#include "base/file_util.h" 13#include "base/logging.h" 14#include "base/memory/scoped_ptr.h" 15#include "chrome/browser/ui/chrome_select_file_policy.h" 16#include "chrome/common/net/x509_certificate_model.h" 17#include "content/public/browser/browser_thread.h" 18#include "grit/generated_resources.h" 19#include "ui/base/l10n/l10n_util.h" 20#include "ui/shell_dialogs/select_file_dialog.h" 21 22using content::BrowserThread; 23using content::WebContents; 24 25namespace { 26 27void WriterCallback(const base::FilePath& path, const std::string& data) { 28 int bytes_written = file_util::WriteFile(path, data.data(), data.size()); 29 if (bytes_written != static_cast<ssize_t>(data.size())) { 30 LOG(ERROR) << "Writing " << path.value() << " (" 31 << data.size() << "B) returned " << bytes_written; 32 } 33} 34 35void WriteFileOnFileThread(const base::FilePath& path, 36 const std::string& data) { 37 BrowserThread::PostTask( 38 BrowserThread::FILE, FROM_HERE, base::Bind(&WriterCallback, path, data)); 39} 40 41std::string WrapAt64(const std::string &str) { 42 std::string result; 43 for (size_t i = 0; i < str.size(); i += 64) { 44 result.append(str, i, 64); // Append clamps the len arg internally. 45 result.append("\r\n"); 46 } 47 return result; 48} 49 50std::string GetBase64String(net::X509Certificate::OSCertHandle cert) { 51 std::string base64; 52 base::Base64Encode(x509_certificate_model::GetDerString(cert), &base64); 53 return "-----BEGIN CERTIFICATE-----\r\n" + 54 WrapAt64(base64) + 55 "-----END CERTIFICATE-----\r\n"; 56} 57 58//////////////////////////////////////////////////////////////////////////////// 59// General utility functions. 60 61class Exporter : public ui::SelectFileDialog::Listener { 62 public: 63 Exporter(WebContents* web_contents, gfx::NativeWindow parent, 64 net::X509Certificate::OSCertHandle cert); 65 virtual ~Exporter(); 66 67 // SelectFileDialog::Listener implemenation. 68 virtual void FileSelected(const base::FilePath& path, 69 int index, void* params) OVERRIDE; 70 virtual void FileSelectionCanceled(void* params) OVERRIDE; 71 private: 72 scoped_refptr<ui::SelectFileDialog> select_file_dialog_; 73 74 // The certificate hierarchy (leaf cert first). 75 net::X509Certificate::OSCertHandles cert_chain_list_; 76}; 77 78Exporter::Exporter(WebContents* web_contents, 79 gfx::NativeWindow parent, 80 net::X509Certificate::OSCertHandle cert) 81 : select_file_dialog_(ui::SelectFileDialog::Create( 82 this, new ChromeSelectFilePolicy(web_contents))) { 83 x509_certificate_model::GetCertChainFromCert(cert, &cert_chain_list_); 84 85 // TODO(mattm): should this default to some directory? 86 // Maybe SavePackage::GetSaveDirPreference? (Except that it's private.) 87 base::FilePath suggested_path("certificate"); 88 std::string cert_title = x509_certificate_model::GetTitle(cert); 89 if (!cert_title.empty()) 90 suggested_path = base::FilePath(cert_title); 91 92 ShowCertSelectFileDialog(select_file_dialog_.get(), 93 ui::SelectFileDialog::SELECT_SAVEAS_FILE, 94 suggested_path, 95 parent, 96 NULL); 97} 98 99Exporter::~Exporter() { 100 // There may be pending file dialogs, we need to tell them that we've gone 101 // away so they don't try and call back to us. 102 if (select_file_dialog_.get()) 103 select_file_dialog_->ListenerDestroyed(); 104 105 x509_certificate_model::DestroyCertChain(&cert_chain_list_); 106} 107 108void Exporter::FileSelected(const base::FilePath& path, int index, 109 void* params) { 110 std::string data; 111 switch (index) { 112 case 2: 113 for (size_t i = 0; i < cert_chain_list_.size(); ++i) 114 data += GetBase64String(cert_chain_list_[i]); 115 break; 116 case 3: 117 data = x509_certificate_model::GetDerString(cert_chain_list_[0]); 118 break; 119 case 4: 120 data = x509_certificate_model::GetCMSString(cert_chain_list_, 0, 1); 121 break; 122 case 5: 123 data = x509_certificate_model::GetCMSString( 124 cert_chain_list_, 0, cert_chain_list_.size()); 125 break; 126 case 1: 127 default: 128 data = GetBase64String(cert_chain_list_[0]); 129 break; 130 } 131 132 if (!data.empty()) 133 WriteFileOnFileThread(path, data); 134 135 delete this; 136} 137 138void Exporter::FileSelectionCanceled(void* params) { 139 delete this; 140} 141 142} // namespace 143 144void ShowCertSelectFileDialog(ui::SelectFileDialog* select_file_dialog, 145 ui::SelectFileDialog::Type type, 146 const base::FilePath& suggested_path, 147 gfx::NativeWindow parent, 148 void* params) { 149 ui::SelectFileDialog::FileTypeInfo file_type_info; 150 file_type_info.extensions.resize(5); 151 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("pem")); 152 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("crt")); 153 file_type_info.extension_description_overrides.push_back( 154 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_BASE64)); 155 file_type_info.extensions[1].push_back(FILE_PATH_LITERAL("pem")); 156 file_type_info.extensions[1].push_back(FILE_PATH_LITERAL("crt")); 157 file_type_info.extension_description_overrides.push_back( 158 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_BASE64_CHAIN)); 159 file_type_info.extensions[2].push_back(FILE_PATH_LITERAL("der")); 160 file_type_info.extension_description_overrides.push_back( 161 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_DER)); 162 file_type_info.extensions[3].push_back(FILE_PATH_LITERAL("p7c")); 163 file_type_info.extension_description_overrides.push_back( 164 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_PKCS7)); 165 file_type_info.extensions[4].push_back(FILE_PATH_LITERAL("p7c")); 166 file_type_info.extension_description_overrides.push_back( 167 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_PKCS7_CHAIN)); 168 file_type_info.include_all_files = true; 169 select_file_dialog->SelectFile( 170 type, base::string16(), 171 suggested_path, &file_type_info, 172 1, // 1-based index for |file_type_info.extensions| to specify default. 173 FILE_PATH_LITERAL("crt"), 174 parent, params); 175} 176 177void ShowCertExportDialog(WebContents* web_contents, 178 gfx::NativeWindow parent, 179 net::X509Certificate::OSCertHandle cert) { 180 new Exporter(web_contents, parent, cert); 181} 182