/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is the Netscape security libraries. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * Ian McGreer * Javier Delgadillo * John Gardiner Myers * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. * */ #include "prmem.h" #include "prerror.h" #include "prprf.h" #include "nsNSSCertHelper.h" #include "cert.h" #include "nsCOMPtr.h" #include "nsNSSASN1Object.h" #include "nsNSSComponent.h" #include "nsNSSCertTrust.h" static nsresult GetIntValue(SECItem *versionItem, unsigned long *version) { SECStatus srv; srv = SEC_ASN1DecodeInteger(versionItem,version); if (srv != SECSuccess) { NS_ASSERTION(0,"Could not decode version of cert"); return NS_ERROR_FAILURE; } return NS_OK; } nsresult ProcessVersion(SECItem *versionItem, nsINSSComponent *nssComponent, nsIASN1PrintableItem **retItem) { nsresult rv; nsAutoString text; nsCOMPtr printableItem = new nsNSSASN1PrintableItem(); if (printableItem == nsnull) return NS_ERROR_OUT_OF_MEMORY; nssComponent->GetPIPNSSBundleString("CertDumpVersion", text); rv = printableItem->SetDisplayName(text); if (NS_FAILED(rv)) return rv; // Now to figure out what version this certificate is. unsigned long version; if (versionItem->data) { rv = GetIntValue(versionItem, &version); if (NS_FAILED(rv)) return rv; } else { // If there is no version present in the cert, then rfc2459 // says we default to v1 (0) version = 0; } switch (version){ case 0: rv = nssComponent->GetPIPNSSBundleString("CertDumpVersion1", text); break; case 1: rv = nssComponent->GetPIPNSSBundleString("CertDumpVersion2", text); break; case 2: rv = nssComponent->GetPIPNSSBundleString("CertDumpVersion3", text); break; default: NS_ASSERTION(0,"Bad value for cert version"); rv = NS_ERROR_FAILURE; } if (NS_FAILED(rv)) return rv; rv = printableItem->SetDisplayValue(text); if (NS_FAILED(rv)) return rv; *retItem = printableItem; NS_ADDREF(*retItem); return NS_OK; } nsresult ProcessSerialNumberDER(SECItem *serialItem, nsINSSComponent *nssComponent, nsIASN1PrintableItem **retItem) { nsresult rv; nsAutoString text; nsCOMPtr printableItem = new nsNSSASN1PrintableItem(); if (printableItem == nsnull) return NS_ERROR_OUT_OF_MEMORY; rv = nssComponent->GetPIPNSSBundleString("CertDumpSerialNo", text); if (NS_FAILED(rv)) return rv; rv = printableItem->SetDisplayName(text); if (NS_FAILED(rv)) return rv; nsXPIDLCString serialNumber; serialNumber.Adopt(CERT_Hexify(serialItem, 1)); if (serialNumber == nsnull) return NS_ERROR_OUT_OF_MEMORY; rv = printableItem->SetDisplayValue(NS_ConvertASCIItoUCS2(serialNumber)); *retItem = printableItem; NS_ADDREF(*retItem); return rv; } static nsresult GetDefaultOIDFormat(SECItem *oid, nsAString &outString) { char buf[300]; unsigned int len; int written; unsigned long val = oid->data[0]; unsigned int i = val % 40; val /= 40; written = PR_snprintf(buf, 300, "%lu %u ", val, i); if (written < 0) return NS_ERROR_FAILURE; len = written; val = 0; for (i = 1; i < oid->len; ++i) { // In this loop, we have to parse a DER formatted // If the first bit is a 1, then the integer is // represented by more than one byte. If the // first bit is set then we continue on and add // the values of the later bytes until we get // a byte without the first bit set. unsigned long j; j = oid->data[i]; val = (val << 7) | (j & 0x7f); if (j & 0x80) continue; written = PR_snprintf(&buf[len], sizeof(buf)-len, "%lu ", val); if (written < 0) return NS_ERROR_FAILURE; len += written; NS_ASSERTION(len < sizeof(buf), "OID data to big to display in 300 chars."); val = 0; } CopyASCIItoUTF16(buf, outString); return NS_OK; } nsresult GetOIDText(SECItem *oid, nsINSSComponent *nssComponent, nsAString &text) { nsresult rv; SECOidTag oidTag = SECOID_FindOIDTag(oid); const char *bundlekey = 0; switch (oidTag) { case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: bundlekey = "CertDumpMD2WithRSA"; break; case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: bundlekey = "CertDumpMD5WithRSA"; break; case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: bundlekey = "CertDumpSHA1WithRSA"; break; case SEC_OID_PKCS1_RSA_ENCRYPTION: bundlekey = "CertDumpRSAEncr"; break; case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: bundlekey = "CertDumpSHA256WithRSA"; break; case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: bundlekey = "CertDumpSHA384WithRSA"; break; case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: bundlekey = "CertDumpSHA512WithRSA"; break; case SEC_OID_NS_CERT_EXT_CERT_TYPE: bundlekey = "CertDumpCertType"; break; case SEC_OID_NS_CERT_EXT_BASE_URL: bundlekey = "CertDumpNSCertExtBaseUrl"; break; case SEC_OID_NS_CERT_EXT_REVOCATION_URL: bundlekey = "CertDumpNSCertExtRevocationUrl"; break; case SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL: bundlekey = "CertDumpNSCertExtCARevocationUrl"; break; case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL: bundlekey = "CertDumpNSCertExtCertRenewalUrl"; break; case SEC_OID_NS_CERT_EXT_CA_POLICY_URL: bundlekey = "CertDumpNSCertExtCAPolicyUrl"; break; case SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME: bundlekey = "CertDumpNSCertExtSslServerName"; break; case SEC_OID_NS_CERT_EXT_COMMENT: bundlekey = "CertDumpNSCertExtComment"; break; case SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL: bundlekey = "CertDumpNSCertExtLostPasswordUrl"; break; case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME: bundlekey = "CertDumpNSCertExtCertRenewalTime"; break; case SEC_OID_NETSCAPE_AOLSCREENNAME: bundlekey = "CertDumpNetscapeAolScreenname"; break; case SEC_OID_AVA_COUNTRY_NAME: bundlekey = "CertDumpAVACountry"; break; case SEC_OID_AVA_COMMON_NAME: bundlekey = "CertDumpAVACN"; break; case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME: bundlekey = "CertDumpAVAOU"; break; case SEC_OID_AVA_ORGANIZATION_NAME: bundlekey = "CertDumpAVAOrg"; break; case SEC_OID_AVA_LOCALITY: bundlekey = "CertDumpAVALocality"; break; case SEC_OID_AVA_DN_QUALIFIER: bundlekey = "CertDumpAVADN"; break; case SEC_OID_AVA_DC: bundlekey = "CertDumpAVADC"; break; case SEC_OID_AVA_STATE_OR_PROVINCE: bundlekey = "CertDumpAVAState"; break; case SEC_OID_X509_SUBJECT_DIRECTORY_ATTR: bundlekey = "CertDumpSubjectDirectoryAttr"; break; case SEC_OID_X509_SUBJECT_KEY_ID: bundlekey = "CertDumpSubjectKeyID"; break; case SEC_OID_X509_KEY_USAGE: bundlekey = "CertDumpKeyUsage"; break; case SEC_OID_X509_SUBJECT_ALT_NAME: bundlekey = "CertDumpSubjectAltName"; break; case SEC_OID_X509_ISSUER_ALT_NAME: bundlekey = "CertDumpIssuerAltName"; break; case SEC_OID_X509_BASIC_CONSTRAINTS: bundlekey = "CertDumpBasicConstraints"; break; case SEC_OID_X509_NAME_CONSTRAINTS: bundlekey = "CertDumpNameConstraints"; break; case SEC_OID_X509_CRL_DIST_POINTS: bundlekey = "CertDumpCrlDistPoints"; break; case SEC_OID_X509_CERTIFICATE_POLICIES: bundlekey = "CertDumpCertPolicies"; break; case SEC_OID_X509_POLICY_MAPPINGS: bundlekey = "CertDumpPolicyMappings"; break; case SEC_OID_X509_POLICY_CONSTRAINTS: bundlekey = "CertDumpPolicyConstraints"; break; case SEC_OID_X509_AUTH_KEY_ID: bundlekey = "CertDumpAuthKeyID"; break; case SEC_OID_X509_EXT_KEY_USAGE: bundlekey = "CertDumpExtKeyUsage"; break; case SEC_OID_X509_AUTH_INFO_ACCESS: bundlekey = "CertDumpAuthInfoAccess"; break; case SEC_OID_ANSIX9_DSA_SIGNATURE: bundlekey = "CertDumpAnsiX9DsaSignature"; break; case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: bundlekey = "CertDumpAnsiX9DsaSignatureWithSha1"; break; case SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST: bundlekey = "CertDumpAnsiX962ECDsaSignatureWithSha1"; break; case SEC_OID_RFC1274_UID: bundlekey = "CertDumpUserID"; break; case SEC_OID_PKCS9_EMAIL_ADDRESS: bundlekey = "CertDumpPK9Email"; break; default: ; } if (bundlekey) { rv = nssComponent->GetPIPNSSBundleString(bundlekey, text); } else { nsAutoString text2; rv = GetDefaultOIDFormat(oid, text2); if (NS_FAILED(rv)) return rv; const PRUnichar *params[1] = {text2.get()}; rv = nssComponent->PIPBundleFormatStringFromName("CertDumpDefOID", params, 1, text); } return rv; } #define SEPARATOR "\n" nsresult ProcessRawBytes(SECItem *data, nsAString &text) { // This function is used to display some DER bytes // that we have not added support for decoding. // It prints the value of the byte out into a // string that can later be displayed as a byte // string. We place a new line after 24 bytes // to break up extermaly long sequence of bytes. PRUint32 i; char buffer[5]; for (i=0; ilen; i++) { PR_snprintf(buffer, 5, "%02x ", data->data[i]); AppendASCIItoUTF16(buffer, text); if ((i+1)%16 == 0) { text.Append(NS_LITERAL_STRING(SEPARATOR).get()); } } return NS_OK; } static nsresult ProcessNSCertTypeExtensions(SECItem *extData, nsAString &text, nsINSSComponent *nssComponent) { nsAutoString local; SECItem decoded; decoded.data = nsnull; decoded.len = 0; if (SECSuccess != SEC_ASN1DecodeItem(nsnull, &decoded, SEC_ASN1_GET(SEC_BitStringTemplate), extData)) { nssComponent->GetPIPNSSBundleString("CertDumpExtensionFailure", local); text.Append(local.get()); return NS_OK; } unsigned char nsCertType = decoded.data[0]; nsMemory::Free(decoded.data); if (nsCertType & NS_CERT_TYPE_SSL_CLIENT) { nssComponent->GetPIPNSSBundleString("VerifySSLClient", local); text.Append(local.get()); text.Append(NS_LITERAL_STRING(SEPARATOR).get()); } if (nsCertType & NS_CERT_TYPE_SSL_SERVER) { nssComponent->GetPIPNSSBundleString("VerifySSLServer", local); text.Append(local.get()); text.Append(NS_LITERAL_STRING(SEPARATOR).get()); } if (nsCertType & NS_CERT_TYPE_EMAIL) { nssComponent->GetPIPNSSBundleString("CertDumpCertTypeEmail", local); text.Append(local.get()); text.Append(NS_LITERAL_STRING(SEPARATOR).get()); } if (nsCertType & NS_CERT_TYPE_OBJECT_SIGNING) { nssComponent->GetPIPNSSBundleString("VerifyObjSign", local); text.Append(local.get()); text.Append(NS_LITERAL_STRING(SEPARATOR).get()); } if (nsCertType & NS_CERT_TYPE_SSL_CA) { nssComponent->GetPIPNSSBundleString("VerifySSLCA", local); text.Append(local.get()); text.Append(NS_LITERAL_STRING(SEPARATOR).get()); } if (nsCertType & NS_CERT_TYPE_EMAIL_CA) { nssComponent->GetPIPNSSBundleString("CertDumpEmailCA", local); text.Append(local.get()); text.Append(NS_LITERAL_STRING(SEPARATOR).get()); } if (nsCertType & NS_CERT_TYPE_OBJECT_SIGNING_CA) { nssComponent->GetPIPNSSBundleString("VerifyObjSign", local); text.Append(local.get()); text.Append(NS_LITERAL_STRING(SEPARATOR).get()); } return NS_OK; } static nsresult ProcessKeyUsageExtension(SECItem *extData, nsAString &text, nsINSSComponent *nssComponent) { nsAutoString local; SECItem decoded; decoded.data = nsnull; decoded.len = 0; if (SECSuccess != SEC_ASN1DecodeItem(nsnull, &decoded, SEC_ASN1_GET(SEC_BitStringTemplate), extData)) { nssComponent->GetPIPNSSBundleString("CertDumpExtensionFailure", local); text.Append(local.get()); return NS_OK; } unsigned char keyUsage = decoded.data[0]; nsMemory::Free(decoded.data); if (keyUsage & KU_DIGITAL_SIGNATURE) { nssComponent->GetPIPNSSBundleString("CertDumpKUSign", local); text.Append(local.get()); text.Append(NS_LITERAL_STRING(SEPARATOR).get()); } if (keyUsage & KU_NON_REPUDIATION) { nssComponent->GetPIPNSSBundleString("CertDumpKUNonRep", local); text.Append(local.get()); text.Append(NS_LITERAL_STRING(SEPARATOR).get()); } if (keyUsage & KU_KEY_ENCIPHERMENT) { nssComponent->GetPIPNSSBundleString("CertDumpKUEnc", local); text.Append(local.get()); text.Append(NS_LITERAL_STRING(SEPARATOR).get()); } if (keyUsage & KU_DATA_ENCIPHERMENT) { nssComponent->GetPIPNSSBundleString("CertDumpKUDEnc", local); text.Append(local.get()); text.Append(NS_LITERAL_STRING(SEPARATOR).get()); } if (keyUsage & KU_KEY_AGREEMENT) { nssComponent->GetPIPNSSBundleString("CertDumpKUKA", local); text.Append(local.get()); text.Append(NS_LITERAL_STRING(SEPARATOR).get()); } if (keyUsage & KU_KEY_CERT_SIGN) { nssComponent->GetPIPNSSBundleString("CertDumpKUCertSign", local); text.Append(local.get()); text.Append(NS_LITERAL_STRING(SEPARATOR).get()); } if (keyUsage & KU_CRL_SIGN) { nssComponent->GetPIPNSSBundleString("CertDumpKUCRLSign", local); text.Append(local.get()); text.Append(NS_LITERAL_STRING(SEPARATOR).get()); } return NS_OK; } static nsresult ProcessExtensionData(SECOidTag oidTag, SECItem *extData, nsAString &text, nsINSSComponent *nssComponent) { nsresult rv; switch (oidTag) { case SEC_OID_NS_CERT_EXT_CERT_TYPE: rv = ProcessNSCertTypeExtensions(extData, text, nssComponent); break; case SEC_OID_X509_KEY_USAGE: rv = ProcessKeyUsageExtension(extData, text, nssComponent); break; default: rv = ProcessRawBytes(extData, text); break; } return rv; } nsresult ProcessSingleExtension(CERTCertExtension *extension, nsINSSComponent *nssComponent, nsIASN1PrintableItem **retExtension) { nsAutoString text; GetOIDText(&extension->id, nssComponent, text); nsCOMPtrextensionItem = new nsNSSASN1PrintableItem(); if (extensionItem == nsnull) return NS_ERROR_OUT_OF_MEMORY; extensionItem->SetDisplayName(text); SECOidTag oidTag = SECOID_FindOIDTag(&extension->id); text.Truncate(); if (extension->critical.data != nsnull) { if (extension->critical.data[0]) { nssComponent->GetPIPNSSBundleString("CertDumpCritical", text); } else { nssComponent->GetPIPNSSBundleString("CertDumpNonCritical", text); } } else { nssComponent->GetPIPNSSBundleString("CertDumpNonCritical", text); } text.Append(NS_LITERAL_STRING(SEPARATOR).get()); nsresult rv = ProcessExtensionData(oidTag, &extension->value, text, nssComponent); if (NS_FAILED(rv)) return rv; extensionItem->SetDisplayValue(text); *retExtension = extensionItem; NS_ADDREF(*retExtension); return NS_OK; } PRUint32 getCertType(CERTCertificate *cert) { nsNSSCertTrust trust(cert->trust); if (cert->nickname && trust.HasAnyUser()) return nsIX509Cert::USER_CERT; if (trust.HasAnyCA()) return nsIX509Cert::CA_CERT; if (trust.HasPeer(PR_TRUE, PR_FALSE, PR_FALSE)) return nsIX509Cert::SERVER_CERT; if (trust.HasPeer(PR_FALSE, PR_TRUE, PR_FALSE) && cert->emailAddr) return nsIX509Cert::EMAIL_CERT; if (CERT_IsCACert(cert,NULL)) return nsIX509Cert::CA_CERT; if (cert->emailAddr) return nsIX509Cert::EMAIL_CERT; return nsIX509Cert::SERVER_CERT; }