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