| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // TODO(mattm): this isn't gtk specific, it shouldn't be under the gtk dir | 5 // TODO(mattm): this isn't gtk specific, it shouldn't be under the gtk dir |
| 6 | 6 |
| 7 // TODO(mattm): the nss export functions should be moved to cert_database_nss or | |
| 8 // x509_certificate_nss. | |
| 9 | |
| 10 #include "chrome/browser/gtk/certificate_dialogs.h" | 7 #include "chrome/browser/gtk/certificate_dialogs.h" |
| 11 | 8 |
| 12 #include <cms.h> | |
| 13 | 9 |
| 14 #include <vector> | 10 #include <vector> |
| 15 | 11 |
| 16 #include "app/l10n_util.h" | 12 #include "app/l10n_util.h" |
| 17 #include "base/base64.h" | 13 #include "base/base64.h" |
| 18 #include "base/file_util.h" | 14 #include "base/file_util.h" |
| 19 #include "base/logging.h" | 15 #include "base/logging.h" |
| 20 #include "base/scoped_ptr.h" | 16 #include "base/scoped_ptr.h" |
| 21 #include "base/task.h" | 17 #include "base/task.h" |
| 22 #include "chrome/browser/chrome_thread.h" | 18 #include "chrome/browser/chrome_thread.h" |
| 23 #include "chrome/browser/shell_dialogs.h" | 19 #include "chrome/browser/shell_dialogs.h" |
| 24 #include "chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h" | 20 #include "chrome/common/net/x509_certificate_model.h" |
| 25 #include "chrome/third_party/mozilla_security_manager/nsNSSCertificate.h" | |
| 26 #include "grit/generated_resources.h" | 21 #include "grit/generated_resources.h" |
| 27 | 22 |
| 28 // PSM = Mozilla's Personal Security Manager. | |
| 29 namespace psm = mozilla_security_manager; | |
| 30 | |
| 31 namespace { | 23 namespace { |
| 32 | 24 |
| 33 //////////////////////////////////////////////////////////////////////////////// | 25 //////////////////////////////////////////////////////////////////////////////// |
| 34 // General utility functions. | 26 // General utility functions. |
| 35 | 27 |
| 36 class Writer : public Task { | 28 class Writer : public Task { |
| 37 public: | 29 public: |
| 38 Writer(const FilePath& path, const std::string& data) | 30 Writer(const FilePath& path, const std::string& data) |
| 39 : path_(path), data_(data) { | 31 : path_(path), data_(data) { |
| 40 } | 32 } |
| 41 | 33 |
| 42 virtual void Run() { | 34 virtual void Run() { |
| 43 int bytes_written = file_util::WriteFile(path_, data_.data(), data_.size()); | 35 int bytes_written = file_util::WriteFile(path_, data_.data(), data_.size()); |
| 44 if (bytes_written != static_cast<ssize_t>(data_.size())) { | 36 if (bytes_written != static_cast<ssize_t>(data_.size())) { |
| 45 LOG(ERROR) << "Writing " << path_.value() << " (" | 37 LOG(ERROR) << "Writing " << path_.value() << " (" |
| 46 << data_.size() << "B) returned " << bytes_written; | 38 << data_.size() << "B) returned " << bytes_written; |
| 47 } | 39 } |
| 48 } | 40 } |
| 49 private: | 41 private: |
| 50 FilePath path_; | 42 FilePath path_; |
| 51 std::string data_; | 43 std::string data_; |
| 52 }; | 44 }; |
| 53 | 45 |
| 54 void WriteFileOnFileThread(const FilePath& path, const std::string& data) { | 46 void WriteFileOnFileThread(const FilePath& path, const std::string& data) { |
| 55 ChromeThread::PostTask( | 47 ChromeThread::PostTask( |
| 56 ChromeThread::FILE, FROM_HERE, new Writer(path, data)); | 48 ChromeThread::FILE, FROM_HERE, new Writer(path, data)); |
| 57 } | 49 } |
| 58 | 50 |
| 59 //////////////////////////////////////////////////////////////////////////////// | |
| 60 // NSS certificate export functions. | |
| 61 | |
| 62 class FreeNSSCMSMessage { | |
| 63 public: | |
| 64 inline void operator()(NSSCMSMessage* x) const { | |
| 65 NSS_CMSMessage_Destroy(x); | |
| 66 } | |
| 67 }; | |
| 68 typedef scoped_ptr_malloc<NSSCMSMessage, FreeNSSCMSMessage> | |
| 69 ScopedNSSCMSMessage; | |
| 70 | |
| 71 class FreeNSSCMSSignedData { | |
| 72 public: | |
| 73 inline void operator()(NSSCMSSignedData* x) const { | |
| 74 NSS_CMSSignedData_Destroy(x); | |
| 75 } | |
| 76 }; | |
| 77 typedef scoped_ptr_malloc<NSSCMSSignedData, FreeNSSCMSSignedData> | |
| 78 ScopedNSSCMSSignedData; | |
| 79 | |
| 80 std::string GetDerString(CERTCertificate* cert) { | |
| 81 return std::string(reinterpret_cast<const char*>(cert->derCert.data), | |
| 82 cert->derCert.len); | |
| 83 } | |
| 84 | |
| 85 std::string WrapAt64(const std::string &str) { | 51 std::string WrapAt64(const std::string &str) { |
| 86 std::string result; | 52 std::string result; |
| 87 for (size_t i = 0; i < str.size(); i += 64) { | 53 for (size_t i = 0; i < str.size(); i += 64) { |
| 88 result.append(str, i, 64); // Append clamps the len arg internally. | 54 result.append(str, i, 64); // Append clamps the len arg internally. |
| 89 result.append("\r\n"); | 55 result.append("\r\n"); |
| 90 } | 56 } |
| 91 return result; | 57 return result; |
| 92 } | 58 } |
| 93 | 59 |
| 94 std::string GetBase64String(CERTCertificate* cert) { | 60 std::string GetBase64String(net::X509Certificate::OSCertHandle cert) { |
| 95 std::string base64; | 61 std::string base64; |
| 96 if (!base::Base64Encode(GetDerString(cert), &base64)) { | 62 if (!base::Base64Encode( |
| 63 x509_certificate_model::GetDerString(cert), &base64)) { |
| 97 LOG(ERROR) << "base64 encoding error"; | 64 LOG(ERROR) << "base64 encoding error"; |
| 98 return ""; | 65 return ""; |
| 99 } | 66 } |
| 100 return "-----BEGIN CERTIFICATE-----\r\n" + | 67 return "-----BEGIN CERTIFICATE-----\r\n" + |
| 101 WrapAt64(base64) + | 68 WrapAt64(base64) + |
| 102 "-----END CERTIFICATE-----\r\n"; | 69 "-----END CERTIFICATE-----\r\n"; |
| 103 } | 70 } |
| 104 | 71 |
| 105 std::string GetCMSString(std::vector<CERTCertificate*> cert_chain, size_t start, | |
| 106 size_t end) { | |
| 107 ScopedPRArenaPool arena(PORT_NewArena(1024)); | |
| 108 CHECK(arena.get()); | |
| 109 | |
| 110 ScopedNSSCMSMessage message(NSS_CMSMessage_Create(arena.get())); | |
| 111 CHECK(message.get()); | |
| 112 | |
| 113 // First, create SignedData with the certificate only (no chain). | |
| 114 ScopedNSSCMSSignedData signed_data( | |
| 115 NSS_CMSSignedData_CreateCertsOnly(message.get(), cert_chain[start], | |
| 116 PR_FALSE)); | |
| 117 if (!signed_data.get()) { | |
| 118 LOG(ERROR) << "NSS_CMSSignedData_Create failed"; | |
| 119 return ""; | |
| 120 } | |
| 121 // Add the rest of the chain (if any). | |
| 122 for (size_t i = start + 1; i < end; ++i) { | |
| 123 if (NSS_CMSSignedData_AddCertificate(signed_data.get(), cert_chain[i]) != | |
| 124 SECSuccess) { | |
| 125 LOG(ERROR) << "NSS_CMSSignedData_AddCertificate failed on " << i; | |
| 126 return ""; | |
| 127 } | |
| 128 } | |
| 129 | |
| 130 NSSCMSContentInfo *cinfo = NSS_CMSMessage_GetContentInfo(message.get()); | |
| 131 if (NSS_CMSContentInfo_SetContent_SignedData( | |
| 132 message.get(), cinfo, signed_data.get()) == SECSuccess) { | |
| 133 ignore_result(signed_data.release()); | |
| 134 } else { | |
| 135 LOG(ERROR) << "NSS_CMSMessage_GetContentInfo failed"; | |
| 136 return ""; | |
| 137 } | |
| 138 | |
| 139 SECItem cert_p7 = { siBuffer, NULL, 0 }; | |
| 140 NSSCMSEncoderContext *ecx = NSS_CMSEncoder_Start(message.get(), NULL, NULL, | |
| 141 &cert_p7, arena.get(), NULL, | |
| 142 NULL, NULL, NULL, NULL, | |
| 143 NULL); | |
| 144 if (!ecx) { | |
| 145 LOG(ERROR) << "NSS_CMSEncoder_Start failed"; | |
| 146 return ""; | |
| 147 } | |
| 148 | |
| 149 if (NSS_CMSEncoder_Finish(ecx) != SECSuccess) { | |
| 150 LOG(ERROR) << "NSS_CMSEncoder_Finish failed"; | |
| 151 return ""; | |
| 152 } | |
| 153 | |
| 154 return std::string(reinterpret_cast<const char*>(cert_p7.data), cert_p7.len); | |
| 155 } | |
| 156 | |
| 157 //////////////////////////////////////////////////////////////////////////////// | 72 //////////////////////////////////////////////////////////////////////////////// |
| 158 // General utility functions. | 73 // General utility functions. |
| 159 | 74 |
| 160 class Exporter : public SelectFileDialog::Listener { | 75 class Exporter : public SelectFileDialog::Listener { |
| 161 public: | 76 public: |
| 162 Exporter(gfx::NativeWindow parent, CERTCertificate* cert); | 77 Exporter(gfx::NativeWindow parent, net::X509Certificate::OSCertHandle cert); |
| 163 ~Exporter(); | 78 ~Exporter(); |
| 164 | 79 |
| 165 // SelectFileDialog::Listener implemenation. | 80 // SelectFileDialog::Listener implemenation. |
| 166 virtual void FileSelected(const FilePath& path, | 81 virtual void FileSelected(const FilePath& path, |
| 167 int index, void* params); | 82 int index, void* params); |
| 168 virtual void FileSelectionCanceled(void* params); | 83 virtual void FileSelectionCanceled(void* params); |
| 169 private: | 84 private: |
| 170 scoped_refptr<SelectFileDialog> select_file_dialog_; | 85 scoped_refptr<SelectFileDialog> select_file_dialog_; |
| 171 | 86 |
| 172 // The certificate hierarchy (leaf cert first). | 87 // The certificate hierarchy (leaf cert first). |
| 173 CERTCertList* cert_chain_list_; | 88 net::X509Certificate::OSCertHandles cert_chain_list_; |
| 174 // The same contents of cert_chain_list_ in a vector for easier access. | |
| 175 std::vector<CERTCertificate*> cert_chain_; | |
| 176 }; | 89 }; |
| 177 | 90 |
| 178 Exporter::Exporter(gfx::NativeWindow parent, CERTCertificate* cert) | 91 Exporter::Exporter(gfx::NativeWindow parent, |
| 92 net::X509Certificate::OSCertHandle cert) |
| 179 : select_file_dialog_(SelectFileDialog::Create(this)) { | 93 : select_file_dialog_(SelectFileDialog::Create(this)) { |
| 180 cert_chain_list_ = CERT_GetCertChainFromCert(cert, PR_Now(), | 94 x509_certificate_model::GetCertChainFromCert(cert, &cert_chain_list_); |
| 181 certUsageSSLServer); | |
| 182 DCHECK(cert_chain_list_); | |
| 183 CERTCertListNode* node; | |
| 184 for (node = CERT_LIST_HEAD(cert_chain_list_); | |
| 185 !CERT_LIST_END(node, cert_chain_list_); | |
| 186 node = CERT_LIST_NEXT(node)) { | |
| 187 cert_chain_.push_back(node->cert); | |
| 188 } | |
| 189 | 95 |
| 190 // TODO(mattm): should this default to some directory? | 96 // TODO(mattm): should this default to some directory? |
| 191 // Maybe SavePackage::GetSaveDirPreference? (Except that it's private.) | 97 // Maybe SavePackage::GetSaveDirPreference? (Except that it's private.) |
| 192 FilePath suggested_path("certificate"); | 98 FilePath suggested_path("certificate"); |
| 193 std::string cert_title = psm::GetCertTitle(cert); | 99 std::string cert_title = x509_certificate_model::GetTitle(cert); |
| 194 if (!cert_title.empty()) | 100 if (!cert_title.empty()) |
| 195 suggested_path = FilePath(cert_title); | 101 suggested_path = FilePath(cert_title); |
| 196 | 102 |
| 197 SelectFileDialog::FileTypeInfo file_type_info; | 103 SelectFileDialog::FileTypeInfo file_type_info; |
| 198 file_type_info.extensions.resize(5); | 104 file_type_info.extensions.resize(5); |
| 199 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("pem")); | 105 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("pem")); |
| 200 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("crt")); | 106 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("crt")); |
| 201 file_type_info.extension_description_overrides.push_back( | 107 file_type_info.extension_description_overrides.push_back( |
| 202 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_BASE64)); | 108 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_BASE64)); |
| 203 file_type_info.extensions[1].push_back(FILE_PATH_LITERAL("pem")); | 109 file_type_info.extensions[1].push_back(FILE_PATH_LITERAL("pem")); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 215 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_PKCS7_CHAIN)); | 121 l10n_util::GetStringUTF16(IDS_CERT_EXPORT_TYPE_PKCS7_CHAIN)); |
| 216 file_type_info.include_all_files = true; | 122 file_type_info.include_all_files = true; |
| 217 select_file_dialog_->SelectFile( | 123 select_file_dialog_->SelectFile( |
| 218 SelectFileDialog::SELECT_SAVEAS_FILE, string16(), | 124 SelectFileDialog::SELECT_SAVEAS_FILE, string16(), |
| 219 suggested_path, &file_type_info, 1, | 125 suggested_path, &file_type_info, 1, |
| 220 FILE_PATH_LITERAL("crt"), parent, | 126 FILE_PATH_LITERAL("crt"), parent, |
| 221 NULL); | 127 NULL); |
| 222 } | 128 } |
| 223 | 129 |
| 224 Exporter::~Exporter() { | 130 Exporter::~Exporter() { |
| 225 CERT_DestroyCertList(cert_chain_list_); | 131 x509_certificate_model::DestroyCertChain(&cert_chain_list_); |
| 226 } | 132 } |
| 227 | 133 |
| 228 void Exporter::FileSelected(const FilePath& path, int index, void* params) { | 134 void Exporter::FileSelected(const FilePath& path, int index, void* params) { |
| 229 std::string data; | 135 std::string data; |
| 230 switch (index) { | 136 switch (index) { |
| 231 case 2: | 137 case 2: |
| 232 for (size_t i = 0; i < cert_chain_.size(); ++i) | 138 for (size_t i = 0; i < cert_chain_list_.size(); ++i) |
| 233 data += GetBase64String(cert_chain_[i]); | 139 data += GetBase64String(cert_chain_list_[i]); |
| 234 break; | 140 break; |
| 235 case 3: | 141 case 3: |
| 236 data = GetDerString(cert_chain_[0]); | 142 data = x509_certificate_model::GetDerString(cert_chain_list_[0]); |
| 237 break; | 143 break; |
| 238 case 4: | 144 case 4: |
| 239 data = GetCMSString(cert_chain_, 0, 1); | 145 data = x509_certificate_model::GetCMSString(cert_chain_list_, 0, 1); |
| 240 break; | 146 break; |
| 241 case 5: | 147 case 5: |
| 242 data = GetCMSString(cert_chain_, 0, cert_chain_.size()); | 148 data = x509_certificate_model::GetCMSString( |
| 149 cert_chain_list_, 0, cert_chain_list_.size()); |
| 243 break; | 150 break; |
| 244 case 1: | 151 case 1: |
| 245 default: | 152 default: |
| 246 data = GetBase64String(cert_chain_[0]); | 153 data = GetBase64String(cert_chain_list_[0]); |
| 247 break; | 154 break; |
| 248 } | 155 } |
| 249 | 156 |
| 250 if (!data.empty()) | 157 if (!data.empty()) |
| 251 WriteFileOnFileThread(path, data); | 158 WriteFileOnFileThread(path, data); |
| 252 | 159 |
| 253 delete this; | 160 delete this; |
| 254 } | 161 } |
| 255 | 162 |
| 256 void Exporter::FileSelectionCanceled(void* params) { | 163 void Exporter::FileSelectionCanceled(void* params) { |
| 257 delete this; | 164 delete this; |
| 258 } | 165 } |
| 259 | 166 |
| 260 } // namespace | 167 } // namespace |
| 261 | 168 |
| 262 void ShowCertExportDialog(gfx::NativeWindow parent, CERTCertificate* cert) { | 169 void ShowCertExportDialog(gfx::NativeWindow parent, |
| 170 net::X509Certificate::OSCertHandle cert) { |
| 263 new Exporter(parent, cert); | 171 new Exporter(parent, cert); |
| 264 } | 172 } |
| OLD | NEW |