Home | History | Annotate | Download | only in gtk
      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