• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/ui/certificate_dialogs.h"
6 
7 
8 #include <vector>
9 
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"
21 
22 using content::BrowserThread;
23 using content::WebContents;
24 
25 namespace {
26 
WriterCallback(const base::FilePath & path,const std::string & data)27 void WriterCallback(const base::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;
32   }
33 }
34 
WriteFileOnFileThread(const base::FilePath & path,const std::string & data)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));
39 }
40 
WrapAt64(const std::string & str)41 std::string WrapAt64(const std::string &str) {
42   std::string result;
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");
46   }
47   return result;
48 }
49 
GetBase64String(net::X509Certificate::OSCertHandle cert)50 std::string GetBase64String(net::X509Certificate::OSCertHandle cert) {
51   std::string base64;
52   base::Base64Encode(x509_certificate_model::GetDerString(cert), &base64);
53   return "-----BEGIN CERTIFICATE-----\r\n" +
54       WrapAt64(base64) +
55       "-----END CERTIFICATE-----\r\n";
56 }
57 
58 ////////////////////////////////////////////////////////////////////////////////
59 // General utility functions.
60 
61 class Exporter : public ui::SelectFileDialog::Listener {
62  public:
63   Exporter(WebContents* web_contents, gfx::NativeWindow parent,
64            net::X509Certificate::OSCertHandle cert);
65   virtual ~Exporter();
66 
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;
71  private:
72   scoped_refptr<ui::SelectFileDialog> select_file_dialog_;
73 
74   // The certificate hierarchy (leaf cert first).
75   net::X509Certificate::OSCertHandles cert_chain_list_;
76 };
77 
Exporter(WebContents * web_contents,gfx::NativeWindow parent,net::X509Certificate::OSCertHandle cert)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_);
84 
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);
91 
92   ShowCertSelectFileDialog(select_file_dialog_.get(),
93                            ui::SelectFileDialog::SELECT_SAVEAS_FILE,
94                            suggested_path,
95                            parent,
96                            NULL);
97 }
98 
~Exporter()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();
104 
105   x509_certificate_model::DestroyCertChain(&cert_chain_list_);
106 }
107 
FileSelected(const base::FilePath & path,int index,void * params)108 void Exporter::FileSelected(const base::FilePath& path, int index,
109                             void* params) {
110   std::string data;
111   switch (index) {
112     case 2:
113       for (size_t i = 0; i < cert_chain_list_.size(); ++i)
114         data += GetBase64String(cert_chain_list_[i]);
115       break;
116     case 3:
117       data = x509_certificate_model::GetDerString(cert_chain_list_[0]);
118       break;
119     case 4:
120       data = x509_certificate_model::GetCMSString(cert_chain_list_, 0, 1);
121       break;
122     case 5:
123       data = x509_certificate_model::GetCMSString(
124           cert_chain_list_, 0, cert_chain_list_.size());
125       break;
126     case 1:
127     default:
128       data = GetBase64String(cert_chain_list_[0]);
129       break;
130   }
131 
132   if (!data.empty())
133     WriteFileOnFileThread(path, data);
134 
135   delete this;
136 }
137 
FileSelectionCanceled(void * params)138 void Exporter::FileSelectionCanceled(void* params) {
139   delete this;
140 }
141 
142 } // namespace
143 
ShowCertSelectFileDialog(ui::SelectFileDialog * select_file_dialog,ui::SelectFileDialog::Type type,const base::FilePath & suggested_path,gfx::NativeWindow parent,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,
148                               void* params) {
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"),
174       parent, params);
175 }
176 
ShowCertExportDialog(WebContents * web_contents,gfx::NativeWindow parent,net::X509Certificate::OSCertHandle cert)177 void ShowCertExportDialog(WebContents* web_contents,
178                           gfx::NativeWindow parent,
179                           net::X509Certificate::OSCertHandle cert) {
180   new Exporter(web_contents, parent, cert);
181 }
182