Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(183)

Side by Side Diff: chrome/common/net/x509_certificate_model_nss.cc

Issue 3565006: Decouples certificates viewers from NSS to prepare support for OpenSSL. (Closed)
Patch Set: Comments / ProcessIDN Created 10 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/common/net/x509_certificate_model.h"
6
7 #include <cert.h>
8 #include <cms.h>
9 #include <hasht.h>
10 #include <pk11pub.h>
11 #include <sechash.h>
12
13 #include <pk11pub.h>
14
15 #include "base/logging.h"
16 #include "base/nss_util.h"
17 #include "base/string_number_conversions.h"
18 #include "net/base/x509_certificate.h"
19 #include "chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h"
20 #include "chrome/third_party/mozilla_security_manager/nsNSSCertificate.h"
21 #include "chrome/third_party/mozilla_security_manager/nsUsageArrayHelper.h"
22
23 namespace psm = mozilla_security_manager;
24
25 namespace {
26
27 // Convert a char* return value from NSS into a std::string and free the NSS
28 // memory. If the arg is NULL, an empty string will be returned instead.
29 std::string Stringize(char* nss_text, const std::string& alternative_text) {
30 if (!nss_text)
31 return alternative_text;
32
33 std::string s = nss_text;
34 PORT_Free(nss_text);
35 return s;
36 }
37
38 // Hash a certificate using the given algorithm, return the result as a
39 // colon-seperated hex string. The len specified is the number of bytes
40 // required for storing the raw fingerprint.
41 // (It's a bit redundant that the caller needs to specify len in addition to the
42 // algorithm, but given the limited uses, not worth fixing.)
43 std::string HashCert(CERTCertificate* cert, HASH_HashType algorithm, int len) {
44 unsigned char fingerprint[HASH_LENGTH_MAX];
45 SECItem fingerprint_item;
46
47 DCHECK(NULL != cert->derCert.data);
48 DCHECK_NE(0U, cert->derCert.len);
49 DCHECK_LE(len, HASH_LENGTH_MAX);
50 memset(fingerprint, 0, len);
51 SECStatus rv = HASH_HashBuf(algorithm, fingerprint, cert->derCert.data,
52 cert->derCert.len);
53 DCHECK_EQ(rv, SECSuccess);
54 fingerprint_item.data = fingerprint;
55 fingerprint_item.len = len;
56 return psm::ProcessRawBytes(&fingerprint_item);
57 }
58
59 std::string ProcessSecAlgorithmInternal(SECAlgorithmID* algorithm_id) {
60 return psm::GetOIDText(&algorithm_id->algorithm);
61 }
62
63 std::string ProcessExtension(
64 const std::string& critical_label,
65 const std::string& non_critical_label,
66 CERTCertExtension* extension) {
67 std::string criticality =
68 extension->critical.data && extension->critical.data[0] ?
69 critical_label : non_critical_label;
70 return criticality + "\n" +
71 psm::ProcessExtensionData(SECOID_FindOIDTag(&extension->id),
72 &extension->value);
73 }
74
75 ////////////////////////////////////////////////////////////////////////////////
76 // NSS certificate export functions.
77
78 class FreeNSSCMSMessage {
79 public:
80 inline void operator()(NSSCMSMessage* x) const {
81 NSS_CMSMessage_Destroy(x);
82 }
83 };
84 typedef scoped_ptr_malloc<NSSCMSMessage, FreeNSSCMSMessage>
85 ScopedNSSCMSMessage;
86
87 class FreeNSSCMSSignedData {
88 public:
89 inline void operator()(NSSCMSSignedData* x) const {
90 NSS_CMSSignedData_Destroy(x);
91 }
92 };
93 typedef scoped_ptr_malloc<NSSCMSSignedData, FreeNSSCMSSignedData>
94 ScopedNSSCMSSignedData;
95
96 } // namespace
97
98 namespace x509_certificate_model {
99
100 using net::X509Certificate;
101 using std::string;
102
103 string GetCertNameOrNickname(X509Certificate::OSCertHandle cert_handle) {
104 string name = ProcessIDN(Stringize(CERT_GetCommonName(&cert_handle->subject),
105 ""));
106 if (name.empty() && cert_handle->nickname) {
107 name = cert_handle->nickname;
108 // Hack copied from mozilla: Cut off text before first :, which seems to
109 // just be the token name.
110 size_t colon_pos = name.find(':');
111 if (colon_pos != string::npos)
112 name = name.substr(colon_pos + 1);
113 }
114 return name;
115 }
116
117 string GetTokenName(X509Certificate::OSCertHandle cert_handle) {
118 return psm::GetCertTokenName(cert_handle);
119 }
120
121 string GetVersion(X509Certificate::OSCertHandle cert_handle) {
122 unsigned long version = ULONG_MAX;
123 if (SEC_ASN1DecodeInteger(&cert_handle->version, &version) == SECSuccess &&
124 version != ULONG_MAX)
125 return base::UintToString(version + 1);
126 return "";
127 }
128
129 net::CertType GetType(X509Certificate::OSCertHandle cert_handle) {
130 return psm::GetCertType(cert_handle);
131 }
132
133 string GetEmailAddress(X509Certificate::OSCertHandle cert_handle) {
134 if (cert_handle->emailAddr)
135 return cert_handle->emailAddr;
136 return "";
137 }
138
139 void GetUsageStrings(X509Certificate::OSCertHandle cert_handle,
140 std::vector<string>* usages) {
141 psm::GetCertUsageStrings(cert_handle, usages);
142 }
143
144 string GetKeyUsageString(X509Certificate::OSCertHandle cert_handle) {
145 SECItem key_usage;
146 key_usage.data = NULL;
147 string key_usage_str;
148 if (CERT_FindKeyUsageExtension(cert_handle, &key_usage) == SECSuccess) {
149 key_usage_str = psm::ProcessKeyUsageBitString(&key_usage, ',');
150 PORT_Free(key_usage.data);
151 }
152 return key_usage_str;
153 }
154
155 string GetSerialNumberHexified(X509Certificate::OSCertHandle cert_handle,
156 const string& alternative_text) {
157 return Stringize(CERT_Hexify(&cert_handle->serialNumber, true),
158 alternative_text);
159 }
160
161 string GetIssuerCommonName(X509Certificate::OSCertHandle cert_handle,
162 const string& alternative_text) {
163 return Stringize(CERT_GetCommonName(&cert_handle->issuer), alternative_text);
164 }
165
166 string GetIssuerOrgName(X509Certificate::OSCertHandle cert_handle,
167 const string& alternative_text) {
168 return Stringize(CERT_GetOrgName(&cert_handle->issuer), alternative_text);
169 }
170
171 string GetIssuerOrgUnitName(X509Certificate::OSCertHandle cert_handle,
172 const string& alternative_text) {
173 return Stringize(CERT_GetOrgUnitName(&cert_handle->issuer), alternative_text);
174 }
175
176 string GetSubjectOrgName(X509Certificate::OSCertHandle cert_handle,
177 const string& alternative_text) {
178 return Stringize(CERT_GetOrgName(&cert_handle->subject), alternative_text);
179 }
180
181 string GetSubjectOrgUnitName(X509Certificate::OSCertHandle cert_handle,
182 const string& alternative_text) {
183 return Stringize(CERT_GetOrgUnitName(&cert_handle->subject),
184 alternative_text);
185 }
186
187 string GetSubjectCommonName(X509Certificate::OSCertHandle cert_handle,
188 const string& alternative_text) {
189 return Stringize(CERT_GetCommonName(&cert_handle->subject), alternative_text);
190 }
191
192 bool GetTimes(X509Certificate::OSCertHandle cert_handle,
193 base::Time* issued, base::Time* expires) {
194 PRTime pr_issued, pr_expires;
195 if (CERT_GetCertTimes(cert_handle, &pr_issued, &pr_expires) == SECSuccess) {
196 *issued = base::PRTimeToBaseTime(pr_issued);
197 *expires = base::PRTimeToBaseTime(pr_expires);
198 return true;
199 }
200 return false;
201 }
202
203 string GetTitle(X509Certificate::OSCertHandle cert_handle) {
204 return psm::GetCertTitle(cert_handle);
205 }
206
207 string GetIssuerName(X509Certificate::OSCertHandle cert_handle) {
208 return psm::ProcessName(&cert_handle->issuer);
209 }
210
211 string GetSubjectName(X509Certificate::OSCertHandle cert_handle) {
212 return psm::ProcessName(&cert_handle->subject);
213 }
214
215 void GetEmailAddresses(X509Certificate::OSCertHandle cert_handle,
216 std::vector<string>* email_addresses) {
217 for (const char* addr = CERT_GetFirstEmailAddress(cert_handle);
218 addr; addr = CERT_GetNextEmailAddress(cert_handle, addr)) {
219 // The first email addr (from Subject) may be duplicated in Subject
220 // Alternative Name, so check subsequent addresses are not equal to the
221 // first one before adding to the list.
222 if (!email_addresses->size() || (*email_addresses)[0] != addr)
223 email_addresses->push_back(addr);
224 }
225 }
226
227 void GetNicknameStringsFromCertList(
228 const std::vector<scoped_refptr<X509Certificate> >& certs,
229 const string& cert_expired,
230 const string& cert_not_yet_valid,
231 std::vector<string>* nick_names) {
232 CERTCertList* cert_list = CERT_NewCertList();
233 for (size_t i = 0; i < certs.size(); ++i) {
234 CERT_AddCertToListTail(
235 cert_list,
236 CERT_DupCertificate(certs[i]->os_cert_handle()));
237 }
238 // Would like to use CERT_GetCertNicknameWithValidity on each cert
239 // individually instead of having to build a CERTCertList for this, but that
240 // function is not exported.
241 CERTCertNicknames* cert_nicknames = CERT_NicknameStringsFromCertList(
242 cert_list,
243 const_cast<char*>(cert_expired.c_str()),
244 const_cast<char*>(cert_not_yet_valid.c_str()));
245 DCHECK_EQ(cert_nicknames->numnicknames,
246 static_cast<int>(certs.size()));
247
248 for (int i = 0; i < cert_nicknames->numnicknames; ++i)
249 nick_names->push_back(cert_nicknames->nicknames[i]);
250
251 CERT_FreeNicknames(cert_nicknames);
252 CERT_DestroyCertList(cert_list);
253 }
254
255 void GetExtensions(
256 const string& critical_label,
257 const string& non_critical_label,
258 X509Certificate::OSCertHandle cert_handle,
259 Extensions* extensions) {
260 if (cert_handle->extensions) {
261 for (size_t i = 0; cert_handle->extensions[i] != NULL; ++i) {
262 Extension extension;
263 extension.name = psm::GetOIDText(&cert_handle->extensions[i]->id);
264 extension.value = ProcessExtension(
265 critical_label, non_critical_label, cert_handle->extensions[i]);
266 extensions->push_back(extension);
267 }
268 }
269 }
270
271 string HashCertSHA256(X509Certificate::OSCertHandle cert_handle) {
272 return HashCert(cert_handle, HASH_AlgSHA256, SHA256_LENGTH);
273 }
274
275 string HashCertSHA1(X509Certificate::OSCertHandle cert_handle) {
276 return HashCert(cert_handle, HASH_AlgSHA1, SHA1_LENGTH);
277 }
278
279 void GetCertChainFromCert(X509Certificate::OSCertHandle cert_handle,
280 X509Certificate::OSCertHandles* cert_handles) {
281 CERTCertList* cert_list =
282 CERT_GetCertChainFromCert(cert_handle, PR_Now(), certUsageSSLServer);
283 CERTCertListNode* node;
284 for (node = CERT_LIST_HEAD(cert_list);
285 !CERT_LIST_END(node, cert_list);
286 node = CERT_LIST_NEXT(node)) {
287 cert_handles->push_back(CERT_DupCertificate(node->cert));
288 }
289 CERT_DestroyCertList(cert_list);
290 }
291
292 void DestroyCertChain(X509Certificate::OSCertHandles* cert_handles) {
293 for (X509Certificate::OSCertHandles::iterator i(cert_handles->begin());
294 i != cert_handles->end(); ++i)
295 CERT_DestroyCertificate(*i);
296 }
297
298 string GetDerString(X509Certificate::OSCertHandle cert_handle) {
299 return string(reinterpret_cast<const char*>(cert_handle->derCert.data),
300 cert_handle->derCert.len);
301 }
302
303 string GetCMSString(const X509Certificate::OSCertHandles& cert_chain,
304 size_t start, size_t end) {
305 ScopedPRArenaPool arena(PORT_NewArena(1024));
306 CHECK(arena.get());
307
308 ScopedNSSCMSMessage message(NSS_CMSMessage_Create(arena.get()));
309 CHECK(message.get());
310
311 // First, create SignedData with the certificate only (no chain).
312 ScopedNSSCMSSignedData signed_data(NSS_CMSSignedData_CreateCertsOnly(
313 message.get(), cert_chain[start], PR_FALSE));
314 if (!signed_data.get()) {
315 LOG(ERROR) << "NSS_CMSSignedData_Create failed";
316 return "";
317 }
318 // Add the rest of the chain (if any).
319 for (size_t i = start + 1; i < end; ++i) {
320 if (NSS_CMSSignedData_AddCertificate(signed_data.get(), cert_chain[i]) !=
321 SECSuccess) {
322 LOG(ERROR) << "NSS_CMSSignedData_AddCertificate failed on " << i;
323 return "";
324 }
325 }
326
327 NSSCMSContentInfo *cinfo = NSS_CMSMessage_GetContentInfo(message.get());
328 if (NSS_CMSContentInfo_SetContent_SignedData(
329 message.get(), cinfo, signed_data.get()) == SECSuccess) {
330 ignore_result(signed_data.release());
331 } else {
332 LOG(ERROR) << "NSS_CMSMessage_GetContentInfo failed";
333 return "";
334 }
335
336 SECItem cert_p7 = { siBuffer, NULL, 0 };
337 NSSCMSEncoderContext *ecx = NSS_CMSEncoder_Start(message.get(), NULL, NULL,
338 &cert_p7, arena.get(), NULL,
339 NULL, NULL, NULL, NULL,
340 NULL);
341 if (!ecx) {
342 LOG(ERROR) << "NSS_CMSEncoder_Start failed";
343 return "";
344 }
345
346 if (NSS_CMSEncoder_Finish(ecx) != SECSuccess) {
347 LOG(ERROR) << "NSS_CMSEncoder_Finish failed";
348 return "";
349 }
350
351 return string(reinterpret_cast<const char*>(cert_p7.data), cert_p7.len);
352 }
353
354 string ProcessSecAlgorithmSignature(X509Certificate::OSCertHandle cert_handle) {
355 return ProcessSecAlgorithmInternal(&cert_handle->signature);
356 }
357
358 string ProcessSecAlgorithmSubjectPublicKey(
359 X509Certificate::OSCertHandle cert_handle) {
360 return ProcessSecAlgorithmInternal(
361 &cert_handle->subjectPublicKeyInfo.algorithm);
362 }
363
364 string ProcessSecAlgorithmSignatureWrap(
365 X509Certificate::OSCertHandle cert_handle) {
366 return ProcessSecAlgorithmInternal(
367 &cert_handle->signatureWrap.signatureAlgorithm);
368 }
369
370 string ProcessSubjectPublicKeyInfo(X509Certificate::OSCertHandle cert_handle) {
371 return psm::ProcessSubjectPublicKeyInfo(&cert_handle->subjectPublicKeyInfo);
372 }
373
374 string ProcessRawBitsSignatureWrap(X509Certificate::OSCertHandle cert_handle) {
375 return psm::ProcessRawBits(&cert_handle->signatureWrap.signature);
376 }
377
378 void RegisterDynamicOids() {
379 }
380
381 } // namespace x509_certificate_model
OLDNEW
« no previous file with comments | « chrome/common/net/x509_certificate_model.cc ('k') | chrome/common/net/x509_certificate_model_openssl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698