Logo Search packages:      
Sourcecode: chromium-browser version File versions  Download package

nsNSSCertHelper.cpp

/* ***** 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 <keyhi.h>
#include <prprf.h>

#include "app/l10n_util.h"
#include "base/i18n/number_formatting.h"
#include "base/utf_string_conversions.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);
}

SECOidTag RegisterDynamicOid(const char* oid_string) {
  SECOidTag rv = SEC_OID_UNKNOWN;
  unsigned char buffer[1024];
  SECOidData od;
  od.oid.type = siDEROID;
  od.oid.data = buffer;
  od.oid.len = sizeof(buffer);

  if (SEC_StringToOID(NULL, &od.oid, oid_string, 0) == SECSuccess) {
    od.offset = SEC_OID_UNKNOWN;
    od.mechanism = CKM_INVALID_MECHANISM;
    od.supportedExtension = INVALID_CERT_EXTENSION;
    od.desc = oid_string;

    rv = SECOID_AddEntry(&od);
  }
  DCHECK_NE(rv, SEC_OID_UNKNOWN) << oid_string;
  return rv;
}

}  // 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;
SECOidTag eku_ms_individual_code_signing = SEC_OID_UNKNOWN;
SECOidTag eku_ms_commercial_code_signing = SEC_OID_UNKNOWN;
SECOidTag eku_ms_trust_list_signing = SEC_OID_UNKNOWN;
SECOidTag eku_ms_time_stamping = SEC_OID_UNKNOWN;
SECOidTag eku_ms_server_gated_crypto = SEC_OID_UNKNOWN;
SECOidTag eku_ms_encrypting_file_system = SEC_OID_UNKNOWN;
SECOidTag eku_ms_file_recovery = SEC_OID_UNKNOWN;
SECOidTag eku_ms_windows_hardware_driver_verification = SEC_OID_UNKNOWN;
SECOidTag eku_ms_qualified_subordination = SEC_OID_UNKNOWN;
SECOidTag eku_ms_key_recovery = SEC_OID_UNKNOWN;
SECOidTag eku_ms_document_signing = SEC_OID_UNKNOWN;
SECOidTag eku_ms_lifetime_signing = SEC_OID_UNKNOWN;
SECOidTag eku_ms_smart_card_logon = SEC_OID_UNKNOWN;
SECOidTag eku_ms_key_recovery_agent = SEC_OID_UNKNOWN;
SECOidTag eku_netscape_international_step_up = SEC_OID_UNKNOWN;

void RegisterDynamicOids() {
  if (ms_cert_ext_certtype != SEC_OID_UNKNOWN)
    return;

  ms_cert_ext_certtype = RegisterDynamicOid("1.3.6.1.4.1.311.20.2");
  ms_certsrv_ca_version = RegisterDynamicOid("1.3.6.1.4.1.311.21.1");
  ms_nt_principal_name = RegisterDynamicOid("1.3.6.1.4.1.311.20.2.3");
  ms_nt_principal_name = RegisterDynamicOid("1.3.6.1.4.1.311.25.1");

  eku_ms_individual_code_signing = RegisterDynamicOid("1.3.6.1.4.1.311.2.1.21");
  eku_ms_commercial_code_signing = RegisterDynamicOid("1.3.6.1.4.1.311.2.1.22");
  eku_ms_trust_list_signing = RegisterDynamicOid("1.3.6.1.4.1.311.10.3.1");
  eku_ms_time_stamping = RegisterDynamicOid("1.3.6.1.4.1.311.10.3.2");
  eku_ms_server_gated_crypto = RegisterDynamicOid("1.3.6.1.4.1.311.10.3.3");
  eku_ms_encrypting_file_system = RegisterDynamicOid("1.3.6.1.4.1.311.10.3.4");
  eku_ms_file_recovery = RegisterDynamicOid("1.3.6.1.4.1.311.10.3.4.1");
  eku_ms_windows_hardware_driver_verification = RegisterDynamicOid(
      "1.3.6.1.4.1.311.10.3.5");
  eku_ms_qualified_subordination = RegisterDynamicOid(
      "1.3.6.1.4.1.311.10.3.10");
  eku_ms_key_recovery = RegisterDynamicOid("1.3.6.1.4.1.311.10.3.11");
  eku_ms_document_signing = RegisterDynamicOid("1.3.6.1.4.1.311.10.3.12");
  eku_ms_lifetime_signing = RegisterDynamicOid("1.3.6.1.4.1.311.10.3.13");
  eku_ms_smart_card_logon = RegisterDynamicOid("1.3.6.1.4.1.311.20.2.2");
  eku_ms_key_recovery_agent = RegisterDynamicOid("1.3.6.1.4.1.311.21.6");
  eku_netscape_international_step_up = RegisterDynamicOid(
      "2.16.840.1.113730.4.1");
}

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;
    case SEC_OID_EXT_KEY_USAGE_SERVER_AUTH:
      string_id = IDS_CERT_EKU_TLS_WEB_SERVER_AUTHENTICATION;
      break;
    case SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH:
      string_id = IDS_CERT_EKU_TLS_WEB_CLIENT_AUTHENTICATION;
      break;
    case SEC_OID_EXT_KEY_USAGE_CODE_SIGN:
      string_id = IDS_CERT_EKU_CODE_SIGNING;
      break;
    case SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT:
      string_id = IDS_CERT_EKU_EMAIL_PROTECTION;
      break;
    case SEC_OID_EXT_KEY_USAGE_TIME_STAMP:
      string_id = IDS_CERT_EKU_TIME_STAMPING;
      break;
    case SEC_OID_OCSP_RESPONDER:
      string_id = IDS_CERT_EKU_OCSP_SIGNING;
      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 if (oid_tag == eku_ms_individual_code_signing)
        string_id = IDS_CERT_EKU_MS_INDIVIDUAL_CODE_SIGNING;
      else if (oid_tag == eku_ms_commercial_code_signing)
        string_id = IDS_CERT_EKU_MS_COMMERCIAL_CODE_SIGNING;
      else if (oid_tag == eku_ms_trust_list_signing)
        string_id = IDS_CERT_EKU_MS_TRUST_LIST_SIGNING;
      else if (oid_tag == eku_ms_time_stamping)
        string_id = IDS_CERT_EKU_MS_TIME_STAMPING;
      else if (oid_tag == eku_ms_server_gated_crypto)
        string_id = IDS_CERT_EKU_MS_SERVER_GATED_CRYPTO;
      else if (oid_tag == eku_ms_encrypting_file_system)
        string_id = IDS_CERT_EKU_MS_ENCRYPTING_FILE_SYSTEM;
      else if (oid_tag == eku_ms_file_recovery)
        string_id = IDS_CERT_EKU_MS_FILE_RECOVERY;
      else if (oid_tag == eku_ms_windows_hardware_driver_verification)
        string_id = IDS_CERT_EKU_MS_WINDOWS_HARDWARE_DRIVER_VERIFICATION;
      else if (oid_tag == eku_ms_qualified_subordination)
        string_id = IDS_CERT_EKU_MS_QUALIFIED_SUBORDINATION;
      else if (oid_tag == eku_ms_key_recovery)
        string_id = IDS_CERT_EKU_MS_KEY_RECOVERY;
      else if (oid_tag == eku_ms_document_signing)
        string_id = IDS_CERT_EKU_MS_DOCUMENT_SIGNING;
      else if (oid_tag == eku_ms_lifetime_signing)
        string_id = IDS_CERT_EKU_MS_LIFETIME_SIGNING;
      else if (oid_tag == eku_ms_smart_card_logon)
        string_id = IDS_CERT_EKU_MS_SMART_CARD_LOGON;
      else if (oid_tag == eku_ms_key_recovery_agent)
        string_id = IDS_CERT_EKU_MS_KEY_RECOVERY_AGENT;
      else if (oid_tag == eku_netscape_international_step_up)
        string_id = IDS_CERT_EKU_NETSCAPE_INTERNATIONAL_STEP_UP;
      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(&current->name.OthName.oid);
      SECOidTag oid_tag = SECOID_FindOIDTag(&current->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),
                               &current->name.OthName.name) == SECSuccess) {
          value = std::string(reinterpret_cast<char*>(decoded.data),
                              decoded.len);
        } else {
          value = ProcessRawBytes(&current->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),
                               &current->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(&current->name.OthName.name);
        }
      } else {
        value = ProcessRawBytes(&current->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(&current->name.other);
      break;
    case certDirectoryName:
      key = l10n_util::GetStringUTF8(IDS_CERT_GENERAL_NAME_DIRECTORY_NAME);
      value = ProcessName(&current->name.directoryName);
      break;
    case certEDIPartyName:
      key = l10n_util::GetStringUTF8(IDS_CERT_GENERAL_NAME_EDI_PARTY_NAME);
      value = ProcessRawBytes(&current->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(&current->name.other);
      }
      break;
    }
    case certRegisterID:
      key = l10n_util::GetStringUTF8(IDS_CERT_GENERAL_NAME_REGISTERED_ID);
      value = DumpOidString(&current->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 int mask;
  int string_id;
};

static std::string ProcessBitField(SECItem* bitfield,
                                   const MaskIdPair* string_map,
                                   size_t len,
                                   char separator) {
  unsigned int bits = 0;
  std::string rv;
  for (size_t i = 0; i * 8 < bitfield->len && i < sizeof(bits); ++i)
    bits |= bitfield->data[i] << (i * 8);
  for (size_t i = 0; i < len; ++i) {
    if (bits & string_map[i].mask) {
      if (!rv.empty())
        rv += separator;
      rv += l10n_util::GetStringUTF8(string_map[i].string_id);
    }
  }
  return rv;
}

static std::string ProcessBitStringExtension(SECItem* extension_data,
                                             const MaskIdPair* string_map,
                                             size_t len,
                                             char separator) {
  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 = ProcessBitField(&decoded, string_map, len, separator);
  PORT_Free(decoded.data);
  return rv;
}

std::string ProcessNSCertTypeExtension(SECItem* extension_data) {
  static const 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), '\n');
}

static const MaskIdPair key_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},
  {KU_ENCIPHER_ONLY, IDS_CERT_X509_KEY_USAGE_ENCIPHER_ONLY},
  // NSS is missing a flag for dechiperOnly, see:
  // https://bugzilla.mozilla.org/show_bug.cgi?id=549952
};

std::string ProcessKeyUsageBitString(SECItem* bitstring, char sep) {
  return ProcessBitField(bitstring, key_usage_string_map,
                         arraysize(key_usage_string_map), sep);
}

std::string ProcessKeyUsageExtension(SECItem* extension_data) {
  return ProcessBitStringExtension(extension_data, key_usage_string_map,
                                   arraysize(key_usage_string_map), '\n');
}

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) {
    oid = *oids;
    std::string oid_dump = DumpOidString(oid);
    std::string oid_text = GetOIDText(oid);

    // If oid is one we recognize, oid_text will have a text description of the OID,
    // which we display along with the oid_dump.  If we don't recognize the OID,
    // GetOIDText will return the same value as DumpOidString, so just display
    // the OID alone.
    if (oid_dump == oid_text)
      rv += oid_dump;
    else
      rv += l10n_util::GetStringFUTF8(IDS_CERT_EXT_KEY_USAGE_FORMAT,
                                      UTF8ToUTF16(oid_text),
                                      UTF8ToUTF16(oid_dump));
    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);
  }
}

std::string ProcessSubjectPublicKeyInfo(CERTSubjectPublicKeyInfo* spki) {
  std::string rv;
  SECKEYPublicKey* key = SECKEY_ExtractPublicKey(spki);
  if (key) {
    switch (key->keyType) {
      case rsaKey: {
        rv = l10n_util::GetStringFUTF8(
            IDS_CERT_RSA_PUBLIC_KEY_DUMP_FORMAT,
            UintToString16(key->u.rsa.modulus.len * 8),
            UTF8ToUTF16(ProcessRawBytes(&key->u.rsa.modulus)),
            UintToString16(key->u.rsa.publicExponent.len * 8),
            UTF8ToUTF16(ProcessRawBytes(&key->u.rsa.publicExponent)));
        break;
      }
      default:
        rv = ProcessRawBits(&spki->subjectPublicKey);
        break;
    }
    SECKEY_DestroyPublicKey(key);
  }
  return rv;
}

}  // namespace mozilla_security_manager

Generated by  Doxygen 1.6.0   Back to index