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