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 void FileSelected(const base::FilePath
& path
,
77 void* params
) override
;
78 void FileSelectionCanceled(void* params
) override
;
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(
93 new ChromeSelectFilePolicy(web_contents
))) {
94 DCHECK(certs_begin
!= certs_end
);
95 for (net::X509Certificate::OSCertHandles::iterator i
= certs_begin
;
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
,
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
,
135 for (size_t i
= 0; i
< cert_chain_list_
.size(); ++i
)
136 data
+= GetBase64String(cert_chain_list_
[i
]);
139 net::X509Certificate::GetDEREncoded(cert_chain_list_
[0], &data
);
142 data
= x509_certificate_model::GetCMSString(cert_chain_list_
, 0, 1);
145 data
= x509_certificate_model::GetCMSString(
146 cert_chain_list_
, 0, cert_chain_list_
.size());
150 data
= GetBase64String(cert_chain_list_
[0]);
155 WriteFileOnFileThread(path
, data
);
160 void Exporter::FileSelectionCanceled(void* params
) {
166 void ShowCertSelectFileDialog(ui::SelectFileDialog
* select_file_dialog
,
167 ui::SelectFileDialog::Type type
,
168 const base::FilePath
& suggested_path
,
169 gfx::NativeWindow parent
,
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"),
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
);