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/l10n/l10n_util.h"
20 #include "ui/shell_dialogs/select_file_dialog.h"
22 using content::BrowserThread
;
23 using content::WebContents
;
27 void WriterCallback(const base::FilePath
& path
, const std::string
& data
) {
28 int bytes_written
= base::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 base::FilePath
& path
,
36 const std::string
& data
) {
37 BrowserThread::PostTask(
38 BrowserThread::FILE, FROM_HERE
, base::Bind(&WriterCallback
, path
, data
));
41 std::string
WrapAt64(const std::string
&str
) {
43 for (size_t i
= 0; i
< str
.size(); i
+= 64) {
44 result
.append(str
, i
, 64); // Append clamps the len arg internally.
45 result
.append("\r\n");
50 std::string
GetBase64String(net::X509Certificate::OSCertHandle cert
) {
52 base::Base64Encode(x509_certificate_model::GetDerString(cert
), &base64
);
53 return "-----BEGIN CERTIFICATE-----\r\n" +
55 "-----END CERTIFICATE-----\r\n";
58 ////////////////////////////////////////////////////////////////////////////////
59 // General utility functions.
61 class Exporter
: public ui::SelectFileDialog::Listener
{
63 Exporter(WebContents
* web_contents
, gfx::NativeWindow parent
,
64 net::X509Certificate::OSCertHandle cert
);
67 // SelectFileDialog::Listener implemenation.
68 virtual void FileSelected(const base::FilePath
& path
,
69 int index
, void* params
) OVERRIDE
;
70 virtual void FileSelectionCanceled(void* params
) OVERRIDE
;
72 scoped_refptr
<ui::SelectFileDialog
> select_file_dialog_
;
74 // The certificate hierarchy (leaf cert first).
75 net::X509Certificate::OSCertHandles cert_chain_list_
;
78 Exporter::Exporter(WebContents
* web_contents
,
79 gfx::NativeWindow parent
,
80 net::X509Certificate::OSCertHandle cert
)
81 : select_file_dialog_(ui::SelectFileDialog::Create(
82 this, new ChromeSelectFilePolicy(web_contents
))) {
83 x509_certificate_model::GetCertChainFromCert(cert
, &cert_chain_list_
);
85 // TODO(mattm): should this default to some directory?
86 // Maybe SavePackage::GetSaveDirPreference? (Except that it's private.)
87 base::FilePath
suggested_path("certificate");
88 std::string cert_title
= x509_certificate_model::GetTitle(cert
);
89 if (!cert_title
.empty())
90 suggested_path
= base::FilePath(cert_title
);
92 ShowCertSelectFileDialog(select_file_dialog_
.get(),
93 ui::SelectFileDialog::SELECT_SAVEAS_FILE
,
99 Exporter::~Exporter() {
100 // There may be pending file dialogs, we need to tell them that we've gone
101 // away so they don't try and call back to us.
102 if (select_file_dialog_
.get())
103 select_file_dialog_
->ListenerDestroyed();
105 x509_certificate_model::DestroyCertChain(&cert_chain_list_
);
108 void Exporter::FileSelected(const base::FilePath
& path
, int index
,
113 for (size_t i
= 0; i
< cert_chain_list_
.size(); ++i
)
114 data
+= GetBase64String(cert_chain_list_
[i
]);
117 data
= x509_certificate_model::GetDerString(cert_chain_list_
[0]);
120 data
= x509_certificate_model::GetCMSString(cert_chain_list_
, 0, 1);
123 data
= x509_certificate_model::GetCMSString(
124 cert_chain_list_
, 0, cert_chain_list_
.size());
128 data
= GetBase64String(cert_chain_list_
[0]);
133 WriteFileOnFileThread(path
, data
);
138 void Exporter::FileSelectionCanceled(void* params
) {
144 void ShowCertSelectFileDialog(ui::SelectFileDialog
* select_file_dialog
,
145 ui::SelectFileDialog::Type type
,
146 const base::FilePath
& suggested_path
,
147 gfx::NativeWindow parent
,
149 ui::SelectFileDialog::FileTypeInfo file_type_info
;
150 file_type_info
.extensions
.resize(5);
151 file_type_info
.extensions
[0].push_back(FILE_PATH_LITERAL("pem"));
152 file_type_info
.extensions
[0].push_back(FILE_PATH_LITERAL("crt"));
153 file_type_info
.extension_description_overrides
.push_back(
154 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_BASE64
));
155 file_type_info
.extensions
[1].push_back(FILE_PATH_LITERAL("pem"));
156 file_type_info
.extensions
[1].push_back(FILE_PATH_LITERAL("crt"));
157 file_type_info
.extension_description_overrides
.push_back(
158 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_BASE64_CHAIN
));
159 file_type_info
.extensions
[2].push_back(FILE_PATH_LITERAL("der"));
160 file_type_info
.extension_description_overrides
.push_back(
161 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_DER
));
162 file_type_info
.extensions
[3].push_back(FILE_PATH_LITERAL("p7c"));
163 file_type_info
.extension_description_overrides
.push_back(
164 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_PKCS7
));
165 file_type_info
.extensions
[4].push_back(FILE_PATH_LITERAL("p7c"));
166 file_type_info
.extension_description_overrides
.push_back(
167 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_PKCS7_CHAIN
));
168 file_type_info
.include_all_files
= true;
169 select_file_dialog
->SelectFile(
170 type
, base::string16(),
171 suggested_path
, &file_type_info
,
172 1, // 1-based index for |file_type_info.extensions| to specify default.
173 FILE_PATH_LITERAL("crt"),
177 void ShowCertExportDialog(WebContents
* web_contents
,
178 gfx::NativeWindow parent
,
179 net::X509Certificate::OSCertHandle cert
) {
180 new Exporter(web_contents
, parent
, cert
);