Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / certificate_dialogs.cc
blobd477a2e99752a62e3e07ebb074e0a87c737e281c
1 // Copyright (c) 2012 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.
5 #include "chrome/browser/ui/certificate_dialogs.h"
7 #include <algorithm>
8 #include <vector>
10 #include "base/base64.h"
11 #include "base/bind.h"
12 #include "base/files/file_util.h"
13 #include "base/logging.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "chrome/browser/ui/chrome_select_file_policy.h"
16 #include "chrome/common/net/x509_certificate_model.h"
17 #include "chrome/grit/generated_resources.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "net/base/filename_util.h"
20 #include "ui/base/l10n/l10n_util.h"
21 #include "ui/shell_dialogs/select_file_dialog.h"
22 #include "url/gurl.h"
24 using content::BrowserThread;
25 using content::WebContents;
27 namespace {
29 void WriterCallback(const base::FilePath& path, const std::string& data) {
30 int bytes_written = base::WriteFile(path, data.data(), data.size());
31 if (bytes_written != static_cast<ssize_t>(data.size())) {
32 LOG(ERROR) << "Writing " << path.value() << " ("
33 << data.size() << "B) returned " << bytes_written;
37 void WriteFileOnFileThread(const base::FilePath& path,
38 const std::string& data) {
39 BrowserThread::PostTask(
40 BrowserThread::FILE, FROM_HERE, base::Bind(&WriterCallback, path, data));
43 std::string WrapAt64(const std::string &str) {
44 std::string result;
45 for (size_t i = 0; i < str.size(); i += 64) {
46 result.append(str, i, 64); // Append clamps the len arg internally.
47 result.append("\r\n");
49 return result;
52 std::string GetBase64String(net::X509Certificate::OSCertHandle cert) {
53 std::string der_cert;
54 if (!net::X509Certificate::GetDEREncoded(cert, &der_cert))
55 return std::string();
56 std::string base64;
57 base::Base64Encode(der_cert, &base64);
58 return "-----BEGIN CERTIFICATE-----\r\n" +
59 WrapAt64(base64) +
60 "-----END CERTIFICATE-----\r\n";
63 ////////////////////////////////////////////////////////////////////////////////
64 // General utility functions.
66 class Exporter : public ui::SelectFileDialog::Listener {
67 public:
68 Exporter(WebContents* web_contents,
69 gfx::NativeWindow parent,
70 net::X509Certificate::OSCertHandles::iterator certs_begin,
71 net::X509Certificate::OSCertHandles::iterator certs_end);
72 ~Exporter() override;
74 // SelectFileDialog::Listener implemenation.
75 void FileSelected(const base::FilePath& path,
76 int index,
77 void* params) override;
78 void FileSelectionCanceled(void* params) override;
80 private:
81 scoped_refptr<ui::SelectFileDialog> select_file_dialog_;
83 // The certificate hierarchy (leaf cert first).
84 net::X509Certificate::OSCertHandles cert_chain_list_;
87 Exporter::Exporter(WebContents* web_contents,
88 gfx::NativeWindow parent,
89 net::X509Certificate::OSCertHandles::iterator certs_begin,
90 net::X509Certificate::OSCertHandles::iterator certs_end)
91 : select_file_dialog_(ui::SelectFileDialog::Create(
92 this,
93 new ChromeSelectFilePolicy(web_contents))) {
94 DCHECK(certs_begin != certs_end);
95 for (net::X509Certificate::OSCertHandles::iterator i = certs_begin;
96 i != certs_end;
97 ++i) {
98 cert_chain_list_.push_back(net::X509Certificate::DupOSCertHandle(*i));
101 // TODO(mattm): should this default to some directory?
102 // Maybe SavePackage::GetSaveDirPreference? (Except that it's private.)
103 std::string cert_title = x509_certificate_model::GetTitle(*certs_begin);
104 base::FilePath suggested_path =
105 net::GenerateFileName(GURL::EmptyGURL(), // url
106 std::string(), // content_disposition
107 std::string(), // referrer_charset
108 cert_title, // suggested_name
109 std::string(), // mime_type
110 "certificate"); // default_name
112 ShowCertSelectFileDialog(select_file_dialog_.get(),
113 ui::SelectFileDialog::SELECT_SAVEAS_FILE,
114 suggested_path,
115 parent,
116 NULL);
119 Exporter::~Exporter() {
120 // There may be pending file dialogs, we need to tell them that we've gone
121 // away so they don't try and call back to us.
122 if (select_file_dialog_.get())
123 select_file_dialog_->ListenerDestroyed();
125 std::for_each(cert_chain_list_.begin(),
126 cert_chain_list_.end(),
127 &net::X509Certificate::FreeOSCertHandle);
130 void Exporter::FileSelected(const base::FilePath& path, int index,
131 void* params) {
132 std::string data;
133 switch (index) {
134 case 2:
135 for (size_t i = 0; i < cert_chain_list_.size(); ++i)
136 data += GetBase64String(cert_chain_list_[i]);
137 break;
138 case 3:
139 net::X509Certificate::GetDEREncoded(cert_chain_list_[0], &data);
140 break;
141 case 4:
142 data = x509_certificate_model::GetCMSString(cert_chain_list_, 0, 1);
143 break;
144 case 5:
145 data = x509_certificate_model::GetCMSString(
146 cert_chain_list_, 0, cert_chain_list_.size());
147 break;
148 case 1:
149 default:
150 data = GetBase64String(cert_chain_list_[0]);
151 break;
154 if (!data.empty())
155 WriteFileOnFileThread(path, data);
157 delete this;
160 void Exporter::FileSelectionCanceled(void* params) {
161 delete this;
164 } // namespace
166 void ShowCertSelectFileDialog(ui::SelectFileDialog* select_file_dialog,
167 ui::SelectFileDialog::Type type,
168 const base::FilePath& suggested_path,
169 gfx::NativeWindow parent,
170 void* params) {
171 ui::SelectFileDialog::FileTypeInfo file_type_info;
172 file_type_info.extensions.resize(5);
173 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("pem"));
174 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("crt"));
175 file_type_info.extension_description_overrides.push_back(
176 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_BASE64));
177 file_type_info.extensions[1].push_back(FILE_PATH_LITERAL("pem"));
178 file_type_info.extensions[1].push_back(FILE_PATH_LITERAL("crt"));
179 file_type_info.extension_description_overrides.push_back(
180 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_BASE64_CHAIN));
181 file_type_info.extensions[2].push_back(FILE_PATH_LITERAL("der"));
182 file_type_info.extension_description_overrides.push_back(
183 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_DER));
184 file_type_info.extensions[3].push_back(FILE_PATH_LITERAL("p7c"));
185 file_type_info.extension_description_overrides.push_back(
186 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_PKCS7));
187 file_type_info.extensions[4].push_back(FILE_PATH_LITERAL("p7c"));
188 file_type_info.extension_description_overrides.push_back(
189 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_PKCS7_CHAIN));
190 file_type_info.include_all_files = true;
191 select_file_dialog->SelectFile(
192 type, base::string16(),
193 suggested_path, &file_type_info,
194 1, // 1-based index for |file_type_info.extensions| to specify default.
195 FILE_PATH_LITERAL("crt"),
196 parent, params);
199 void ShowCertExportDialog(WebContents* web_contents,
200 gfx::NativeWindow parent,
201 const scoped_refptr<net::X509Certificate>& cert) {
202 net::X509Certificate::OSCertHandles cert_chain;
203 cert_chain.push_back(cert->os_cert_handle());
204 const net::X509Certificate::OSCertHandles& certs =
205 cert->GetIntermediateCertificates();
206 cert_chain.insert(cert_chain.end(), certs.begin(), certs.end());
207 new Exporter(web_contents, parent, cert_chain.begin(), cert_chain.end());
210 void ShowCertExportDialog(
211 content::WebContents* web_contents,
212 gfx::NativeWindow parent,
213 net::X509Certificate::OSCertHandles::iterator certs_begin,
214 net::X509Certificate::OSCertHandles::iterator certs_end) {
215 new Exporter(web_contents, parent, certs_begin, certs_end);