root/chrome/third_party/mozilla_security_manager/nsNSSCertHelper.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. BMPtoUTF8
  2. RegisterDynamicOid
  3. ProcessRawBytes
  4. RegisterDynamicOids
  5. DumpOidString
  6. GetOIDText
  7. ProcessRDN
  8. ProcessName
  9. ProcessBasicConstraints
  10. ProcessGeneralName
  11. ProcessGeneralNames
  12. ProcessAltName
  13. ProcessSubjectKeyId
  14. ProcessAuthKeyId
  15. ProcessUserNotice
  16. ProcessCertificatePolicies
  17. ProcessCrlDistPoints
  18. ProcessAuthInfoAccess
  19. ProcessIA5String
  20. ProcessBMPString
  21. ProcessBitField
  22. ProcessBitStringExtension
  23. ProcessNSCertTypeExtension
  24. ProcessKeyUsageBitString
  25. ProcessKeyUsageExtension
  26. ProcessExtKeyUsage
  27. ProcessExtensionData
  28. ProcessSubjectPublicKeyInfo
  29. GetCertType

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

#include "base/i18n/number_formatting.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/common/net/x509_certificate_model.h"
#include "crypto/scoped_nss_types.h"
#include "grit/generated_resources.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_util.h"
#include "ui/base/l10n/l10n_util.h"

#if !defined(CERTDB_TERMINAL_RECORD)
/* NSS 3.13 renames CERTDB_VALID_PEER to CERTDB_TERMINAL_RECORD
 * and marks CERTDB_VALID_PEER as deprecated.
 * If we're using an older version, rename it ourselves.
 */
#define CERTDB_TERMINAL_RECORD CERTDB_VALID_PEER
#endif

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;
}

// Format a SECItem as a space separated string, with 16 bytes on each line.
std::string ProcessRawBytes(SECItem* data) {
  return x509_certificate_model::ProcessRawBytes(data->data, data->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;
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;
SECOidTag cert_attribute_business_category = SEC_OID_UNKNOWN;
SECOidTag cert_attribute_ev_incorporation_country = 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_ntds_replication = 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");

  // These two OIDs will be built-in as SEC_OID_BUSINESS_CATEGORY and
  // SEC_OID_EV_INCORPORATION_COUNTRY starting in NSS 3.13.  Until then,
  // we need to add them dynamically.
  cert_attribute_business_category = RegisterDynamicOid("2.5.4.15");
  cert_attribute_ev_incorporation_country = RegisterDynamicOid(
      "1.3.6.1.4.1.311.60.2.1.3");
}

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;
    case SEC_OID_PKIX_CPS_POINTER_QUALIFIER:
      string_id = IDS_CERT_PKIX_CPS_POINTER_QUALIFIER;
      break;
    case SEC_OID_PKIX_USER_NOTICE_QUALIFIER:
      string_id = IDS_CERT_PKIX_USER_NOTICE_QUALIFIER;
      break;
    case SEC_OID_UNKNOWN:
      string_id = -1;
      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 if (oid_tag == cert_attribute_business_category)
        string_id = IDS_CERT_OID_BUSINESS_CATEGORY;
      else if (oid_tag == cert_attribute_ev_incorporation_country)
        string_id = IDS_CERT_OID_EV_INCORPORATION_COUNTRY;
      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);
      if (SECOID_FindOIDTag(&avas[i]->type) == SEC_OID_AVA_COMMON_NAME)
        value = x509_certificate_model::ProcessIDN(value);
      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) {
    base::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;
          base::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);
      value = x509_certificate_model::ProcessIDN(value);
      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);

      net::IPAddressNumber ip(
          current->name.other.data,
          current->name.other.data + current->name.other.len);

      if (net::GetAddressFamily(ip) != net::ADDRESS_FAMILY_UNSPECIFIED) {
        value = net::IPAddressToString(ip);
      } else {
        // 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,
                                           base::UTF8ToUTF16(key),
                                           base::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;
    current = CERT_GetNextGeneralName(current);
  } while (current != name_list);
  return rv;
}

std::string ProcessAltName(SECItem* extension_data) {
  CERTGeneralName* name_list;

  crypto::ScopedPLArenaPool 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;
  crypto::ScopedPLArenaPool 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,
                                 base::ASCIIToUTF16(ProcessRawBytes(&decoded)));
  return rv;
}

std::string ProcessAuthKeyId(SECItem* extension_data) {
  CERTAuthKeyID* ret;
  crypto::ScopedPLArenaPool 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,
                                    base::ASCIIToUTF16(
                                        ProcessRawBytes(&ret->keyID)));
    rv += '\n';
  }

  if (ret->authCertIssuer) {
    rv += l10n_util::GetStringFUTF8(
        IDS_CERT_ISSUER_FORMAT,
        base::UTF8ToUTF16(
            ProcessGeneralNames(arena.get(), ret->authCertIssuer)));
    rv += '\n';
  }

  if (ret->authCertSerialNumber.len > 0) {
    rv += l10n_util::GetStringFUTF8(
        IDS_CERT_SERIAL_NUMBER_FORMAT,
        base::ASCIIToUTF16(ProcessRawBytes(&ret->authCertSerialNumber)));
    rv += '\n';
  }

  return rv;
}

std::string ProcessUserNotice(SECItem* der_notice) {
  CERTUserNotice* notice = CERT_DecodeUserNotice(der_notice);
  if (!notice)
    return ProcessRawBytes(der_notice);

  std::string rv;
  if (notice->noticeReference.organization.len != 0) {
    switch (notice->noticeReference.organization.type) {
      case siAsciiString:
      case siVisibleString:
      case siUTF8String:
        rv += std::string(
            reinterpret_cast<char*>(notice->noticeReference.organization.data),
            notice->noticeReference.organization.len);
        break;
      case siBMPString:
        rv += ProcessBMPString(&notice->noticeReference.organization);
        break;
      default:
        break;
    }
    rv += " - ";
    SECItem** itemList = notice->noticeReference.noticeNumbers;
    while (*itemList) {
      unsigned long number;
      if (SEC_ASN1DecodeInteger(*itemList, &number) == SECSuccess) {
        if (itemList != notice->noticeReference.noticeNumbers)
          rv += ", ";
        rv += '#';
        rv += base::UTF16ToUTF8(base::UintToString16(number));
      }
      itemList++;
    }
  }
  if (notice->displayText.len != 0) {
    rv += "\n    ";
    switch (notice->displayText.type) {
      case siAsciiString:
      case siVisibleString:
      case siUTF8String:
        rv += std::string(reinterpret_cast<char*>(notice->displayText.data),
                          notice->displayText.len);
        break;
      case siBMPString:
        rv += ProcessBMPString(&notice->displayText);
        break;
      default:
        break;
    }
  }

  CERT_DestroyUserNotice(notice);
  return rv;
}

std::string ProcessCertificatePolicies(SECItem* extension_data) {
  std::string rv;

  CERTCertificatePolicies* policies = CERT_DecodeCertificatePoliciesExtension(
      extension_data);
  if (!policies)
    return l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_DUMP_ERROR);

  CERTPolicyInfo** policyInfos = policies->policyInfos;
  while (*policyInfos) {
    CERTPolicyInfo* policyInfo = *policyInfos++;
    std::string key = GetOIDText(&policyInfo->policyID);

    // If we have policy qualifiers, display the oid text
    // with a ':', otherwise just put the oid text and a newline.
    // TODO(mattm): Add extra note if this is the ev oid?  (It's a bit
    // complicated, since we don't want to do the EV check synchronously.)
    if (policyInfo->policyQualifiers) {
      rv += l10n_util::GetStringFUTF8(IDS_CERT_MULTILINE_INFO_START_FORMAT,
                                      base::UTF8ToUTF16(key));
    } else {
      rv += key;
    }
    rv += '\n';

    if (policyInfo->policyQualifiers) {
      // Add all qualifiers on separate lines, indented.
      CERTPolicyQualifier** policyQualifiers = policyInfo->policyQualifiers;
      while (*policyQualifiers != NULL) {
        rv += "  ";

        CERTPolicyQualifier* policyQualifier = *policyQualifiers++;
        rv += l10n_util::GetStringFUTF8(
            IDS_CERT_MULTILINE_INFO_START_FORMAT,
            base::UTF8ToUTF16(GetOIDText(&policyQualifier->qualifierID)));
        switch(policyQualifier->oid) {
          case SEC_OID_PKIX_CPS_POINTER_QUALIFIER:
            rv += "    ";
            /* The CPS pointer ought to be the cPSuri alternative
               of the Qualifier choice. */
            rv += ProcessIA5String(&policyQualifier->qualifierValue);
            break;
          case SEC_OID_PKIX_USER_NOTICE_QUALIFIER:
            rv += ProcessUserNotice(&policyQualifier->qualifierValue);
            break;
          default:
            rv += ProcessRawBytes(&policyQualifier->qualifierValue);
            break;
        }
        rv += '\n';
      }
    }
  }

  CERT_DestroyCertificatePoliciesExtension(policies);
  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},
  };

  crypto::ScopedPLArenaPool 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:
        // generalName is a typo in upstream NSS; fullName is actually a
        // GeneralNames (SEQUENCE OF GeneralName). See Mozilla Bug #615100.
        rv += ProcessGeneralNames(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);
          comma = true;
        }
      }
      rv += '\n';
    }
    if (point->crlIssuer) {
      rv += l10n_util::GetStringFUTF8(
          IDS_CERT_ISSUER_FORMAT,
          base::UTF8ToUTF16(
              ProcessGeneralNames(arena.get(), point->crlIssuer)));
    }
  }
  return rv;
}

std::string ProcessAuthInfoAccess(SECItem* extension_data) {
  std::string rv;
  CERTAuthInfoAccess** aia;
  CERTAuthInfoAccess* desc;
  crypto::ScopedPLArenaPool 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++;
    base::string16 location_str =
        base::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,
                                      base::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;
  crypto::ScopedPLArenaPool 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,
                                      base::UTF8ToUTF16(oid_text),
                                      base::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);
    case SEC_OID_X509_CERTIFICATE_POLICIES:
      return ProcessCertificatePolicies(extension_data);
    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,
            base::UintToString16(key->u.rsa.modulus.len * 8),
            base::UTF8ToUTF16(ProcessRawBytes(&key->u.rsa.modulus)),
            base::UintToString16(key->u.rsa.publicExponent.len * 8),
            base::UTF8ToUTF16(ProcessRawBytes(&key->u.rsa.publicExponent)));
        break;
      }
      default:
        rv = x509_certificate_model::ProcessRawBits(
            spki->subjectPublicKey.data, spki->subjectPublicKey.len);
        break;
    }
    SECKEY_DestroyPublicKey(key);
  }
  return rv;
}

net::CertType GetCertType(CERTCertificate *cert) {
  CERTCertTrust trust = {0};
  CERT_GetCertTrust(cert, &trust);

  unsigned all_flags = trust.sslFlags | trust.emailFlags |
      trust.objectSigningFlags;

  if (cert->nickname && (all_flags & CERTDB_USER))
    return net::USER_CERT;
  if ((all_flags & CERTDB_VALID_CA) || CERT_IsCACert(cert, NULL))
    return net::CA_CERT;
  // TODO(mattm): http://crbug.com/128633.
  if (trust.sslFlags & CERTDB_TERMINAL_RECORD)
    return net::SERVER_CERT;
  return net::OTHER_CERT;
}

}  // namespace mozilla_security_manager

/* [<][>][^][v][top][bottom][index][help] */