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 |