172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// TODO(mattm): this isn't gtk specific, it shouldn't be under the gtk dir
6731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/certificate_dialogs.h"
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <vector>
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/base64.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_util.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h"
15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/task.h"
17731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/common/net/x509_certificate_model.h"
18dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h"
2072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch////////////////////////////////////////////////////////////////////////////////
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// General utility functions.
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass Writer : public Task {
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Writer(const FilePath& path, const std::string& data)
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      : path_(path), data_(data) {
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void Run() {
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int bytes_written = file_util::WriteFile(path_, data_.data(), data_.size());
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (bytes_written != static_cast<ssize_t>(data_.size())) {
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(ERROR) << "Writing " << path_.value() << " ("
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 << data_.size() << "B) returned " << bytes_written;
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath path_;
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string data_;
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WriteFileOnFileThread(const FilePath& path, const std::string& data) {
46731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
47731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::FILE, FROM_HERE, new Writer(path, data));
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::string WrapAt64(const std::string &str) {
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string result;
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < str.size(); i += 64) {
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result.append(str, i, 64);  // Append clamps the len arg internally.
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result.append("\r\n");
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result;
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
59731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickstd::string GetBase64String(net::X509Certificate::OSCertHandle cert) {
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string base64;
61731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (!base::Base64Encode(
62731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      x509_certificate_model::GetDerString(cert), &base64)) {
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(ERROR) << "base64 encoding error";
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return "";
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return "-----BEGIN CERTIFICATE-----\r\n" +
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      WrapAt64(base64) +
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "-----END CERTIFICATE-----\r\n";
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch////////////////////////////////////////////////////////////////////////////////
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// General utility functions.
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass Exporter : public SelectFileDialog::Listener {
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Exporter(TabContents* tab_contents, gfx::NativeWindow parent,
77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen           net::X509Certificate::OSCertHandle cert);
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ~Exporter();
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // SelectFileDialog::Listener implemenation.
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void FileSelected(const FilePath& path,
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            int index, void* params);
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void FileSelectionCanceled(void* params);
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<SelectFileDialog> select_file_dialog_;
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The certificate hierarchy (leaf cert first).
88731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  net::X509Certificate::OSCertHandles cert_chain_list_;
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenExporter::Exporter(TabContents* tab_contents,
92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                   gfx::NativeWindow parent,
93731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                   net::X509Certificate::OSCertHandle cert)
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : select_file_dialog_(SelectFileDialog::Create(this)) {
95731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  x509_certificate_model::GetCertChainFromCert(cert, &cert_chain_list_);
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(mattm): should this default to some directory?
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Maybe SavePackage::GetSaveDirPreference? (Except that it's private.)
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath suggested_path("certificate");
100731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  std::string cert_title = x509_certificate_model::GetTitle(cert);
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!cert_title.empty())
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    suggested_path = FilePath(cert_title);
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
104731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  ShowCertSelectFileDialog(select_file_dialog_.get(),
105731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                           SelectFileDialog::SELECT_SAVEAS_FILE,
106731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                           suggested_path,
107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                           tab_contents,
108731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                           parent,
109731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                           NULL);
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochExporter::~Exporter() {
113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // There may be pending file dialogs, we need to tell them that we've gone
114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // away so they don't try and call back to us.
115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (select_file_dialog_.get())
116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    select_file_dialog_->ListenerDestroyed();
117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
118731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  x509_certificate_model::DestroyCertChain(&cert_chain_list_);
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid Exporter::FileSelected(const FilePath& path, int index, void* params) {
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string data;
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  switch (index) {
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case 2:
125731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      for (size_t i = 0; i < cert_chain_list_.size(); ++i)
126731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        data += GetBase64String(cert_chain_list_[i]);
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case 3:
129731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      data = x509_certificate_model::GetDerString(cert_chain_list_[0]);
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case 4:
132731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      data = x509_certificate_model::GetCMSString(cert_chain_list_, 0, 1);
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case 5:
135731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      data = x509_certificate_model::GetCMSString(
136731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          cert_chain_list_, 0, cert_chain_list_.size());
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case 1:
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    default:
140731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      data = GetBase64String(cert_chain_list_[0]);
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!data.empty())
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    WriteFileOnFileThread(path, data);
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delete this;
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid Exporter::FileSelectionCanceled(void* params) {
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delete this;
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
156731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid ShowCertSelectFileDialog(SelectFileDialog* select_file_dialog,
157731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                              SelectFileDialog::Type type,
158731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                              const FilePath& suggested_path,
159ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                              TabContents* tab_contents,
160731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                              gfx::NativeWindow parent,
161731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                              void* params) {
162731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  SelectFileDialog::FileTypeInfo file_type_info;
163731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  file_type_info.extensions.resize(5);
164731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("pem"));
165731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("crt"));
166731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  file_type_info.extension_description_overrides.push_back(
167731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_BASE64));
168731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  file_type_info.extensions[1].push_back(FILE_PATH_LITERAL("pem"));
169731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  file_type_info.extensions[1].push_back(FILE_PATH_LITERAL("crt"));
170731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  file_type_info.extension_description_overrides.push_back(
171731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_BASE64_CHAIN));
172731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  file_type_info.extensions[2].push_back(FILE_PATH_LITERAL("der"));
173731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  file_type_info.extension_description_overrides.push_back(
174731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_DER));
175731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  file_type_info.extensions[3].push_back(FILE_PATH_LITERAL("p7c"));
176731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  file_type_info.extension_description_overrides.push_back(
177731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_PKCS7));
178731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  file_type_info.extensions[4].push_back(FILE_PATH_LITERAL("p7c"));
179731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  file_type_info.extension_description_overrides.push_back(
180731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_PKCS7_CHAIN));
181731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  file_type_info.include_all_files = true;
182731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  select_file_dialog->SelectFile(
183731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      type, string16(),
184731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      suggested_path, &file_type_info, 1,
185ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      FILE_PATH_LITERAL("crt"), tab_contents,
186ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      parent, params);
187731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
188731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
189ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid ShowCertExportDialog(TabContents* tab_contents,
190ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                          gfx::NativeWindow parent,
191731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                          net::X509Certificate::OSCertHandle cert) {
192ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  new Exporter(tab_contents, parent, cert);
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
194