michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "prerror.h" michael@0: #include "prprf.h" michael@0: michael@0: #include "ScopedNSSTypes.h" michael@0: #include "nsNSSCertHelper.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsNSSCertificate.h" michael@0: #include "secder.h" michael@0: #include "nsComponentManagerUtils.h" michael@0: #include "nsNSSCertValidity.h" michael@0: #include "nsNSSASN1Object.h" michael@0: #include "nsNSSComponent.h" michael@0: #include "nsNSSCertTrust.h" michael@0: #include "nsIDateTimeFormat.h" michael@0: #include "nsDateTimeFormatCID.h" michael@0: #include "nsServiceManagerUtils.h" michael@0: #include michael@0: michael@0: using namespace mozilla; michael@0: michael@0: /* Object Identifier constants */ michael@0: #define CONST_OID static const unsigned char michael@0: #define MICROSOFT_OID 0x2b, 0x6, 0x1, 0x4, 0x1, 0x82, 0x37 michael@0: #define PKIX_OID 0x2b, 0x6, 0x01, 0x05, 0x05, 0x07 michael@0: CONST_OID msCertExtCerttype[] = { MICROSOFT_OID, 20, 2}; michael@0: CONST_OID msNTPrincipalName[] = { MICROSOFT_OID, 20, 2, 3 }; michael@0: CONST_OID msCertsrvCAVersion[] = { MICROSOFT_OID, 21, 1 }; michael@0: CONST_OID msNTDSReplication[] = { MICROSOFT_OID, 25, 1 }; michael@0: CONST_OID pkixLogotype[] = { PKIX_OID, 1, 12 }; michael@0: michael@0: #define OI(x) { siDEROID, (unsigned char *)x, sizeof x } michael@0: #define OD(oid,desc,mech,ext) {OI(oid), SEC_OID_UNKNOWN, desc, mech, ext} michael@0: #define SEC_OID(tag) more_oids[tag].offset michael@0: michael@0: static SECOidData more_oids[] = { michael@0: /* Microsoft OIDs */ michael@0: #define MS_CERT_EXT_CERTTYPE 0 michael@0: OD( msCertExtCerttype, michael@0: "Microsoft Certificate Template Name", michael@0: CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ), michael@0: michael@0: #define MS_NT_PRINCIPAL_NAME 1 michael@0: OD( msNTPrincipalName, michael@0: "Microsoft Principal Name", michael@0: CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ), michael@0: michael@0: #define MS_CERTSERV_CA_VERSION 2 michael@0: OD( msCertsrvCAVersion, michael@0: "Microsoft CA Version", michael@0: CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ), michael@0: michael@0: #define MS_NTDS_REPLICATION 3 michael@0: OD( msNTDSReplication, michael@0: "Microsoft Domain GUID", michael@0: CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ), michael@0: michael@0: #define PKIX_LOGOTYPE 4 michael@0: OD( pkixLogotype, michael@0: "Logotype", michael@0: CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ), michael@0: }; michael@0: michael@0: static const unsigned int numOids = (sizeof more_oids) / (sizeof more_oids[0]); michael@0: michael@0: static nsresult michael@0: GetIntValue(SECItem *versionItem, michael@0: unsigned long *version) michael@0: { michael@0: SECStatus srv; michael@0: michael@0: srv = SEC_ASN1DecodeInteger(versionItem,version); michael@0: if (srv != SECSuccess) { michael@0: NS_ERROR("Could not decode version of cert"); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessVersion(SECItem *versionItem, michael@0: nsINSSComponent *nssComponent, michael@0: nsIASN1PrintableItem **retItem) michael@0: { michael@0: nsresult rv; michael@0: nsAutoString text; michael@0: nsCOMPtr printableItem = new nsNSSASN1PrintableItem(); michael@0: michael@0: nssComponent->GetPIPNSSBundleString("CertDumpVersion", text); michael@0: rv = printableItem->SetDisplayName(text); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: // Now to figure out what version this certificate is. michael@0: unsigned long version; michael@0: michael@0: if (versionItem->data) { michael@0: rv = GetIntValue(versionItem, &version); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: } else { michael@0: // If there is no version present in the cert, then rfc2459 michael@0: // says we default to v1 (0) michael@0: version = 0; michael@0: } michael@0: michael@0: switch (version){ michael@0: case 0: michael@0: rv = nssComponent->GetPIPNSSBundleString("CertDumpVersion1", text); michael@0: break; michael@0: case 1: michael@0: rv = nssComponent->GetPIPNSSBundleString("CertDumpVersion2", text); michael@0: break; michael@0: case 2: michael@0: rv = nssComponent->GetPIPNSSBundleString("CertDumpVersion3", text); michael@0: break; michael@0: default: michael@0: NS_ERROR("Bad value for cert version"); michael@0: rv = NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: rv = printableItem->SetDisplayValue(text); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: *retItem = printableItem; michael@0: NS_ADDREF(*retItem); michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessSerialNumberDER(SECItem *serialItem, michael@0: nsINSSComponent *nssComponent, michael@0: nsIASN1PrintableItem **retItem) michael@0: { michael@0: nsresult rv; michael@0: nsAutoString text; michael@0: nsCOMPtr printableItem = new nsNSSASN1PrintableItem(); michael@0: michael@0: rv = nssComponent->GetPIPNSSBundleString("CertDumpSerialNo", text); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: rv = printableItem->SetDisplayName(text); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: nsXPIDLCString serialNumber; michael@0: serialNumber.Adopt(CERT_Hexify(serialItem, 1)); michael@0: if (!serialNumber) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: rv = printableItem->SetDisplayValue(NS_ConvertASCIItoUTF16(serialNumber)); michael@0: *retItem = printableItem; michael@0: NS_ADDREF(*retItem); michael@0: return rv; michael@0: } michael@0: michael@0: static nsresult michael@0: GetDefaultOIDFormat(SECItem *oid, michael@0: nsINSSComponent *nssComponent, michael@0: nsAString &outString, michael@0: char separator) michael@0: { michael@0: char buf[300]; michael@0: unsigned int len = 0; michael@0: int written, invalidCount = 0; michael@0: michael@0: unsigned int i; michael@0: unsigned long val = 0; michael@0: bool invalid = false; michael@0: bool first = true; michael@0: michael@0: val = 0; michael@0: for (i = 0; i < oid->len; ++i) { michael@0: // In this loop, we have to parse a DER formatted michael@0: // If the first bit is a 1, then the integer is michael@0: // represented by more than one byte. If the michael@0: // first bit is set then we continue on and add michael@0: // the values of the later bytes until we get michael@0: // a byte without the first bit set. michael@0: unsigned long j; michael@0: michael@0: j = oid->data[i]; michael@0: val = (val << 7) | (j & 0x7f); michael@0: if (j & 0x80) { michael@0: // - If val is 0 in this block, the OID number particle starts with 0x80 michael@0: // what is specified as an invalid formating. michael@0: // - If val is larger then 2^32-7, on next left shift by 7 we will loose michael@0: // the most significant bits, this OID number particle cannot be read michael@0: // by our implementation. michael@0: // - If the first bit is set while this is the last component of the OID michael@0: // we are also in an invalid state. michael@0: if (val == 0 || (val >= (1 << (32-7))) || (i == oid->len-1)) { michael@0: invalid = true; michael@0: } michael@0: michael@0: if (i < oid->len-1) michael@0: continue; michael@0: } michael@0: michael@0: if (!invalid) { michael@0: if (first) { michael@0: unsigned long one = std::min(val/40, 2UL); // never > 2 michael@0: unsigned long two = val - (one * 40); michael@0: michael@0: written = PR_snprintf(&buf[len], sizeof(buf)-len, "%lu%c%lu", michael@0: one, separator, two); michael@0: } michael@0: else { michael@0: written = PR_snprintf(&buf[len], sizeof(buf)-len, "%c%lu", michael@0: separator, val); michael@0: } michael@0: } michael@0: else { michael@0: nsAutoString unknownText; michael@0: nssComponent->GetPIPNSSBundleString("CertUnknown", michael@0: unknownText); michael@0: if (first) { michael@0: written = PR_snprintf(&buf[len], sizeof(buf)-len, "%s", michael@0: NS_ConvertUTF16toUTF8(unknownText).get()); michael@0: } michael@0: else { michael@0: written = PR_snprintf(&buf[len], sizeof(buf)-len, "%c%s", michael@0: separator, michael@0: NS_ConvertUTF16toUTF8(unknownText).get()); michael@0: } michael@0: michael@0: if (++invalidCount > 3) { michael@0: // Allow only 3 occurences of Unknown in OID display string to michael@0: // prevent bloat. michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (written < 0) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: len += written; michael@0: NS_ASSERTION(len < sizeof(buf), "OID data to big to display in 300 chars."); michael@0: val = 0; michael@0: invalid = false; michael@0: first = false; michael@0: } michael@0: michael@0: CopyASCIItoUTF16(buf, outString); michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsresult michael@0: GetOIDText(SECItem *oid, nsINSSComponent *nssComponent, nsAString &text) michael@0: { michael@0: nsresult rv; michael@0: SECOidTag oidTag = SECOID_FindOIDTag(oid); michael@0: const char *bundlekey = 0; michael@0: michael@0: switch (oidTag) { michael@0: case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: michael@0: bundlekey = "CertDumpMD2WithRSA"; michael@0: break; michael@0: case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: michael@0: bundlekey = "CertDumpMD5WithRSA"; michael@0: break; michael@0: case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: michael@0: bundlekey = "CertDumpSHA1WithRSA"; michael@0: break; michael@0: case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: michael@0: bundlekey = "CertDumpSHA256WithRSA"; michael@0: break; michael@0: case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: michael@0: bundlekey = "CertDumpSHA384WithRSA"; michael@0: break; michael@0: case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: michael@0: bundlekey = "CertDumpSHA512WithRSA"; michael@0: break; michael@0: case SEC_OID_PKCS1_RSA_ENCRYPTION: michael@0: bundlekey = "CertDumpRSAEncr"; michael@0: break; michael@0: case SEC_OID_PKCS1_RSA_PSS_SIGNATURE: michael@0: bundlekey = "CertDumpRSAPSSSignature"; michael@0: break; michael@0: case SEC_OID_NS_CERT_EXT_CERT_TYPE: michael@0: bundlekey = "CertDumpCertType"; michael@0: break; michael@0: case SEC_OID_NS_CERT_EXT_BASE_URL: michael@0: bundlekey = "CertDumpNSCertExtBaseUrl"; michael@0: break; michael@0: case SEC_OID_NS_CERT_EXT_REVOCATION_URL: michael@0: bundlekey = "CertDumpNSCertExtRevocationUrl"; michael@0: break; michael@0: case SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL: michael@0: bundlekey = "CertDumpNSCertExtCARevocationUrl"; michael@0: break; michael@0: case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL: michael@0: bundlekey = "CertDumpNSCertExtCertRenewalUrl"; michael@0: break; michael@0: case SEC_OID_NS_CERT_EXT_CA_POLICY_URL: michael@0: bundlekey = "CertDumpNSCertExtCAPolicyUrl"; michael@0: break; michael@0: case SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME: michael@0: bundlekey = "CertDumpNSCertExtSslServerName"; michael@0: break; michael@0: case SEC_OID_NS_CERT_EXT_COMMENT: michael@0: bundlekey = "CertDumpNSCertExtComment"; michael@0: break; michael@0: case SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL: michael@0: bundlekey = "CertDumpNSCertExtLostPasswordUrl"; michael@0: break; michael@0: case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME: michael@0: bundlekey = "CertDumpNSCertExtCertRenewalTime"; michael@0: break; michael@0: case SEC_OID_NETSCAPE_AOLSCREENNAME: michael@0: bundlekey = "CertDumpNetscapeAolScreenname"; michael@0: break; michael@0: case SEC_OID_AVA_COUNTRY_NAME: michael@0: bundlekey = "CertDumpAVACountry"; michael@0: break; michael@0: case SEC_OID_AVA_COMMON_NAME: michael@0: bundlekey = "CertDumpAVACN"; michael@0: break; michael@0: case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME: michael@0: bundlekey = "CertDumpAVAOU"; michael@0: break; michael@0: case SEC_OID_AVA_ORGANIZATION_NAME: michael@0: bundlekey = "CertDumpAVAOrg"; michael@0: break; michael@0: case SEC_OID_AVA_LOCALITY: michael@0: bundlekey = "CertDumpAVALocality"; michael@0: break; michael@0: case SEC_OID_AVA_DN_QUALIFIER: michael@0: bundlekey = "CertDumpAVADN"; michael@0: break; michael@0: case SEC_OID_AVA_DC: michael@0: bundlekey = "CertDumpAVADC"; michael@0: break; michael@0: case SEC_OID_AVA_STATE_OR_PROVINCE: michael@0: bundlekey = "CertDumpAVAState"; michael@0: break; michael@0: case SEC_OID_AVA_SURNAME: michael@0: bundlekey = "CertDumpSurname"; michael@0: break; michael@0: case SEC_OID_AVA_GIVEN_NAME: michael@0: bundlekey = "CertDumpGivenName"; michael@0: break; michael@0: case SEC_OID_X509_SUBJECT_DIRECTORY_ATTR: michael@0: bundlekey = "CertDumpSubjectDirectoryAttr"; michael@0: break; michael@0: case SEC_OID_X509_SUBJECT_KEY_ID: michael@0: bundlekey = "CertDumpSubjectKeyID"; michael@0: break; michael@0: case SEC_OID_X509_KEY_USAGE: michael@0: bundlekey = "CertDumpKeyUsage"; michael@0: break; michael@0: case SEC_OID_X509_SUBJECT_ALT_NAME: michael@0: bundlekey = "CertDumpSubjectAltName"; michael@0: break; michael@0: case SEC_OID_X509_ISSUER_ALT_NAME: michael@0: bundlekey = "CertDumpIssuerAltName"; michael@0: break; michael@0: case SEC_OID_X509_BASIC_CONSTRAINTS: michael@0: bundlekey = "CertDumpBasicConstraints"; michael@0: break; michael@0: case SEC_OID_X509_NAME_CONSTRAINTS: michael@0: bundlekey = "CertDumpNameConstraints"; michael@0: break; michael@0: case SEC_OID_X509_CRL_DIST_POINTS: michael@0: bundlekey = "CertDumpCrlDistPoints"; michael@0: break; michael@0: case SEC_OID_X509_CERTIFICATE_POLICIES: michael@0: bundlekey = "CertDumpCertPolicies"; michael@0: break; michael@0: case SEC_OID_X509_POLICY_MAPPINGS: michael@0: bundlekey = "CertDumpPolicyMappings"; michael@0: break; michael@0: case SEC_OID_X509_POLICY_CONSTRAINTS: michael@0: bundlekey = "CertDumpPolicyConstraints"; michael@0: break; michael@0: case SEC_OID_X509_AUTH_KEY_ID: michael@0: bundlekey = "CertDumpAuthKeyID"; michael@0: break; michael@0: case SEC_OID_X509_EXT_KEY_USAGE: michael@0: bundlekey = "CertDumpExtKeyUsage"; michael@0: break; michael@0: case SEC_OID_X509_AUTH_INFO_ACCESS: michael@0: bundlekey = "CertDumpAuthInfoAccess"; michael@0: break; michael@0: case SEC_OID_ANSIX9_DSA_SIGNATURE: michael@0: bundlekey = "CertDumpAnsiX9DsaSignature"; michael@0: break; michael@0: case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: michael@0: bundlekey = "CertDumpAnsiX9DsaSignatureWithSha1"; michael@0: break; michael@0: case SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST: michael@0: bundlekey = "CertDumpAnsiX962ECDsaSignatureWithSha1"; michael@0: break; michael@0: case SEC_OID_RFC1274_UID: michael@0: bundlekey = "CertDumpUserID"; michael@0: break; michael@0: case SEC_OID_PKCS9_EMAIL_ADDRESS: michael@0: bundlekey = "CertDumpPK9Email"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_PUBLIC_KEY: michael@0: bundlekey = "CertDumpECPublicKey"; michael@0: break; michael@0: /* ANSI X9.62 named elliptic curves (prime field) */ michael@0: case SEC_OID_ANSIX962_EC_PRIME192V1: michael@0: /* same as SEC_OID_SECG_EC_SECP192r1 */ michael@0: bundlekey = "CertDumpECprime192v1"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_PRIME192V2: michael@0: bundlekey = "CertDumpECprime192v2"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_PRIME192V3: michael@0: bundlekey = "CertDumpECprime192v3"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_PRIME239V1: michael@0: bundlekey = "CertDumpECprime239v1"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_PRIME239V2: michael@0: bundlekey = "CertDumpECprime239v2"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_PRIME239V3: michael@0: bundlekey = "CertDumpECprime239v3"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_PRIME256V1: michael@0: /* same as SEC_OID_SECG_EC_SECP256r1 */ michael@0: bundlekey = "CertDumpECprime256v1"; michael@0: break; michael@0: /* SECG named elliptic curves (prime field) */ michael@0: case SEC_OID_SECG_EC_SECP112R1: michael@0: bundlekey = "CertDumpECsecp112r1"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECP112R2: michael@0: bundlekey = "CertDumpECsecp112r2"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECP128R1: michael@0: bundlekey = "CertDumpECsecp128r1"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECP128R2: michael@0: bundlekey = "CertDumpECsecp128r2"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECP160K1: michael@0: bundlekey = "CertDumpECsecp160k1"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECP160R1: michael@0: bundlekey = "CertDumpECsecp160r1"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECP160R2: michael@0: bundlekey = "CertDumpECsecp160r2"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECP192K1: michael@0: bundlekey = "CertDumpECsecp192k1"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECP224K1: michael@0: bundlekey = "CertDumpECsecp224k1"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECP224R1: michael@0: bundlekey = "CertDumpECsecp224r1"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECP256K1: michael@0: bundlekey = "CertDumpECsecp256k1"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECP384R1: michael@0: bundlekey = "CertDumpECsecp384r1"; michael@0: break; michael@0: michael@0: case SEC_OID_SECG_EC_SECP521R1: michael@0: bundlekey = "CertDumpECsecp521r1"; michael@0: break; michael@0: /* ANSI X9.62 named elliptic curves (characteristic two field) */ michael@0: case SEC_OID_ANSIX962_EC_C2PNB163V1: michael@0: bundlekey = "CertDumpECc2pnb163v1"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_C2PNB163V2: michael@0: bundlekey = "CertDumpECc2pnb163v2"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_C2PNB163V3: michael@0: bundlekey = "CertDumpECc2pnb163v3"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_C2PNB176V1: michael@0: bundlekey = "CertDumpECc2pnb176v1"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_C2TNB191V1: michael@0: bundlekey = "CertDumpECc2tnb191v1"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_C2TNB191V2: michael@0: bundlekey = "CertDumpECc2tnb191v2"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_C2TNB191V3: michael@0: bundlekey = "CertDumpECc2tnb191v3"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_C2ONB191V4: michael@0: bundlekey = "CertDumpECc2onb191v4"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_C2ONB191V5: michael@0: bundlekey = "CertDumpECc2onb191v5"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_C2PNB208W1: michael@0: bundlekey = "CertDumpECc2pnb208w1"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_C2TNB239V1: michael@0: bundlekey = "CertDumpECc2tnb239v1"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_C2TNB239V2: michael@0: bundlekey = "CertDumpECc2tnb239v2"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_C2TNB239V3: michael@0: bundlekey = "CertDumpECc2tnb239v3"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_C2ONB239V4: michael@0: bundlekey = "CertDumpECc2onb239v4"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_C2ONB239V5: michael@0: bundlekey = "CertDumpECc2onb239v5"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_C2PNB272W1: michael@0: bundlekey = "CertDumpECc2pnb272w1"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_C2PNB304W1: michael@0: bundlekey = "CertDumpECc2pnb304w1"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_C2TNB359V1: michael@0: bundlekey = "CertDumpECc2tnb359v1"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_C2PNB368W1: michael@0: bundlekey = "CertDumpECc2pnb368w1"; michael@0: break; michael@0: case SEC_OID_ANSIX962_EC_C2TNB431R1: michael@0: bundlekey = "CertDumpECc2tnb431r1"; michael@0: break; michael@0: /* SECG named elliptic curves (characteristic two field) */ michael@0: case SEC_OID_SECG_EC_SECT113R1: michael@0: bundlekey = "CertDumpECsect113r1"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECT113R2: michael@0: bundlekey = "CertDumpECsect113r2"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECT131R1: michael@0: bundlekey = "CertDumpECsect131r1"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECT131R2: michael@0: bundlekey = "CertDumpECsect131r2"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECT163K1: michael@0: bundlekey = "CertDumpECsect163k1"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECT163R1: michael@0: bundlekey = "CertDumpECsect163r1"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECT163R2: michael@0: bundlekey = "CertDumpECsect163r2"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECT193R1: michael@0: bundlekey = "CertDumpECsect193r1"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECT193R2: michael@0: bundlekey = "CertDumpECsect193r2"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECT233K1: michael@0: bundlekey = "CertDumpECsect233k1"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECT233R1: michael@0: bundlekey = "CertDumpECsect233r1"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECT239K1: michael@0: bundlekey = "CertDumpECsect239k1"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECT283K1: michael@0: bundlekey = "CertDumpECsect283k1"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECT283R1: michael@0: bundlekey = "CertDumpECsect283r1"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECT409K1: michael@0: bundlekey = "CertDumpECsect409k1"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECT409R1: michael@0: bundlekey = "CertDumpECsect409r1"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECT571K1: michael@0: bundlekey = "CertDumpECsect571k1"; michael@0: break; michael@0: case SEC_OID_SECG_EC_SECT571R1: michael@0: bundlekey = "CertDumpECsect571r1"; michael@0: break; michael@0: default: michael@0: if (oidTag == SEC_OID(MS_CERT_EXT_CERTTYPE)) { michael@0: bundlekey = "CertDumpMSCerttype"; michael@0: break; michael@0: } michael@0: if (oidTag == SEC_OID(MS_CERTSERV_CA_VERSION)) { michael@0: bundlekey = "CertDumpMSCAVersion"; michael@0: break; michael@0: } michael@0: if (oidTag == SEC_OID(PKIX_LOGOTYPE)) { michael@0: bundlekey = "CertDumpLogotype"; michael@0: break; michael@0: } michael@0: /* fallthrough */ michael@0: } michael@0: michael@0: if (bundlekey) { michael@0: rv = nssComponent->GetPIPNSSBundleString(bundlekey, text); michael@0: } else { michael@0: nsAutoString text2; michael@0: rv = GetDefaultOIDFormat(oid, nssComponent, text2, ' '); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: const char16_t *params[1] = {text2.get()}; michael@0: rv = nssComponent->PIPBundleFormatStringFromName("CertDumpDefOID", michael@0: params, 1, text); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: #define SEPARATOR "\n" michael@0: michael@0: static nsresult michael@0: ProcessRawBytes(nsINSSComponent *nssComponent, SECItem *data, michael@0: nsAString &text, bool wantHeader = true) michael@0: { michael@0: // This function is used to display some DER bytes michael@0: // that we have not added support for decoding. michael@0: // If it's short, let's display as an integer, no size header. michael@0: michael@0: if (data->len <= 4) { michael@0: int i_pv = DER_GetInteger(data); michael@0: nsAutoString value; michael@0: value.AppendInt(i_pv); michael@0: text.Append(value); michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR).get()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Else produce a hex dump. michael@0: michael@0: if (wantHeader) { michael@0: nsAutoString bytelen, bitlen; michael@0: bytelen.AppendInt(data->len); michael@0: bitlen.AppendInt(data->len*8); michael@0: michael@0: const char16_t *params[2] = {bytelen.get(), bitlen.get()}; michael@0: nsresult rv = nssComponent->PIPBundleFormatStringFromName("CertDumpRawBytesHeader", michael@0: params, 2, text); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR).get()); michael@0: } michael@0: michael@0: // This prints the value of the byte out into a michael@0: // string that can later be displayed as a byte michael@0: // string. We place a new line after 24 bytes michael@0: // to break up extermaly long sequence of bytes. michael@0: michael@0: uint32_t i; michael@0: char buffer[5]; michael@0: for (i=0; ilen; i++) { michael@0: PR_snprintf(buffer, 5, "%02x ", data->data[i]); michael@0: AppendASCIItoUTF16(buffer, text); michael@0: if ((i+1)%16 == 0) { michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR).get()); michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessNSCertTypeExtensions(SECItem *extData, michael@0: nsAString &text, michael@0: nsINSSComponent *nssComponent) michael@0: { michael@0: nsAutoString local; michael@0: SECItem decoded; michael@0: decoded.data = nullptr; michael@0: decoded.len = 0; michael@0: if (SECSuccess != SEC_ASN1DecodeItem(nullptr, &decoded, michael@0: SEC_ASN1_GET(SEC_BitStringTemplate), extData)) { michael@0: nssComponent->GetPIPNSSBundleString("CertDumpExtensionFailure", local); michael@0: text.Append(local.get()); michael@0: return NS_OK; michael@0: } michael@0: unsigned char nsCertType = decoded.data[0]; michael@0: nsMemory::Free(decoded.data); michael@0: if (nsCertType & NS_CERT_TYPE_SSL_CLIENT) { michael@0: nssComponent->GetPIPNSSBundleString("VerifySSLClient", local); michael@0: text.Append(local.get()); michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR).get()); michael@0: } michael@0: if (nsCertType & NS_CERT_TYPE_SSL_SERVER) { michael@0: nssComponent->GetPIPNSSBundleString("VerifySSLServer", local); michael@0: text.Append(local.get()); michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR).get()); michael@0: } michael@0: if (nsCertType & NS_CERT_TYPE_EMAIL) { michael@0: nssComponent->GetPIPNSSBundleString("CertDumpCertTypeEmail", local); michael@0: text.Append(local.get()); michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR).get()); michael@0: } michael@0: if (nsCertType & NS_CERT_TYPE_OBJECT_SIGNING) { michael@0: nssComponent->GetPIPNSSBundleString("VerifyObjSign", local); michael@0: text.Append(local.get()); michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR).get()); michael@0: } michael@0: if (nsCertType & NS_CERT_TYPE_SSL_CA) { michael@0: nssComponent->GetPIPNSSBundleString("VerifySSLCA", local); michael@0: text.Append(local.get()); michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR).get()); michael@0: } michael@0: if (nsCertType & NS_CERT_TYPE_EMAIL_CA) { michael@0: nssComponent->GetPIPNSSBundleString("CertDumpEmailCA", local); michael@0: text.Append(local.get()); michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR).get()); michael@0: } michael@0: if (nsCertType & NS_CERT_TYPE_OBJECT_SIGNING_CA) { michael@0: nssComponent->GetPIPNSSBundleString("VerifyObjSign", local); michael@0: text.Append(local.get()); michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR).get()); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessKeyUsageExtension(SECItem *extData, nsAString &text, michael@0: nsINSSComponent *nssComponent) michael@0: { michael@0: nsAutoString local; michael@0: SECItem decoded; michael@0: decoded.data = nullptr; michael@0: decoded.len = 0; michael@0: if (SECSuccess != SEC_ASN1DecodeItem(nullptr, &decoded, michael@0: SEC_ASN1_GET(SEC_BitStringTemplate), extData)) { michael@0: nssComponent->GetPIPNSSBundleString("CertDumpExtensionFailure", local); michael@0: text.Append(local.get()); michael@0: return NS_OK; michael@0: } michael@0: unsigned char keyUsage = decoded.data[0]; michael@0: nsMemory::Free(decoded.data); michael@0: if (keyUsage & KU_DIGITAL_SIGNATURE) { michael@0: nssComponent->GetPIPNSSBundleString("CertDumpKUSign", local); michael@0: text.Append(local.get()); michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR).get()); michael@0: } michael@0: if (keyUsage & KU_NON_REPUDIATION) { michael@0: nssComponent->GetPIPNSSBundleString("CertDumpKUNonRep", local); michael@0: text.Append(local.get()); michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR).get()); michael@0: } michael@0: if (keyUsage & KU_KEY_ENCIPHERMENT) { michael@0: nssComponent->GetPIPNSSBundleString("CertDumpKUEnc", local); michael@0: text.Append(local.get()); michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR).get()); michael@0: } michael@0: if (keyUsage & KU_DATA_ENCIPHERMENT) { michael@0: nssComponent->GetPIPNSSBundleString("CertDumpKUDEnc", local); michael@0: text.Append(local.get()); michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR).get()); michael@0: } michael@0: if (keyUsage & KU_KEY_AGREEMENT) { michael@0: nssComponent->GetPIPNSSBundleString("CertDumpKUKA", local); michael@0: text.Append(local.get()); michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR).get()); michael@0: } michael@0: if (keyUsage & KU_KEY_CERT_SIGN) { michael@0: nssComponent->GetPIPNSSBundleString("CertDumpKUCertSign", local); michael@0: text.Append(local.get()); michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR).get()); michael@0: } michael@0: if (keyUsage & KU_CRL_SIGN) { michael@0: nssComponent->GetPIPNSSBundleString("CertDumpKUCRLSigner", local); michael@0: text.Append(local.get()); michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR).get()); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessBasicConstraints(SECItem *extData, michael@0: nsAString &text, michael@0: nsINSSComponent *nssComponent) michael@0: { michael@0: nsAutoString local; michael@0: CERTBasicConstraints value; michael@0: SECStatus rv; michael@0: nsresult rv2; michael@0: michael@0: value.pathLenConstraint = -1; michael@0: rv = CERT_DecodeBasicConstraintValue (&value, extData); michael@0: if (rv != SECSuccess) { michael@0: ProcessRawBytes(nssComponent, extData, text); michael@0: return NS_OK; michael@0: } michael@0: if (value.isCA) michael@0: rv2 = nssComponent->GetPIPNSSBundleString("CertDumpIsCA", local); michael@0: else michael@0: rv2 = nssComponent->GetPIPNSSBundleString("CertDumpIsNotCA", local); michael@0: if (NS_FAILED(rv2)) michael@0: return rv2; michael@0: text.Append(local.get()); michael@0: if (value.pathLenConstraint != -1) { michael@0: nsAutoString depth; michael@0: if (value.pathLenConstraint == CERT_UNLIMITED_PATH_CONSTRAINT) michael@0: nssComponent->GetPIPNSSBundleString("CertDumpPathLenUnlimited", depth); michael@0: else michael@0: depth.AppendInt(value.pathLenConstraint); michael@0: const char16_t *params[1] = {depth.get()}; michael@0: rv2 = nssComponent->PIPBundleFormatStringFromName("CertDumpPathLen", michael@0: params, 1, local); michael@0: if (NS_FAILED(rv2)) michael@0: return rv2; michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR).get()); michael@0: text.Append(local.get()); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessExtKeyUsage(SECItem *extData, michael@0: nsAString &text, michael@0: nsINSSComponent *nssComponent) michael@0: { michael@0: nsAutoString local; michael@0: CERTOidSequence *extKeyUsage = nullptr; michael@0: SECItem **oids; michael@0: SECItem *oid; michael@0: nsresult rv; michael@0: michael@0: extKeyUsage = CERT_DecodeOidSequence(extData); michael@0: if (!extKeyUsage) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: oids = extKeyUsage->oids; michael@0: while (oids && *oids) { michael@0: // For each OID, try to find a bundle string michael@0: // of the form CertDumpEKU_ michael@0: nsAutoString oidname; michael@0: oid = *oids; michael@0: rv = GetDefaultOIDFormat(oid, nssComponent, oidname, '_'); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: nsAutoString bundlekey = NS_LITERAL_STRING("CertDumpEKU_")+ oidname; michael@0: NS_ConvertUTF16toUTF8 bk_ascii(bundlekey); michael@0: michael@0: rv = nssComponent->GetPIPNSSBundleString(bk_ascii.get(), local); michael@0: nsresult rv2 = GetDefaultOIDFormat(oid, nssComponent, oidname, '.'); michael@0: if (NS_FAILED(rv2)) michael@0: return rv2; michael@0: if (NS_SUCCEEDED(rv)) { michael@0: // display name and OID in parentheses michael@0: text.Append(local); michael@0: text.Append(NS_LITERAL_STRING(" (")); michael@0: text.Append(oidname); michael@0: text.Append(NS_LITERAL_STRING(")")); michael@0: } else michael@0: // If there is no bundle string, just display the OID itself michael@0: text.Append(oidname); michael@0: michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR).get()); michael@0: oids++; michael@0: } michael@0: michael@0: CERT_DestroyOidSequence(extKeyUsage); michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessRDN(CERTRDN* rdn, nsAString &finalString, nsINSSComponent *nssComponent) michael@0: { michael@0: nsresult rv; michael@0: CERTAVA** avas; michael@0: CERTAVA* ava; michael@0: SECItem *decodeItem = nullptr; michael@0: nsString avavalue; michael@0: nsString type; michael@0: nsAutoString temp; michael@0: const char16_t *params[2]; michael@0: michael@0: avas = rdn->avas; michael@0: while ((ava = *avas++) != 0) { michael@0: rv = GetOIDText(&ava->type, nssComponent, type); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: //This function returns a string in UTF8 format. michael@0: decodeItem = CERT_DecodeAVAValue(&ava->value); michael@0: if(!decodeItem) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // We know we can fit buffer of this length. CERT_RFC1485_EscapeAndQuote michael@0: // will fail if we provide smaller buffer then the result can fit to. michael@0: int escapedValueCapacity = decodeItem->len * 3 + 3; michael@0: ScopedDeleteArray escapedValue(new char[escapedValueCapacity]); michael@0: michael@0: SECStatus status = CERT_RFC1485_EscapeAndQuote( michael@0: escapedValue.get(), michael@0: escapedValueCapacity, michael@0: (char*)decodeItem->data, michael@0: decodeItem->len); michael@0: if (SECSuccess != status) { michael@0: SECITEM_FreeItem(decodeItem, true); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: avavalue = NS_ConvertUTF8toUTF16(escapedValue); michael@0: michael@0: SECITEM_FreeItem(decodeItem, true); michael@0: params[0] = type.get(); michael@0: params[1] = avavalue.get(); michael@0: nssComponent->PIPBundleFormatStringFromName("AVATemplate", michael@0: params, 2, temp); michael@0: finalString += temp + NS_LITERAL_STRING("\n"); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessName(CERTName *name, nsINSSComponent *nssComponent, char16_t **value) michael@0: { michael@0: CERTRDN** rdns; michael@0: CERTRDN** rdn; michael@0: nsString finalString; michael@0: michael@0: rdns = name->rdns; michael@0: michael@0: nsresult rv; michael@0: CERTRDN **lastRdn; michael@0: lastRdn = rdns; michael@0: michael@0: michael@0: /* find last RDN */ michael@0: lastRdn = rdns; michael@0: while (*lastRdn) lastRdn++; michael@0: // The above whille loop will put us at the last member michael@0: // of the array which is a nullptr pointer. So let's back michael@0: // up one spot so that we have the last non-nullptr entry in michael@0: // the array in preparation for traversing the michael@0: // RDN's (Relative Distinguished Name) in reverse oder. michael@0: lastRdn--; michael@0: michael@0: /* michael@0: * Loop over name contents in _reverse_ RDN order appending to string michael@0: * When building the Ascii string, NSS loops over these entries in michael@0: * reverse order, so I will as well. The difference is that NSS michael@0: * will always place them in a one line string separated by commas, michael@0: * where I want each entry on a single line. I can't just use a comma michael@0: * as my delimitter because it is a valid character to have in the michael@0: * value portion of the AVA and could cause trouble when parsing. michael@0: */ michael@0: for (rdn = lastRdn; rdn >= rdns; rdn--) { michael@0: rv = ProcessRDN(*rdn, finalString, nssComponent); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: } michael@0: *value = ToNewUnicode(finalString); michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessIA5String(SECItem *extData, michael@0: nsAString &text, michael@0: nsINSSComponent *nssComponent) michael@0: { michael@0: SECItem item; michael@0: nsAutoString local; michael@0: if (SECSuccess != SEC_ASN1DecodeItem(nullptr, &item, michael@0: SEC_ASN1_GET(SEC_IA5StringTemplate), michael@0: extData)) michael@0: return NS_ERROR_FAILURE; michael@0: local.AssignASCII((char*)item.data, item.len); michael@0: nsMemory::Free(item.data); michael@0: text.Append(local); michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsresult michael@0: AppendBMPtoUTF16(PLArenaPool *arena, michael@0: unsigned char* data, unsigned int len, michael@0: nsAString& text) michael@0: { michael@0: unsigned int utf8ValLen; michael@0: unsigned char *utf8Val; michael@0: michael@0: if (len % 2 != 0) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: /* XXX instead of converting to and from UTF-8, it would michael@0: be sufficient to just swap bytes, or do nothing */ michael@0: utf8ValLen = len * 3 + 1; michael@0: utf8Val = (unsigned char*)PORT_ArenaZAlloc(arena, utf8ValLen); michael@0: if (!PORT_UCS2_UTF8Conversion(false, data, len, michael@0: utf8Val, utf8ValLen, &utf8ValLen)) michael@0: return NS_ERROR_FAILURE; michael@0: AppendUTF8toUTF16((char*)utf8Val, text); michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessBMPString(SECItem *extData, michael@0: nsAString &text, michael@0: nsINSSComponent *nssComponent) michael@0: { michael@0: SECItem item; michael@0: PLArenaPool *arena; michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if (!arena) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: if (SECSuccess == SEC_ASN1DecodeItem(arena, &item, michael@0: SEC_ASN1_GET(SEC_BMPStringTemplate), michael@0: extData)) michael@0: rv = AppendBMPtoUTF16(arena, item.data, item.len, text); michael@0: PORT_FreeArena(arena, false); michael@0: return rv; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessGeneralName(PLArenaPool *arena, michael@0: CERTGeneralName *current, michael@0: nsAString &text, michael@0: nsINSSComponent *nssComponent) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(current); michael@0: michael@0: nsAutoString key; michael@0: nsXPIDLString value; michael@0: nsresult rv = NS_OK; michael@0: michael@0: switch (current->type) { michael@0: case certOtherName: { michael@0: SECOidTag oidTag = SECOID_FindOIDTag(¤t->name.OthName.oid); michael@0: if (oidTag == SEC_OID(MS_NT_PRINCIPAL_NAME)) { michael@0: /* The type of this name is apparently nowhere explicitly michael@0: documented. However, in the generated templates, it is always michael@0: UTF-8. So try to decode this as UTF-8; if that fails, dump the michael@0: raw data. */ michael@0: SECItem decoded; michael@0: nssComponent->GetPIPNSSBundleString("CertDumpMSNTPrincipal", key); michael@0: if (SEC_ASN1DecodeItem(arena, &decoded, michael@0: SEC_ASN1_GET(SEC_UTF8StringTemplate), michael@0: ¤t->name.OthName.name) == SECSuccess) { michael@0: AppendUTF8toUTF16(nsAutoCString((char*)decoded.data, decoded.len), michael@0: value); michael@0: } else { michael@0: ProcessRawBytes(nssComponent, ¤t->name.OthName.name, value); michael@0: } michael@0: break; michael@0: } else if (oidTag == SEC_OID(MS_NTDS_REPLICATION)) { michael@0: /* This should be a 16-byte GUID */ michael@0: SECItem guid; michael@0: nssComponent->GetPIPNSSBundleString("CertDumpMSDomainGUID", key); michael@0: if (SEC_ASN1DecodeItem(arena, &guid, michael@0: SEC_ASN1_GET(SEC_OctetStringTemplate), michael@0: ¤t->name.OthName.name) == SECSuccess michael@0: && guid.len == 16) { michael@0: char buf[40]; michael@0: unsigned char *d = guid.data; michael@0: PR_snprintf(buf, sizeof(buf), michael@0: "{%.2x%.2x%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x}", michael@0: d[3], d[2], d[1], d[0], d[5], d[4], d[7], d[6], michael@0: d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]); michael@0: value.AssignASCII(buf); michael@0: } else { michael@0: ProcessRawBytes(nssComponent, ¤t->name.OthName.name, value); michael@0: } michael@0: } else { michael@0: rv = GetDefaultOIDFormat(¤t->name.OthName.oid, nssComponent, key, ' '); michael@0: if (NS_FAILED(rv)) michael@0: goto finish; michael@0: ProcessRawBytes(nssComponent, ¤t->name.OthName.name, value); michael@0: } michael@0: break; michael@0: } michael@0: case certRFC822Name: michael@0: nssComponent->GetPIPNSSBundleString("CertDumpRFC822Name", key); michael@0: value.AssignASCII((char*)current->name.other.data, current->name.other.len); michael@0: break; michael@0: case certDNSName: michael@0: nssComponent->GetPIPNSSBundleString("CertDumpDNSName", key); michael@0: value.AssignASCII((char*)current->name.other.data, current->name.other.len); michael@0: break; michael@0: case certX400Address: michael@0: nssComponent->GetPIPNSSBundleString("CertDumpX400Address", key); michael@0: ProcessRawBytes(nssComponent, ¤t->name.other, value); michael@0: break; michael@0: case certDirectoryName: michael@0: nssComponent->GetPIPNSSBundleString("CertDumpDirectoryName", key); michael@0: rv = ProcessName(¤t->name.directoryName, nssComponent, michael@0: getter_Copies(value)); michael@0: if (NS_FAILED(rv)) michael@0: goto finish; michael@0: break; michael@0: case certEDIPartyName: michael@0: nssComponent->GetPIPNSSBundleString("CertDumpEDIPartyName", key); michael@0: ProcessRawBytes(nssComponent, ¤t->name.other, value); michael@0: break; michael@0: case certURI: michael@0: nssComponent->GetPIPNSSBundleString("CertDumpURI", key); michael@0: value.AssignASCII((char*)current->name.other.data, current->name.other.len); michael@0: break; michael@0: case certIPAddress: michael@0: { michael@0: char buf[INET6_ADDRSTRLEN]; michael@0: PRStatus status = PR_FAILURE; michael@0: PRNetAddr addr; michael@0: memset(&addr, 0, sizeof(addr)); michael@0: nssComponent->GetPIPNSSBundleString("CertDumpIPAddress", key); michael@0: if (current->name.other.len == 4) { michael@0: addr.inet.family = PR_AF_INET; michael@0: memcpy(&addr.inet.ip, current->name.other.data, current->name.other.len); michael@0: status = PR_NetAddrToString(&addr, buf, sizeof(buf)); michael@0: } else if (current->name.other.len == 16) { michael@0: addr.ipv6.family = PR_AF_INET6; michael@0: memcpy(&addr.ipv6.ip, current->name.other.data, current->name.other.len); michael@0: status = PR_NetAddrToString(&addr, buf, sizeof(buf)); michael@0: } michael@0: if (status == PR_SUCCESS) { michael@0: value.AssignASCII(buf); michael@0: } else { michael@0: /* invalid IP address */ michael@0: ProcessRawBytes(nssComponent, ¤t->name.other, value); michael@0: } michael@0: break; michael@0: } michael@0: case certRegisterID: michael@0: nssComponent->GetPIPNSSBundleString("CertDumpRegisterID", key); michael@0: rv = GetDefaultOIDFormat(¤t->name.other, nssComponent, value, '.'); michael@0: if (NS_FAILED(rv)) michael@0: goto finish; michael@0: break; michael@0: } michael@0: text.Append(key); michael@0: text.Append(NS_LITERAL_STRING(": ")); michael@0: text.Append(value); michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR)); michael@0: finish: michael@0: return rv; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessGeneralNames(PLArenaPool *arena, michael@0: CERTGeneralName *nameList, michael@0: nsAString &text, michael@0: nsINSSComponent *nssComponent) michael@0: { michael@0: CERTGeneralName *current = nameList; michael@0: nsresult rv; michael@0: michael@0: do { michael@0: rv = ProcessGeneralName(arena, current, text, nssComponent); michael@0: if (NS_FAILED(rv)) michael@0: break; michael@0: current = CERT_GetNextGeneralName(current); michael@0: } while (current != nameList); michael@0: return rv; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessAltName(SECItem *extData, michael@0: nsAString &text, michael@0: nsINSSComponent *nssComponent) michael@0: { michael@0: nsresult rv = NS_OK; michael@0: PLArenaPool *arena; michael@0: CERTGeneralName *nameList; michael@0: michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if (!arena) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nameList = CERT_DecodeAltNameExtension(arena, extData); michael@0: if (!nameList) michael@0: goto finish; michael@0: michael@0: rv = ProcessGeneralNames(arena, nameList, text, nssComponent); michael@0: michael@0: finish: michael@0: PORT_FreeArena(arena, false); michael@0: return rv; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessSubjectKeyId(SECItem *extData, michael@0: nsAString &text, michael@0: nsINSSComponent *nssComponent) michael@0: { michael@0: PLArenaPool *arena; michael@0: nsresult rv = NS_OK; michael@0: SECItem decoded; michael@0: nsAutoString local; michael@0: michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if (!arena) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: if (SEC_QuickDERDecodeItem(arena, &decoded, michael@0: SEC_ASN1_GET(SEC_OctetStringTemplate), michael@0: extData) != SECSuccess) { michael@0: rv = NS_ERROR_FAILURE; michael@0: goto finish; michael@0: } michael@0: michael@0: nssComponent->GetPIPNSSBundleString("CertDumpKeyID", local); michael@0: text.Append(local); michael@0: text.Append(NS_LITERAL_STRING(": ")); michael@0: ProcessRawBytes(nssComponent, &decoded, text); michael@0: michael@0: finish: michael@0: PORT_FreeArena(arena, false); michael@0: return rv; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessAuthKeyId(SECItem *extData, michael@0: nsAString &text, michael@0: nsINSSComponent *nssComponent) michael@0: { michael@0: CERTAuthKeyID *ret; michael@0: PLArenaPool *arena; michael@0: nsresult rv = NS_OK; michael@0: nsAutoString local; michael@0: michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if (!arena) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: ret = CERT_DecodeAuthKeyID (arena, extData); michael@0: if (!ret) { michael@0: rv = NS_ERROR_FAILURE; michael@0: goto finish; michael@0: } michael@0: michael@0: if (ret->keyID.len > 0) { michael@0: nssComponent->GetPIPNSSBundleString("CertDumpKeyID", local); michael@0: text.Append(local); michael@0: text.Append(NS_LITERAL_STRING(": ")); michael@0: ProcessRawBytes(nssComponent, &ret->keyID, text); michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR)); michael@0: } michael@0: michael@0: if (ret->authCertIssuer) { michael@0: nssComponent->GetPIPNSSBundleString("CertDumpIssuer", local); michael@0: text.Append(local); michael@0: text.Append(NS_LITERAL_STRING(": ")); michael@0: rv = ProcessGeneralNames(arena, ret->authCertIssuer, text, nssComponent); michael@0: if (NS_FAILED(rv)) michael@0: goto finish; michael@0: } michael@0: michael@0: if (ret->authCertSerialNumber.len > 0) { michael@0: nssComponent->GetPIPNSSBundleString("CertDumpSerialNo", local); michael@0: text.Append(local); michael@0: text.Append(NS_LITERAL_STRING(": ")); michael@0: ProcessRawBytes(nssComponent, &ret->authCertSerialNumber, text); michael@0: } michael@0: michael@0: finish: michael@0: PORT_FreeArena(arena, false); michael@0: return rv; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessUserNotice(SECItem *der_notice, michael@0: nsAString &text, michael@0: nsINSSComponent *nssComponent) michael@0: { michael@0: CERTUserNotice *notice = nullptr; michael@0: SECItem **itemList; michael@0: PLArenaPool *arena; michael@0: michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if (!arena) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: notice = CERT_DecodeUserNotice(der_notice); michael@0: if (!notice) { michael@0: ProcessRawBytes(nssComponent, der_notice, text); michael@0: goto finish; michael@0: } michael@0: michael@0: if (notice->noticeReference.organization.len != 0) { michael@0: switch (notice->noticeReference.organization.type) { michael@0: case siAsciiString: michael@0: case siVisibleString: michael@0: case siUTF8String: michael@0: text.Append(NS_ConvertUTF8toUTF16( michael@0: (const char *)notice->noticeReference.organization.data, michael@0: notice->noticeReference.organization.len)); michael@0: break; michael@0: case siBMPString: michael@0: AppendBMPtoUTF16(arena, notice->noticeReference.organization.data, michael@0: notice->noticeReference.organization.len, text); michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: text.Append(NS_LITERAL_STRING(" - ")); michael@0: itemList = notice->noticeReference.noticeNumbers; michael@0: while (*itemList) { michael@0: unsigned long number; michael@0: char buffer[60]; michael@0: if (SEC_ASN1DecodeInteger(*itemList, &number) == SECSuccess) { michael@0: PR_snprintf(buffer, sizeof(buffer), "#%d", number); michael@0: if (itemList != notice->noticeReference.noticeNumbers) michael@0: text.Append(NS_LITERAL_STRING(", ")); michael@0: AppendASCIItoUTF16(buffer, text); michael@0: } michael@0: itemList++; michael@0: } michael@0: } michael@0: if (notice->displayText.len != 0) { michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR)); michael@0: text.Append(NS_LITERAL_STRING(" ")); michael@0: switch (notice->displayText.type) { michael@0: case siAsciiString: michael@0: case siVisibleString: michael@0: case siUTF8String: michael@0: text.Append(NS_ConvertUTF8toUTF16((const char *)notice->displayText.data, michael@0: notice->displayText.len)); michael@0: break; michael@0: case siBMPString: michael@0: AppendBMPtoUTF16(arena, notice->displayText.data, notice->displayText.len, michael@0: text); michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: } michael@0: finish: michael@0: if (notice) michael@0: CERT_DestroyUserNotice(notice); michael@0: PORT_FreeArena(arena, false); michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessCertificatePolicies(SECItem *extData, michael@0: nsAString &text, michael@0: SECOidTag ev_oid_tag, // SEC_OID_UNKNOWN means: not EV michael@0: nsINSSComponent *nssComponent) michael@0: { michael@0: CERTCertificatePolicies *policies; michael@0: CERTPolicyInfo **policyInfos, *policyInfo; michael@0: CERTPolicyQualifier **policyQualifiers, *policyQualifier; michael@0: nsAutoString local; michael@0: nsresult rv = NS_OK; michael@0: michael@0: policies = CERT_DecodeCertificatePoliciesExtension(extData); michael@0: if (!policies) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: policyInfos = policies->policyInfos; michael@0: while (*policyInfos) { michael@0: policyInfo = *policyInfos++; michael@0: switch (policyInfo->oid) { michael@0: case SEC_OID_VERISIGN_USER_NOTICES: michael@0: nssComponent->GetPIPNSSBundleString("CertDumpVerisignNotices", local); michael@0: text.Append(local); michael@0: break; michael@0: default: michael@0: GetDefaultOIDFormat(&policyInfo->policyID, nssComponent, local, '.'); michael@0: text.Append(local); michael@0: } michael@0: michael@0: bool needColon = true; michael@0: if (ev_oid_tag != SEC_OID_UNKNOWN) { michael@0: // This is an EV cert. Let's see if this oid is the EV oid, michael@0: // because we want to display the EV information string michael@0: // next to the correct OID. michael@0: michael@0: if (policyInfo->oid == ev_oid_tag) { michael@0: text.Append(NS_LITERAL_STRING(":")); michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR)); michael@0: needColon = false; michael@0: nssComponent->GetPIPNSSBundleString("CertDumpPolicyOidEV", local); michael@0: text.Append(local); michael@0: } michael@0: } michael@0: michael@0: if (policyInfo->policyQualifiers) { michael@0: /* Add all qualifiers on separate lines, indented */ michael@0: policyQualifiers = policyInfo->policyQualifiers; michael@0: if (needColon) michael@0: text.Append(NS_LITERAL_STRING(":")); michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR)); michael@0: while (*policyQualifiers) { michael@0: text.Append(NS_LITERAL_STRING(" ")); michael@0: policyQualifier = *policyQualifiers++; michael@0: switch(policyQualifier->oid) { michael@0: case SEC_OID_PKIX_CPS_POINTER_QUALIFIER: michael@0: nssComponent->GetPIPNSSBundleString("CertDumpCPSPointer", local); michael@0: text.Append(local); michael@0: text.Append(NS_LITERAL_STRING(":")); michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR)); michael@0: text.Append(NS_LITERAL_STRING(" ")); michael@0: /* The CPS pointer ought to be the cPSuri alternative michael@0: of the Qualifier choice. */ michael@0: rv = ProcessIA5String(&policyQualifier->qualifierValue, michael@0: text, nssComponent); michael@0: if (NS_FAILED(rv)) michael@0: goto finish; michael@0: break; michael@0: case SEC_OID_PKIX_USER_NOTICE_QUALIFIER: michael@0: nssComponent->GetPIPNSSBundleString("CertDumpUserNotice", local); michael@0: text.Append(local); michael@0: text.Append(NS_LITERAL_STRING(": ")); michael@0: rv = ProcessUserNotice(&policyQualifier->qualifierValue, michael@0: text, nssComponent); michael@0: break; michael@0: default: michael@0: GetDefaultOIDFormat(&policyQualifier->qualifierID, nssComponent, local, '.'); michael@0: text.Append(local); michael@0: text.Append(NS_LITERAL_STRING(": ")); michael@0: ProcessRawBytes(nssComponent, &policyQualifier->qualifierValue, text); michael@0: } michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR)); michael@0: } /* while policyQualifiers */ michael@0: } /* if policyQualifiers */ michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR)); michael@0: } michael@0: michael@0: finish: michael@0: CERT_DestroyCertificatePoliciesExtension(policies); michael@0: return rv; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessCrlDistPoints(SECItem *extData, michael@0: nsAString &text, michael@0: nsINSSComponent *nssComponent) michael@0: { michael@0: CERTCrlDistributionPoints *crldp; michael@0: CRLDistributionPoint **points, *point; michael@0: PLArenaPool *arena; michael@0: nsresult rv = NS_OK; michael@0: nsAutoString local; michael@0: int reasons, comma; michael@0: michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if (!arena) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: crldp = CERT_DecodeCRLDistributionPoints(arena, extData); michael@0: if (!crldp || !crldp->distPoints) { michael@0: rv = NS_ERROR_FAILURE; michael@0: goto finish; michael@0: } michael@0: michael@0: for(points = crldp->distPoints; *points; points++) { michael@0: point = *points; michael@0: switch (point->distPointType) { michael@0: case generalName: michael@0: rv = ProcessGeneralName(arena, point->distPoint.fullName, michael@0: text, nssComponent); michael@0: if (NS_FAILED(rv)) michael@0: goto finish; michael@0: break; michael@0: case relativeDistinguishedName: michael@0: rv = ProcessRDN(&point->distPoint.relativeName, michael@0: text, nssComponent); michael@0: if (NS_FAILED(rv)) michael@0: goto finish; michael@0: break; michael@0: } michael@0: if (point->reasons.len) { michael@0: reasons = point->reasons.data[0]; michael@0: text.Append(NS_LITERAL_STRING(" ")); michael@0: comma = 0; michael@0: if (reasons & RF_UNUSED) { michael@0: nssComponent->GetPIPNSSBundleString("CertDumpUnused", local); michael@0: text.Append(local); comma = 1; michael@0: } michael@0: if (reasons & RF_KEY_COMPROMISE) { michael@0: if (comma) text.Append(NS_LITERAL_STRING(", ")); michael@0: nssComponent->GetPIPNSSBundleString("CertDumpKeyCompromise", local); michael@0: text.Append(local); comma = 1; michael@0: } michael@0: if (reasons & RF_CA_COMPROMISE) { michael@0: if (comma) text.Append(NS_LITERAL_STRING(", ")); michael@0: nssComponent->GetPIPNSSBundleString("CertDumpCACompromise", local); michael@0: text.Append(local); comma = 1; michael@0: } michael@0: if (reasons & RF_AFFILIATION_CHANGED) { michael@0: if (comma) text.Append(NS_LITERAL_STRING(", ")); michael@0: nssComponent->GetPIPNSSBundleString("CertDumpAffiliationChanged", local); michael@0: text.Append(local); comma = 1; michael@0: } michael@0: if (reasons & RF_SUPERSEDED) { michael@0: if (comma) text.Append(NS_LITERAL_STRING(", ")); michael@0: nssComponent->GetPIPNSSBundleString("CertDumpSuperseded", local); michael@0: text.Append(local); comma = 1; michael@0: } michael@0: if (reasons & RF_CESSATION_OF_OPERATION) { michael@0: if (comma) text.Append(NS_LITERAL_STRING(", ")); michael@0: nssComponent->GetPIPNSSBundleString("CertDumpCessation", local); michael@0: text.Append(local); comma = 1; michael@0: } michael@0: if (reasons & RF_CERTIFICATE_HOLD) { michael@0: if (comma) text.Append(NS_LITERAL_STRING(", ")); michael@0: nssComponent->GetPIPNSSBundleString("CertDumpHold", local); michael@0: text.Append(local); comma = 1; michael@0: } michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR)); michael@0: } michael@0: if (point->crlIssuer) { michael@0: nssComponent->GetPIPNSSBundleString("CertDumpIssuer", local); michael@0: text.Append(local); michael@0: text.Append(NS_LITERAL_STRING(": ")); michael@0: rv = ProcessGeneralNames(arena, point->crlIssuer, michael@0: text, nssComponent); michael@0: if (NS_FAILED(rv)) michael@0: goto finish; michael@0: } michael@0: } michael@0: michael@0: finish: michael@0: PORT_FreeArena(arena, false); michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessAuthInfoAccess(SECItem *extData, michael@0: nsAString &text, michael@0: nsINSSComponent *nssComponent) michael@0: { michael@0: CERTAuthInfoAccess **aia, *desc; michael@0: PLArenaPool *arena; michael@0: nsresult rv = NS_OK; michael@0: nsAutoString local; michael@0: michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if (!arena) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: aia = CERT_DecodeAuthInfoAccessExtension(arena, extData); michael@0: if (!aia) michael@0: goto finish; michael@0: michael@0: while (*aia) { michael@0: desc = *aia++; michael@0: switch (SECOID_FindOIDTag(&desc->method)) { michael@0: case SEC_OID_PKIX_OCSP: michael@0: nssComponent->GetPIPNSSBundleString("CertDumpOCSPResponder", local); michael@0: break; michael@0: case SEC_OID_PKIX_CA_ISSUERS: michael@0: nssComponent->GetPIPNSSBundleString("CertDumpCAIssuers", local); michael@0: break; michael@0: default: michael@0: rv = GetDefaultOIDFormat(&desc->method, nssComponent, local, '.'); michael@0: if (NS_FAILED(rv)) michael@0: goto finish; michael@0: } michael@0: text.Append(local); michael@0: text.Append(NS_LITERAL_STRING(": ")); michael@0: rv = ProcessGeneralName(arena, desc->location, text, nssComponent); michael@0: if (NS_FAILED(rv)) michael@0: goto finish; michael@0: } michael@0: michael@0: finish: michael@0: PORT_FreeArena(arena, false); michael@0: return rv; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessMSCAVersion(SECItem *extData, michael@0: nsAString &text, michael@0: nsINSSComponent *nssComponent) michael@0: { michael@0: unsigned long version; michael@0: nsresult rv; michael@0: char buf[50]; michael@0: SECItem decoded; michael@0: michael@0: if (SECSuccess != SEC_ASN1DecodeItem(nullptr, &decoded, michael@0: SEC_ASN1_GET(SEC_IntegerTemplate), michael@0: extData)) michael@0: /* This extension used to be an Integer when this code michael@0: was written, but apparently isn't anymore. Display michael@0: the raw bytes instead. */ michael@0: return ProcessRawBytes(nssComponent, extData, text); michael@0: michael@0: rv = GetIntValue(&decoded, &version); michael@0: nsMemory::Free(decoded.data); michael@0: if (NS_FAILED(rv)) michael@0: /* Value out of range, display raw bytes */ michael@0: return ProcessRawBytes(nssComponent, extData, text); michael@0: michael@0: /* Apparently, the encoding is , with 16 bits each */ michael@0: PR_snprintf(buf, sizeof(buf), "%d.%d", version & 0xFFFF, version>>16); michael@0: text.AppendASCII(buf); michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessExtensionData(SECOidTag oidTag, SECItem *extData, michael@0: nsAString &text, michael@0: SECOidTag ev_oid_tag, // SEC_OID_UNKNOWN means: not EV michael@0: nsINSSComponent *nssComponent) michael@0: { michael@0: nsresult rv; michael@0: switch (oidTag) { michael@0: case SEC_OID_NS_CERT_EXT_CERT_TYPE: michael@0: rv = ProcessNSCertTypeExtensions(extData, text, nssComponent); michael@0: break; michael@0: case SEC_OID_X509_KEY_USAGE: michael@0: rv = ProcessKeyUsageExtension(extData, text, nssComponent); michael@0: break; michael@0: case SEC_OID_X509_BASIC_CONSTRAINTS: michael@0: rv = ProcessBasicConstraints(extData, text, nssComponent); michael@0: break; michael@0: case SEC_OID_X509_EXT_KEY_USAGE: michael@0: rv = ProcessExtKeyUsage(extData, text, nssComponent); michael@0: break; michael@0: case SEC_OID_X509_ISSUER_ALT_NAME: michael@0: case SEC_OID_X509_SUBJECT_ALT_NAME: michael@0: rv = ProcessAltName(extData, text, nssComponent); michael@0: break; michael@0: case SEC_OID_X509_SUBJECT_KEY_ID: michael@0: rv = ProcessSubjectKeyId(extData, text, nssComponent); michael@0: break; michael@0: case SEC_OID_X509_AUTH_KEY_ID: michael@0: rv = ProcessAuthKeyId(extData, text, nssComponent); michael@0: break; michael@0: case SEC_OID_X509_CERTIFICATE_POLICIES: michael@0: rv = ProcessCertificatePolicies(extData, text, ev_oid_tag, nssComponent); michael@0: break; michael@0: case SEC_OID_X509_CRL_DIST_POINTS: michael@0: rv = ProcessCrlDistPoints(extData, text, nssComponent); michael@0: break; michael@0: case SEC_OID_X509_AUTH_INFO_ACCESS: michael@0: rv = ProcessAuthInfoAccess(extData, text, nssComponent); michael@0: break; michael@0: case SEC_OID_NS_CERT_EXT_BASE_URL: michael@0: case SEC_OID_NS_CERT_EXT_REVOCATION_URL: michael@0: case SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL: michael@0: case SEC_OID_NS_CERT_EXT_CA_CERT_URL: michael@0: case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL: michael@0: case SEC_OID_NS_CERT_EXT_CA_POLICY_URL: michael@0: case SEC_OID_NS_CERT_EXT_HOMEPAGE_URL: michael@0: case SEC_OID_NS_CERT_EXT_COMMENT: michael@0: case SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME: michael@0: case SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL: michael@0: rv = ProcessIA5String(extData, text, nssComponent); michael@0: break; michael@0: default: michael@0: if (oidTag == SEC_OID(MS_CERT_EXT_CERTTYPE)) { michael@0: rv = ProcessBMPString(extData, text, nssComponent); michael@0: break; michael@0: } michael@0: if (oidTag == SEC_OID(MS_CERTSERV_CA_VERSION)) { michael@0: rv = ProcessMSCAVersion(extData, text, nssComponent); michael@0: break; michael@0: } michael@0: rv = ProcessRawBytes(nssComponent, extData, text); michael@0: break; michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessSingleExtension(CERTCertExtension *extension, michael@0: SECOidTag ev_oid_tag, // SEC_OID_UNKNOWN means: not EV michael@0: nsINSSComponent *nssComponent, michael@0: nsIASN1PrintableItem **retExtension) michael@0: { michael@0: nsAutoString text, extvalue; michael@0: GetOIDText(&extension->id, nssComponent, text); michael@0: nsCOMPtrextensionItem = new nsNSSASN1PrintableItem(); michael@0: michael@0: extensionItem->SetDisplayName(text); michael@0: SECOidTag oidTag = SECOID_FindOIDTag(&extension->id); michael@0: text.Truncate(); michael@0: if (extension->critical.data) { michael@0: if (extension->critical.data[0]) { michael@0: nssComponent->GetPIPNSSBundleString("CertDumpCritical", text); michael@0: } else { michael@0: nssComponent->GetPIPNSSBundleString("CertDumpNonCritical", text); michael@0: } michael@0: } else { michael@0: nssComponent->GetPIPNSSBundleString("CertDumpNonCritical", text); michael@0: } michael@0: text.Append(NS_LITERAL_STRING(SEPARATOR).get()); michael@0: nsresult rv = ProcessExtensionData(oidTag, &extension->value, extvalue, michael@0: ev_oid_tag, nssComponent); michael@0: if (NS_FAILED(rv)) { michael@0: extvalue.Truncate(); michael@0: rv = ProcessRawBytes(nssComponent, &extension->value, extvalue, false); michael@0: } michael@0: text.Append(extvalue); michael@0: michael@0: extensionItem->SetDisplayValue(text); michael@0: *retExtension = extensionItem; michael@0: NS_ADDREF(*retExtension); michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessSECAlgorithmID(SECAlgorithmID *algID, michael@0: nsINSSComponent *nssComponent, michael@0: nsIASN1Sequence **retSequence) michael@0: { michael@0: SECOidTag algOIDTag = SECOID_FindOIDTag(&algID->algorithm); michael@0: SECItem paramsOID = { siBuffer, nullptr, 0 }; michael@0: nsCOMPtr sequence = new nsNSSASN1Sequence(); michael@0: michael@0: *retSequence = nullptr; michael@0: nsString text; michael@0: GetOIDText(&algID->algorithm, nssComponent, text); michael@0: if (!algID->parameters.len || algID->parameters.data[0] == nsIASN1Object::ASN1_NULL) { michael@0: sequence->SetDisplayValue(text); michael@0: sequence->SetIsValidContainer(false); michael@0: } else { michael@0: nsCOMPtr printableItem = new nsNSSASN1PrintableItem(); michael@0: michael@0: printableItem->SetDisplayValue(text); michael@0: nsCOMPtr asn1Objects; michael@0: sequence->GetASN1Objects(getter_AddRefs(asn1Objects)); michael@0: asn1Objects->AppendElement(printableItem, false); michael@0: nssComponent->GetPIPNSSBundleString("CertDumpAlgID", text); michael@0: printableItem->SetDisplayName(text); michael@0: michael@0: printableItem = new nsNSSASN1PrintableItem(); michael@0: michael@0: asn1Objects->AppendElement(printableItem, false); michael@0: nssComponent->GetPIPNSSBundleString("CertDumpParams", text); michael@0: printableItem->SetDisplayName(text); michael@0: if ((algOIDTag == SEC_OID_ANSIX962_EC_PUBLIC_KEY) && michael@0: (algID->parameters.len > 2) && michael@0: (algID->parameters.data[0] == nsIASN1Object::ASN1_OBJECT_ID)) { michael@0: paramsOID.len = algID->parameters.len - 2; michael@0: paramsOID.data = algID->parameters.data + 2; michael@0: GetOIDText(¶msOID, nssComponent, text); michael@0: } else { michael@0: ProcessRawBytes(nssComponent, &algID->parameters,text); michael@0: } michael@0: printableItem->SetDisplayValue(text); michael@0: } michael@0: *retSequence = sequence; michael@0: NS_ADDREF(*retSequence); michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessTime(PRTime dispTime, const char16_t *displayName, michael@0: nsIASN1Sequence *parentSequence) michael@0: { michael@0: nsresult rv; michael@0: nsCOMPtr dateFormatter = michael@0: do_CreateInstance(NS_DATETIMEFORMAT_CONTRACTID, &rv); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: nsString text; michael@0: nsString tempString; michael@0: michael@0: PRExplodedTime explodedTime; michael@0: PR_ExplodeTime(dispTime, PR_LocalTimeParameters, &explodedTime); michael@0: michael@0: dateFormatter->FormatPRExplodedTime(nullptr, kDateFormatShort, kTimeFormatSecondsForce24Hour, michael@0: &explodedTime, tempString); michael@0: michael@0: text.Append(tempString); michael@0: text.AppendLiteral("\n("); michael@0: michael@0: PRExplodedTime explodedTimeGMT; michael@0: PR_ExplodeTime(dispTime, PR_GMTParameters, &explodedTimeGMT); michael@0: michael@0: dateFormatter->FormatPRExplodedTime(nullptr, kDateFormatShort, kTimeFormatSecondsForce24Hour, michael@0: &explodedTimeGMT, tempString); michael@0: michael@0: text.Append(tempString); michael@0: text.Append(NS_LITERAL_STRING(" GMT)")); michael@0: michael@0: nsCOMPtr printableItem = new nsNSSASN1PrintableItem(); michael@0: michael@0: printableItem->SetDisplayValue(text); michael@0: printableItem->SetDisplayName(nsDependentString(displayName)); michael@0: nsCOMPtr asn1Objects; michael@0: parentSequence->GetASN1Objects(getter_AddRefs(asn1Objects)); michael@0: asn1Objects->AppendElement(printableItem, false); michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessSubjectPublicKeyInfo(CERTSubjectPublicKeyInfo *spki, michael@0: nsIASN1Sequence *parentSequence, michael@0: nsINSSComponent *nssComponent) michael@0: { michael@0: nsCOMPtr spkiSequence = new nsNSSASN1Sequence(); michael@0: michael@0: nsString text; michael@0: nssComponent->GetPIPNSSBundleString("CertDumpSPKI", text); michael@0: spkiSequence->SetDisplayName(text); michael@0: michael@0: nssComponent->GetPIPNSSBundleString("CertDumpSPKIAlg", text); michael@0: nsCOMPtr sequenceItem; michael@0: nsresult rv = ProcessSECAlgorithmID(&spki->algorithm, nssComponent, michael@0: getter_AddRefs(sequenceItem)); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: sequenceItem->SetDisplayName(text); michael@0: nsCOMPtr asn1Objects; michael@0: spkiSequence->GetASN1Objects(getter_AddRefs(asn1Objects)); michael@0: asn1Objects->AppendElement(sequenceItem, false); michael@0: michael@0: nsCOMPtr printableItem = new nsNSSASN1PrintableItem(); michael@0: michael@0: text.Truncate(); michael@0: michael@0: SECKEYPublicKey *key = SECKEY_ExtractPublicKey(spki); michael@0: bool displayed = false; michael@0: if (key) { michael@0: switch (key->keyType) { michael@0: case rsaKey: { michael@0: displayed = true; michael@0: nsAutoString length1, length2, data1, data2; michael@0: length1.AppendInt(key->u.rsa.modulus.len * 8); michael@0: length2.AppendInt(key->u.rsa.publicExponent.len * 8); michael@0: ProcessRawBytes(nssComponent, &key->u.rsa.modulus, data1, michael@0: false); michael@0: ProcessRawBytes(nssComponent, &key->u.rsa.publicExponent, data2, michael@0: false); michael@0: const char16_t *params[4] = {length1.get(), data1.get(), michael@0: length2.get(), data2.get()}; michael@0: nssComponent->PIPBundleFormatStringFromName("CertDumpRSATemplate", michael@0: params, 4, text); michael@0: break; michael@0: } michael@0: case ecKey: { michael@0: displayed = true; michael@0: SECKEYECPublicKey &ecpk = key->u.ec; michael@0: int fieldSizeLenAsBits = michael@0: SECKEY_ECParamsToKeySize(&ecpk.DEREncodedParams); michael@0: int basePointOrderLenAsBits = michael@0: SECKEY_ECParamsToBasePointOrderLen(&ecpk.DEREncodedParams); michael@0: nsAutoString s_fsl, s_bpol, s_pv; michael@0: s_fsl.AppendInt(fieldSizeLenAsBits); michael@0: s_bpol.AppendInt(basePointOrderLenAsBits); michael@0: michael@0: if (ecpk.publicValue.len > 4) { michael@0: ProcessRawBytes(nssComponent, &ecpk.publicValue, s_pv, false); michael@0: } else { michael@0: int i_pv = DER_GetInteger(&ecpk.publicValue); michael@0: s_pv.AppendInt(i_pv); michael@0: } michael@0: const char16_t *params[] = {s_fsl.get(), s_bpol.get(), s_pv.get()}; michael@0: nssComponent->PIPBundleFormatStringFromName("CertDumpECTemplate", michael@0: params, 3, text); michael@0: break; michael@0: } michael@0: default: michael@0: /* Algorithm unknown, or too rarely used to bother displaying it */ michael@0: break; michael@0: } michael@0: SECKEY_DestroyPublicKey (key); michael@0: } michael@0: if (!displayed) { michael@0: // Algorithm unknown, display raw bytes michael@0: // The subjectPublicKey field is encoded as a bit string. michael@0: // ProcessRawBytes expects the length to be in bytes, so michael@0: // let's convert the lenght into a temporary SECItem. michael@0: SECItem data; michael@0: data.data = spki->subjectPublicKey.data; michael@0: data.len = spki->subjectPublicKey.len / 8; michael@0: ProcessRawBytes(nssComponent, &data, text); michael@0: michael@0: } michael@0: michael@0: printableItem->SetDisplayValue(text); michael@0: nssComponent->GetPIPNSSBundleString("CertDumpSubjPubKey", text); michael@0: printableItem->SetDisplayName(text); michael@0: asn1Objects->AppendElement(printableItem, false); michael@0: michael@0: parentSequence->GetASN1Objects(getter_AddRefs(asn1Objects)); michael@0: asn1Objects->AppendElement(spkiSequence, false); michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsresult michael@0: ProcessExtensions(CERTCertExtension **extensions, michael@0: nsIASN1Sequence *parentSequence, michael@0: SECOidTag ev_oid_tag, // SEC_OID_UNKNOWN means: not EV michael@0: nsINSSComponent *nssComponent) michael@0: { michael@0: nsCOMPtr extensionSequence = new nsNSSASN1Sequence; michael@0: michael@0: nsString text; michael@0: nssComponent->GetPIPNSSBundleString("CertDumpExtensions", text); michael@0: extensionSequence->SetDisplayName(text); michael@0: int32_t i; michael@0: nsresult rv; michael@0: nsCOMPtr newExtension; michael@0: nsCOMPtr asn1Objects; michael@0: extensionSequence->GetASN1Objects(getter_AddRefs(asn1Objects)); michael@0: for (i=0; extensions[i] != nullptr; i++) { michael@0: rv = ProcessSingleExtension(extensions[i], michael@0: ev_oid_tag, michael@0: nssComponent, michael@0: getter_AddRefs(newExtension)); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: asn1Objects->AppendElement(newExtension, false); michael@0: } michael@0: parentSequence->GetASN1Objects(getter_AddRefs(asn1Objects)); michael@0: asn1Objects->AppendElement(extensionSequence, false); michael@0: return NS_OK; michael@0: } michael@0: michael@0: static bool registered; michael@0: static SECStatus RegisterDynamicOids() michael@0: { michael@0: unsigned int i; michael@0: SECStatus rv = SECSuccess; michael@0: michael@0: if (registered) michael@0: return rv; michael@0: michael@0: for (i = 0; i < numOids; i++) { michael@0: SECOidTag tag = SECOID_AddEntry(&more_oids[i]); michael@0: if (tag == SEC_OID_UNKNOWN) { michael@0: rv = SECFailure; michael@0: continue; michael@0: } michael@0: more_oids[i].offset = tag; michael@0: } michael@0: registered = true; michael@0: return rv; michael@0: } michael@0: michael@0: nsresult michael@0: nsNSSCertificate::CreateTBSCertificateASN1Struct(nsIASN1Sequence **retSequence, michael@0: nsINSSComponent *nssComponent) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: if (RegisterDynamicOids() != SECSuccess) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: // michael@0: // TBSCertificate ::= SEQUENCE { michael@0: // version [0] EXPLICIT Version DEFAULT v1, michael@0: // serialNumber CertificateSerialNumber, michael@0: // signature AlgorithmIdentifier, michael@0: // issuer Name, michael@0: // validity Validity, michael@0: // subject Name, michael@0: // subjectPublicKeyInfo SubjectPublicKeyInfo, michael@0: // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, michael@0: // -- If present, version shall be v2 or v3 michael@0: // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, michael@0: // -- If present, version shall be v2 or v3 michael@0: // extensions [3] EXPLICIT Extensions OPTIONAL michael@0: // -- If present, version shall be v3 michael@0: // } michael@0: // michael@0: // This is the ASN1 structure we should be dealing with at this point. michael@0: // The code in this method will assert this is the structure we're dealing michael@0: // and then add more user friendly text for that field. michael@0: nsCOMPtr sequence = new nsNSSASN1Sequence(); michael@0: michael@0: nsString text; michael@0: nssComponent->GetPIPNSSBundleString("CertDumpCertificate", text); michael@0: sequence->SetDisplayName(text); michael@0: nsCOMPtr printableItem; michael@0: michael@0: nsCOMPtr asn1Objects; michael@0: sequence->GetASN1Objects(getter_AddRefs(asn1Objects)); michael@0: michael@0: nsresult rv = ProcessVersion(&mCert->version, nssComponent, michael@0: getter_AddRefs(printableItem)); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: asn1Objects->AppendElement(printableItem, false); michael@0: michael@0: rv = ProcessSerialNumberDER(&mCert->serialNumber, nssComponent, michael@0: getter_AddRefs(printableItem)); michael@0: michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: asn1Objects->AppendElement(printableItem, false); michael@0: michael@0: nsCOMPtr algID; michael@0: rv = ProcessSECAlgorithmID(&mCert->signature, michael@0: nssComponent, getter_AddRefs(algID)); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: nssComponent->GetPIPNSSBundleString("CertDumpSigAlg", text); michael@0: algID->SetDisplayName(text); michael@0: asn1Objects->AppendElement(algID, false); michael@0: michael@0: nsXPIDLString value; michael@0: ProcessName(&mCert->issuer, nssComponent, getter_Copies(value)); michael@0: michael@0: printableItem = new nsNSSASN1PrintableItem(); michael@0: michael@0: printableItem->SetDisplayValue(value); michael@0: nssComponent->GetPIPNSSBundleString("CertDumpIssuer", text); michael@0: printableItem->SetDisplayName(text); michael@0: asn1Objects->AppendElement(printableItem, false); michael@0: michael@0: nsCOMPtr validitySequence = new nsNSSASN1Sequence(); michael@0: nssComponent->GetPIPNSSBundleString("CertDumpValidity", text); michael@0: validitySequence->SetDisplayName(text); michael@0: asn1Objects->AppendElement(validitySequence, false); michael@0: nssComponent->GetPIPNSSBundleString("CertDumpNotBefore", text); michael@0: nsCOMPtr validityData; michael@0: GetValidity(getter_AddRefs(validityData)); michael@0: PRTime notBefore, notAfter; michael@0: michael@0: validityData->GetNotBefore(¬Before); michael@0: validityData->GetNotAfter(¬After); michael@0: validityData = 0; michael@0: rv = ProcessTime(notBefore, text.get(), validitySequence); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: nssComponent->GetPIPNSSBundleString("CertDumpNotAfter", text); michael@0: rv = ProcessTime(notAfter, text.get(), validitySequence); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: nssComponent->GetPIPNSSBundleString("CertDumpSubject", text); michael@0: michael@0: printableItem = new nsNSSASN1PrintableItem(); michael@0: michael@0: printableItem->SetDisplayName(text); michael@0: ProcessName(&mCert->subject, nssComponent,getter_Copies(value)); michael@0: printableItem->SetDisplayValue(value); michael@0: asn1Objects->AppendElement(printableItem, false); michael@0: michael@0: rv = ProcessSubjectPublicKeyInfo(&mCert->subjectPublicKeyInfo, sequence, michael@0: nssComponent); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: SECItem data; michael@0: // Is there an issuerUniqueID? michael@0: if (mCert->issuerID.data) { michael@0: // The issuerID is encoded as a bit string. michael@0: // The function ProcessRawBytes expects the michael@0: // length to be in bytes, so let's convert the michael@0: // length in a temporary SECItem michael@0: data.data = mCert->issuerID.data; michael@0: data.len = (mCert->issuerID.len + 7) / 8; michael@0: michael@0: ProcessRawBytes(nssComponent, &data, text); michael@0: printableItem = new nsNSSASN1PrintableItem(); michael@0: michael@0: printableItem->SetDisplayValue(text); michael@0: nssComponent->GetPIPNSSBundleString("CertDumpIssuerUniqueID", text); michael@0: printableItem->SetDisplayName(text); michael@0: asn1Objects->AppendElement(printableItem, false); michael@0: } michael@0: michael@0: if (mCert->subjectID.data) { michael@0: // The subjectID is encoded as a bit string. michael@0: // The function ProcessRawBytes expects the michael@0: // length to be in bytes, so let's convert the michael@0: // length in a temporary SECItem michael@0: data.data = mCert->subjectID.data; michael@0: data.len = (mCert->subjectID.len + 7) / 8; michael@0: michael@0: ProcessRawBytes(nssComponent, &data, text); michael@0: printableItem = new nsNSSASN1PrintableItem(); michael@0: michael@0: printableItem->SetDisplayValue(text); michael@0: nssComponent->GetPIPNSSBundleString("CertDumpSubjectUniqueID", text); michael@0: printableItem->SetDisplayName(text); michael@0: asn1Objects->AppendElement(printableItem, false); michael@0: michael@0: } michael@0: if (mCert->extensions) { michael@0: SECOidTag ev_oid_tag = SEC_OID_UNKNOWN; michael@0: michael@0: #ifndef MOZ_NO_EV_CERTS michael@0: bool validEV; michael@0: rv = hasValidEVOidTag(ev_oid_tag, validEV); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: if (!validEV) michael@0: ev_oid_tag = SEC_OID_UNKNOWN; michael@0: #endif michael@0: michael@0: rv = ProcessExtensions(mCert->extensions, sequence, ev_oid_tag, nssComponent); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: } michael@0: *retSequence = sequence; michael@0: NS_ADDREF(*retSequence); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsNSSCertificate::CreateASN1Struct(nsIASN1Object** aRetVal) michael@0: { michael@0: static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); michael@0: michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: nsCOMPtr sequence = new nsNSSASN1Sequence(); michael@0: michael@0: nsCOMPtr asn1Objects; michael@0: sequence->GetASN1Objects(getter_AddRefs(asn1Objects)); michael@0: nsXPIDLCString title; michael@0: GetWindowTitle(getter_Copies(title)); michael@0: michael@0: sequence->SetDisplayName(NS_ConvertUTF8toUTF16(title)); michael@0: sequence.forget(aRetVal); michael@0: michael@0: // This sequence will be contain the tbsCertificate, signatureAlgorithm, michael@0: // and signatureValue. michael@0: nsresult rv; michael@0: nsCOMPtr nssComponent(do_GetService(kNSSComponentCID, &rv)); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: rv = CreateTBSCertificateASN1Struct(getter_AddRefs(sequence), michael@0: nssComponent); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: asn1Objects->AppendElement(sequence, false); michael@0: nsCOMPtr algID; michael@0: michael@0: rv = ProcessSECAlgorithmID(&mCert->signatureWrap.signatureAlgorithm, michael@0: nssComponent, getter_AddRefs(algID)); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: nsString text; michael@0: nssComponent->GetPIPNSSBundleString("CertDumpSigAlg", text); michael@0: algID->SetDisplayName(text); michael@0: asn1Objects->AppendElement(algID, false); michael@0: nsCOMPtrprintableItem = new nsNSSASN1PrintableItem(); michael@0: nssComponent->GetPIPNSSBundleString("CertDumpCertSig", text); michael@0: printableItem->SetDisplayName(text); michael@0: // The signatureWrap is encoded as a bit string. michael@0: // The function ProcessRawBytes expects the michael@0: // length to be in bytes, so let's convert the michael@0: // length in a temporary SECItem michael@0: SECItem temp; michael@0: temp.data = mCert->signatureWrap.signature.data; michael@0: temp.len = mCert->signatureWrap.signature.len / 8; michael@0: text.Truncate(); michael@0: ProcessRawBytes(nssComponent, &temp,text); michael@0: printableItem->SetDisplayValue(text); michael@0: asn1Objects->AppendElement(printableItem, false); michael@0: return NS_OK; michael@0: } michael@0: michael@0: uint32_t michael@0: getCertType(CERTCertificate *cert) michael@0: { michael@0: nsNSSCertTrust trust(cert->trust); michael@0: if (cert->nickname && trust.HasAnyUser()) michael@0: return nsIX509Cert::USER_CERT; michael@0: if (trust.HasAnyCA()) michael@0: return nsIX509Cert::CA_CERT; michael@0: if (trust.HasPeer(true, false, false)) michael@0: return nsIX509Cert::SERVER_CERT; michael@0: if (trust.HasPeer(false, true, false) && cert->emailAddr) michael@0: return nsIX509Cert::EMAIL_CERT; michael@0: if (CERT_IsCACert(cert, nullptr)) michael@0: return nsIX509Cert::CA_CERT; michael@0: if (cert->emailAddr) michael@0: return nsIX509Cert::EMAIL_CERT; michael@0: return nsIX509Cert::UNKNOWN_CERT; michael@0: } michael@0: michael@0: CERTCertNicknames * michael@0: getNSSCertNicknamesFromCertList(CERTCertList *certList) michael@0: { michael@0: static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); michael@0: michael@0: nsresult rv; michael@0: michael@0: nsCOMPtr nssComponent(do_GetService(kNSSComponentCID, &rv)); michael@0: if (NS_FAILED(rv)) michael@0: return nullptr; michael@0: michael@0: nsAutoString expiredString, notYetValidString; michael@0: nsAutoString expiredStringLeadingSpace, notYetValidStringLeadingSpace; michael@0: michael@0: nssComponent->GetPIPNSSBundleString("NicknameExpired", expiredString); michael@0: nssComponent->GetPIPNSSBundleString("NicknameNotYetValid", notYetValidString); michael@0: michael@0: expiredStringLeadingSpace.Append(NS_LITERAL_STRING(" ")); michael@0: expiredStringLeadingSpace.Append(expiredString); michael@0: michael@0: notYetValidStringLeadingSpace.Append(NS_LITERAL_STRING(" ")); michael@0: notYetValidStringLeadingSpace.Append(notYetValidString); michael@0: michael@0: NS_ConvertUTF16toUTF8 aUtf8ExpiredString(expiredStringLeadingSpace); michael@0: NS_ConvertUTF16toUTF8 aUtf8NotYetValidString(notYetValidStringLeadingSpace); michael@0: michael@0: return CERT_NicknameStringsFromCertList(certList, michael@0: const_cast(aUtf8ExpiredString.get()), michael@0: const_cast(aUtf8NotYetValidString.get())); michael@0: michael@0: } michael@0: michael@0: nsresult michael@0: GetCertFingerprintByOidTag(CERTCertificate* nsscert, michael@0: SECOidTag aOidTag, michael@0: nsCString &fp) michael@0: { michael@0: Digest digest; michael@0: nsresult rv = digest.DigestBuf(aOidTag, nsscert->derCert.data, michael@0: nsscert->derCert.len); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: char *tmpstr = CERT_Hexify(const_cast(&digest.get()), 1); michael@0: NS_ENSURE_TRUE(tmpstr, NS_ERROR_OUT_OF_MEMORY); michael@0: michael@0: fp.Assign(tmpstr); michael@0: PORT_Free(tmpstr); michael@0: return NS_OK; michael@0: }