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"
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"
24 using content::BrowserThread
;
25 using content::WebContents
;
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
) {
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");
52 std::string
GetBase64String(net::X509Certificate::OSCertHandle cert
) {
54 if (!net::X509Certificate::GetDEREncoded(cert
, &der_cert
))
57 base::Base64Encode(der_cert
, &base64
);
58 return "-----BEGIN CERTIFICATE-----\r\n" +
60 "-----END CERTIFICATE-----\r\n";
63 ////////////////////////////////////////////////////////////////////////////////
64 // General utility functions.
66 class Exporter
: public ui::SelectFileDialog::Listener
{
68 Exporter(WebContents
* web_contents
,
69 gfx::NativeWindow parent
,
70 net::X509Certificate::OSCertHandles::iterator certs_begin
,
71 net::X509Certificate::OSCertHandles::iterator certs_end
);
74 // SelectFileDialog::Listener implemenation.
75 virtual void FileSelected(const base::FilePath
& path
,
76 int index
, void* params
) override
;
77 virtual void FileSelectionCanceled(void* params
) override
;
79 scoped_refptr
<ui::SelectFileDialog
> select_file_dialog_
;
81 // The certificate hierarchy (leaf cert first).
82 net::X509Certificate::OSCertHandles cert_chain_list_
;
85 Exporter::Exporter(WebContents
* web_contents
,
86 gfx::NativeWindow parent
,
87 net::X509Certificate::OSCertHandles::iterator certs_begin
,
88 net::X509Certificate::OSCertHandles::iterator certs_end
)
89 : select_file_dialog_(ui::SelectFileDialog::Create(
91 new ChromeSelectFilePolicy(web_contents
))) {
92 DCHECK(certs_begin
!= certs_end
);
93 for (net::X509Certificate::OSCertHandles::iterator i
= certs_begin
;
96 cert_chain_list_
.push_back(net::X509Certificate::DupOSCertHandle(*i
));
99 // TODO(mattm): should this default to some directory?
100 // Maybe SavePackage::GetSaveDirPreference? (Except that it's private.)
101 std::string cert_title
= x509_certificate_model::GetTitle(*certs_begin
);
102 base::FilePath suggested_path
=
103 net::GenerateFileName(GURL::EmptyGURL(), // url
104 std::string(), // content_disposition
105 std::string(), // referrer_charset
106 cert_title
, // suggested_name
107 std::string(), // mime_type
108 "certificate"); // default_name
110 ShowCertSelectFileDialog(select_file_dialog_
.get(),
111 ui::SelectFileDialog::SELECT_SAVEAS_FILE
,
117 Exporter::~Exporter() {
118 // There may be pending file dialogs, we need to tell them that we've gone
119 // away so they don't try and call back to us.
120 if (select_file_dialog_
.get())
121 select_file_dialog_
->ListenerDestroyed();
123 std::for_each(cert_chain_list_
.begin(),
124 cert_chain_list_
.end(),
125 &net::X509Certificate::FreeOSCertHandle
);
128 void Exporter::FileSelected(const base::FilePath
& path
, int index
,
133 for (size_t i
= 0; i
< cert_chain_list_
.size(); ++i
)
134 data
+= GetBase64String(cert_chain_list_
[i
]);
137 net::X509Certificate::GetDEREncoded(cert_chain_list_
[0], &data
);
140 data
= x509_certificate_model::GetCMSString(cert_chain_list_
, 0, 1);
143 data
= x509_certificate_model::GetCMSString(
144 cert_chain_list_
, 0, cert_chain_list_
.size());
148 data
= GetBase64String(cert_chain_list_
[0]);
153 WriteFileOnFileThread(path
, data
);
158 void Exporter::FileSelectionCanceled(void* params
) {
164 void ShowCertSelectFileDialog(ui::SelectFileDialog
* select_file_dialog
,
165 ui::SelectFileDialog::Type type
,
166 const base::FilePath
& suggested_path
,
167 gfx::NativeWindow parent
,
169 ui::SelectFileDialog::FileTypeInfo file_type_info
;
170 file_type_info
.extensions
.resize(5);
171 file_type_info
.extensions
[0].push_back(FILE_PATH_LITERAL("pem"));
172 file_type_info
.extensions
[0].push_back(FILE_PATH_LITERAL("crt"));
173 file_type_info
.extension_description_overrides
.push_back(
174 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_BASE64
));
175 file_type_info
.extensions
[1].push_back(FILE_PATH_LITERAL("pem"));
176 file_type_info
.extensions
[1].push_back(FILE_PATH_LITERAL("crt"));
177 file_type_info
.extension_description_overrides
.push_back(
178 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_BASE64_CHAIN
));
179 file_type_info
.extensions
[2].push_back(FILE_PATH_LITERAL("der"));
180 file_type_info
.extension_description_overrides
.push_back(
181 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_DER
));
182 file_type_info
.extensions
[3].push_back(FILE_PATH_LITERAL("p7c"));
183 file_type_info
.extension_description_overrides
.push_back(
184 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_PKCS7
));
185 file_type_info
.extensions
[4].push_back(FILE_PATH_LITERAL("p7c"));
186 file_type_info
.extension_description_overrides
.push_back(
187 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_PKCS7_CHAIN
));
188 file_type_info
.include_all_files
= true;
189 select_file_dialog
->SelectFile(
190 type
, base::string16(),
191 suggested_path
, &file_type_info
,
192 1, // 1-based index for |file_type_info.extensions| to specify default.
193 FILE_PATH_LITERAL("crt"),
197 void ShowCertExportDialog(WebContents
* web_contents
,
198 gfx::NativeWindow parent
,
199 const scoped_refptr
<net::X509Certificate
>& cert
) {
200 net::X509Certificate::OSCertHandles cert_chain
;
201 cert_chain
.push_back(cert
->os_cert_handle());
202 const net::X509Certificate::OSCertHandles
& certs
=
203 cert
->GetIntermediateCertificates();
204 cert_chain
.insert(cert_chain
.end(), certs
.begin(), certs
.end());
205 new Exporter(web_contents
, parent
, cert_chain
.begin(), cert_chain
.end());
208 void ShowCertExportDialog(
209 content::WebContents
* web_contents
,
210 gfx::NativeWindow parent
,
211 net::X509Certificate::OSCertHandles::iterator certs_begin
,
212 net::X509Certificate::OSCertHandles::iterator certs_end
) {
213 new Exporter(web_contents
, parent
, certs_begin
, certs_end
);