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