172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// TODO(mattm): this isn't gtk specific, it shouldn't be under the gtk dir 6731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/certificate_dialogs.h" 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <vector> 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/base64.h" 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_util.h" 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h" 15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h" 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/task.h" 17731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/common/net/x509_certificate_model.h" 18dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h" 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h" 2072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h" 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// General utility functions. 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass Writer : public Task { 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Writer(const FilePath& path, const std::string& data) 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : path_(path), data_(data) { 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void Run() { 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int bytes_written = file_util::WriteFile(path_, data_.data(), data_.size()); 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (bytes_written != static_cast<ssize_t>(data_.size())) { 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LOG(ERROR) << "Writing " << path_.value() << " (" 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << data_.size() << "B) returned " << bytes_written; 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath path_; 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string data_; 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteFileOnFileThread(const FilePath& path, const std::string& data) { 46731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::PostTask( 47731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick BrowserThread::FILE, FROM_HERE, new Writer(path, data)); 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::string WrapAt64(const std::string &str) { 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string result; 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (size_t i = 0; i < str.size(); i += 64) { 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch result.append(str, i, 64); // Append clamps the len arg internally. 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch result.append("\r\n"); 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return result; 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 59731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickstd::string GetBase64String(net::X509Certificate::OSCertHandle cert) { 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string base64; 61731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (!base::Base64Encode( 62731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick x509_certificate_model::GetDerString(cert), &base64)) { 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LOG(ERROR) << "base64 encoding error"; 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return ""; 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return "-----BEGIN CERTIFICATE-----\r\n" + 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WrapAt64(base64) + 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch "-----END CERTIFICATE-----\r\n"; 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//////////////////////////////////////////////////////////////////////////////// 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// General utility functions. 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass Exporter : public SelectFileDialog::Listener { 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public: 76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Exporter(TabContents* tab_contents, gfx::NativeWindow parent, 77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen net::X509Certificate::OSCertHandle cert); 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ~Exporter(); 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // SelectFileDialog::Listener implemenation. 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void FileSelected(const FilePath& path, 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int index, void* params); 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch virtual void FileSelectionCanceled(void* params); 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private: 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_refptr<SelectFileDialog> select_file_dialog_; 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The certificate hierarchy (leaf cert first). 88731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick net::X509Certificate::OSCertHandles cert_chain_list_; 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenExporter::Exporter(TabContents* tab_contents, 92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen gfx::NativeWindow parent, 93731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick net::X509Certificate::OSCertHandle cert) 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : select_file_dialog_(SelectFileDialog::Create(this)) { 95731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick x509_certificate_model::GetCertChainFromCert(cert, &cert_chain_list_); 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(mattm): should this default to some directory? 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Maybe SavePackage::GetSaveDirPreference? (Except that it's private.) 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FilePath suggested_path("certificate"); 100731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick std::string cert_title = x509_certificate_model::GetTitle(cert); 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!cert_title.empty()) 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch suggested_path = FilePath(cert_title); 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 104731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick ShowCertSelectFileDialog(select_file_dialog_.get(), 105731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick SelectFileDialog::SELECT_SAVEAS_FILE, 106731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick suggested_path, 107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen tab_contents, 108731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick parent, 109731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick NULL); 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochExporter::~Exporter() { 113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // There may be pending file dialogs, we need to tell them that we've gone 114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // away so they don't try and call back to us. 115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (select_file_dialog_.get()) 116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen select_file_dialog_->ListenerDestroyed(); 117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 118731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick x509_certificate_model::DestroyCertChain(&cert_chain_list_); 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid Exporter::FileSelected(const FilePath& path, int index, void* params) { 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::string data; 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (index) { 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case 2: 125731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick for (size_t i = 0; i < cert_chain_list_.size(); ++i) 126731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick data += GetBase64String(cert_chain_list_[i]); 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case 3: 129731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick data = x509_certificate_model::GetDerString(cert_chain_list_[0]); 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case 4: 132731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick data = x509_certificate_model::GetCMSString(cert_chain_list_, 0, 1); 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case 5: 135731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick data = x509_certificate_model::GetCMSString( 136731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick cert_chain_list_, 0, cert_chain_list_.size()); 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case 1: 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default: 140731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick data = GetBase64String(cert_chain_list_[0]); 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!data.empty()) 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch WriteFileOnFileThread(path, data); 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete this; 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid Exporter::FileSelectionCanceled(void* params) { 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete this; 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 156731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid ShowCertSelectFileDialog(SelectFileDialog* select_file_dialog, 157731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick SelectFileDialog::Type type, 158731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick const FilePath& suggested_path, 159ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen TabContents* tab_contents, 160731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick gfx::NativeWindow parent, 161731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick void* params) { 162731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick SelectFileDialog::FileTypeInfo file_type_info; 163731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick file_type_info.extensions.resize(5); 164731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("pem")); 165731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("crt")); 166731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick file_type_info.extension_description_overrides.push_back( 167731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_BASE64)); 168731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick file_type_info.extensions[1].push_back(FILE_PATH_LITERAL("pem")); 169731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick file_type_info.extensions[1].push_back(FILE_PATH_LITERAL("crt")); 170731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick file_type_info.extension_description_overrides.push_back( 171731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_BASE64_CHAIN)); 172731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick file_type_info.extensions[2].push_back(FILE_PATH_LITERAL("der")); 173731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick file_type_info.extension_description_overrides.push_back( 174731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_DER)); 175731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick file_type_info.extensions[3].push_back(FILE_PATH_LITERAL("p7c")); 176731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick file_type_info.extension_description_overrides.push_back( 177731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_PKCS7)); 178731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick file_type_info.extensions[4].push_back(FILE_PATH_LITERAL("p7c")); 179731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick file_type_info.extension_description_overrides.push_back( 180731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_PKCS7_CHAIN)); 181731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick file_type_info.include_all_files = true; 182731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick select_file_dialog->SelectFile( 183731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick type, string16(), 184731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick suggested_path, &file_type_info, 1, 185ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen FILE_PATH_LITERAL("crt"), tab_contents, 186ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen parent, params); 187731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick} 188731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 189ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid ShowCertExportDialog(TabContents* tab_contents, 190ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen gfx::NativeWindow parent, 191731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick net::X509Certificate::OSCertHandle cert) { 192ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen new Exporter(tab_contents, parent, cert); 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 194