• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
Writer(const FilePath & path,const std::string & data)29   Writer(const FilePath& path, const std::string& data)
30       : path_(path), data_(data) {
31   }
32 
Run()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 
WriteFileOnFileThread(const FilePath & path,const std::string & data)45 void WriteFileOnFileThread(const FilePath& path, const std::string& data) {
46   BrowserThread::PostTask(
47       BrowserThread::FILE, FROM_HERE, new Writer(path, data));
48 }
49 
WrapAt64(const std::string & str)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 
GetBase64String(net::X509Certificate::OSCertHandle cert)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 
Exporter(TabContents * tab_contents,gfx::NativeWindow parent,net::X509Certificate::OSCertHandle cert)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 
~Exporter()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 
FileSelected(const FilePath & path,int index,void * params)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 
FileSelectionCanceled(void * params)150 void Exporter::FileSelectionCanceled(void* params) {
151   delete this;
152 }
153 
154 } // namespace
155 
ShowCertSelectFileDialog(SelectFileDialog * select_file_dialog,SelectFileDialog::Type type,const FilePath & suggested_path,TabContents * tab_contents,gfx::NativeWindow parent,void * params)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 
ShowCertExportDialog(TabContents * tab_contents,gfx::NativeWindow parent,net::X509Certificate::OSCertHandle cert)189 void ShowCertExportDialog(TabContents* tab_contents,
190                           gfx::NativeWindow parent,
191                           net::X509Certificate::OSCertHandle cert) {
192   new Exporter(tab_contents, parent, cert);
193 }
194