Coverage Report

Created: 2018-09-25 14:53

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