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