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/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 "content/public/browser/browser_thread.h"
18 #include "grit/generated_resources.h"
19 #include "ui/base/dialogs/select_file_dialog.h"
20 #include "ui/base/l10n/l10n_util.h"
22 using content::BrowserThread
;
23 using content::WebContents
;
27 void WriterCallback(const FilePath
& path
, const std::string
& data
) {
28 int bytes_written
= file_util::WriteFile(path
, data
.data(), data
.size());
29 if (bytes_written
!= static_cast<ssize_t
>(data
.size())) {
30 LOG(ERROR
) << "Writing " << path
.value() << " ("
31 << data
.size() << "B) returned " << bytes_written
;
35 void WriteFileOnFileThread(const FilePath
& path
, const std::string
& data
) {
36 BrowserThread::PostTask(
37 BrowserThread::FILE, FROM_HERE
, base::Bind(&WriterCallback
, path
, data
));
40 std::string
WrapAt64(const std::string
&str
) {
42 for (size_t i
= 0; i
< str
.size(); i
+= 64) {
43 result
.append(str
, i
, 64); // Append clamps the len arg internally.
44 result
.append("\r\n");
49 std::string
GetBase64String(net::X509Certificate::OSCertHandle cert
) {
51 if (!base::Base64Encode(
52 x509_certificate_model::GetDerString(cert
), &base64
)) {
53 LOG(ERROR
) << "base64 encoding error";
56 return "-----BEGIN CERTIFICATE-----\r\n" +
58 "-----END CERTIFICATE-----\r\n";
61 ////////////////////////////////////////////////////////////////////////////////
62 // General utility functions.
64 class Exporter
: public ui::SelectFileDialog::Listener
{
66 Exporter(WebContents
* web_contents
, gfx::NativeWindow parent
,
67 net::X509Certificate::OSCertHandle cert
);
70 // SelectFileDialog::Listener implemenation.
71 virtual void FileSelected(const FilePath
& path
,
72 int index
, void* params
);
73 virtual void FileSelectionCanceled(void* params
);
75 scoped_refptr
<ui::SelectFileDialog
> select_file_dialog_
;
77 // The certificate hierarchy (leaf cert first).
78 net::X509Certificate::OSCertHandles cert_chain_list_
;
81 Exporter::Exporter(WebContents
* web_contents
,
82 gfx::NativeWindow parent
,
83 net::X509Certificate::OSCertHandle cert
)
84 : select_file_dialog_(ui::SelectFileDialog::Create(
85 this, new ChromeSelectFilePolicy(web_contents
))) {
86 x509_certificate_model::GetCertChainFromCert(cert
, &cert_chain_list_
);
88 // TODO(mattm): should this default to some directory?
89 // Maybe SavePackage::GetSaveDirPreference? (Except that it's private.)
90 FilePath
suggested_path("certificate");
91 std::string cert_title
= x509_certificate_model::GetTitle(cert
);
92 if (!cert_title
.empty())
93 suggested_path
= FilePath(cert_title
);
95 ShowCertSelectFileDialog(select_file_dialog_
.get(),
96 ui::SelectFileDialog::SELECT_SAVEAS_FILE
,
102 Exporter::~Exporter() {
103 // There may be pending file dialogs, we need to tell them that we've gone
104 // away so they don't try and call back to us.
105 if (select_file_dialog_
.get())
106 select_file_dialog_
->ListenerDestroyed();
108 x509_certificate_model::DestroyCertChain(&cert_chain_list_
);
111 void Exporter::FileSelected(const FilePath
& path
, int index
, void* params
) {
115 for (size_t i
= 0; i
< cert_chain_list_
.size(); ++i
)
116 data
+= GetBase64String(cert_chain_list_
[i
]);
119 data
= x509_certificate_model::GetDerString(cert_chain_list_
[0]);
122 data
= x509_certificate_model::GetCMSString(cert_chain_list_
, 0, 1);
125 data
= x509_certificate_model::GetCMSString(
126 cert_chain_list_
, 0, cert_chain_list_
.size());
130 data
= GetBase64String(cert_chain_list_
[0]);
135 WriteFileOnFileThread(path
, data
);
140 void Exporter::FileSelectionCanceled(void* params
) {
146 void ShowCertSelectFileDialog(ui::SelectFileDialog
* select_file_dialog
,
147 ui::SelectFileDialog::Type type
,
148 const FilePath
& suggested_path
,
149 gfx::NativeWindow parent
,
151 ui::SelectFileDialog::FileTypeInfo file_type_info
;
152 file_type_info
.extensions
.resize(5);
153 file_type_info
.extensions
[0].push_back(FILE_PATH_LITERAL("pem"));
154 file_type_info
.extensions
[0].push_back(FILE_PATH_LITERAL("crt"));
155 file_type_info
.extension_description_overrides
.push_back(
156 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_BASE64
));
157 file_type_info
.extensions
[1].push_back(FILE_PATH_LITERAL("pem"));
158 file_type_info
.extensions
[1].push_back(FILE_PATH_LITERAL("crt"));
159 file_type_info
.extension_description_overrides
.push_back(
160 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_BASE64_CHAIN
));
161 file_type_info
.extensions
[2].push_back(FILE_PATH_LITERAL("der"));
162 file_type_info
.extension_description_overrides
.push_back(
163 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_DER
));
164 file_type_info
.extensions
[3].push_back(FILE_PATH_LITERAL("p7c"));
165 file_type_info
.extension_description_overrides
.push_back(
166 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_PKCS7
));
167 file_type_info
.extensions
[4].push_back(FILE_PATH_LITERAL("p7c"));
168 file_type_info
.extension_description_overrides
.push_back(
169 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_PKCS7_CHAIN
));
170 file_type_info
.include_all_files
= true;
171 select_file_dialog
->SelectFile(
173 suggested_path
, &file_type_info
, 1,
174 FILE_PATH_LITERAL("crt"),
178 void ShowCertExportDialog(WebContents
* web_contents
,
179 gfx::NativeWindow parent
,
180 net::X509Certificate::OSCertHandle cert
) {
181 new Exporter(web_contents
, parent
, cert
);