1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #include "nsNSSCertHelper.h"
6
7 #include <algorithm>
8
9 #include "ScopedNSSTypes.h"
10 #include "mozilla/Casting.h"
11 #include "mozilla/NotNull.h"
12 #include "mozilla/Sprintf.h"
13 #include "mozilla/UniquePtr.h"
14 #include "nsCOMPtr.h"
15 #include "nsComponentManagerUtils.h"
16 #include "nsDateTimeFormatCID.h"
17 #include "nsIDateTimeFormat.h"
18 #include "nsNSSASN1Object.h"
19 #include "nsNSSCertTrust.h"
20 #include "nsNSSCertValidity.h"
21 #include "nsNSSCertificate.h"
22 #include "nsNSSComponent.h"
23 #include "nsServiceManagerUtils.h"
24 #include "prerror.h"
25 #include "secder.h"
26
27 using namespace mozilla;
28
29 /* Object Identifier constants */
30 #define CONST_OID static const unsigned char
31 #define MICROSOFT_OID 0x2b, 0x6, 0x1, 0x4, 0x1, 0x82, 0x37
32 #define PKIX_OID 0x2b, 0x6, 0x01, 0x05, 0x05, 0x07
33 CONST_OID msCertExtCerttype[] = { MICROSOFT_OID, 20, 2};
34 CONST_OID msNTPrincipalName[] = { MICROSOFT_OID, 20, 2, 3 };
35 CONST_OID msCertsrvCAVersion[] = { MICROSOFT_OID, 21, 1 };
36 CONST_OID msNTDSReplication[] = { MICROSOFT_OID, 25, 1 };
37 CONST_OID pkixLogotype[] = { PKIX_OID, 1, 12 };
38
39 #define OI(x) { siDEROID, (unsigned char *)x, sizeof x }
40 #define OD(oid,desc,mech,ext) {OI(oid), SEC_OID_UNKNOWN, desc, mech, ext}
41 #define SEC_OID(tag) more_oids[tag].offset
42
43 static SECOidData more_oids[] = {
44 /* Microsoft OIDs */
45 #define MS_CERT_EXT_CERTTYPE 0
46 OD( msCertExtCerttype,
47 "Microsoft Certificate Template Name",
48 CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
49
50 #define MS_NT_PRINCIPAL_NAME 1
51 OD( msNTPrincipalName,
52 "Microsoft Principal Name",
53 CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
54
55 #define MS_CERTSERV_CA_VERSION 2
56 OD( msCertsrvCAVersion,
57 "Microsoft CA Version",
58 CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
59
60 #define MS_NTDS_REPLICATION 3
61 OD( msNTDSReplication,
62 "Microsoft Domain GUID",
63 CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
64
65 #define PKIX_LOGOTYPE 4
66 OD( pkixLogotype,
67 "Logotype",
68 CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
69 };
70
71 static const unsigned int numOids = (sizeof more_oids) / (sizeof more_oids[0]);
72
73 static nsresult
ProcessVersion(SECItem * versionItem,nsINSSComponent * nssComponent,nsIASN1PrintableItem ** retItem)74 ProcessVersion(SECItem* versionItem, nsINSSComponent* nssComponent,
75 nsIASN1PrintableItem** retItem)
76 {
77 nsAutoString text;
78 nssComponent->GetPIPNSSBundleString("CertDumpVersion", text);
79 nsCOMPtr<nsIASN1PrintableItem> printableItem = new nsNSSASN1PrintableItem();
80 nsresult rv = printableItem->SetDisplayName(text);
81 if (NS_FAILED(rv)) {
82 return rv;
83 }
84
85 // Now to figure out what version this certificate is.
86 unsigned int version;
87 if (versionItem->data) {
88 // Filter out totally bogus version values/encodings.
89 if (versionItem->len != 1) {
90 return NS_ERROR_FAILURE;
91 }
92 version = *BitwiseCast<uint8_t*, unsigned char*>(versionItem->data);
93 } else {
94 // If there is no version present in the cert, then RFC 5280 says we
95 // default to v1 (0).
96 version = 0;
97 }
98
99 // A value of n actually corresponds to version n + 1
100 nsAutoString versionString;
101 versionString.AppendInt(version + 1);
102 const char16_t* params[1] = { versionString.get() };
103 rv = nssComponent->PIPBundleFormatStringFromName("CertDumpVersionValue",
104 params,
105 MOZ_ARRAY_LENGTH(params),
106 text);
107 if (NS_FAILED(rv)) {
108 return rv;
109 }
110
111 rv = printableItem->SetDisplayValue(text);
112 if (NS_FAILED(rv)) {
113 return rv;
114 }
115
116 printableItem.forget(retItem);
117 return NS_OK;
118 }
119
120 static nsresult
ProcessSerialNumberDER(const SECItem & serialItem,NotNull<nsINSSComponent * > nssComponent,nsCOMPtr<nsIASN1PrintableItem> & retItem)121 ProcessSerialNumberDER(const SECItem& serialItem,
122 NotNull<nsINSSComponent*> nssComponent,
123 /*out*/ nsCOMPtr<nsIASN1PrintableItem>& retItem)
124 {
125 nsAutoString text;
126 nsresult rv = nssComponent->GetPIPNSSBundleString("CertDumpSerialNo", text);
127 if (NS_FAILED(rv)) {
128 return rv;
129 }
130
131 nsCOMPtr<nsIASN1PrintableItem> printableItem = new nsNSSASN1PrintableItem();
132 rv = printableItem->SetDisplayName(text);
133 if (NS_FAILED(rv)) {
134 return rv;
135 }
136
137 UniquePORTString serialNumber(
138 CERT_Hexify(const_cast<SECItem*>(&serialItem), 1));
139 if (!serialNumber) {
140 return NS_ERROR_OUT_OF_MEMORY;
141 }
142
143 rv = printableItem->SetDisplayValue(NS_ConvertASCIItoUTF16(serialNumber.get()));
144 if (NS_FAILED(rv)) {
145 return rv;
146 }
147
148 retItem = printableItem.forget();
149 return NS_OK;
150 }
151
152 static nsresult
GetDefaultOIDFormat(SECItem * oid,nsINSSComponent * nssComponent,nsAString & outString,char separator)153 GetDefaultOIDFormat(SECItem *oid,
154 nsINSSComponent *nssComponent,
155 nsAString &outString,
156 char separator)
157 {
158 outString.Truncate();
159 int invalidCount = 0;
160
161 unsigned int i;
162 unsigned long val = 0;
163 bool invalid = false;
164 bool first = true;
165
166 val = 0;
167 for (i = 0; i < oid->len; ++i) {
168 // In this loop, we have to parse a DER formatted
169 // If the first bit is a 1, then the integer is
170 // represented by more than one byte. If the
171 // first bit is set then we continue on and add
172 // the values of the later bytes until we get
173 // a byte without the first bit set.
174 unsigned long j;
175
176 j = oid->data[i];
177 val = (val << 7) | (j & 0x7f);
178 if (j & 0x80) {
179 // - If val is 0 in this block, the OID number particle starts with 0x80
180 // what is specified as an invalid formating.
181 // - If val is larger then 2^32-7, on next left shift by 7 we will loose
182 // the most significant bits, this OID number particle cannot be read
183 // by our implementation.
184 // - If the first bit is set while this is the last component of the OID
185 // we are also in an invalid state.
186 if (val == 0 || (val >= (1 << (32-7))) || (i == oid->len-1)) {
187 invalid = true;
188 }
189
190 if (i < oid->len-1)
191 continue;
192 }
193
194 if (!invalid) {
195 if (first) {
196 unsigned long one = std::min(val/40, 2UL); // never > 2
197 unsigned long two = val - (one * 40);
198
199 outString.AppendPrintf("%lu%c%lu", one, separator, two);
200 }
201 else {
202 outString.AppendPrintf("%c%lu", separator, val);
203 }
204 }
205 else {
206 if (!first) {
207 outString.AppendPrintf("%c", separator);
208 }
209 nsAutoString unknownText;
210 nssComponent->GetPIPNSSBundleString("CertUnknown",
211 unknownText);
212 outString.Append(unknownText);
213
214 if (++invalidCount > 3) {
215 // Allow only 3 occurences of Unknown in OID display string to
216 // prevent bloat.
217 break;
218 }
219 }
220
221 val = 0;
222 invalid = false;
223 first = false;
224 }
225
226 return NS_OK;
227 }
228
229 static nsresult
GetOIDText(SECItem * oid,nsINSSComponent * nssComponent,nsAString & text)230 GetOIDText(SECItem *oid, nsINSSComponent *nssComponent, nsAString &text)
231 {
232 nsresult rv;
233 SECOidTag oidTag = SECOID_FindOIDTag(oid);
234 const char *bundlekey = 0;
235
236 switch (oidTag) {
237 case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
238 bundlekey = "CertDumpMD2WithRSA";
239 break;
240 case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
241 bundlekey = "CertDumpMD5WithRSA";
242 break;
243 case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
244 bundlekey = "CertDumpSHA1WithRSA";
245 break;
246 case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
247 bundlekey = "CertDumpSHA256WithRSA";
248 break;
249 case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
250 bundlekey = "CertDumpSHA384WithRSA";
251 break;
252 case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
253 bundlekey = "CertDumpSHA512WithRSA";
254 break;
255 case SEC_OID_PKCS1_RSA_ENCRYPTION:
256 bundlekey = "CertDumpRSAEncr";
257 break;
258 case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
259 bundlekey = "CertDumpRSAPSSSignature";
260 break;
261 case SEC_OID_AVA_COUNTRY_NAME:
262 bundlekey = "CertDumpAVACountry";
263 break;
264 case SEC_OID_AVA_COMMON_NAME:
265 bundlekey = "CertDumpAVACN";
266 break;
267 case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME:
268 bundlekey = "CertDumpAVAOU";
269 break;
270 case SEC_OID_AVA_ORGANIZATION_NAME:
271 bundlekey = "CertDumpAVAOrg";
272 break;
273 case SEC_OID_AVA_LOCALITY:
274 bundlekey = "CertDumpAVALocality";
275 break;
276 case SEC_OID_AVA_DN_QUALIFIER:
277 bundlekey = "CertDumpAVADN";
278 break;
279 case SEC_OID_AVA_DC:
280 bundlekey = "CertDumpAVADC";
281 break;
282 case SEC_OID_AVA_STATE_OR_PROVINCE:
283 bundlekey = "CertDumpAVAState";
284 break;
285 case SEC_OID_AVA_SURNAME:
286 bundlekey = "CertDumpSurname";
287 break;
288 case SEC_OID_AVA_GIVEN_NAME:
289 bundlekey = "CertDumpGivenName";
290 break;
291 case SEC_OID_X509_SUBJECT_DIRECTORY_ATTR:
292 bundlekey = "CertDumpSubjectDirectoryAttr";
293 break;
294 case SEC_OID_X509_SUBJECT_KEY_ID:
295 bundlekey = "CertDumpSubjectKeyID";
296 break;
297 case SEC_OID_X509_KEY_USAGE:
298 bundlekey = "CertDumpKeyUsage";
299 break;
300 case SEC_OID_X509_SUBJECT_ALT_NAME:
301 bundlekey = "CertDumpSubjectAltName";
302 break;
303 case SEC_OID_X509_ISSUER_ALT_NAME:
304 bundlekey = "CertDumpIssuerAltName";
305 break;
306 case SEC_OID_X509_BASIC_CONSTRAINTS:
307 bundlekey = "CertDumpBasicConstraints";
308 break;
309 case SEC_OID_X509_NAME_CONSTRAINTS:
310 bundlekey = "CertDumpNameConstraints";
311 break;
312 case SEC_OID_X509_CRL_DIST_POINTS:
313 bundlekey = "CertDumpCrlDistPoints";
314 break;
315 case SEC_OID_X509_CERTIFICATE_POLICIES:
316 bundlekey = "CertDumpCertPolicies";
317 break;
318 case SEC_OID_X509_POLICY_MAPPINGS:
319 bundlekey = "CertDumpPolicyMappings";
320 break;
321 case SEC_OID_X509_POLICY_CONSTRAINTS:
322 bundlekey = "CertDumpPolicyConstraints";
323 break;
324 case SEC_OID_X509_AUTH_KEY_ID:
325 bundlekey = "CertDumpAuthKeyID";
326 break;
327 case SEC_OID_X509_EXT_KEY_USAGE:
328 bundlekey = "CertDumpExtKeyUsage";
329 break;
330 case SEC_OID_X509_AUTH_INFO_ACCESS:
331 bundlekey = "CertDumpAuthInfoAccess";
332 break;
333 case SEC_OID_ANSIX9_DSA_SIGNATURE:
334 bundlekey = "CertDumpAnsiX9DsaSignature";
335 break;
336 case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST:
337 bundlekey = "CertDumpAnsiX9DsaSignatureWithSha1";
338 break;
339 case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE:
340 bundlekey = "CertDumpAnsiX962ECDsaSignatureWithSha1";
341 break;
342 case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE:
343 bundlekey = "CertDumpAnsiX962ECDsaSignatureWithSha224";
344 break;
345 case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE:
346 bundlekey = "CertDumpAnsiX962ECDsaSignatureWithSha256";
347 break;
348 case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE:
349 bundlekey = "CertDumpAnsiX962ECDsaSignatureWithSha384";
350 break;
351 case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE:
352 bundlekey = "CertDumpAnsiX962ECDsaSignatureWithSha512";
353 break;
354 case SEC_OID_RFC1274_UID:
355 bundlekey = "CertDumpUserID";
356 break;
357 case SEC_OID_PKCS9_EMAIL_ADDRESS:
358 bundlekey = "CertDumpPK9Email";
359 break;
360 case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
361 bundlekey = "CertDumpECPublicKey";
362 break;
363 /* ANSI X9.62 named elliptic curves (prime field) */
364 case SEC_OID_ANSIX962_EC_PRIME192V1:
365 /* same as SEC_OID_SECG_EC_SECP192r1 */
366 bundlekey = "CertDumpECprime192v1";
367 break;
368 case SEC_OID_ANSIX962_EC_PRIME192V2:
369 bundlekey = "CertDumpECprime192v2";
370 break;
371 case SEC_OID_ANSIX962_EC_PRIME192V3:
372 bundlekey = "CertDumpECprime192v3";
373 break;
374 case SEC_OID_ANSIX962_EC_PRIME239V1:
375 bundlekey = "CertDumpECprime239v1";
376 break;
377 case SEC_OID_ANSIX962_EC_PRIME239V2:
378 bundlekey = "CertDumpECprime239v2";
379 break;
380 case SEC_OID_ANSIX962_EC_PRIME239V3:
381 bundlekey = "CertDumpECprime239v3";
382 break;
383 case SEC_OID_ANSIX962_EC_PRIME256V1:
384 /* same as SEC_OID_SECG_EC_SECP256r1 */
385 bundlekey = "CertDumpECprime256v1";
386 break;
387 /* SECG named elliptic curves (prime field) */
388 case SEC_OID_SECG_EC_SECP112R1:
389 bundlekey = "CertDumpECsecp112r1";
390 break;
391 case SEC_OID_SECG_EC_SECP112R2:
392 bundlekey = "CertDumpECsecp112r2";
393 break;
394 case SEC_OID_SECG_EC_SECP128R1:
395 bundlekey = "CertDumpECsecp128r1";
396 break;
397 case SEC_OID_SECG_EC_SECP128R2:
398 bundlekey = "CertDumpECsecp128r2";
399 break;
400 case SEC_OID_SECG_EC_SECP160K1:
401 bundlekey = "CertDumpECsecp160k1";
402 break;
403 case SEC_OID_SECG_EC_SECP160R1:
404 bundlekey = "CertDumpECsecp160r1";
405 break;
406 case SEC_OID_SECG_EC_SECP160R2:
407 bundlekey = "CertDumpECsecp160r2";
408 break;
409 case SEC_OID_SECG_EC_SECP192K1:
410 bundlekey = "CertDumpECsecp192k1";
411 break;
412 case SEC_OID_SECG_EC_SECP224K1:
413 bundlekey = "CertDumpECsecp224k1";
414 break;
415 case SEC_OID_SECG_EC_SECP224R1:
416 bundlekey = "CertDumpECsecp224r1";
417 break;
418 case SEC_OID_SECG_EC_SECP256K1:
419 bundlekey = "CertDumpECsecp256k1";
420 break;
421 case SEC_OID_SECG_EC_SECP384R1:
422 bundlekey = "CertDumpECsecp384r1";
423 break;
424
425 case SEC_OID_SECG_EC_SECP521R1:
426 bundlekey = "CertDumpECsecp521r1";
427 break;
428 /* ANSI X9.62 named elliptic curves (characteristic two field) */
429 case SEC_OID_ANSIX962_EC_C2PNB163V1:
430 bundlekey = "CertDumpECc2pnb163v1";
431 break;
432 case SEC_OID_ANSIX962_EC_C2PNB163V2:
433 bundlekey = "CertDumpECc2pnb163v2";
434 break;
435 case SEC_OID_ANSIX962_EC_C2PNB163V3:
436 bundlekey = "CertDumpECc2pnb163v3";
437 break;
438 case SEC_OID_ANSIX962_EC_C2PNB176V1:
439 bundlekey = "CertDumpECc2pnb176v1";
440 break;
441 case SEC_OID_ANSIX962_EC_C2TNB191V1:
442 bundlekey = "CertDumpECc2tnb191v1";
443 break;
444 case SEC_OID_ANSIX962_EC_C2TNB191V2:
445 bundlekey = "CertDumpECc2tnb191v2";
446 break;
447 case SEC_OID_ANSIX962_EC_C2TNB191V3:
448 bundlekey = "CertDumpECc2tnb191v3";
449 break;
450 case SEC_OID_ANSIX962_EC_C2ONB191V4:
451 bundlekey = "CertDumpECc2onb191v4";
452 break;
453 case SEC_OID_ANSIX962_EC_C2ONB191V5:
454 bundlekey = "CertDumpECc2onb191v5";
455 break;
456 case SEC_OID_ANSIX962_EC_C2PNB208W1:
457 bundlekey = "CertDumpECc2pnb208w1";
458 break;
459 case SEC_OID_ANSIX962_EC_C2TNB239V1:
460 bundlekey = "CertDumpECc2tnb239v1";
461 break;
462 case SEC_OID_ANSIX962_EC_C2TNB239V2:
463 bundlekey = "CertDumpECc2tnb239v2";
464 break;
465 case SEC_OID_ANSIX962_EC_C2TNB239V3:
466 bundlekey = "CertDumpECc2tnb239v3";
467 break;
468 case SEC_OID_ANSIX962_EC_C2ONB239V4:
469 bundlekey = "CertDumpECc2onb239v4";
470 break;
471 case SEC_OID_ANSIX962_EC_C2ONB239V5:
472 bundlekey = "CertDumpECc2onb239v5";
473 break;
474 case SEC_OID_ANSIX962_EC_C2PNB272W1:
475 bundlekey = "CertDumpECc2pnb272w1";
476 break;
477 case SEC_OID_ANSIX962_EC_C2PNB304W1:
478 bundlekey = "CertDumpECc2pnb304w1";
479 break;
480 case SEC_OID_ANSIX962_EC_C2TNB359V1:
481 bundlekey = "CertDumpECc2tnb359v1";
482 break;
483 case SEC_OID_ANSIX962_EC_C2PNB368W1:
484 bundlekey = "CertDumpECc2pnb368w1";
485 break;
486 case SEC_OID_ANSIX962_EC_C2TNB431R1:
487 bundlekey = "CertDumpECc2tnb431r1";
488 break;
489 /* SECG named elliptic curves (characteristic two field) */
490 case SEC_OID_SECG_EC_SECT113R1:
491 bundlekey = "CertDumpECsect113r1";
492 break;
493 case SEC_OID_SECG_EC_SECT113R2:
494 bundlekey = "CertDumpECsect113r2";
495 break;
496 case SEC_OID_SECG_EC_SECT131R1:
497 bundlekey = "CertDumpECsect131r1";
498 break;
499 case SEC_OID_SECG_EC_SECT131R2:
500 bundlekey = "CertDumpECsect131r2";
501 break;
502 case SEC_OID_SECG_EC_SECT163K1:
503 bundlekey = "CertDumpECsect163k1";
504 break;
505 case SEC_OID_SECG_EC_SECT163R1:
506 bundlekey = "CertDumpECsect163r1";
507 break;
508 case SEC_OID_SECG_EC_SECT163R2:
509 bundlekey = "CertDumpECsect163r2";
510 break;
511 case SEC_OID_SECG_EC_SECT193R1:
512 bundlekey = "CertDumpECsect193r1";
513 break;
514 case SEC_OID_SECG_EC_SECT193R2:
515 bundlekey = "CertDumpECsect193r2";
516 break;
517 case SEC_OID_SECG_EC_SECT233K1:
518 bundlekey = "CertDumpECsect233k1";
519 break;
520 case SEC_OID_SECG_EC_SECT233R1:
521 bundlekey = "CertDumpECsect233r1";
522 break;
523 case SEC_OID_SECG_EC_SECT239K1:
524 bundlekey = "CertDumpECsect239k1";
525 break;
526 case SEC_OID_SECG_EC_SECT283K1:
527 bundlekey = "CertDumpECsect283k1";
528 break;
529 case SEC_OID_SECG_EC_SECT283R1:
530 bundlekey = "CertDumpECsect283r1";
531 break;
532 case SEC_OID_SECG_EC_SECT409K1:
533 bundlekey = "CertDumpECsect409k1";
534 break;
535 case SEC_OID_SECG_EC_SECT409R1:
536 bundlekey = "CertDumpECsect409r1";
537 break;
538 case SEC_OID_SECG_EC_SECT571K1:
539 bundlekey = "CertDumpECsect571k1";
540 break;
541 case SEC_OID_SECG_EC_SECT571R1:
542 bundlekey = "CertDumpECsect571r1";
543 break;
544 default:
545 if (oidTag == SEC_OID(MS_CERT_EXT_CERTTYPE)) {
546 bundlekey = "CertDumpMSCerttype";
547 break;
548 }
549 if (oidTag == SEC_OID(MS_CERTSERV_CA_VERSION)) {
550 bundlekey = "CertDumpMSCAVersion";
551 break;
552 }
553 if (oidTag == SEC_OID(PKIX_LOGOTYPE)) {
554 bundlekey = "CertDumpLogotype";
555 break;
556 }
557 /* fallthrough */
558 }
559
560 if (bundlekey) {
561 rv = nssComponent->GetPIPNSSBundleString(bundlekey, text);
562 } else {
563 nsAutoString text2;
564 rv = GetDefaultOIDFormat(oid, nssComponent, text2, ' ');
565 if (NS_FAILED(rv))
566 return rv;
567
568 const char16_t *params[1] = {text2.get()};
569 rv = nssComponent->PIPBundleFormatStringFromName("CertDumpDefOID",
570 params, 1, text);
571 }
572 return rv;
573 }
574
575 #define SEPARATOR "\n"
576
577 static nsresult
ProcessRawBytes(nsINSSComponent * nssComponent,SECItem * data,nsAString & text,bool wantHeader=true)578 ProcessRawBytes(nsINSSComponent *nssComponent, SECItem *data,
579 nsAString &text, bool wantHeader = true)
580 {
581 // This function is used to display some DER bytes
582 // that we have not added support for decoding.
583 // If it's short, let's display as an integer, no size header.
584
585 if (data->len <= 4) {
586 int i_pv = DER_GetInteger(data);
587 nsAutoString value;
588 value.AppendInt(i_pv);
589 text.Append(value);
590 text.AppendLiteral(SEPARATOR);
591 return NS_OK;
592 }
593
594 // Else produce a hex dump.
595
596 if (wantHeader) {
597 nsAutoString bytelen, bitlen;
598 bytelen.AppendInt(data->len);
599 bitlen.AppendInt(data->len*8);
600
601 const char16_t *params[2] = {bytelen.get(), bitlen.get()};
602 nsresult rv = nssComponent->PIPBundleFormatStringFromName("CertDumpRawBytesHeader",
603 params, 2, text);
604 if (NS_FAILED(rv))
605 return rv;
606
607 text.AppendLiteral(SEPARATOR);
608 }
609
610 // This prints the value of the byte out into a
611 // string that can later be displayed as a byte
612 // string. We place a new line after 24 bytes
613 // to break up extermaly long sequence of bytes.
614
615 uint32_t i;
616 char buffer[5];
617 for (i=0; i<data->len; i++) {
618 SprintfLiteral(buffer, "%02x ", data->data[i]);
619 AppendASCIItoUTF16(buffer, text);
620 if ((i+1)%16 == 0) {
621 text.AppendLiteral(SEPARATOR);
622 }
623 }
624 return NS_OK;
625 }
626
627 /**
628 * Appends a pipnss bundle string to the given string.
629 *
630 * @param nssComponent For accessing the string bundle.
631 * @param bundleKey Key for the string to append.
632 * @param currentText The text to append to, using |SEPARATOR| as the separator.
633 */
634 template<size_t N>
AppendBundleString(const NotNull<nsINSSComponent * > & nssComponent,const char (& bundleKey)[N],nsAString & currentText)635 void AppendBundleString(const NotNull<nsINSSComponent*>& nssComponent,
636 const char (&bundleKey)[N],
637 /*in/out*/ nsAString& currentText)
638 {
639 nsAutoString bundleString;
640 nsresult rv = nssComponent->GetPIPNSSBundleString(bundleKey, bundleString);
641 if (NS_FAILED(rv)) {
642 return;
643 }
644
645 currentText.Append(bundleString);
646 currentText.AppendLiteral(SEPARATOR);
647 }
648
649 static nsresult
ProcessKeyUsageExtension(SECItem * extData,nsAString & text,nsINSSComponent * nssComponent)650 ProcessKeyUsageExtension(SECItem *extData, nsAString &text,
651 nsINSSComponent *nssComponent)
652 {
653 MOZ_ASSERT(extData);
654 MOZ_ASSERT(nssComponent);
655 NS_ENSURE_ARG(extData);
656 NS_ENSURE_ARG(nssComponent);
657
658 NotNull<nsINSSComponent*> wrappedNSSComponent = WrapNotNull(nssComponent);
659 ScopedAutoSECItem decoded;
660 if (SEC_ASN1DecodeItem(nullptr, &decoded, SEC_ASN1_GET(SEC_BitStringTemplate),
661 extData) != SECSuccess) {
662 AppendBundleString(wrappedNSSComponent, "CertDumpExtensionFailure", text);
663 return NS_OK;
664 }
665 unsigned char keyUsage = 0;
666 if (decoded.len) {
667 keyUsage = decoded.data[0];
668 }
669
670 if (keyUsage & KU_DIGITAL_SIGNATURE) {
671 AppendBundleString(wrappedNSSComponent, "CertDumpKUSign", text);
672 }
673 if (keyUsage & KU_NON_REPUDIATION) {
674 AppendBundleString(wrappedNSSComponent, "CertDumpKUNonRep", text);
675 }
676 if (keyUsage & KU_KEY_ENCIPHERMENT) {
677 AppendBundleString(wrappedNSSComponent, "CertDumpKUEnc", text);
678 }
679 if (keyUsage & KU_DATA_ENCIPHERMENT) {
680 AppendBundleString(wrappedNSSComponent, "CertDumpKUDEnc", text);
681 }
682 if (keyUsage & KU_KEY_AGREEMENT) {
683 AppendBundleString(wrappedNSSComponent, "CertDumpKUKA", text);
684 }
685 if (keyUsage & KU_KEY_CERT_SIGN) {
686 AppendBundleString(wrappedNSSComponent, "CertDumpKUCertSign", text);
687 }
688 if (keyUsage & KU_CRL_SIGN) {
689 AppendBundleString(wrappedNSSComponent, "CertDumpKUCRLSigner", text);
690 }
691
692 return NS_OK;
693 }
694
695 static nsresult
ProcessBasicConstraints(SECItem * extData,nsAString & text,nsINSSComponent * nssComponent)696 ProcessBasicConstraints(SECItem *extData,
697 nsAString &text,
698 nsINSSComponent *nssComponent)
699 {
700 nsAutoString local;
701 CERTBasicConstraints value;
702 SECStatus rv;
703 nsresult rv2;
704
705 value.pathLenConstraint = -1;
706 rv = CERT_DecodeBasicConstraintValue (&value, extData);
707 if (rv != SECSuccess) {
708 ProcessRawBytes(nssComponent, extData, text);
709 return NS_OK;
710 }
711 if (value.isCA)
712 rv2 = nssComponent->GetPIPNSSBundleString("CertDumpIsCA", local);
713 else
714 rv2 = nssComponent->GetPIPNSSBundleString("CertDumpIsNotCA", local);
715 if (NS_FAILED(rv2))
716 return rv2;
717 text.Append(local.get());
718 if (value.pathLenConstraint != -1) {
719 nsAutoString depth;
720 if (value.pathLenConstraint == CERT_UNLIMITED_PATH_CONSTRAINT)
721 nssComponent->GetPIPNSSBundleString("CertDumpPathLenUnlimited", depth);
722 else
723 depth.AppendInt(value.pathLenConstraint);
724 const char16_t *params[1] = {depth.get()};
725 rv2 = nssComponent->PIPBundleFormatStringFromName("CertDumpPathLen",
726 params, 1, local);
727 if (NS_FAILED(rv2))
728 return rv2;
729 text.AppendLiteral(SEPARATOR);
730 text.Append(local.get());
731 }
732 return NS_OK;
733 }
734
735 static nsresult
ProcessExtKeyUsage(SECItem * extData,nsAString & text,nsINSSComponent * nssComponent)736 ProcessExtKeyUsage(SECItem *extData,
737 nsAString &text,
738 nsINSSComponent *nssComponent)
739 {
740 nsAutoString local;
741 SECItem **oids;
742 SECItem *oid;
743 nsresult rv;
744
745 UniqueCERTOidSequence extKeyUsage(CERT_DecodeOidSequence(extData));
746 if (!extKeyUsage) {
747 return NS_ERROR_FAILURE;
748 }
749
750 oids = extKeyUsage->oids;
751 while (oids && *oids) {
752 // For each OID, try to find a bundle string
753 // of the form CertDumpEKU_<underlined-OID>
754 nsAutoString oidname;
755 oid = *oids;
756 rv = GetDefaultOIDFormat(oid, nssComponent, oidname, '_');
757 if (NS_FAILED(rv))
758 return rv;
759 nsAutoString bundlekey = NS_LITERAL_STRING("CertDumpEKU_")+ oidname;
760 NS_ConvertUTF16toUTF8 bk_ascii(bundlekey);
761
762 rv = nssComponent->GetPIPNSSBundleString(bk_ascii.get(), local);
763 nsresult rv2 = GetDefaultOIDFormat(oid, nssComponent, oidname, '.');
764 if (NS_FAILED(rv2))
765 return rv2;
766 if (NS_SUCCEEDED(rv)) {
767 // display name and OID in parentheses
768 text.Append(local);
769 text.AppendLiteral(" (");
770 text.Append(oidname);
771 text.Append(')');
772 } else
773 // If there is no bundle string, just display the OID itself
774 text.Append(oidname);
775
776 text.AppendLiteral(SEPARATOR);
777 oids++;
778 }
779
780 return NS_OK;
781 }
782
783 static nsresult
ProcessRDN(CERTRDN * rdn,nsAString & finalString,nsINSSComponent * nssComponent)784 ProcessRDN(CERTRDN* rdn, nsAString &finalString, nsINSSComponent *nssComponent)
785 {
786 nsresult rv;
787 CERTAVA** avas;
788 CERTAVA* ava;
789 nsString avavalue;
790 nsString type;
791 nsAutoString temp;
792 const char16_t *params[2];
793
794 avas = rdn->avas;
795 while ((ava = *avas++) != 0) {
796 rv = GetOIDText(&ava->type, nssComponent, type);
797 if (NS_FAILED(rv)) {
798 return rv;
799 }
800
801 //This function returns a string in UTF8 format.
802 UniqueSECItem decodeItem(CERT_DecodeAVAValue(&ava->value));
803 if (!decodeItem) {
804 return NS_ERROR_FAILURE;
805 }
806
807 // We know we can fit buffer of this length. CERT_RFC1485_EscapeAndQuote
808 // will fail if we provide smaller buffer then the result can fit to.
809 int escapedValueCapacity = decodeItem->len * 3 + 3;
810 UniquePtr<char[]> escapedValue = MakeUnique<char[]>(escapedValueCapacity);
811
812 SECStatus status = CERT_RFC1485_EscapeAndQuote(
813 escapedValue.get(),
814 escapedValueCapacity,
815 (char*)decodeItem->data,
816 decodeItem->len);
817 if (SECSuccess != status) {
818 return NS_ERROR_FAILURE;
819 }
820
821 avavalue = NS_ConvertUTF8toUTF16(escapedValue.get());
822
823 params[0] = type.get();
824 params[1] = avavalue.get();
825 nssComponent->PIPBundleFormatStringFromName("AVATemplate",
826 params, 2, temp);
827 finalString += temp + NS_LITERAL_STRING("\n");
828 }
829 return NS_OK;
830 }
831
832 static nsresult
ProcessName(CERTName * name,nsINSSComponent * nssComponent,char16_t ** value)833 ProcessName(CERTName *name, nsINSSComponent *nssComponent, char16_t **value)
834 {
835 CERTRDN** rdns;
836 CERTRDN** rdn;
837 nsString finalString;
838
839 rdns = name->rdns;
840
841 nsresult rv;
842 CERTRDN **lastRdn;
843 /* find last RDN */
844 lastRdn = rdns;
845 while (*lastRdn) lastRdn++;
846 // The above whille loop will put us at the last member
847 // of the array which is a nullptr pointer. So let's back
848 // up one spot so that we have the last non-nullptr entry in
849 // the array in preparation for traversing the
850 // RDN's (Relative Distinguished Name) in reverse oder.
851 lastRdn--;
852
853 /*
854 * Loop over name contents in _reverse_ RDN order appending to string
855 * When building the Ascii string, NSS loops over these entries in
856 * reverse order, so I will as well. The difference is that NSS
857 * will always place them in a one line string separated by commas,
858 * where I want each entry on a single line. I can't just use a comma
859 * as my delimitter because it is a valid character to have in the
860 * value portion of the AVA and could cause trouble when parsing.
861 */
862 for (rdn = lastRdn; rdn >= rdns; rdn--) {
863 rv = ProcessRDN(*rdn, finalString, nssComponent);
864 if (NS_FAILED(rv))
865 return rv;
866 }
867 *value = ToNewUnicode(finalString);
868 return NS_OK;
869 }
870
871 static nsresult
ProcessIA5String(const SECItem & extData,nsAString & text)872 ProcessIA5String(const SECItem& extData, /*in/out*/ nsAString& text)
873 {
874 ScopedAutoSECItem item;
875 if (SEC_ASN1DecodeItem(nullptr, &item, SEC_ASN1_GET(SEC_IA5StringTemplate),
876 &extData) != SECSuccess) {
877 return NS_ERROR_FAILURE;
878 }
879
880 text.AppendASCII(BitwiseCast<char*, unsigned char*>(item.data),
881 AssertedCast<uint32_t>(item.len));
882 return NS_OK;
883 }
884
885 static nsresult
AppendBMPtoUTF16(const UniquePLArenaPool & arena,unsigned char * data,unsigned int len,nsAString & text)886 AppendBMPtoUTF16(const UniquePLArenaPool& arena, unsigned char* data,
887 unsigned int len, nsAString& text)
888 {
889 if (len % 2 != 0) {
890 return NS_ERROR_FAILURE;
891 }
892
893 /* XXX instead of converting to and from UTF-8, it would
894 be sufficient to just swap bytes, or do nothing */
895 unsigned int utf8ValLen = len * 3 + 1;
896 unsigned char* utf8Val = (unsigned char*)PORT_ArenaZAlloc(arena.get(),
897 utf8ValLen);
898 if (!PORT_UCS2_UTF8Conversion(false, data, len, utf8Val, utf8ValLen,
899 &utf8ValLen)) {
900 return NS_ERROR_FAILURE;
901 }
902 AppendUTF8toUTF16((char*)utf8Val, text);
903 return NS_OK;
904 }
905
906 static nsresult
ProcessBMPString(SECItem * extData,nsAString & text)907 ProcessBMPString(SECItem* extData, nsAString& text)
908 {
909 UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
910 if (!arena) {
911 return NS_ERROR_OUT_OF_MEMORY;
912 }
913
914 SECItem item;
915 if (SEC_ASN1DecodeItem(arena.get(), &item, SEC_ASN1_GET(SEC_BMPStringTemplate),
916 extData) != SECSuccess) {
917 return NS_ERROR_FAILURE;
918 }
919
920 return AppendBMPtoUTF16(arena, item.data, item.len, text);
921 }
922
923 static nsresult
ProcessGeneralName(const UniquePLArenaPool & arena,CERTGeneralName * current,nsAString & text,nsINSSComponent * nssComponent)924 ProcessGeneralName(const UniquePLArenaPool& arena, CERTGeneralName* current,
925 nsAString& text, nsINSSComponent* nssComponent)
926 {
927 NS_ENSURE_ARG_POINTER(current);
928
929 nsAutoString key;
930 nsXPIDLString value;
931 nsresult rv = NS_OK;
932
933 switch (current->type) {
934 case certOtherName: {
935 SECOidTag oidTag = SECOID_FindOIDTag(¤t->name.OthName.oid);
936 if (oidTag == SEC_OID(MS_NT_PRINCIPAL_NAME)) {
937 /* The type of this name is apparently nowhere explicitly
938 documented. However, in the generated templates, it is always
939 UTF-8. So try to decode this as UTF-8; if that fails, dump the
940 raw data. */
941 SECItem decoded;
942 nssComponent->GetPIPNSSBundleString("CertDumpMSNTPrincipal", key);
943 if (SEC_ASN1DecodeItem(arena.get(), &decoded,
944 SEC_ASN1_GET(SEC_UTF8StringTemplate),
945 ¤t->name.OthName.name) == SECSuccess) {
946 AppendUTF8toUTF16(nsAutoCString((char*)decoded.data, decoded.len),
947 value);
948 } else {
949 ProcessRawBytes(nssComponent, ¤t->name.OthName.name, value);
950 }
951 break;
952 } else if (oidTag == SEC_OID(MS_NTDS_REPLICATION)) {
953 /* This should be a 16-byte GUID */
954 SECItem guid;
955 nssComponent->GetPIPNSSBundleString("CertDumpMSDomainGUID", key);
956 if (SEC_ASN1DecodeItem(arena.get(), &guid,
957 SEC_ASN1_GET(SEC_OctetStringTemplate),
958 ¤t->name.OthName.name) == SECSuccess
959 && guid.len == 16) {
960 char buf[40];
961 unsigned char *d = guid.data;
962 SprintfLiteral(buf,
963 "{%.2x%.2x%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x}",
964 d[3], d[2], d[1], d[0], d[5], d[4], d[7], d[6],
965 d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
966 value.AssignASCII(buf);
967 } else {
968 ProcessRawBytes(nssComponent, ¤t->name.OthName.name, value);
969 }
970 } else {
971 rv = GetDefaultOIDFormat(¤t->name.OthName.oid, nssComponent, key, ' ');
972 if (NS_FAILED(rv)) {
973 return rv;
974 }
975 ProcessRawBytes(nssComponent, ¤t->name.OthName.name, value);
976 }
977 break;
978 }
979 case certRFC822Name:
980 nssComponent->GetPIPNSSBundleString("CertDumpRFC822Name", key);
981 value.AssignASCII((char*)current->name.other.data, current->name.other.len);
982 break;
983 case certDNSName:
984 nssComponent->GetPIPNSSBundleString("CertDumpDNSName", key);
985 value.AssignASCII((char*)current->name.other.data, current->name.other.len);
986 break;
987 case certX400Address:
988 nssComponent->GetPIPNSSBundleString("CertDumpX400Address", key);
989 ProcessRawBytes(nssComponent, ¤t->name.other, value);
990 break;
991 case certDirectoryName:
992 nssComponent->GetPIPNSSBundleString("CertDumpDirectoryName", key);
993 rv = ProcessName(¤t->name.directoryName, nssComponent,
994 getter_Copies(value));
995 if (NS_FAILED(rv)) {
996 return rv;
997 }
998 break;
999 case certEDIPartyName:
1000 nssComponent->GetPIPNSSBundleString("CertDumpEDIPartyName", key);
1001 ProcessRawBytes(nssComponent, ¤t->name.other, value);
1002 break;
1003 case certURI:
1004 nssComponent->GetPIPNSSBundleString("CertDumpURI", key);
1005 value.AssignASCII((char*)current->name.other.data, current->name.other.len);
1006 break;
1007 case certIPAddress:
1008 {
1009 char buf[INET6_ADDRSTRLEN];
1010 PRStatus status = PR_FAILURE;
1011 PRNetAddr addr;
1012 memset(&addr, 0, sizeof(addr));
1013 nssComponent->GetPIPNSSBundleString("CertDumpIPAddress", key);
1014 if (current->name.other.len == 4) {
1015 addr.inet.family = PR_AF_INET;
1016 memcpy(&addr.inet.ip, current->name.other.data, current->name.other.len);
1017 status = PR_NetAddrToString(&addr, buf, sizeof(buf));
1018 } else if (current->name.other.len == 16) {
1019 addr.ipv6.family = PR_AF_INET6;
1020 memcpy(&addr.ipv6.ip, current->name.other.data, current->name.other.len);
1021 status = PR_NetAddrToString(&addr, buf, sizeof(buf));
1022 }
1023 if (status == PR_SUCCESS) {
1024 value.AssignASCII(buf);
1025 } else {
1026 /* invalid IP address */
1027 ProcessRawBytes(nssComponent, ¤t->name.other, value);
1028 }
1029 break;
1030 }
1031 case certRegisterID:
1032 nssComponent->GetPIPNSSBundleString("CertDumpRegisterID", key);
1033 rv = GetDefaultOIDFormat(¤t->name.other, nssComponent, value, '.');
1034 if (NS_FAILED(rv)) {
1035 return rv;
1036 }
1037 break;
1038 }
1039 text.Append(key);
1040 text.AppendLiteral(": ");
1041 text.Append(value);
1042 text.AppendLiteral(SEPARATOR);
1043
1044 return rv;
1045 }
1046
1047 static nsresult
ProcessGeneralNames(const UniquePLArenaPool & arena,CERTGeneralName * nameList,nsAString & text,nsINSSComponent * nssComponent)1048 ProcessGeneralNames(const UniquePLArenaPool& arena, CERTGeneralName* nameList,
1049 nsAString& text, nsINSSComponent* nssComponent)
1050 {
1051 CERTGeneralName* current = nameList;
1052 nsresult rv;
1053
1054 do {
1055 rv = ProcessGeneralName(arena, current, text, nssComponent);
1056 if (NS_FAILED(rv)) {
1057 break;
1058 }
1059 current = CERT_GetNextGeneralName(current);
1060 } while (current != nameList);
1061 return rv;
1062 }
1063
1064 static nsresult
ProcessAltName(SECItem * extData,nsAString & text,nsINSSComponent * nssComponent)1065 ProcessAltName(SECItem* extData, nsAString& text, nsINSSComponent* nssComponent)
1066 {
1067 UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
1068 if (!arena) {
1069 return NS_ERROR_OUT_OF_MEMORY;
1070 }
1071
1072 CERTGeneralName* nameList = CERT_DecodeAltNameExtension(arena.get(), extData);
1073 if (!nameList) {
1074 return NS_OK;
1075 }
1076
1077 return ProcessGeneralNames(arena, nameList, text, nssComponent);
1078 }
1079
1080 static nsresult
ProcessSubjectKeyId(SECItem * extData,nsAString & text,nsINSSComponent * nssComponent)1081 ProcessSubjectKeyId(SECItem *extData,
1082 nsAString &text,
1083 nsINSSComponent *nssComponent)
1084 {
1085 SECItem decoded;
1086 nsAutoString local;
1087
1088 UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
1089 if (!arena) {
1090 return NS_ERROR_OUT_OF_MEMORY;
1091 }
1092
1093 if (SEC_QuickDERDecodeItem(arena.get(), &decoded,
1094 SEC_ASN1_GET(SEC_OctetStringTemplate),
1095 extData) != SECSuccess) {
1096 return NS_ERROR_FAILURE;
1097 }
1098
1099 nssComponent->GetPIPNSSBundleString("CertDumpKeyID", local);
1100 text.Append(local);
1101 text.AppendLiteral(": ");
1102 ProcessRawBytes(nssComponent, &decoded, text);
1103
1104 return NS_OK;
1105 }
1106
1107 static nsresult
ProcessAuthKeyId(SECItem * extData,nsAString & text,nsINSSComponent * nssComponent)1108 ProcessAuthKeyId(SECItem *extData,
1109 nsAString &text,
1110 nsINSSComponent *nssComponent)
1111 {
1112 nsresult rv = NS_OK;
1113 nsAutoString local;
1114
1115 UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
1116 if (!arena) {
1117 return NS_ERROR_OUT_OF_MEMORY;
1118 }
1119
1120 CERTAuthKeyID* ret = CERT_DecodeAuthKeyID(arena.get(), extData);
1121 if (!ret) {
1122 return NS_ERROR_FAILURE;
1123 }
1124
1125 if (ret->keyID.len > 0) {
1126 nssComponent->GetPIPNSSBundleString("CertDumpKeyID", local);
1127 text.Append(local);
1128 text.AppendLiteral(": ");
1129 ProcessRawBytes(nssComponent, &ret->keyID, text);
1130 text.AppendLiteral(SEPARATOR);
1131 }
1132
1133 if (ret->authCertIssuer) {
1134 nssComponent->GetPIPNSSBundleString("CertDumpIssuer", local);
1135 text.Append(local);
1136 text.AppendLiteral(": ");
1137 rv = ProcessGeneralNames(arena, ret->authCertIssuer, text, nssComponent);
1138 if (NS_FAILED(rv)) {
1139 return rv;
1140 }
1141 }
1142
1143 if (ret->authCertSerialNumber.len > 0) {
1144 nssComponent->GetPIPNSSBundleString("CertDumpSerialNo", local);
1145 text.Append(local);
1146 text.AppendLiteral(": ");
1147 ProcessRawBytes(nssComponent, &ret->authCertSerialNumber, text);
1148 }
1149
1150 return rv;
1151 }
1152
1153 static nsresult
ProcessUserNotice(SECItem * derNotice,nsAString & text,nsINSSComponent * nssComponent)1154 ProcessUserNotice(SECItem* derNotice, nsAString& text,
1155 nsINSSComponent* nssComponent)
1156 {
1157 UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
1158 if (!arena) {
1159 return NS_ERROR_OUT_OF_MEMORY;
1160 }
1161
1162 UniqueCERTUserNotice notice(CERT_DecodeUserNotice(derNotice));
1163 if (!notice) {
1164 ProcessRawBytes(nssComponent, derNotice, text);
1165 return NS_OK;
1166 }
1167
1168 if (notice->noticeReference.organization.len != 0) {
1169 switch (notice->noticeReference.organization.type) {
1170 case siAsciiString:
1171 case siVisibleString:
1172 case siUTF8String:
1173 text.Append(NS_ConvertUTF8toUTF16(
1174 (const char *)notice->noticeReference.organization.data,
1175 notice->noticeReference.organization.len));
1176 break;
1177 case siBMPString:
1178 AppendBMPtoUTF16(arena, notice->noticeReference.organization.data,
1179 notice->noticeReference.organization.len, text);
1180 break;
1181 default:
1182 break;
1183 }
1184 text.AppendLiteral(" - ");
1185 SECItem** itemList = notice->noticeReference.noticeNumbers;
1186 while (*itemList) {
1187 unsigned long number;
1188 char buffer[60];
1189 if (SEC_ASN1DecodeInteger(*itemList, &number) == SECSuccess) {
1190 SprintfLiteral(buffer, "#%lu", number);
1191 if (itemList != notice->noticeReference.noticeNumbers)
1192 text.AppendLiteral(", ");
1193 AppendASCIItoUTF16(buffer, text);
1194 }
1195 itemList++;
1196 }
1197 }
1198 if (notice->displayText.len != 0) {
1199 text.AppendLiteral(SEPARATOR);
1200 text.AppendLiteral(" ");
1201 switch (notice->displayText.type) {
1202 case siAsciiString:
1203 case siVisibleString:
1204 case siUTF8String:
1205 text.Append(NS_ConvertUTF8toUTF16((const char *)notice->displayText.data,
1206 notice->displayText.len));
1207 break;
1208 case siBMPString:
1209 AppendBMPtoUTF16(arena, notice->displayText.data, notice->displayText.len,
1210 text);
1211 break;
1212 default:
1213 break;
1214 }
1215 }
1216
1217 return NS_OK;
1218 }
1219
1220 static nsresult
ProcessCertificatePolicies(SECItem * extData,nsAString & text,nsINSSComponent * nssComponent)1221 ProcessCertificatePolicies(SECItem *extData,
1222 nsAString &text,
1223 nsINSSComponent *nssComponent)
1224 {
1225 CERTPolicyInfo **policyInfos, *policyInfo;
1226 CERTPolicyQualifier **policyQualifiers, *policyQualifier;
1227 nsAutoString local;
1228 nsresult rv = NS_OK;
1229
1230 UniqueCERTCertificatePolicies policies(
1231 CERT_DecodeCertificatePoliciesExtension(extData));
1232 if (!policies) {
1233 return NS_ERROR_FAILURE;
1234 }
1235
1236 policyInfos = policies->policyInfos;
1237 while (*policyInfos) {
1238 policyInfo = *policyInfos++;
1239 switch (policyInfo->oid) {
1240 case SEC_OID_VERISIGN_USER_NOTICES:
1241 nssComponent->GetPIPNSSBundleString("CertDumpVerisignNotices", local);
1242 text.Append(local);
1243 break;
1244 default:
1245 GetDefaultOIDFormat(&policyInfo->policyID, nssComponent, local, '.');
1246 text.Append(local);
1247 }
1248
1249 if (policyInfo->policyQualifiers) {
1250 /* Add all qualifiers on separate lines, indented */
1251 policyQualifiers = policyInfo->policyQualifiers;
1252 text.Append(':');
1253 text.AppendLiteral(SEPARATOR);
1254 while (*policyQualifiers) {
1255 text.AppendLiteral(" ");
1256 policyQualifier = *policyQualifiers++;
1257 switch(policyQualifier->oid) {
1258 case SEC_OID_PKIX_CPS_POINTER_QUALIFIER:
1259 nssComponent->GetPIPNSSBundleString("CertDumpCPSPointer", local);
1260 text.Append(local);
1261 text.Append(':');
1262 text.AppendLiteral(SEPARATOR);
1263 text.AppendLiteral(" ");
1264 /* The CPS pointer ought to be the cPSuri alternative
1265 of the Qualifier choice. */
1266 rv = ProcessIA5String(policyQualifier->qualifierValue, text);
1267 if (NS_FAILED(rv)) {
1268 return rv;
1269 }
1270 break;
1271 case SEC_OID_PKIX_USER_NOTICE_QUALIFIER:
1272 nssComponent->GetPIPNSSBundleString("CertDumpUserNotice", local);
1273 text.Append(local);
1274 text.AppendLiteral(": ");
1275 rv = ProcessUserNotice(&policyQualifier->qualifierValue,
1276 text, nssComponent);
1277 break;
1278 default:
1279 GetDefaultOIDFormat(&policyQualifier->qualifierID, nssComponent, local, '.');
1280 text.Append(local);
1281 text.AppendLiteral(": ");
1282 ProcessRawBytes(nssComponent, &policyQualifier->qualifierValue, text);
1283 }
1284 text.AppendLiteral(SEPARATOR);
1285 } /* while policyQualifiers */
1286 } /* if policyQualifiers */
1287 text.AppendLiteral(SEPARATOR);
1288 }
1289
1290 return rv;
1291 }
1292
1293 static nsresult
ProcessCrlDistPoints(SECItem * extData,nsAString & text,nsINSSComponent * nssComponent)1294 ProcessCrlDistPoints(SECItem *extData,
1295 nsAString &text,
1296 nsINSSComponent *nssComponent)
1297 {
1298 nsresult rv = NS_OK;
1299 nsAutoString local;
1300
1301 UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
1302 if (!arena) {
1303 return NS_ERROR_OUT_OF_MEMORY;
1304 }
1305
1306 CERTCrlDistributionPoints* crldp =
1307 CERT_DecodeCRLDistributionPoints(arena.get(), extData);
1308 if (!crldp || !crldp->distPoints) {
1309 return NS_ERROR_FAILURE;
1310 }
1311
1312 for (CRLDistributionPoint** points = crldp->distPoints; *points; points++) {
1313 CRLDistributionPoint* point = *points;
1314 switch (point->distPointType) {
1315 case generalName:
1316 rv = ProcessGeneralName(arena, point->distPoint.fullName,
1317 text, nssComponent);
1318 if (NS_FAILED(rv)) {
1319 return rv;
1320 }
1321 break;
1322 case relativeDistinguishedName:
1323 rv = ProcessRDN(&point->distPoint.relativeName,
1324 text, nssComponent);
1325 if (NS_FAILED(rv)) {
1326 return rv;
1327 }
1328 break;
1329 }
1330 if (point->reasons.len) {
1331 int reasons = point->reasons.data[0];
1332 text.Append(' ');
1333 bool comma = false;
1334 if (reasons & RF_UNUSED) {
1335 nssComponent->GetPIPNSSBundleString("CertDumpUnused", local);
1336 text.Append(local);
1337 comma = true;
1338 }
1339 if (reasons & RF_KEY_COMPROMISE) {
1340 if (comma) text.AppendLiteral(", ");
1341 nssComponent->GetPIPNSSBundleString("CertDumpKeyCompromise", local);
1342 text.Append(local);
1343 comma = true;
1344 }
1345 if (reasons & RF_CA_COMPROMISE) {
1346 if (comma) text.AppendLiteral(", ");
1347 nssComponent->GetPIPNSSBundleString("CertDumpCACompromise", local);
1348 text.Append(local);
1349 comma = true;
1350 }
1351 if (reasons & RF_AFFILIATION_CHANGED) {
1352 if (comma) text.AppendLiteral(", ");
1353 nssComponent->GetPIPNSSBundleString("CertDumpAffiliationChanged", local);
1354 text.Append(local);
1355 comma = true;
1356 }
1357 if (reasons & RF_SUPERSEDED) {
1358 if (comma) text.AppendLiteral(", ");
1359 nssComponent->GetPIPNSSBundleString("CertDumpSuperseded", local);
1360 text.Append(local);
1361 comma = true;
1362 }
1363 if (reasons & RF_CESSATION_OF_OPERATION) {
1364 if (comma) text.AppendLiteral(", ");
1365 nssComponent->GetPIPNSSBundleString("CertDumpCessation", local);
1366 text.Append(local);
1367 comma = true;
1368 }
1369 if (reasons & RF_CERTIFICATE_HOLD) {
1370 if (comma) text.AppendLiteral(", ");
1371 nssComponent->GetPIPNSSBundleString("CertDumpHold", local);
1372 text.Append(local);
1373 comma = true;
1374 }
1375 text.AppendLiteral(SEPARATOR);
1376 }
1377 if (point->crlIssuer) {
1378 nssComponent->GetPIPNSSBundleString("CertDumpIssuer", local);
1379 text.Append(local);
1380 text.AppendLiteral(": ");
1381 rv = ProcessGeneralNames(arena, point->crlIssuer,
1382 text, nssComponent);
1383 if (NS_FAILED(rv)) {
1384 return rv;
1385 }
1386 }
1387 }
1388
1389 return NS_OK;
1390 }
1391
1392 static nsresult
ProcessAuthInfoAccess(SECItem * extData,nsAString & text,nsINSSComponent * nssComponent)1393 ProcessAuthInfoAccess(SECItem *extData,
1394 nsAString &text,
1395 nsINSSComponent *nssComponent)
1396 {
1397 nsresult rv = NS_OK;
1398 nsAutoString local;
1399
1400 UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
1401 if (!arena) {
1402 return NS_ERROR_OUT_OF_MEMORY;
1403 }
1404
1405 CERTAuthInfoAccess** aia = CERT_DecodeAuthInfoAccessExtension(arena.get(),
1406 extData);
1407 if (!aia) {
1408 return NS_OK;
1409 }
1410
1411 while (*aia) {
1412 CERTAuthInfoAccess* desc = *aia++;
1413 switch (SECOID_FindOIDTag(&desc->method)) {
1414 case SEC_OID_PKIX_OCSP:
1415 nssComponent->GetPIPNSSBundleString("CertDumpOCSPResponder", local);
1416 break;
1417 case SEC_OID_PKIX_CA_ISSUERS:
1418 nssComponent->GetPIPNSSBundleString("CertDumpCAIssuers", local);
1419 break;
1420 default:
1421 rv = GetDefaultOIDFormat(&desc->method, nssComponent, local, '.');
1422 if (NS_FAILED(rv)) {
1423 return rv;
1424 }
1425 }
1426 text.Append(local);
1427 text.AppendLiteral(": ");
1428 rv = ProcessGeneralName(arena, desc->location, text, nssComponent);
1429 if (NS_FAILED(rv)) {
1430 return rv;
1431 }
1432 }
1433
1434 return rv;
1435 }
1436
1437 static nsresult
ProcessMSCAVersion(SECItem * extData,nsAString & text,nsINSSComponent * nssComponent)1438 ProcessMSCAVersion(SECItem *extData,
1439 nsAString &text,
1440 nsINSSComponent *nssComponent)
1441 {
1442 MOZ_ASSERT(extData);
1443 NS_ENSURE_ARG(extData);
1444
1445 ScopedAutoSECItem decoded;
1446 if (SEC_ASN1DecodeItem(nullptr, &decoded, SEC_ASN1_GET(SEC_IntegerTemplate),
1447 extData) != SECSuccess) {
1448 /* This extension used to be an Integer when this code
1449 was written, but apparently isn't anymore. Display
1450 the raw bytes instead. */
1451 return ProcessRawBytes(nssComponent, extData, text);
1452 }
1453
1454 unsigned long version;
1455 if (SEC_ASN1DecodeInteger(&decoded, &version) != SECSuccess) {
1456 /* Value out of range, display raw bytes */
1457 return ProcessRawBytes(nssComponent, extData, text);
1458 }
1459
1460 /* Apparently, the encoding is <minor><major>, with 16 bits each */
1461 char buf[50];
1462 if (SprintfLiteral(buf, "%lu.%lu", version & 0xFFFF, version >> 16) <= 0) {
1463 return NS_ERROR_FAILURE;
1464 }
1465
1466 text.AppendASCII(buf);
1467 return NS_OK;
1468 }
1469
1470 static nsresult
ProcessExtensionData(SECOidTag oidTag,SECItem * extData,nsAString & text,nsINSSComponent * nssComponent)1471 ProcessExtensionData(SECOidTag oidTag, SECItem *extData,
1472 nsAString &text,
1473 nsINSSComponent *nssComponent)
1474 {
1475 nsresult rv;
1476 switch (oidTag) {
1477 case SEC_OID_X509_KEY_USAGE:
1478 rv = ProcessKeyUsageExtension(extData, text, nssComponent);
1479 break;
1480 case SEC_OID_X509_BASIC_CONSTRAINTS:
1481 rv = ProcessBasicConstraints(extData, text, nssComponent);
1482 break;
1483 case SEC_OID_X509_EXT_KEY_USAGE:
1484 rv = ProcessExtKeyUsage(extData, text, nssComponent);
1485 break;
1486 case SEC_OID_X509_ISSUER_ALT_NAME:
1487 case SEC_OID_X509_SUBJECT_ALT_NAME:
1488 rv = ProcessAltName(extData, text, nssComponent);
1489 break;
1490 case SEC_OID_X509_SUBJECT_KEY_ID:
1491 rv = ProcessSubjectKeyId(extData, text, nssComponent);
1492 break;
1493 case SEC_OID_X509_AUTH_KEY_ID:
1494 rv = ProcessAuthKeyId(extData, text, nssComponent);
1495 break;
1496 case SEC_OID_X509_CERTIFICATE_POLICIES:
1497 rv = ProcessCertificatePolicies(extData, text, nssComponent);
1498 break;
1499 case SEC_OID_X509_CRL_DIST_POINTS:
1500 rv = ProcessCrlDistPoints(extData, text, nssComponent);
1501 break;
1502 case SEC_OID_X509_AUTH_INFO_ACCESS:
1503 rv = ProcessAuthInfoAccess(extData, text, nssComponent);
1504 break;
1505 default:
1506 if (oidTag == SEC_OID(MS_CERT_EXT_CERTTYPE)) {
1507 rv = ProcessBMPString(extData, text);
1508 break;
1509 }
1510 if (oidTag == SEC_OID(MS_CERTSERV_CA_VERSION)) {
1511 rv = ProcessMSCAVersion(extData, text, nssComponent);
1512 break;
1513 }
1514 rv = ProcessRawBytes(nssComponent, extData, text);
1515 break;
1516 }
1517 return rv;
1518 }
1519
1520 static nsresult
ProcessSingleExtension(CERTCertExtension * extension,nsINSSComponent * nssComponent,nsIASN1PrintableItem ** retExtension)1521 ProcessSingleExtension(CERTCertExtension *extension,
1522 nsINSSComponent *nssComponent,
1523 nsIASN1PrintableItem **retExtension)
1524 {
1525 nsAutoString text, extvalue;
1526 GetOIDText(&extension->id, nssComponent, text);
1527 nsCOMPtr<nsIASN1PrintableItem>extensionItem = new nsNSSASN1PrintableItem();
1528
1529 extensionItem->SetDisplayName(text);
1530 SECOidTag oidTag = SECOID_FindOIDTag(&extension->id);
1531 text.Truncate();
1532 if (extension->critical.data) {
1533 if (extension->critical.data[0]) {
1534 nssComponent->GetPIPNSSBundleString("CertDumpCritical", text);
1535 } else {
1536 nssComponent->GetPIPNSSBundleString("CertDumpNonCritical", text);
1537 }
1538 } else {
1539 nssComponent->GetPIPNSSBundleString("CertDumpNonCritical", text);
1540 }
1541 text.AppendLiteral(SEPARATOR);
1542 nsresult rv = ProcessExtensionData(oidTag, &extension->value, extvalue,
1543 nssComponent);
1544 if (NS_FAILED(rv)) {
1545 extvalue.Truncate();
1546 rv = ProcessRawBytes(nssComponent, &extension->value, extvalue, false);
1547 }
1548 text.Append(extvalue);
1549
1550 extensionItem->SetDisplayValue(text);
1551 extensionItem.forget(retExtension);
1552 return NS_OK;
1553 }
1554
1555 static nsresult
ProcessSECAlgorithmID(SECAlgorithmID * algID,nsINSSComponent * nssComponent,nsIASN1Sequence ** retSequence)1556 ProcessSECAlgorithmID(SECAlgorithmID *algID,
1557 nsINSSComponent *nssComponent,
1558 nsIASN1Sequence **retSequence)
1559 {
1560 SECOidTag algOIDTag = SECOID_FindOIDTag(&algID->algorithm);
1561 SECItem paramsOID = { siBuffer, nullptr, 0 };
1562 nsCOMPtr<nsIASN1Sequence> sequence = new nsNSSASN1Sequence();
1563
1564 *retSequence = nullptr;
1565 nsString text;
1566 GetOIDText(&algID->algorithm, nssComponent, text);
1567 if (!algID->parameters.len || algID->parameters.data[0] == nsIASN1Object::ASN1_NULL) {
1568 sequence->SetDisplayValue(text);
1569 sequence->SetIsValidContainer(false);
1570 } else {
1571 nsCOMPtr<nsIASN1PrintableItem> printableItem = new nsNSSASN1PrintableItem();
1572
1573 printableItem->SetDisplayValue(text);
1574 nsCOMPtr<nsIMutableArray> asn1Objects;
1575 sequence->GetASN1Objects(getter_AddRefs(asn1Objects));
1576 asn1Objects->AppendElement(printableItem, false);
1577 nssComponent->GetPIPNSSBundleString("CertDumpAlgID", text);
1578 printableItem->SetDisplayName(text);
1579
1580 printableItem = new nsNSSASN1PrintableItem();
1581
1582 asn1Objects->AppendElement(printableItem, false);
1583 nssComponent->GetPIPNSSBundleString("CertDumpParams", text);
1584 printableItem->SetDisplayName(text);
1585 if ((algOIDTag == SEC_OID_ANSIX962_EC_PUBLIC_KEY) &&
1586 (algID->parameters.len > 2) &&
1587 (algID->parameters.data[0] == nsIASN1Object::ASN1_OBJECT_ID)) {
1588 paramsOID.len = algID->parameters.len - 2;
1589 paramsOID.data = algID->parameters.data + 2;
1590 GetOIDText(¶msOID, nssComponent, text);
1591 } else {
1592 ProcessRawBytes(nssComponent, &algID->parameters,text);
1593 }
1594 printableItem->SetDisplayValue(text);
1595 }
1596 sequence.forget(retSequence);
1597 return NS_OK;
1598 }
1599
1600 static nsresult
ProcessTime(PRTime dispTime,const char16_t * displayName,nsIASN1Sequence * parentSequence)1601 ProcessTime(PRTime dispTime, const char16_t* displayName,
1602 nsIASN1Sequence* parentSequence)
1603 {
1604 nsCOMPtr<nsIDateTimeFormat> dateFormatter = nsIDateTimeFormat::Create();
1605 if (!dateFormatter) {
1606 return NS_ERROR_FAILURE;
1607 }
1608
1609 nsString text;
1610 nsString tempString;
1611
1612 PRExplodedTime explodedTime;
1613 PR_ExplodeTime(dispTime, PR_LocalTimeParameters, &explodedTime);
1614
1615 dateFormatter->FormatPRExplodedTime(nullptr, kDateFormatLong,
1616 kTimeFormatSeconds, &explodedTime,
1617 tempString);
1618
1619 text.Append(tempString);
1620 text.AppendLiteral("\n(");
1621
1622 PRExplodedTime explodedTimeGMT;
1623 PR_ExplodeTime(dispTime, PR_GMTParameters, &explodedTimeGMT);
1624
1625 dateFormatter->FormatPRExplodedTime(nullptr, kDateFormatLong,
1626 kTimeFormatSeconds, &explodedTimeGMT,
1627 tempString);
1628
1629 text.Append(tempString);
1630 text.AppendLiteral(" GMT)");
1631
1632 nsCOMPtr<nsIASN1PrintableItem> printableItem = new nsNSSASN1PrintableItem();
1633
1634 printableItem->SetDisplayValue(text);
1635 printableItem->SetDisplayName(nsDependentString(displayName));
1636 nsCOMPtr<nsIMutableArray> asn1Objects;
1637 parentSequence->GetASN1Objects(getter_AddRefs(asn1Objects));
1638 asn1Objects->AppendElement(printableItem, false);
1639 return NS_OK;
1640 }
1641
1642 static nsresult
ProcessSubjectPublicKeyInfo(CERTSubjectPublicKeyInfo * spki,nsIASN1Sequence * parentSequence,nsINSSComponent * nssComponent)1643 ProcessSubjectPublicKeyInfo(CERTSubjectPublicKeyInfo *spki,
1644 nsIASN1Sequence *parentSequence,
1645 nsINSSComponent *nssComponent)
1646 {
1647 nsCOMPtr<nsIASN1Sequence> spkiSequence = new nsNSSASN1Sequence();
1648
1649 nsString text;
1650 nssComponent->GetPIPNSSBundleString("CertDumpSPKI", text);
1651 spkiSequence->SetDisplayName(text);
1652
1653 nssComponent->GetPIPNSSBundleString("CertDumpSPKIAlg", text);
1654 nsCOMPtr<nsIASN1Sequence> sequenceItem;
1655 nsresult rv = ProcessSECAlgorithmID(&spki->algorithm, nssComponent,
1656 getter_AddRefs(sequenceItem));
1657 if (NS_FAILED(rv))
1658 return rv;
1659 sequenceItem->SetDisplayName(text);
1660 nsCOMPtr<nsIMutableArray> asn1Objects;
1661 spkiSequence->GetASN1Objects(getter_AddRefs(asn1Objects));
1662 asn1Objects->AppendElement(sequenceItem, false);
1663
1664 nsCOMPtr<nsIASN1PrintableItem> printableItem = new nsNSSASN1PrintableItem();
1665
1666 text.Truncate();
1667
1668 UniqueSECKEYPublicKey key(SECKEY_ExtractPublicKey(spki));
1669 bool displayed = false;
1670 if (key) {
1671 switch (key->keyType) {
1672 case rsaKey: {
1673 displayed = true;
1674 nsAutoString length1, length2, data1, data2;
1675 length1.AppendInt(key->u.rsa.modulus.len * 8);
1676 length2.AppendInt(key->u.rsa.publicExponent.len * 8);
1677 ProcessRawBytes(nssComponent, &key->u.rsa.modulus, data1,
1678 false);
1679 ProcessRawBytes(nssComponent, &key->u.rsa.publicExponent, data2,
1680 false);
1681 const char16_t *params[4] = {length1.get(), data1.get(),
1682 length2.get(), data2.get()};
1683 nssComponent->PIPBundleFormatStringFromName("CertDumpRSATemplate",
1684 params, 4, text);
1685 break;
1686 }
1687 case ecKey: {
1688 displayed = true;
1689 SECKEYECPublicKey &ecpk = key->u.ec;
1690 int fieldSizeLenAsBits =
1691 SECKEY_ECParamsToKeySize(&ecpk.DEREncodedParams);
1692 int basePointOrderLenAsBits =
1693 SECKEY_ECParamsToBasePointOrderLen(&ecpk.DEREncodedParams);
1694 nsAutoString s_fsl, s_bpol, s_pv;
1695 s_fsl.AppendInt(fieldSizeLenAsBits);
1696 s_bpol.AppendInt(basePointOrderLenAsBits);
1697
1698 if (ecpk.publicValue.len > 4) {
1699 ProcessRawBytes(nssComponent, &ecpk.publicValue, s_pv, false);
1700 } else {
1701 int i_pv = DER_GetInteger(&ecpk.publicValue);
1702 s_pv.AppendInt(i_pv);
1703 }
1704 const char16_t *params[] = {s_fsl.get(), s_bpol.get(), s_pv.get()};
1705 nssComponent->PIPBundleFormatStringFromName("CertDumpECTemplate",
1706 params, 3, text);
1707 break;
1708 }
1709 default:
1710 /* Algorithm unknown, or too rarely used to bother displaying it */
1711 break;
1712 }
1713 }
1714 if (!displayed) {
1715 // Algorithm unknown, display raw bytes
1716 // The subjectPublicKey field is encoded as a bit string.
1717 // ProcessRawBytes expects the length to be in bytes, so
1718 // let's convert the lenght into a temporary SECItem.
1719 SECItem data;
1720 data.data = spki->subjectPublicKey.data;
1721 data.len = spki->subjectPublicKey.len / 8;
1722 ProcessRawBytes(nssComponent, &data, text);
1723
1724 }
1725
1726 printableItem->SetDisplayValue(text);
1727 nssComponent->GetPIPNSSBundleString("CertDumpSubjPubKey", text);
1728 printableItem->SetDisplayName(text);
1729 asn1Objects->AppendElement(printableItem, false);
1730
1731 parentSequence->GetASN1Objects(getter_AddRefs(asn1Objects));
1732 asn1Objects->AppendElement(spkiSequence, false);
1733 return NS_OK;
1734 }
1735
1736 static nsresult
ProcessExtensions(CERTCertExtension ** extensions,nsIASN1Sequence * parentSequence,nsINSSComponent * nssComponent)1737 ProcessExtensions(CERTCertExtension **extensions,
1738 nsIASN1Sequence *parentSequence,
1739 nsINSSComponent *nssComponent)
1740 {
1741 nsCOMPtr<nsIASN1Sequence> extensionSequence = new nsNSSASN1Sequence;
1742
1743 nsString text;
1744 nssComponent->GetPIPNSSBundleString("CertDumpExtensions", text);
1745 extensionSequence->SetDisplayName(text);
1746 int32_t i;
1747 nsresult rv;
1748 nsCOMPtr<nsIASN1PrintableItem> newExtension;
1749 nsCOMPtr<nsIMutableArray> asn1Objects;
1750 extensionSequence->GetASN1Objects(getter_AddRefs(asn1Objects));
1751 for (i=0; extensions[i] != nullptr; i++) {
1752 rv = ProcessSingleExtension(extensions[i],
1753 nssComponent,
1754 getter_AddRefs(newExtension));
1755 if (NS_FAILED(rv))
1756 return rv;
1757
1758 asn1Objects->AppendElement(newExtension, false);
1759 }
1760 parentSequence->GetASN1Objects(getter_AddRefs(asn1Objects));
1761 asn1Objects->AppendElement(extensionSequence, false);
1762 return NS_OK;
1763 }
1764
1765 static bool registered;
RegisterDynamicOids()1766 static SECStatus RegisterDynamicOids()
1767 {
1768 unsigned int i;
1769 SECStatus rv = SECSuccess;
1770
1771 if (registered)
1772 return rv;
1773
1774 for (i = 0; i < numOids; i++) {
1775 SECOidTag tag = SECOID_AddEntry(&more_oids[i]);
1776 if (tag == SEC_OID_UNKNOWN) {
1777 rv = SECFailure;
1778 continue;
1779 }
1780 more_oids[i].offset = tag;
1781 }
1782 registered = true;
1783 return rv;
1784 }
1785
1786 nsresult
CreateTBSCertificateASN1Struct(nsIASN1Sequence ** retSequence,nsINSSComponent * nssComponent)1787 nsNSSCertificate::CreateTBSCertificateASN1Struct(nsIASN1Sequence **retSequence,
1788 nsINSSComponent *nssComponent)
1789 {
1790 MOZ_ASSERT(nssComponent);
1791 NS_ENSURE_ARG(nssComponent);
1792
1793 nsNSSShutDownPreventionLock locker;
1794 if (isAlreadyShutDown())
1795 return NS_ERROR_NOT_AVAILABLE;
1796
1797 if (RegisterDynamicOids() != SECSuccess)
1798 return NS_ERROR_FAILURE;
1799
1800 //
1801 // TBSCertificate ::= SEQUENCE {
1802 // version [0] EXPLICIT Version DEFAULT v1,
1803 // serialNumber CertificateSerialNumber,
1804 // signature AlgorithmIdentifier,
1805 // issuer Name,
1806 // validity Validity,
1807 // subject Name,
1808 // subjectPublicKeyInfo SubjectPublicKeyInfo,
1809 // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
1810 // -- If present, version shall be v2 or v3
1811 // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
1812 // -- If present, version shall be v2 or v3
1813 // extensions [3] EXPLICIT Extensions OPTIONAL
1814 // -- If present, version shall be v3
1815 // }
1816 //
1817 // This is the ASN1 structure we should be dealing with at this point.
1818 // The code in this method will assert this is the structure we're dealing
1819 // and then add more user friendly text for that field.
1820 nsCOMPtr<nsIASN1Sequence> sequence = new nsNSSASN1Sequence();
1821
1822 nsString text;
1823 nssComponent->GetPIPNSSBundleString("CertDumpCertificate", text);
1824 sequence->SetDisplayName(text);
1825 nsCOMPtr<nsIASN1PrintableItem> printableItem;
1826
1827 nsCOMPtr<nsIMutableArray> asn1Objects;
1828 sequence->GetASN1Objects(getter_AddRefs(asn1Objects));
1829
1830 nsresult rv = ProcessVersion(&mCert->version, nssComponent,
1831 getter_AddRefs(printableItem));
1832 if (NS_FAILED(rv))
1833 return rv;
1834
1835 asn1Objects->AppendElement(printableItem, false);
1836
1837 rv = ProcessSerialNumberDER(mCert->serialNumber, WrapNotNull(nssComponent),
1838 printableItem);
1839 if (NS_FAILED(rv))
1840 return rv;
1841 asn1Objects->AppendElement(printableItem, false);
1842
1843 nsCOMPtr<nsIASN1Sequence> algID;
1844 rv = ProcessSECAlgorithmID(&mCert->signature,
1845 nssComponent, getter_AddRefs(algID));
1846 if (NS_FAILED(rv))
1847 return rv;
1848
1849 nssComponent->GetPIPNSSBundleString("CertDumpSigAlg", text);
1850 algID->SetDisplayName(text);
1851 asn1Objects->AppendElement(algID, false);
1852
1853 nsXPIDLString value;
1854 ProcessName(&mCert->issuer, nssComponent, getter_Copies(value));
1855
1856 printableItem = new nsNSSASN1PrintableItem();
1857
1858 printableItem->SetDisplayValue(value);
1859 nssComponent->GetPIPNSSBundleString("CertDumpIssuer", text);
1860 printableItem->SetDisplayName(text);
1861 asn1Objects->AppendElement(printableItem, false);
1862
1863 nsCOMPtr<nsIASN1Sequence> validitySequence = new nsNSSASN1Sequence();
1864 nssComponent->GetPIPNSSBundleString("CertDumpValidity", text);
1865 validitySequence->SetDisplayName(text);
1866 asn1Objects->AppendElement(validitySequence, false);
1867 nssComponent->GetPIPNSSBundleString("CertDumpNotBefore", text);
1868 nsCOMPtr<nsIX509CertValidity> validityData;
1869 GetValidity(getter_AddRefs(validityData));
1870 PRTime notBefore, notAfter;
1871
1872 validityData->GetNotBefore(¬Before);
1873 validityData->GetNotAfter(¬After);
1874 validityData = nullptr;
1875 rv = ProcessTime(notBefore, text.get(), validitySequence);
1876 if (NS_FAILED(rv))
1877 return rv;
1878
1879 nssComponent->GetPIPNSSBundleString("CertDumpNotAfter", text);
1880 rv = ProcessTime(notAfter, text.get(), validitySequence);
1881 if (NS_FAILED(rv))
1882 return rv;
1883
1884 nssComponent->GetPIPNSSBundleString("CertDumpSubject", text);
1885
1886 printableItem = new nsNSSASN1PrintableItem();
1887
1888 printableItem->SetDisplayName(text);
1889 ProcessName(&mCert->subject, nssComponent,getter_Copies(value));
1890 printableItem->SetDisplayValue(value);
1891 asn1Objects->AppendElement(printableItem, false);
1892
1893 rv = ProcessSubjectPublicKeyInfo(&mCert->subjectPublicKeyInfo, sequence,
1894 nssComponent);
1895 if (NS_FAILED(rv))
1896 return rv;
1897
1898 SECItem data;
1899 // Is there an issuerUniqueID?
1900 if (mCert->issuerID.data) {
1901 // The issuerID is encoded as a bit string.
1902 // The function ProcessRawBytes expects the
1903 // length to be in bytes, so let's convert the
1904 // length in a temporary SECItem
1905 data.data = mCert->issuerID.data;
1906 data.len = (mCert->issuerID.len + 7) / 8;
1907
1908 ProcessRawBytes(nssComponent, &data, text);
1909 printableItem = new nsNSSASN1PrintableItem();
1910
1911 printableItem->SetDisplayValue(text);
1912 nssComponent->GetPIPNSSBundleString("CertDumpIssuerUniqueID", text);
1913 printableItem->SetDisplayName(text);
1914 asn1Objects->AppendElement(printableItem, false);
1915 }
1916
1917 if (mCert->subjectID.data) {
1918 // The subjectID is encoded as a bit string.
1919 // The function ProcessRawBytes expects the
1920 // length to be in bytes, so let's convert the
1921 // length in a temporary SECItem
1922 data.data = mCert->subjectID.data;
1923 data.len = (mCert->subjectID.len + 7) / 8;
1924
1925 ProcessRawBytes(nssComponent, &data, text);
1926 printableItem = new nsNSSASN1PrintableItem();
1927
1928 printableItem->SetDisplayValue(text);
1929 nssComponent->GetPIPNSSBundleString("CertDumpSubjectUniqueID", text);
1930 printableItem->SetDisplayName(text);
1931 asn1Objects->AppendElement(printableItem, false);
1932
1933 }
1934 if (mCert->extensions) {
1935 rv = ProcessExtensions(mCert->extensions, sequence, nssComponent);
1936 if (NS_FAILED(rv))
1937 return rv;
1938 }
1939 sequence.forget(retSequence);
1940 return NS_OK;
1941 }
1942
1943 nsresult
CreateASN1Struct(nsIASN1Object ** aRetVal)1944 nsNSSCertificate::CreateASN1Struct(nsIASN1Object** aRetVal)
1945 {
1946 static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
1947
1948 nsNSSShutDownPreventionLock locker;
1949 if (isAlreadyShutDown())
1950 return NS_ERROR_NOT_AVAILABLE;
1951
1952 nsCOMPtr<nsIASN1Sequence> sequence = new nsNSSASN1Sequence();
1953
1954 nsCOMPtr<nsIMutableArray> asn1Objects;
1955 sequence->GetASN1Objects(getter_AddRefs(asn1Objects));
1956
1957 nsAutoString title;
1958 nsresult rv = GetWindowTitle(title);
1959 if (NS_FAILED(rv)) {
1960 return rv;
1961 }
1962
1963 sequence->SetDisplayName(title);
1964 sequence.forget(aRetVal);
1965
1966 // This sequence will be contain the tbsCertificate, signatureAlgorithm,
1967 // and signatureValue.
1968 nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
1969 if (NS_FAILED(rv))
1970 return rv;
1971
1972 rv = CreateTBSCertificateASN1Struct(getter_AddRefs(sequence),
1973 nssComponent);
1974 if (NS_FAILED(rv))
1975 return rv;
1976
1977 asn1Objects->AppendElement(sequence, false);
1978 nsCOMPtr<nsIASN1Sequence> algID;
1979
1980 rv = ProcessSECAlgorithmID(&mCert->signatureWrap.signatureAlgorithm,
1981 nssComponent, getter_AddRefs(algID));
1982 if (NS_FAILED(rv))
1983 return rv;
1984 nsString text;
1985 nssComponent->GetPIPNSSBundleString("CertDumpSigAlg", text);
1986 algID->SetDisplayName(text);
1987 asn1Objects->AppendElement(algID, false);
1988 nsCOMPtr<nsIASN1PrintableItem>printableItem = new nsNSSASN1PrintableItem();
1989 nssComponent->GetPIPNSSBundleString("CertDumpCertSig", text);
1990 printableItem->SetDisplayName(text);
1991 // The signatureWrap is encoded as a bit string.
1992 // The function ProcessRawBytes expects the
1993 // length to be in bytes, so let's convert the
1994 // length in a temporary SECItem
1995 SECItem temp;
1996 temp.data = mCert->signatureWrap.signature.data;
1997 temp.len = mCert->signatureWrap.signature.len / 8;
1998 text.Truncate();
1999 ProcessRawBytes(nssComponent, &temp,text);
2000 printableItem->SetDisplayValue(text);
2001 asn1Objects->AppendElement(printableItem, false);
2002 return NS_OK;
2003 }
2004
2005 uint32_t
getCertType(CERTCertificate * cert)2006 getCertType(CERTCertificate *cert)
2007 {
2008 nsNSSCertTrust trust(cert->trust);
2009 if (cert->nickname && trust.HasAnyUser())
2010 return nsIX509Cert::USER_CERT;
2011 if (trust.HasAnyCA())
2012 return nsIX509Cert::CA_CERT;
2013 if (trust.HasPeer(true, false, false))
2014 return nsIX509Cert::SERVER_CERT;
2015 if (trust.HasPeer(false, true, false) && cert->emailAddr)
2016 return nsIX509Cert::EMAIL_CERT;
2017 if (CERT_IsCACert(cert, nullptr))
2018 return nsIX509Cert::CA_CERT;
2019 if (cert->emailAddr)
2020 return nsIX509Cert::EMAIL_CERT;
2021 return nsIX509Cert::UNKNOWN_CERT;
2022 }
2023
2024 nsresult
GetCertFingerprintByOidTag(CERTCertificate * nsscert,SECOidTag aOidTag,nsCString & fp)2025 GetCertFingerprintByOidTag(CERTCertificate* nsscert,
2026 SECOidTag aOidTag,
2027 nsCString &fp)
2028 {
2029 Digest digest;
2030 nsresult rv = digest.DigestBuf(aOidTag, nsscert->derCert.data,
2031 nsscert->derCert.len);
2032 NS_ENSURE_SUCCESS(rv, rv);
2033
2034 UniquePORTString tmpstr(CERT_Hexify(const_cast<SECItem*>(&digest.get()), 1));
2035 NS_ENSURE_TRUE(tmpstr, NS_ERROR_OUT_OF_MEMORY);
2036
2037 fp.Assign(tmpstr.get());
2038 return NS_OK;
2039 }
2040