diff options
author | mattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-26 22:38:20 +0000 |
---|---|---|
committer | mattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-26 22:38:20 +0000 |
commit | e505a900d371c2012fd32a6d763ae283a98f72a1 (patch) | |
tree | fef99fd74e520c2e10d7a7fe88174c93b349b237 /chrome/third_party/mozilla_security_manager | |
parent | da65cbb338400a9b29857d8e0e818e4bed3c9318 (diff) | |
download | chromium_src-e505a900d371c2012fd32a6d763ae283a98f72a1.zip chromium_src-e505a900d371c2012fd32a6d763ae283a98f72a1.tar.gz chromium_src-e505a900d371c2012fd32a6d763ae283a98f72a1.tar.bz2 |
Linux: Add decoding for a bunch of certificate extensions.
BUG=18119
TEST=open https site in firefox and chrome, compare certificate extension details
Review URL: http://codereview.chromium.org/557046
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@40172 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/third_party/mozilla_security_manager')
5 files changed, 1040 insertions, 0 deletions
diff --git a/chrome/third_party/mozilla_security_manager/README.chromium b/chrome/third_party/mozilla_security_manager/README.chromium new file mode 100644 index 0000000..18bb62b --- /dev/null +++ b/chrome/third_party/mozilla_security_manager/README.chromium @@ -0,0 +1,12 @@ +URL: http://mxr.mozilla.org/mozilla-central/source/security/manager/ +InfoURL: http://www.mozilla.org/ +Version: 36838:a59a5f030021 +License: MPL 1.1/GPL 2.0/LGPL 2.1 + +Description: +This is selected code bits from Mozilla's Personal Security Manager. + +Local Modifications: +Files are forked from Mozilla's because of the heavy adaptations necessary. +Differences are using Chromium localization and other libraries instead of +Mozilla's, matching the Chromium style, etc. diff --git a/chrome/third_party/mozilla_security_manager/nsNSSCertHelper.cpp b/chrome/third_party/mozilla_security_manager/nsNSSCertHelper.cpp new file mode 100644 index 0000000..6f6d9f2 --- /dev/null +++ b/chrome/third_party/mozilla_security_manager/nsNSSCertHelper.cpp @@ -0,0 +1,811 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * 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 the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Ian McGreer <mcgreer@netscape.com> + * Javier Delgadillo <javi@netscape.com> + * John Gardiner Myers <jgmyers@speakeasy.net> + * Martin v. Loewis <martin@v.loewis.de> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h" + +#include <prprf.h> + +#include "app/l10n_util.h" +#include "base/i18n/number_formatting.h" +#include "grit/generated_resources.h" +#include "net/base/net_util.h" + +namespace { + +std::string BMPtoUTF8(PRArenaPool* arena, unsigned char* data, + unsigned int len) { + if (len % 2 != 0) + return l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_DUMP_ERROR); + + unsigned int utf8_val_len = len * 3 + 1; + std::vector<unsigned char> utf8_val(utf8_val_len); + if (!PORT_UCS2_UTF8Conversion(PR_FALSE, data, len, + &utf8_val.front(), utf8_val_len, &utf8_val_len)) + return l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_DUMP_ERROR); + return std::string(reinterpret_cast<char*>(&utf8_val.front()), utf8_val_len); +} + +} // namespace + +namespace mozilla_security_manager { + +SECOidTag ms_cert_ext_certtype = SEC_OID_UNKNOWN; +SECOidTag ms_certsrv_ca_version = SEC_OID_UNKNOWN; +SECOidTag ms_nt_principal_name = SEC_OID_UNKNOWN; +SECOidTag ms_ntds_replication = SEC_OID_UNKNOWN; +#define MICROSOFT_OID 0x2b, 0x6, 0x1, 0x4, 0x1, 0x82, 0x37 +static const unsigned char kMsCertExtCerttype[] = {MICROSOFT_OID, 20, 2}; +static const unsigned char kMsCertSrvCAVersion[] = {MICROSOFT_OID, 21, 1}; +static const unsigned char kMsNTPrincipalName[] = {MICROSOFT_OID, 20, 2, 3}; +static const unsigned char kMsNTDSReplication[] = {MICROSOFT_OID, 25, 1}; + +void RegisterDynamicOids() { + if (ms_cert_ext_certtype != SEC_OID_UNKNOWN) + return; + + SECOidData od; + od.oid.data = const_cast<unsigned char*>(kMsCertExtCerttype); + od.oid.len = sizeof(kMsCertExtCerttype); + od.offset = SEC_OID_UNKNOWN; + od.mechanism = CKM_INVALID_MECHANISM; + od.supportedExtension = INVALID_CERT_EXTENSION; + od.desc = "ms_cert_ext_certtype"; + ms_cert_ext_certtype = SECOID_AddEntry(&od); + DCHECK_NE(ms_cert_ext_certtype, SEC_OID_UNKNOWN); + + od.oid.data = const_cast<unsigned char*>(kMsCertSrvCAVersion); + od.oid.len = sizeof(kMsCertSrvCAVersion); + od.offset = SEC_OID_UNKNOWN; + od.mechanism = CKM_INVALID_MECHANISM; + od.supportedExtension = INVALID_CERT_EXTENSION; + od.desc = "ms_certsrv_ca_version"; + ms_certsrv_ca_version = SECOID_AddEntry(&od); + DCHECK_NE(ms_certsrv_ca_version, SEC_OID_UNKNOWN); + + od.oid.data = const_cast<unsigned char*>(kMsNTPrincipalName); + od.oid.len = sizeof(kMsNTPrincipalName); + od.offset = SEC_OID_UNKNOWN; + od.mechanism = CKM_INVALID_MECHANISM; + od.supportedExtension = INVALID_CERT_EXTENSION; + od.desc = "ms_nt_principal_name"; + ms_nt_principal_name = SECOID_AddEntry(&od); + DCHECK_NE(ms_nt_principal_name, SEC_OID_UNKNOWN); + + od.oid.data = const_cast<unsigned char*>(kMsNTDSReplication); + od.oid.len = sizeof(kMsNTDSReplication); + od.offset = SEC_OID_UNKNOWN; + od.mechanism = CKM_INVALID_MECHANISM; + od.supportedExtension = INVALID_CERT_EXTENSION; + od.desc = "ms_ntds_replication"; + ms_ntds_replication = SECOID_AddEntry(&od); + DCHECK_NE(ms_ntds_replication, SEC_OID_UNKNOWN); +} + +std::string ProcessRawBytes(SECItem* data) { + static const char kHexChars[] = "0123456789ABCDEF"; + + // Each input byte creates two output hex characters + a space or newline, + // except for the last byte. + std::string ret(std::max(0u, data->len * 3 - 1), '\0'); + + for (size_t i = 0; i < data->len; ++i) { + unsigned char b = data->data[i]; + ret[i * 3] = kHexChars[(b >> 4) & 0xf]; + ret[i * 3 + 1] = kHexChars[b & 0xf]; + if (i + 1 < data->len) { + if ((i + 1) % 16 == 0) + ret[i * 3 + 2] = '\n'; + else + ret[i * 3 + 2] = ' '; + } + } + return ret; +} + +std::string ProcessRawBits(SECItem* data) { + SECItem bytedata; + bytedata.data = data->data; + bytedata.len = data->len / 8; + return ProcessRawBytes(&bytedata); +} + +std::string DumpOidString(SECItem* oid) { + char* pr_string = CERT_GetOidString(oid); + if (pr_string) { + std::string rv = pr_string; + PR_smprintf_free(pr_string); + return rv; + } + + return ProcessRawBytes(oid); +} + +std::string GetOIDText(SECItem* oid) { + int string_id; + SECOidTag oid_tag = SECOID_FindOIDTag(oid); + switch (oid_tag) { + case SEC_OID_AVA_COMMON_NAME: + string_id = IDS_CERT_OID_AVA_COMMON_NAME; + break; + case SEC_OID_AVA_STATE_OR_PROVINCE: + string_id = IDS_CERT_OID_AVA_STATE_OR_PROVINCE; + break; + case SEC_OID_AVA_ORGANIZATION_NAME: + string_id = IDS_CERT_OID_AVA_ORGANIZATION_NAME; + break; + case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME: + string_id = IDS_CERT_OID_AVA_ORGANIZATIONAL_UNIT_NAME; + break; + case SEC_OID_AVA_DN_QUALIFIER: + string_id = IDS_CERT_OID_AVA_DN_QUALIFIER; + break; + case SEC_OID_AVA_COUNTRY_NAME: + string_id = IDS_CERT_OID_AVA_COUNTRY_NAME; + break; + case SEC_OID_AVA_SERIAL_NUMBER: + string_id = IDS_CERT_OID_AVA_SERIAL_NUMBER; + break; + case SEC_OID_AVA_LOCALITY: + string_id = IDS_CERT_OID_AVA_LOCALITY; + break; + case SEC_OID_AVA_DC: + string_id = IDS_CERT_OID_AVA_DC; + break; + case SEC_OID_RFC1274_MAIL: + string_id = IDS_CERT_OID_RFC1274_MAIL; + break; + case SEC_OID_RFC1274_UID: + string_id = IDS_CERT_OID_RFC1274_UID; + break; + case SEC_OID_PKCS9_EMAIL_ADDRESS: + string_id = IDS_CERT_OID_PKCS9_EMAIL_ADDRESS; + break; + case SEC_OID_PKCS1_RSA_ENCRYPTION: + string_id = IDS_CERT_OID_PKCS1_RSA_ENCRYPTION; + break; + case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: + string_id = IDS_CERT_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION; + break; + case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: + string_id = IDS_CERT_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION; + break; + case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: + string_id = IDS_CERT_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; + break; + case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: + string_id = IDS_CERT_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; + break; + case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: + string_id = IDS_CERT_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; + break; + case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: + string_id = IDS_CERT_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; + break; + case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: + string_id = IDS_CERT_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; + break; + case SEC_OID_NS_CERT_EXT_CERT_TYPE: + string_id = IDS_CERT_EXT_NS_CERT_TYPE; + break; + case SEC_OID_NS_CERT_EXT_BASE_URL: + string_id = IDS_CERT_EXT_NS_CERT_BASE_URL; + break; + case SEC_OID_NS_CERT_EXT_REVOCATION_URL: + string_id = IDS_CERT_EXT_NS_CERT_REVOCATION_URL; + break; + case SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL: + string_id = IDS_CERT_EXT_NS_CA_REVOCATION_URL; + break; + case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL: + string_id = IDS_CERT_EXT_NS_CERT_RENEWAL_URL; + break; + case SEC_OID_NS_CERT_EXT_CA_POLICY_URL: + string_id = IDS_CERT_EXT_NS_CA_POLICY_URL; + break; + case SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME: + string_id = IDS_CERT_EXT_NS_SSL_SERVER_NAME; + break; + case SEC_OID_NS_CERT_EXT_COMMENT: + string_id = IDS_CERT_EXT_NS_COMMENT; + break; + case SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL: + string_id = IDS_CERT_EXT_NS_LOST_PASSWORD_URL; + break; + case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME: + string_id = IDS_CERT_EXT_NS_CERT_RENEWAL_TIME; + break; + case SEC_OID_X509_SUBJECT_DIRECTORY_ATTR: + string_id = IDS_CERT_X509_SUBJECT_DIRECTORY_ATTR; + break; + case SEC_OID_X509_SUBJECT_KEY_ID: + string_id = IDS_CERT_X509_SUBJECT_KEYID; + break; + case SEC_OID_X509_KEY_USAGE: + string_id = IDS_CERT_X509_KEY_USAGE; + break; + case SEC_OID_X509_SUBJECT_ALT_NAME: + string_id = IDS_CERT_X509_SUBJECT_ALT_NAME; + break; + case SEC_OID_X509_ISSUER_ALT_NAME: + string_id = IDS_CERT_X509_ISSUER_ALT_NAME; + break; + case SEC_OID_X509_BASIC_CONSTRAINTS: + string_id = IDS_CERT_X509_BASIC_CONSTRAINTS; + break; + case SEC_OID_X509_NAME_CONSTRAINTS: + string_id = IDS_CERT_X509_NAME_CONSTRAINTS; + break; + case SEC_OID_X509_CRL_DIST_POINTS: + string_id = IDS_CERT_X509_CRL_DIST_POINTS; + break; + case SEC_OID_X509_CERTIFICATE_POLICIES: + string_id = IDS_CERT_X509_CERT_POLICIES; + break; + case SEC_OID_X509_POLICY_MAPPINGS: + string_id = IDS_CERT_X509_POLICY_MAPPINGS; + break; + case SEC_OID_X509_POLICY_CONSTRAINTS: + string_id = IDS_CERT_X509_POLICY_CONSTRAINTS; + break; + case SEC_OID_X509_AUTH_KEY_ID: + string_id = IDS_CERT_X509_AUTH_KEYID; + break; + case SEC_OID_X509_EXT_KEY_USAGE: + string_id = IDS_CERT_X509_EXT_KEY_USAGE; + break; + case SEC_OID_X509_AUTH_INFO_ACCESS: + string_id = IDS_CERT_X509_AUTH_INFO_ACCESS; + break; + + // There are a billionty other OIDs we could add here. I tried to get the + // important ones... + default: + if (oid_tag == ms_cert_ext_certtype) + string_id = IDS_CERT_EXT_MS_CERT_TYPE; + else if (oid_tag == ms_certsrv_ca_version) + string_id = IDS_CERT_EXT_MS_CA_VERSION; + else if (oid_tag == ms_nt_principal_name) + string_id = IDS_CERT_EXT_MS_NT_PRINCIPAL_NAME; + else if (oid_tag == ms_ntds_replication) + string_id = IDS_CERT_EXT_MS_NTDS_REPLICATION; + else + string_id = -1; + break; + } + if (string_id >= 0) + return l10n_util::GetStringUTF8(string_id); + + return DumpOidString(oid); +} + + +// Get a display string from a Relative Distinguished Name. +std::string ProcessRDN(CERTRDN* rdn) { + std::string rv; + + CERTAVA** avas = rdn->avas; + for (size_t i = 0; avas[i] != NULL; ++i) { + rv += GetOIDText(&avas[i]->type); + SECItem* decode_item = CERT_DecodeAVAValue(&avas[i]->value); + if (decode_item) { + // TODO(mattm): Pass decode_item to CERT_RFC1485_EscapeAndQuote. + rv += " = "; + std::string value(reinterpret_cast<char*>(decode_item->data), + decode_item->len); + rv += value; + SECITEM_FreeItem(decode_item, PR_TRUE); + } + rv += '\n'; + } + + return rv; +} + +std::string ProcessName(CERTName* name) { + std::string rv; + CERTRDN** last_rdn; + + // Find last non-NULL rdn. + for (last_rdn = name->rdns; last_rdn[0]; last_rdn++) {} + last_rdn--; + + for (CERTRDN** rdn = last_rdn; rdn >= name->rdns; rdn--) + rv += ProcessRDN(*rdn); + return rv; +} + +std::string ProcessBasicConstraints(SECItem* extension_data) { + CERTBasicConstraints value; + value.pathLenConstraint = -1; + if (CERT_DecodeBasicConstraintValue(&value, extension_data) != SECSuccess) + return ProcessRawBytes(extension_data); + + std::string rv; + if (value.isCA) + rv = l10n_util::GetStringUTF8(IDS_CERT_X509_BASIC_CONSTRAINT_IS_CA); + else + rv = l10n_util::GetStringUTF8(IDS_CERT_X509_BASIC_CONSTRAINT_IS_NOT_CA); + rv += '\n'; + if (value.pathLenConstraint != -1) { + string16 depth; + if (value.pathLenConstraint == CERT_UNLIMITED_PATH_CONSTRAINT) { + depth = l10n_util::GetStringUTF16( + IDS_CERT_X509_BASIC_CONSTRAINT_PATH_LEN_UNLIMITED); + } else { + depth = base::FormatNumber(value.pathLenConstraint); + } + rv += l10n_util::GetStringFUTF8(IDS_CERT_X509_BASIC_CONSTRAINT_PATH_LEN, + depth); + } + return rv; +} + +std::string ProcessGeneralName(PRArenaPool* arena, + CERTGeneralName* current) { + DCHECK(current); + + std::string key; + std::string value; + + switch (current->type) { + case certOtherName: { + key = GetOIDText(¤t->name.OthName.oid); + SECOidTag oid_tag = SECOID_FindOIDTag(¤t->name.OthName.oid); + if (oid_tag == ms_nt_principal_name) { + // The type of this name is apparently nowhere explicitly + // documented. However, in the generated templates, it is always + // UTF-8. So try to decode this as UTF-8; if that fails, dump the + // raw data. + SECItem decoded; + if (SEC_ASN1DecodeItem(arena, &decoded, + SEC_ASN1_GET(SEC_UTF8StringTemplate), + ¤t->name.OthName.name) == SECSuccess) { + value = std::string(reinterpret_cast<char*>(decoded.data), + decoded.len); + } else { + value = ProcessRawBytes(¤t->name.OthName.name); + } + break; + } else if (oid_tag == ms_ntds_replication) { + // This should be a 16-byte GUID. + SECItem guid; + if (SEC_ASN1DecodeItem(arena, &guid, + SEC_ASN1_GET(SEC_OctetStringTemplate), + ¤t->name.OthName.name) == SECSuccess && + guid.len == 16) { + unsigned char* d = guid.data; + SStringPrintf(&value, + "{%.2x%.2x%.2x%.2x-%.2x%.2x-%.2x%.2x-" + "%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x}", + d[3], d[2], d[1], d[0], d[5], d[4], d[7], d[6], + d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]); + } else { + value = ProcessRawBytes(¤t->name.OthName.name); + } + } else { + value = ProcessRawBytes(¤t->name.OthName.name); + } + break; + } + case certRFC822Name: + key = l10n_util::GetStringUTF8(IDS_CERT_GENERAL_NAME_RFC822_NAME); + value = std::string(reinterpret_cast<char*>(current->name.other.data), + current->name.other.len); + break; + case certDNSName: + key = l10n_util::GetStringUTF8(IDS_CERT_GENERAL_NAME_DNS_NAME); + value = std::string(reinterpret_cast<char*>(current->name.other.data), + current->name.other.len); + break; + case certX400Address: + key = l10n_util::GetStringUTF8(IDS_CERT_GENERAL_NAME_X400_ADDRESS); + value = ProcessRawBytes(¤t->name.other); + break; + case certDirectoryName: + key = l10n_util::GetStringUTF8(IDS_CERT_GENERAL_NAME_DIRECTORY_NAME); + value = ProcessName(¤t->name.directoryName); + break; + case certEDIPartyName: + key = l10n_util::GetStringUTF8(IDS_CERT_GENERAL_NAME_EDI_PARTY_NAME); + value = ProcessRawBytes(¤t->name.other); + break; + case certURI: + key = l10n_util::GetStringUTF8(IDS_CERT_GENERAL_NAME_URI); + value = std::string(reinterpret_cast<char*>(current->name.other.data), + current->name.other.len); + break; + case certIPAddress: { + key = l10n_util::GetStringUTF8(IDS_CERT_GENERAL_NAME_IP_ADDRESS); + struct addrinfo addr = {0}; + if (current->name.other.len == 4) { + struct sockaddr_in addr4 = {0}; + addr.ai_addr = reinterpret_cast<sockaddr*>(&addr4); + addr.ai_addrlen = sizeof(addr4); + addr.ai_family = AF_INET; + addr4.sin_family = addr.ai_family; + memcpy(&addr4.sin_addr, current->name.other.data, + current->name.other.len); + value = net::NetAddressToString(&addr); + } else if (current->name.other.len == 16) { + struct sockaddr_in6 addr6 = {0}; + addr.ai_addr = reinterpret_cast<sockaddr*>(&addr6); + addr.ai_addrlen = sizeof(addr6); + addr.ai_family = AF_INET6; + addr6.sin6_family = addr.ai_family; + memcpy(&addr6.sin6_addr, current->name.other.data, + current->name.other.len); + value = net::NetAddressToString(&addr); + } + if (value.empty()) { + // Invalid IP address. + value = ProcessRawBytes(¤t->name.other); + } + break; + } + case certRegisterID: + key = l10n_util::GetStringUTF8(IDS_CERT_GENERAL_NAME_REGISTERED_ID); + value = DumpOidString(¤t->name.other); + break; + } + std::string rv(l10n_util::GetStringFUTF8(IDS_CERT_UNKNOWN_OID_INFO_FORMAT, + UTF8ToUTF16(key), + UTF8ToUTF16(value))); + rv += '\n'; + return rv; +} + +std::string ProcessGeneralNames(PRArenaPool* arena, + CERTGeneralName* name_list) { + std::string rv; + CERTGeneralName* current = name_list; + + do { + std::string text = ProcessGeneralName(arena, current); + if (text.empty()) + break; + rv += text + '\n'; + current = CERT_GetNextGeneralName(current); + } while (current != name_list); + return rv; +} + +std::string ProcessAltName(SECItem* extension_data) { + CERTGeneralName* name_list; + + ScopedPRArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); + CHECK(arena.get()); + + name_list = CERT_DecodeAltNameExtension(arena.get(), extension_data); + if (!name_list) + return l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_DUMP_ERROR); + + return ProcessGeneralNames(arena.get(), name_list); +} + +std::string ProcessSubjectKeyId(SECItem* extension_data) { + SECItem decoded; + ScopedPRArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); + CHECK(arena.get()); + + std::string rv; + if (SEC_QuickDERDecodeItem(arena.get(), &decoded, + SEC_ASN1_GET(SEC_OctetStringTemplate), + extension_data) != SECSuccess) { + rv = l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_DUMP_ERROR); + return rv; + } + + rv = l10n_util::GetStringFUTF8(IDS_CERT_KEYID_FORMAT, + ASCIIToUTF16(ProcessRawBytes(&decoded))); + return rv; +} + +std::string ProcessAuthKeyId(SECItem* extension_data) { + CERTAuthKeyID* ret; + ScopedPRArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); + std::string rv; + + CHECK(arena.get()); + + ret = CERT_DecodeAuthKeyID(arena.get(), extension_data); + + if (ret->keyID.len > 0) { + rv += l10n_util::GetStringFUTF8(IDS_CERT_KEYID_FORMAT, + ASCIIToUTF16(ProcessRawBytes(&ret->keyID))); + rv += '\n'; + } + + if (ret->authCertIssuer) { + rv += l10n_util::GetStringFUTF8( + IDS_CERT_ISSUER_FORMAT, + UTF8ToUTF16(ProcessGeneralNames(arena.get(), ret->authCertIssuer))); + rv += '\n'; + } + + if (ret->authCertSerialNumber.len > 0) { + rv += l10n_util::GetStringFUTF8( + IDS_CERT_SERIAL_NUMBER_FORMAT, + ASCIIToUTF16(ProcessRawBytes(&ret->authCertSerialNumber))); + rv += '\n'; + } + + return rv; +} + +std::string ProcessCrlDistPoints(SECItem* extension_data) { + std::string rv; + CERTCrlDistributionPoints* crldp; + CRLDistributionPoint** points; + CRLDistributionPoint* point; + bool comma; + + static const struct { + int reason; + int string_id; + } reason_string_map[] = { + {RF_UNUSED, IDS_CERT_REVOCATION_REASON_UNUSED}, + {RF_KEY_COMPROMISE, IDS_CERT_REVOCATION_REASON_KEY_COMPROMISE}, + {RF_CA_COMPROMISE, IDS_CERT_REVOCATION_REASON_CA_COMPROMISE}, + {RF_AFFILIATION_CHANGED, IDS_CERT_REVOCATION_REASON_AFFILIATION_CHANGED}, + {RF_SUPERSEDED, IDS_CERT_REVOCATION_REASON_SUPERSEDED}, + {RF_CESSATION_OF_OPERATION, + IDS_CERT_REVOCATION_REASON_CESSATION_OF_OPERATION}, + {RF_CERTIFICATE_HOLD, IDS_CERT_REVOCATION_REASON_CERTIFICATE_HOLD}, + }; + + ScopedPRArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); + CHECK(arena.get()); + + crldp = CERT_DecodeCRLDistributionPoints(arena.get(), extension_data); + if (!crldp || !crldp->distPoints) { + rv = l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_DUMP_ERROR); + return rv; + } + + for (points = crldp->distPoints; *points; ++points) { + point = *points; + switch (point->distPointType) { + case generalName: + rv += ProcessGeneralName(arena.get(), point->distPoint.fullName); + break; + case relativeDistinguishedName: + rv += ProcessRDN(&point->distPoint.relativeName); + break; + } + if (point->reasons.len) { + rv += ' '; + comma = false; + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(reason_string_map); ++i) { + if (point->reasons.data[0] & reason_string_map[i].reason) { + if (comma) + rv += ','; + rv += l10n_util::GetStringUTF8(reason_string_map[i].string_id); + } + } + rv += '\n'; + } + if (point->crlIssuer) { + rv += l10n_util::GetStringFUTF8( + IDS_CERT_ISSUER_FORMAT, + UTF8ToUTF16(ProcessGeneralNames(arena.get(), point->crlIssuer))); + } + } + return rv; +} + +std::string ProcessAuthInfoAccess(SECItem* extension_data) { + std::string rv; + CERTAuthInfoAccess** aia; + CERTAuthInfoAccess* desc; + ScopedPRArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); + CHECK(arena.get()); + + aia = CERT_DecodeAuthInfoAccessExtension(arena.get(), extension_data); + if (aia == NULL) + return l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_DUMP_ERROR); + + while (*aia != NULL) { + desc = *aia++; + string16 location_str = UTF8ToUTF16(ProcessGeneralName(arena.get(), + desc->location)); + switch (SECOID_FindOIDTag(&desc->method)) { + case SEC_OID_PKIX_OCSP: + rv += l10n_util::GetStringFUTF8(IDS_CERT_OCSP_RESPONDER_FORMAT, + location_str); + break; + case SEC_OID_PKIX_CA_ISSUERS: + rv += l10n_util::GetStringFUTF8(IDS_CERT_CA_ISSUERS_FORMAT, + location_str); + break; + default: + rv += l10n_util::GetStringFUTF8(IDS_CERT_UNKNOWN_OID_INFO_FORMAT, + UTF8ToUTF16(GetOIDText(&desc->method)), + location_str); + break; + } + } + return rv; +} + +std::string ProcessIA5String(SECItem* extension_data) { + SECItem item; + if (SEC_ASN1DecodeItem(NULL, &item, SEC_ASN1_GET(SEC_IA5StringTemplate), + extension_data) != SECSuccess) + return l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_DUMP_ERROR); + std::string rv((char*)item.data, item.len); // ASCII data. + PORT_Free(item.data); + return rv; +} + +std::string ProcessBMPString(SECItem* extension_data) { + std::string rv; + SECItem item; + ScopedPRArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); + CHECK(arena.get()); + + if (SEC_ASN1DecodeItem(arena.get(), &item, + SEC_ASN1_GET(SEC_BMPStringTemplate), extension_data) == + SECSuccess) + rv = BMPtoUTF8(arena.get(), item.data, item.len); + return rv; +} + +struct MaskIdPair { + unsigned char mask; + int string_id; +}; + +static std::string ProcessBitStringExtension(SECItem* extension_data, + const MaskIdPair* string_map, + size_t len) { + SECItem decoded; + decoded.type = siBuffer; + decoded.data = NULL; + decoded.len = 0; + if (SEC_ASN1DecodeItem(NULL, &decoded, SEC_ASN1_GET(SEC_BitStringTemplate), + extension_data) != SECSuccess) + return l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_DUMP_ERROR); + + std::string rv; + for (size_t i = 0; i < len; ++i) { + if (decoded.data[0] & string_map[i].mask) { + rv += l10n_util::GetStringUTF8(string_map[i].string_id) + '\n'; + } + } + PORT_Free(decoded.data); + return rv; +} + +std::string ProcessNSCertTypeExtension(SECItem* extension_data) { + MaskIdPair usage_string_map[] = { + {NS_CERT_TYPE_SSL_CLIENT, IDS_CERT_USAGE_SSL_CLIENT}, + {NS_CERT_TYPE_SSL_SERVER, IDS_CERT_USAGE_SSL_SERVER}, + {NS_CERT_TYPE_EMAIL, IDS_CERT_EXT_NS_CERT_TYPE_EMAIL}, + {NS_CERT_TYPE_OBJECT_SIGNING, IDS_CERT_USAGE_OBJECT_SIGNER}, + {NS_CERT_TYPE_SSL_CA, IDS_CERT_USAGE_SSL_CA}, + {NS_CERT_TYPE_EMAIL_CA, IDS_CERT_EXT_NS_CERT_TYPE_EMAIL_CA}, + {NS_CERT_TYPE_OBJECT_SIGNING_CA, IDS_CERT_USAGE_OBJECT_SIGNER}, + }; + return ProcessBitStringExtension(extension_data, usage_string_map, + ARRAYSIZE_UNSAFE(usage_string_map)); +} + +std::string ProcessKeyUsageExtension(SECItem* extension_data) { + MaskIdPair usage_string_map[] = { + {KU_DIGITAL_SIGNATURE, IDS_CERT_X509_KEY_USAGE_SIGNING}, + {KU_NON_REPUDIATION, IDS_CERT_X509_KEY_USAGE_NONREP}, + {KU_KEY_ENCIPHERMENT, IDS_CERT_X509_KEY_USAGE_ENCIPHERMENT}, + {KU_DATA_ENCIPHERMENT, IDS_CERT_X509_KEY_USAGE_DATA_ENCIPHERMENT}, + {KU_KEY_AGREEMENT, IDS_CERT_X509_KEY_USAGE_KEY_AGREEMENT}, + {KU_KEY_CERT_SIGN, IDS_CERT_X509_KEY_USAGE_CERT_SIGNER}, + {KU_CRL_SIGN, IDS_CERT_X509_KEY_USAGE_CRL_SIGNER}, + }; + return ProcessBitStringExtension(extension_data, usage_string_map, + ARRAYSIZE_UNSAFE(usage_string_map)); +} + +std::string ProcessExtKeyUsage(SECItem* extension_data) { + std::string rv; + CERTOidSequence* extension_key_usage = NULL; + extension_key_usage = CERT_DecodeOidSequence(extension_data); + if (extension_key_usage == NULL) + return l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_DUMP_ERROR); + + SECItem** oids; + SECItem* oid; + for (oids = extension_key_usage->oids; oids != NULL && *oids != NULL; + ++oids) { + // TODO(mattm): Need to either lookup strings here based on the OIDs or add + // more OIDS to GetOIDText. (See the strings of the form + // CertDumpEKU_<underlined-OID> in Mozilla.) + + oid = *oids; + rv += GetOIDText(oid); + rv += '\n'; + } + CERT_DestroyOidSequence(extension_key_usage); + return rv; +} + +std::string ProcessExtensionData(SECOidTag oid_tag, SECItem* extension_data) { + // This (and its sub-functions) are based on the same-named functions in + // security/manager/ssl/src/nsNSSCertHelper.cpp. + switch (oid_tag) { + case SEC_OID_NS_CERT_EXT_CERT_TYPE: + return ProcessNSCertTypeExtension(extension_data); + case SEC_OID_X509_KEY_USAGE: + return ProcessKeyUsageExtension(extension_data); + case SEC_OID_X509_BASIC_CONSTRAINTS: + return ProcessBasicConstraints(extension_data); + case SEC_OID_X509_EXT_KEY_USAGE: + return ProcessExtKeyUsage(extension_data); + case SEC_OID_X509_ISSUER_ALT_NAME: + case SEC_OID_X509_SUBJECT_ALT_NAME: + return ProcessAltName(extension_data); + case SEC_OID_X509_SUBJECT_KEY_ID: + return ProcessSubjectKeyId(extension_data); + case SEC_OID_X509_AUTH_KEY_ID: + return ProcessAuthKeyId(extension_data); + // TODO(mattm): + // case SEC_OID_X509_CERTIFICATE_POLICIES: + // return ProcessCertificatePolicies(extension_data, ev_oid_tag); + case SEC_OID_X509_CRL_DIST_POINTS: + return ProcessCrlDistPoints(extension_data); + case SEC_OID_X509_AUTH_INFO_ACCESS: + return ProcessAuthInfoAccess(extension_data); + case SEC_OID_NS_CERT_EXT_BASE_URL: + case SEC_OID_NS_CERT_EXT_REVOCATION_URL: + case SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL: + case SEC_OID_NS_CERT_EXT_CA_CERT_URL: + case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL: + case SEC_OID_NS_CERT_EXT_CA_POLICY_URL: + case SEC_OID_NS_CERT_EXT_HOMEPAGE_URL: + case SEC_OID_NS_CERT_EXT_COMMENT: + case SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME: + case SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL: + return ProcessIA5String(extension_data); + default: + if (oid_tag == ms_cert_ext_certtype) + return ProcessBMPString(extension_data); + return ProcessRawBytes(extension_data); + } +} + +} // namespace mozilla_security_manager diff --git a/chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h b/chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h new file mode 100644 index 0000000..ba0a445 --- /dev/null +++ b/chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h @@ -0,0 +1,97 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * 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 the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Ian McGreer <mcgreer@netscape.com> + * Javier Delgadillo <javi@netscape.com> + * John Gardiner Myers <jgmyers@speakeasy.net> + * Martin v. Loewis <martin@v.loewis.de> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef CHROME_THIRD_PARTY_MOZILLA_SECURITY_MANAGER_NSNSSCERTHELPER_H_ +#define CHROME_THIRD_PARTY_MOZILLA_SECURITY_MANAGER_NSNSSCERTHELPER_H_ + +#include <cert.h> + +#include <string> + +#include "base/scoped_ptr.h" + +class FreePRArenaPool { + public: + inline void operator()(PRArenaPool* x) const { + PORT_FreeArena(x, PR_FALSE); + } +}; +typedef scoped_ptr_malloc<PRArenaPool, FreePRArenaPool> ScopedPRArenaPool; + +namespace mozilla_security_manager { + +extern SECOidTag ms_cert_ext_certtype; +extern SECOidTag ms_certsrv_ca_version; +extern SECOidTag ms_nt_principal_name; +extern SECOidTag ms_ntds_replication; + +void RegisterDynamicOids(); + +// Format a SECItem as a space separated string, with 16 bytes on each line. +std::string ProcessRawBytes(SECItem* data); + +// For fields which have the length specified in bits, rather than bytes. +std::string ProcessRawBits(SECItem* data); + +std::string DumpOidString(SECItem* oid); +std::string GetOIDText(SECItem* oid); + +std::string ProcessRDN(CERTRDN* rdn); +std::string ProcessName(CERTName* name); +std::string ProcessBasicConstraints(SECItem* extension_data); +std::string ProcessGeneralName(PRArenaPool* arena, + CERTGeneralName* current); +std::string ProcessGeneralNames(PRArenaPool* arena, + CERTGeneralName* name_list); +std::string ProcessAltName(SECItem* extension_data); +std::string ProcessSubjectKeyId(SECItem* extension_data); +std::string ProcessAuthKeyId(SECItem* extension_data); +std::string ProcessCrlDistPoints(SECItem* extension_data); +std::string ProcessAuthInfoAccess(SECItem* extension_data); +std::string ProcessIA5String(SECItem* extension_data); +std::string ProcessBMPString(SECItem* extension_data); +std::string ProcessNSCertTypeExtension(SECItem* extension_data); +std::string ProcessKeyUsageExtension(SECItem* extension_data); +std::string ProcessExtKeyUsage(SECItem* extension_data); +std::string ProcessExtensionData(SECOidTag oid_tag, SECItem* extension_data); + +} // namespace mozilla_security_manager + +#endif // CHROME_THIRD_PARTY_MOZILLA_SECURITY_MANAGER_NSNSSCERTHELPER_H_ diff --git a/chrome/third_party/mozilla_security_manager/nsNSSCertificate.cpp b/chrome/third_party/mozilla_security_manager/nsNSSCertificate.cpp new file mode 100644 index 0000000..9d1abe8 --- /dev/null +++ b/chrome/third_party/mozilla_security_manager/nsNSSCertificate.cpp @@ -0,0 +1,65 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * 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 the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Ian McGreer <mcgreer@netscape.com> + * Javier Delgadillo <javi@netscape.com> + * Kai Engert <kengert@redhat.com> + * Jesper Kristensen <mail@jesperkristensen.dk> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "chrome/third_party/mozilla_security_manager/nsNSSCertificate.h" + +namespace mozilla_security_manager { + +std::string GetCertTitle(CERTCertificate* cert) { + std::string rv; + if (cert->nickname) { + rv = cert->nickname; + } else { + char* cn = CERT_GetCommonName(&cert->subject); + if (cn) { + rv = cn; + PORT_Free(cn); + } else if (cert->subjectName) { + rv = cert->subjectName; + } else if (cert->emailAddr) { + rv = cert->emailAddr; + } + } + // TODO(mattm): Should we return something other than an empty string when all + // the checks fail? + return rv; +} + +} // namespace mozilla_security_manager diff --git a/chrome/third_party/mozilla_security_manager/nsNSSCertificate.h b/chrome/third_party/mozilla_security_manager/nsNSSCertificate.h new file mode 100644 index 0000000..8ac10e6 --- /dev/null +++ b/chrome/third_party/mozilla_security_manager/nsNSSCertificate.h @@ -0,0 +1,55 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * 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 the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Ian McGreer <mcgreer@netscape.com> + * Javier Delgadillo <javi@netscape.com> + * Kai Engert <kengert@redhat.com> + * Jesper Kristensen <mail@jesperkristensen.dk> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef CHROME_THIRD_PARTY_MOZILLA_SECURITY_MANAGER_NSNSSCERTIFICATE_H_ +#define CHROME_THIRD_PARTY_MOZILLA_SECURITY_MANAGER_NSNSSCERTIFICATE_H_ + +#include <cert.h> + +#include <string> + +namespace mozilla_security_manager { + +// Based on nsNSSCertificate::GetWindowTitle. +std::string GetCertTitle(CERTCertificate* cert); + +} // namespace mozilla_security_manager + +#endif // CHROME_THIRD_PARTY_MOZILLA_SECURITY_MANAGER_NSNSSCERTIFICATE_H_ |