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(&current->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 			       &current->name.OthName.name) == SECSuccess) {
946 	  AppendUTF8toUTF16(nsAutoCString((char*)decoded.data, decoded.len),
947 			    value);
948 	} else {
949 	  ProcessRawBytes(nssComponent, &current->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 			       &current->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, &current->name.OthName.name, value);
969 	}
970     } else {
971       rv = GetDefaultOIDFormat(&current->name.OthName.oid, nssComponent, key, ' ');
972       if (NS_FAILED(rv)) {
973         return rv;
974       }
975       ProcessRawBytes(nssComponent, &current->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, &current->name.other, value);
990     break;
991   case certDirectoryName:
992     nssComponent->GetPIPNSSBundleString("CertDumpDirectoryName", key);
993     rv = ProcessName(&current->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, &current->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, &current->name.other, value);
1028       }
1029       break;
1030     }
1031   case certRegisterID:
1032     nssComponent->GetPIPNSSBundleString("CertDumpRegisterID", key);
1033     rv = GetDefaultOIDFormat(&current->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(&paramsOID, 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(&notBefore);
1873   validityData->GetNotAfter(&notAfter);
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