Home | History | Annotate | Download | only in mozilla_security_manager
      1 /* ***** BEGIN LICENSE BLOCK *****
      2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
      3  *
      4  * The contents of this file are subject to the Mozilla Public License Version
      5  * 1.1 (the "License"); you may not use this file except in compliance with
      6  * the License. You may obtain a copy of the License at
      7  * http://www.mozilla.org/MPL/
      8  *
      9  * Software distributed under the License is distributed on an "AS IS" basis,
     10  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
     11  * for the specific language governing rights and limitations under the
     12  * License.
     13  *
     14  * The Original Code is the Netscape security libraries.
     15  *
     16  * The Initial Developer of the Original Code is
     17  * Netscape Communications Corporation.
     18  * Portions created by the Initial Developer are Copyright (C) 2000
     19  * the Initial Developer. All Rights Reserved.
     20  *
     21  * Contributor(s):
     22  *   Ian McGreer <mcgreer (at) netscape.com>
     23  *   Javier Delgadillo <javi (at) netscape.com>
     24  *   John Gardiner Myers <jgmyers (at) speakeasy.net>
     25  *   Martin v. Loewis <martin (at) v.loewis.de>
     26  *
     27  * Alternatively, the contents of this file may be used under the terms of
     28  * either the GNU General Public License Version 2 or later (the "GPL"), or
     29  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
     30  * in which case the provisions of the GPL or the LGPL are applicable instead
     31  * of those above. If you wish to allow use of your version of this file only
     32  * under the terms of either the GPL or the LGPL, and not to allow others to
     33  * use your version of this file under the terms of the MPL, indicate your
     34  * decision by deleting the provisions above and replace them with the notice
     35  * and other provisions required by the GPL or the LGPL. If you do not delete
     36  * the provisions above, a recipient may use your version of this file under
     37  * the terms of any one of the MPL, the GPL or the LGPL.
     38  *
     39  * ***** END LICENSE BLOCK ***** */
     40 
     41 #include "chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h"
     42 
     43 #include <certdb.h>
     44 #include <keyhi.h>
     45 #include <prprf.h>
     46 #include <unicode/uidna.h>
     47 
     48 #include "base/i18n/number_formatting.h"
     49 #include "base/lazy_instance.h"
     50 #include "base/strings/string_number_conversions.h"
     51 #include "base/strings/stringprintf.h"
     52 #include "base/strings/utf_string_conversions.h"
     53 #include "chrome/common/net/x509_certificate_model.h"
     54 #include "crypto/scoped_nss_types.h"
     55 #include "chrome/grit/generated_resources.h"
     56 #include "net/base/ip_endpoint.h"
     57 #include "net/base/net_util.h"
     58 #include "ui/base/l10n/l10n_util.h"
     59 
     60 #if !defined(CERTDB_TERMINAL_RECORD)
     61 /* NSS 3.13 renames CERTDB_VALID_PEER to CERTDB_TERMINAL_RECORD
     62  * and marks CERTDB_VALID_PEER as deprecated.
     63  * If we're using an older version, rename it ourselves.
     64  */
     65 #define CERTDB_TERMINAL_RECORD CERTDB_VALID_PEER
     66 #endif
     67 
     68 namespace {
     69 
     70 std::string BMPtoUTF8(PRArenaPool* arena, unsigned char* data,
     71                       unsigned int len) {
     72   if (len % 2 != 0)
     73     return l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_DUMP_ERROR);
     74 
     75   unsigned int utf8_val_len = len * 3 + 1;
     76   std::vector<unsigned char> utf8_val(utf8_val_len);
     77   if (!PORT_UCS2_UTF8Conversion(PR_FALSE, data, len,
     78                                 &utf8_val.front(), utf8_val_len, &utf8_val_len))
     79     return l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_DUMP_ERROR);
     80   return std::string(reinterpret_cast<char*>(&utf8_val.front()), utf8_val_len);
     81 }
     82 
     83 SECOidTag RegisterDynamicOid(const char* oid_string) {
     84   SECOidTag rv = SEC_OID_UNKNOWN;
     85   unsigned char buffer[1024];
     86   SECOidData od;
     87   od.oid.type = siDEROID;
     88   od.oid.data = buffer;
     89   od.oid.len = sizeof(buffer);
     90 
     91   if (SEC_StringToOID(NULL, &od.oid, oid_string, 0) == SECSuccess) {
     92     od.offset = SEC_OID_UNKNOWN;
     93     od.mechanism = CKM_INVALID_MECHANISM;
     94     od.supportedExtension = INVALID_CERT_EXTENSION;
     95     od.desc = oid_string;
     96 
     97     rv = SECOID_AddEntry(&od);
     98   }
     99   DCHECK_NE(rv, SEC_OID_UNKNOWN) << oid_string;
    100   return rv;
    101 }
    102 
    103 // Format a SECItem as a space separated string, with 16 bytes on each line.
    104 std::string ProcessRawBytes(SECItem* data) {
    105   return x509_certificate_model::ProcessRawBytes(data->data, data->len);
    106 }
    107 
    108 SECOidTag ms_cert_ext_certtype = SEC_OID_UNKNOWN;
    109 SECOidTag ms_certsrv_ca_version = SEC_OID_UNKNOWN;
    110 SECOidTag ms_nt_principal_name = SEC_OID_UNKNOWN;
    111 SECOidTag ms_ntds_replication = SEC_OID_UNKNOWN;
    112 SECOidTag eku_ms_individual_code_signing = SEC_OID_UNKNOWN;
    113 SECOidTag eku_ms_commercial_code_signing = SEC_OID_UNKNOWN;
    114 SECOidTag eku_ms_trust_list_signing = SEC_OID_UNKNOWN;
    115 SECOidTag eku_ms_time_stamping = SEC_OID_UNKNOWN;
    116 SECOidTag eku_ms_server_gated_crypto = SEC_OID_UNKNOWN;
    117 SECOidTag eku_ms_encrypting_file_system = SEC_OID_UNKNOWN;
    118 SECOidTag eku_ms_file_recovery = SEC_OID_UNKNOWN;
    119 SECOidTag eku_ms_windows_hardware_driver_verification = SEC_OID_UNKNOWN;
    120 SECOidTag eku_ms_qualified_subordination = SEC_OID_UNKNOWN;
    121 SECOidTag eku_ms_key_recovery = SEC_OID_UNKNOWN;
    122 SECOidTag eku_ms_document_signing = SEC_OID_UNKNOWN;
    123 SECOidTag eku_ms_lifetime_signing = SEC_OID_UNKNOWN;
    124 SECOidTag eku_ms_smart_card_logon = SEC_OID_UNKNOWN;
    125 SECOidTag eku_ms_key_recovery_agent = SEC_OID_UNKNOWN;
    126 SECOidTag eku_netscape_international_step_up = SEC_OID_UNKNOWN;
    127 SECOidTag cert_attribute_business_category = SEC_OID_UNKNOWN;
    128 SECOidTag cert_attribute_ev_incorporation_country = SEC_OID_UNKNOWN;
    129 
    130 class DynamicOidRegisterer {
    131  public:
    132   DynamicOidRegisterer() {
    133     ms_cert_ext_certtype = RegisterDynamicOid("1.3.6.1.4.1.311.20.2");
    134     ms_certsrv_ca_version = RegisterDynamicOid("1.3.6.1.4.1.311.21.1");
    135     ms_nt_principal_name = RegisterDynamicOid("1.3.6.1.4.1.311.20.2.3");
    136     ms_ntds_replication = RegisterDynamicOid("1.3.6.1.4.1.311.25.1");
    137 
    138     eku_ms_individual_code_signing = RegisterDynamicOid("1.3.6.1.4.1.311.2.1.21");
    139     eku_ms_commercial_code_signing = RegisterDynamicOid("1.3.6.1.4.1.311.2.1.22");
    140     eku_ms_trust_list_signing = RegisterDynamicOid("1.3.6.1.4.1.311.10.3.1");
    141     eku_ms_time_stamping = RegisterDynamicOid("1.3.6.1.4.1.311.10.3.2");
    142     eku_ms_server_gated_crypto = RegisterDynamicOid("1.3.6.1.4.1.311.10.3.3");
    143     eku_ms_encrypting_file_system = RegisterDynamicOid("1.3.6.1.4.1.311.10.3.4");
    144     eku_ms_file_recovery = RegisterDynamicOid("1.3.6.1.4.1.311.10.3.4.1");
    145     eku_ms_windows_hardware_driver_verification = RegisterDynamicOid(
    146         "1.3.6.1.4.1.311.10.3.5");
    147     eku_ms_qualified_subordination = RegisterDynamicOid(
    148         "1.3.6.1.4.1.311.10.3.10");
    149     eku_ms_key_recovery = RegisterDynamicOid("1.3.6.1.4.1.311.10.3.11");
    150     eku_ms_document_signing = RegisterDynamicOid("1.3.6.1.4.1.311.10.3.12");
    151     eku_ms_lifetime_signing = RegisterDynamicOid("1.3.6.1.4.1.311.10.3.13");
    152     eku_ms_smart_card_logon = RegisterDynamicOid("1.3.6.1.4.1.311.20.2.2");
    153     eku_ms_key_recovery_agent = RegisterDynamicOid("1.3.6.1.4.1.311.21.6");
    154     eku_netscape_international_step_up = RegisterDynamicOid(
    155         "2.16.840.1.113730.4.1");
    156 
    157     // These two OIDs will be built-in as SEC_OID_BUSINESS_CATEGORY and
    158     // SEC_OID_EV_INCORPORATION_COUNTRY starting in NSS 3.13.  Until then,
    159     // we need to add them dynamically.
    160     cert_attribute_business_category = RegisterDynamicOid("2.5.4.15");
    161     cert_attribute_ev_incorporation_country = RegisterDynamicOid(
    162         "1.3.6.1.4.1.311.60.2.1.3");
    163   }
    164 };
    165 
    166 static base::LazyInstance<DynamicOidRegisterer>::Leaky
    167     g_dynamic_oid_registerer = LAZY_INSTANCE_INITIALIZER;
    168 
    169 }  // namespace
    170 
    171 namespace mozilla_security_manager {
    172 
    173 std::string DumpOidString(SECItem* oid) {
    174   char* pr_string = CERT_GetOidString(oid);
    175   if (pr_string) {
    176     std::string rv = pr_string;
    177     PR_smprintf_free(pr_string);
    178     return rv;
    179   }
    180 
    181   return ProcessRawBytes(oid);
    182 }
    183 
    184 std::string GetOIDText(SECItem* oid) {
    185   g_dynamic_oid_registerer.Get();
    186 
    187   int string_id;
    188   SECOidTag oid_tag = SECOID_FindOIDTag(oid);
    189   switch (oid_tag) {
    190     case SEC_OID_AVA_COMMON_NAME:
    191       string_id = IDS_CERT_OID_AVA_COMMON_NAME;
    192       break;
    193     case SEC_OID_AVA_STATE_OR_PROVINCE:
    194       string_id = IDS_CERT_OID_AVA_STATE_OR_PROVINCE;
    195       break;
    196     case SEC_OID_AVA_ORGANIZATION_NAME:
    197       string_id = IDS_CERT_OID_AVA_ORGANIZATION_NAME;
    198       break;
    199     case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME:
    200       string_id = IDS_CERT_OID_AVA_ORGANIZATIONAL_UNIT_NAME;
    201       break;
    202     case SEC_OID_AVA_DN_QUALIFIER:
    203       string_id = IDS_CERT_OID_AVA_DN_QUALIFIER;
    204       break;
    205     case SEC_OID_AVA_COUNTRY_NAME:
    206       string_id = IDS_CERT_OID_AVA_COUNTRY_NAME;
    207       break;
    208     case SEC_OID_AVA_SERIAL_NUMBER:
    209       string_id = IDS_CERT_OID_AVA_SERIAL_NUMBER;
    210       break;
    211     case SEC_OID_AVA_LOCALITY:
    212       string_id = IDS_CERT_OID_AVA_LOCALITY;
    213       break;
    214     case SEC_OID_AVA_DC:
    215       string_id = IDS_CERT_OID_AVA_DC;
    216       break;
    217     case SEC_OID_RFC1274_MAIL:
    218       string_id = IDS_CERT_OID_RFC1274_MAIL;
    219       break;
    220     case SEC_OID_RFC1274_UID:
    221       string_id = IDS_CERT_OID_RFC1274_UID;
    222       break;
    223     case SEC_OID_PKCS9_EMAIL_ADDRESS:
    224       string_id = IDS_CERT_OID_PKCS9_EMAIL_ADDRESS;
    225       break;
    226     case SEC_OID_PKCS1_RSA_ENCRYPTION:
    227       string_id = IDS_CERT_OID_PKCS1_RSA_ENCRYPTION;
    228       break;
    229     case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
    230       string_id = IDS_CERT_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION;
    231       break;
    232     case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
    233       string_id = IDS_CERT_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION;
    234       break;
    235     case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
    236       string_id = IDS_CERT_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
    237       break;
    238     case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
    239       string_id = IDS_CERT_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
    240       break;
    241     case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
    242       string_id = IDS_CERT_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
    243       break;
    244     case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
    245       string_id = IDS_CERT_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
    246       break;
    247     case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
    248       string_id = IDS_CERT_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
    249       break;
    250     case SEC_OID_NS_CERT_EXT_CERT_TYPE:
    251       string_id = IDS_CERT_EXT_NS_CERT_TYPE;
    252       break;
    253     case SEC_OID_NS_CERT_EXT_BASE_URL:
    254       string_id = IDS_CERT_EXT_NS_CERT_BASE_URL;
    255       break;
    256     case SEC_OID_NS_CERT_EXT_REVOCATION_URL:
    257       string_id = IDS_CERT_EXT_NS_CERT_REVOCATION_URL;
    258       break;
    259     case SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL:
    260       string_id = IDS_CERT_EXT_NS_CA_REVOCATION_URL;
    261       break;
    262     case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL:
    263       string_id = IDS_CERT_EXT_NS_CERT_RENEWAL_URL;
    264       break;
    265     case SEC_OID_NS_CERT_EXT_CA_POLICY_URL:
    266       string_id = IDS_CERT_EXT_NS_CA_POLICY_URL;
    267       break;
    268     case SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME:
    269       string_id = IDS_CERT_EXT_NS_SSL_SERVER_NAME;
    270       break;
    271     case SEC_OID_NS_CERT_EXT_COMMENT:
    272       string_id = IDS_CERT_EXT_NS_COMMENT;
    273       break;
    274     case SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL:
    275       string_id = IDS_CERT_EXT_NS_LOST_PASSWORD_URL;
    276       break;
    277     case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME:
    278       string_id = IDS_CERT_EXT_NS_CERT_RENEWAL_TIME;
    279       break;
    280     case SEC_OID_X509_SUBJECT_DIRECTORY_ATTR:
    281       string_id = IDS_CERT_X509_SUBJECT_DIRECTORY_ATTR;
    282       break;
    283     case SEC_OID_X509_SUBJECT_KEY_ID:
    284       string_id = IDS_CERT_X509_SUBJECT_KEYID;
    285       break;
    286     case SEC_OID_X509_KEY_USAGE:
    287       string_id = IDS_CERT_X509_KEY_USAGE;
    288       break;
    289     case SEC_OID_X509_SUBJECT_ALT_NAME:
    290       string_id = IDS_CERT_X509_SUBJECT_ALT_NAME;
    291       break;
    292     case SEC_OID_X509_ISSUER_ALT_NAME:
    293       string_id = IDS_CERT_X509_ISSUER_ALT_NAME;
    294       break;
    295     case SEC_OID_X509_BASIC_CONSTRAINTS:
    296       string_id = IDS_CERT_X509_BASIC_CONSTRAINTS;
    297       break;
    298     case SEC_OID_X509_NAME_CONSTRAINTS:
    299       string_id = IDS_CERT_X509_NAME_CONSTRAINTS;
    300       break;
    301     case SEC_OID_X509_CRL_DIST_POINTS:
    302       string_id = IDS_CERT_X509_CRL_DIST_POINTS;
    303       break;
    304     case SEC_OID_X509_CERTIFICATE_POLICIES:
    305       string_id = IDS_CERT_X509_CERT_POLICIES;
    306       break;
    307     case SEC_OID_X509_POLICY_MAPPINGS:
    308       string_id = IDS_CERT_X509_POLICY_MAPPINGS;
    309       break;
    310     case SEC_OID_X509_POLICY_CONSTRAINTS:
    311       string_id = IDS_CERT_X509_POLICY_CONSTRAINTS;
    312       break;
    313     case SEC_OID_X509_AUTH_KEY_ID:
    314       string_id = IDS_CERT_X509_AUTH_KEYID;
    315       break;
    316     case SEC_OID_X509_EXT_KEY_USAGE:
    317       string_id = IDS_CERT_X509_EXT_KEY_USAGE;
    318       break;
    319     case SEC_OID_X509_AUTH_INFO_ACCESS:
    320       string_id = IDS_CERT_X509_AUTH_INFO_ACCESS;
    321       break;
    322     case SEC_OID_EXT_KEY_USAGE_SERVER_AUTH:
    323       string_id = IDS_CERT_EKU_TLS_WEB_SERVER_AUTHENTICATION;
    324       break;
    325     case SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH:
    326       string_id = IDS_CERT_EKU_TLS_WEB_CLIENT_AUTHENTICATION;
    327       break;
    328     case SEC_OID_EXT_KEY_USAGE_CODE_SIGN:
    329       string_id = IDS_CERT_EKU_CODE_SIGNING;
    330       break;
    331     case SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT:
    332       string_id = IDS_CERT_EKU_EMAIL_PROTECTION;
    333       break;
    334     case SEC_OID_EXT_KEY_USAGE_TIME_STAMP:
    335       string_id = IDS_CERT_EKU_TIME_STAMPING;
    336       break;
    337     case SEC_OID_OCSP_RESPONDER:
    338       string_id = IDS_CERT_EKU_OCSP_SIGNING;
    339       break;
    340     case SEC_OID_PKIX_CPS_POINTER_QUALIFIER:
    341       string_id = IDS_CERT_PKIX_CPS_POINTER_QUALIFIER;
    342       break;
    343     case SEC_OID_PKIX_USER_NOTICE_QUALIFIER:
    344       string_id = IDS_CERT_PKIX_USER_NOTICE_QUALIFIER;
    345       break;
    346     case SEC_OID_UNKNOWN:
    347       string_id = -1;
    348       break;
    349 
    350     // There are a billionty other OIDs we could add here.  I tried to get the
    351     // important ones...
    352     default:
    353       if (oid_tag == ms_cert_ext_certtype)
    354         string_id = IDS_CERT_EXT_MS_CERT_TYPE;
    355       else if (oid_tag == ms_certsrv_ca_version)
    356         string_id = IDS_CERT_EXT_MS_CA_VERSION;
    357       else if (oid_tag == ms_nt_principal_name)
    358         string_id = IDS_CERT_EXT_MS_NT_PRINCIPAL_NAME;
    359       else if (oid_tag == ms_ntds_replication)
    360         string_id = IDS_CERT_EXT_MS_NTDS_REPLICATION;
    361       else if (oid_tag == eku_ms_individual_code_signing)
    362         string_id = IDS_CERT_EKU_MS_INDIVIDUAL_CODE_SIGNING;
    363       else if (oid_tag == eku_ms_commercial_code_signing)
    364         string_id = IDS_CERT_EKU_MS_COMMERCIAL_CODE_SIGNING;
    365       else if (oid_tag == eku_ms_trust_list_signing)
    366         string_id = IDS_CERT_EKU_MS_TRUST_LIST_SIGNING;
    367       else if (oid_tag == eku_ms_time_stamping)
    368         string_id = IDS_CERT_EKU_MS_TIME_STAMPING;
    369       else if (oid_tag == eku_ms_server_gated_crypto)
    370         string_id = IDS_CERT_EKU_MS_SERVER_GATED_CRYPTO;
    371       else if (oid_tag == eku_ms_encrypting_file_system)
    372         string_id = IDS_CERT_EKU_MS_ENCRYPTING_FILE_SYSTEM;
    373       else if (oid_tag == eku_ms_file_recovery)
    374         string_id = IDS_CERT_EKU_MS_FILE_RECOVERY;
    375       else if (oid_tag == eku_ms_windows_hardware_driver_verification)
    376         string_id = IDS_CERT_EKU_MS_WINDOWS_HARDWARE_DRIVER_VERIFICATION;
    377       else if (oid_tag == eku_ms_qualified_subordination)
    378         string_id = IDS_CERT_EKU_MS_QUALIFIED_SUBORDINATION;
    379       else if (oid_tag == eku_ms_key_recovery)
    380         string_id = IDS_CERT_EKU_MS_KEY_RECOVERY;
    381       else if (oid_tag == eku_ms_document_signing)
    382         string_id = IDS_CERT_EKU_MS_DOCUMENT_SIGNING;
    383       else if (oid_tag == eku_ms_lifetime_signing)
    384         string_id = IDS_CERT_EKU_MS_LIFETIME_SIGNING;
    385       else if (oid_tag == eku_ms_smart_card_logon)
    386         string_id = IDS_CERT_EKU_MS_SMART_CARD_LOGON;
    387       else if (oid_tag == eku_ms_key_recovery_agent)
    388         string_id = IDS_CERT_EKU_MS_KEY_RECOVERY_AGENT;
    389       else if (oid_tag == eku_netscape_international_step_up)
    390         string_id = IDS_CERT_EKU_NETSCAPE_INTERNATIONAL_STEP_UP;
    391       else if (oid_tag == cert_attribute_business_category)
    392         string_id = IDS_CERT_OID_BUSINESS_CATEGORY;
    393       else if (oid_tag == cert_attribute_ev_incorporation_country)
    394         string_id = IDS_CERT_OID_EV_INCORPORATION_COUNTRY;
    395       else
    396         string_id = -1;
    397       break;
    398   }
    399   if (string_id >= 0)
    400     return l10n_util::GetStringUTF8(string_id);
    401 
    402   return DumpOidString(oid);
    403 }
    404 
    405 // Get a display string from a Relative Distinguished Name.
    406 std::string ProcessRDN(CERTRDN* rdn) {
    407   std::string rv;
    408 
    409   CERTAVA** avas = rdn->avas;
    410   for (size_t i = 0; avas[i] != NULL; ++i) {
    411     rv += GetOIDText(&avas[i]->type);
    412     SECItem* decode_item = CERT_DecodeAVAValue(&avas[i]->value);
    413     if (decode_item) {
    414       // TODO(mattm): Pass decode_item to CERT_RFC1485_EscapeAndQuote.
    415       rv += " = ";
    416       std::string value(reinterpret_cast<char*>(decode_item->data),
    417                         decode_item->len);
    418       if (SECOID_FindOIDTag(&avas[i]->type) == SEC_OID_AVA_COMMON_NAME)
    419         value = x509_certificate_model::ProcessIDN(value);
    420       rv += value;
    421       SECITEM_FreeItem(decode_item, PR_TRUE);
    422     }
    423     rv += '\n';
    424   }
    425 
    426   return rv;
    427 }
    428 
    429 std::string ProcessName(CERTName* name) {
    430   std::string rv;
    431   CERTRDN** last_rdn;
    432 
    433   // Find last non-NULL rdn.
    434   for (last_rdn = name->rdns; last_rdn[0]; last_rdn++) {}
    435   last_rdn--;
    436 
    437   for (CERTRDN** rdn = last_rdn; rdn >= name->rdns; rdn--)
    438     rv += ProcessRDN(*rdn);
    439   return rv;
    440 }
    441 
    442 std::string ProcessBasicConstraints(SECItem* extension_data) {
    443   CERTBasicConstraints value;
    444   value.pathLenConstraint = -1;
    445   if (CERT_DecodeBasicConstraintValue(&value, extension_data) != SECSuccess)
    446     return ProcessRawBytes(extension_data);
    447 
    448   std::string rv;
    449   if (value.isCA)
    450     rv = l10n_util::GetStringUTF8(IDS_CERT_X509_BASIC_CONSTRAINT_IS_CA);
    451   else
    452     rv = l10n_util::GetStringUTF8(IDS_CERT_X509_BASIC_CONSTRAINT_IS_NOT_CA);
    453   rv += '\n';
    454   if (value.pathLenConstraint != -1) {
    455     base::string16 depth;
    456     if (value.pathLenConstraint == CERT_UNLIMITED_PATH_CONSTRAINT) {
    457       depth = l10n_util::GetStringUTF16(
    458           IDS_CERT_X509_BASIC_CONSTRAINT_PATH_LEN_UNLIMITED);
    459     } else {
    460       depth = base::FormatNumber(value.pathLenConstraint);
    461     }
    462     rv += l10n_util::GetStringFUTF8(IDS_CERT_X509_BASIC_CONSTRAINT_PATH_LEN,
    463                                     depth);
    464   }
    465   return rv;
    466 }
    467 
    468 std::string ProcessGeneralName(PRArenaPool* arena,
    469                                CERTGeneralName* current) {
    470   DCHECK(current);
    471 
    472   std::string key;
    473   std::string value;
    474 
    475   switch (current->type) {
    476     case certOtherName: {
    477       key = GetOIDText(&current->name.OthName.oid);
    478       // g_dynamic_oid_registerer.Get() will have been run by GetOIDText.
    479       SECOidTag oid_tag = SECOID_FindOIDTag(&current->name.OthName.oid);
    480       if (oid_tag == ms_nt_principal_name) {
    481         // The type of this name is apparently nowhere explicitly
    482         // documented. However, in the generated templates, it is always
    483         // UTF-8. So try to decode this as UTF-8; if that fails, dump the
    484         // raw data.
    485         SECItem decoded;
    486         if (SEC_ASN1DecodeItem(arena, &decoded,
    487                                SEC_ASN1_GET(SEC_UTF8StringTemplate),
    488                                &current->name.OthName.name) == SECSuccess) {
    489           value = std::string(reinterpret_cast<char*>(decoded.data),
    490                               decoded.len);
    491         } else {
    492           value = ProcessRawBytes(&current->name.OthName.name);
    493         }
    494         break;
    495       } else if (oid_tag == ms_ntds_replication) {
    496         // This should be a 16-byte GUID.
    497         SECItem guid;
    498         if (SEC_ASN1DecodeItem(arena, &guid,
    499                                SEC_ASN1_GET(SEC_OctetStringTemplate),
    500                                &current->name.OthName.name) == SECSuccess &&
    501             guid.len == 16) {
    502           unsigned char* d = guid.data;
    503           base::SStringPrintf(
    504               &value,
    505               "{%.2x%.2x%.2x%.2x-%.2x%.2x-%.2x%.2x-"
    506               "%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x}",
    507               d[3], d[2], d[1], d[0], d[5], d[4], d[7], d[6],
    508               d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
    509         } else {
    510           value = ProcessRawBytes(&current->name.OthName.name);
    511         }
    512       } else {
    513         value = ProcessRawBytes(&current->name.OthName.name);
    514       }
    515       break;
    516     }
    517     case certRFC822Name:
    518       key = l10n_util::GetStringUTF8(IDS_CERT_GENERAL_NAME_RFC822_NAME);
    519       value = std::string(reinterpret_cast<char*>(current->name.other.data),
    520                           current->name.other.len);
    521       break;
    522     case certDNSName:
    523       key = l10n_util::GetStringUTF8(IDS_CERT_GENERAL_NAME_DNS_NAME);
    524       value = std::string(reinterpret_cast<char*>(current->name.other.data),
    525                           current->name.other.len);
    526       value = x509_certificate_model::ProcessIDN(value);
    527       break;
    528     case certX400Address:
    529       key = l10n_util::GetStringUTF8(IDS_CERT_GENERAL_NAME_X400_ADDRESS);
    530       value = ProcessRawBytes(&current->name.other);
    531       break;
    532     case certDirectoryName:
    533       key = l10n_util::GetStringUTF8(IDS_CERT_GENERAL_NAME_DIRECTORY_NAME);
    534       value = ProcessName(&current->name.directoryName);
    535       break;
    536     case certEDIPartyName:
    537       key = l10n_util::GetStringUTF8(IDS_CERT_GENERAL_NAME_EDI_PARTY_NAME);
    538       value = ProcessRawBytes(&current->name.other);
    539       break;
    540     case certURI:
    541       key = l10n_util::GetStringUTF8(IDS_CERT_GENERAL_NAME_URI);
    542       value = std::string(reinterpret_cast<char*>(current->name.other.data),
    543                           current->name.other.len);
    544       break;
    545     case certIPAddress: {
    546       key = l10n_util::GetStringUTF8(IDS_CERT_GENERAL_NAME_IP_ADDRESS);
    547 
    548       net::IPAddressNumber ip(
    549           current->name.other.data,
    550           current->name.other.data + current->name.other.len);
    551 
    552       if (net::GetAddressFamily(ip) != net::ADDRESS_FAMILY_UNSPECIFIED) {
    553         value = net::IPAddressToString(ip);
    554       } else {
    555         // Invalid IP address.
    556         value = ProcessRawBytes(&current->name.other);
    557       }
    558       break;
    559     }
    560     case certRegisterID:
    561       key = l10n_util::GetStringUTF8(IDS_CERT_GENERAL_NAME_REGISTERED_ID);
    562       value = DumpOidString(&current->name.other);
    563       break;
    564   }
    565   std::string rv(l10n_util::GetStringFUTF8(IDS_CERT_UNKNOWN_OID_INFO_FORMAT,
    566                                            base::UTF8ToUTF16(key),
    567                                            base::UTF8ToUTF16(value)));
    568   rv += '\n';
    569   return rv;
    570 }
    571 
    572 std::string ProcessGeneralNames(PRArenaPool* arena,
    573                                 CERTGeneralName* name_list) {
    574   std::string rv;
    575   CERTGeneralName* current = name_list;
    576 
    577   do {
    578     std::string text = ProcessGeneralName(arena, current);
    579     if (text.empty())
    580       break;
    581     rv += text;
    582     current = CERT_GetNextGeneralName(current);
    583   } while (current != name_list);
    584   return rv;
    585 }
    586 
    587 std::string ProcessAltName(SECItem* extension_data) {
    588   CERTGeneralName* name_list;
    589 
    590   crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
    591   CHECK(arena.get());
    592 
    593   name_list = CERT_DecodeAltNameExtension(arena.get(), extension_data);
    594   if (!name_list)
    595     return l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_DUMP_ERROR);
    596 
    597   return ProcessGeneralNames(arena.get(), name_list);
    598 }
    599 
    600 std::string ProcessSubjectKeyId(SECItem* extension_data) {
    601   SECItem decoded;
    602   crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
    603   CHECK(arena.get());
    604 
    605   std::string rv;
    606   if (SEC_QuickDERDecodeItem(arena.get(), &decoded,
    607                              SEC_ASN1_GET(SEC_OctetStringTemplate),
    608                              extension_data) != SECSuccess) {
    609     rv = l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_DUMP_ERROR);
    610     return rv;
    611   }
    612 
    613   rv = l10n_util::GetStringFUTF8(IDS_CERT_KEYID_FORMAT,
    614                                  base::ASCIIToUTF16(ProcessRawBytes(&decoded)));
    615   return rv;
    616 }
    617 
    618 std::string ProcessAuthKeyId(SECItem* extension_data) {
    619   CERTAuthKeyID* ret;
    620   crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
    621   std::string rv;
    622 
    623   CHECK(arena.get());
    624 
    625   ret = CERT_DecodeAuthKeyID(arena.get(), extension_data);
    626 
    627   if (ret->keyID.len > 0) {
    628     rv += l10n_util::GetStringFUTF8(IDS_CERT_KEYID_FORMAT,
    629                                     base::ASCIIToUTF16(
    630                                         ProcessRawBytes(&ret->keyID)));
    631     rv += '\n';
    632   }
    633 
    634   if (ret->authCertIssuer) {
    635     rv += l10n_util::GetStringFUTF8(
    636         IDS_CERT_ISSUER_FORMAT,
    637         base::UTF8ToUTF16(
    638             ProcessGeneralNames(arena.get(), ret->authCertIssuer)));
    639     rv += '\n';
    640   }
    641 
    642   if (ret->authCertSerialNumber.len > 0) {
    643     rv += l10n_util::GetStringFUTF8(
    644         IDS_CERT_SERIAL_NUMBER_FORMAT,
    645         base::ASCIIToUTF16(ProcessRawBytes(&ret->authCertSerialNumber)));
    646     rv += '\n';
    647   }
    648 
    649   return rv;
    650 }
    651 
    652 std::string ProcessUserNotice(SECItem* der_notice) {
    653   CERTUserNotice* notice = CERT_DecodeUserNotice(der_notice);
    654   if (!notice)
    655     return ProcessRawBytes(der_notice);
    656 
    657   std::string rv;
    658   if (notice->noticeReference.organization.len != 0) {
    659     switch (notice->noticeReference.organization.type) {
    660       case siAsciiString:
    661       case siVisibleString:
    662       case siUTF8String:
    663         rv += std::string(
    664             reinterpret_cast<char*>(notice->noticeReference.organization.data),
    665             notice->noticeReference.organization.len);
    666         break;
    667       case siBMPString:
    668         rv += ProcessBMPString(&notice->noticeReference.organization);
    669         break;
    670       default:
    671         break;
    672     }
    673     rv += " - ";
    674     SECItem** itemList = notice->noticeReference.noticeNumbers;
    675     while (*itemList) {
    676       unsigned long number;
    677       if (SEC_ASN1DecodeInteger(*itemList, &number) == SECSuccess) {
    678         if (itemList != notice->noticeReference.noticeNumbers)
    679           rv += ", ";
    680         rv += '#';
    681         rv += base::UTF16ToUTF8(base::UintToString16(number));
    682       }
    683       itemList++;
    684     }
    685   }
    686   if (notice->displayText.len != 0) {
    687     rv += "\n    ";
    688     switch (notice->displayText.type) {
    689       case siAsciiString:
    690       case siVisibleString:
    691       case siUTF8String:
    692         rv += std::string(reinterpret_cast<char*>(notice->displayText.data),
    693                           notice->displayText.len);
    694         break;
    695       case siBMPString:
    696         rv += ProcessBMPString(&notice->displayText);
    697         break;
    698       default:
    699         break;
    700     }
    701   }
    702 
    703   CERT_DestroyUserNotice(notice);
    704   return rv;
    705 }
    706 
    707 std::string ProcessCertificatePolicies(SECItem* extension_data) {
    708   std::string rv;
    709 
    710   CERTCertificatePolicies* policies = CERT_DecodeCertificatePoliciesExtension(
    711       extension_data);
    712   if (!policies)
    713     return l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_DUMP_ERROR);
    714 
    715   CERTPolicyInfo** policyInfos = policies->policyInfos;
    716   while (*policyInfos) {
    717     CERTPolicyInfo* policyInfo = *policyInfos++;
    718     std::string key = GetOIDText(&policyInfo->policyID);
    719 
    720     // If we have policy qualifiers, display the oid text
    721     // with a ':', otherwise just put the oid text and a newline.
    722     // TODO(mattm): Add extra note if this is the ev oid?  (It's a bit
    723     // complicated, since we don't want to do the EV check synchronously.)
    724     if (policyInfo->policyQualifiers) {
    725       rv += l10n_util::GetStringFUTF8(IDS_CERT_MULTILINE_INFO_START_FORMAT,
    726                                       base::UTF8ToUTF16(key));
    727     } else {
    728       rv += key;
    729     }
    730     rv += '\n';
    731 
    732     if (policyInfo->policyQualifiers) {
    733       // Add all qualifiers on separate lines, indented.
    734       CERTPolicyQualifier** policyQualifiers = policyInfo->policyQualifiers;
    735       while (*policyQualifiers != NULL) {
    736         rv += "  ";
    737 
    738         CERTPolicyQualifier* policyQualifier = *policyQualifiers++;
    739         rv += l10n_util::GetStringFUTF8(
    740             IDS_CERT_MULTILINE_INFO_START_FORMAT,
    741             base::UTF8ToUTF16(GetOIDText(&policyQualifier->qualifierID)));
    742         switch(policyQualifier->oid) {
    743           case SEC_OID_PKIX_CPS_POINTER_QUALIFIER:
    744             rv += "    ";
    745             /* The CPS pointer ought to be the cPSuri alternative
    746                of the Qualifier choice. */
    747             rv += ProcessIA5String(&policyQualifier->qualifierValue);
    748             break;
    749           case SEC_OID_PKIX_USER_NOTICE_QUALIFIER:
    750             rv += ProcessUserNotice(&policyQualifier->qualifierValue);
    751             break;
    752           default:
    753             rv += ProcessRawBytes(&policyQualifier->qualifierValue);
    754             break;
    755         }
    756         rv += '\n';
    757       }
    758     }
    759   }
    760 
    761   CERT_DestroyCertificatePoliciesExtension(policies);
    762   return rv;
    763 }
    764 
    765 std::string ProcessCrlDistPoints(SECItem* extension_data) {
    766   std::string rv;
    767   CERTCrlDistributionPoints* crldp;
    768   CRLDistributionPoint** points;
    769   CRLDistributionPoint* point;
    770   bool comma;
    771 
    772   static const struct {
    773     int reason;
    774     int string_id;
    775   } reason_string_map[] = {
    776     {RF_UNUSED, IDS_CERT_REVOCATION_REASON_UNUSED},
    777     {RF_KEY_COMPROMISE, IDS_CERT_REVOCATION_REASON_KEY_COMPROMISE},
    778     {RF_CA_COMPROMISE, IDS_CERT_REVOCATION_REASON_CA_COMPROMISE},
    779     {RF_AFFILIATION_CHANGED, IDS_CERT_REVOCATION_REASON_AFFILIATION_CHANGED},
    780     {RF_SUPERSEDED, IDS_CERT_REVOCATION_REASON_SUPERSEDED},
    781     {RF_CESSATION_OF_OPERATION,
    782      IDS_CERT_REVOCATION_REASON_CESSATION_OF_OPERATION},
    783     {RF_CERTIFICATE_HOLD, IDS_CERT_REVOCATION_REASON_CERTIFICATE_HOLD},
    784   };
    785 
    786   crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
    787   CHECK(arena.get());
    788 
    789   crldp = CERT_DecodeCRLDistributionPoints(arena.get(), extension_data);
    790   if (!crldp || !crldp->distPoints) {
    791     rv = l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_DUMP_ERROR);
    792     return rv;
    793   }
    794 
    795   for (points = crldp->distPoints; *points; ++points) {
    796     point = *points;
    797     switch (point->distPointType) {
    798       case generalName:
    799         // generalName is a typo in upstream NSS; fullName is actually a
    800         // GeneralNames (SEQUENCE OF GeneralName). See Mozilla Bug #615100.
    801         rv += ProcessGeneralNames(arena.get(), point->distPoint.fullName);
    802         break;
    803       case relativeDistinguishedName:
    804         rv += ProcessRDN(&point->distPoint.relativeName);
    805         break;
    806     }
    807     if (point->reasons.len) {
    808       rv += ' ';
    809       comma = false;
    810       for (size_t i = 0; i < ARRAYSIZE_UNSAFE(reason_string_map); ++i) {
    811         if (point->reasons.data[0] & reason_string_map[i].reason) {
    812           if (comma)
    813             rv += ',';
    814           rv += l10n_util::GetStringUTF8(reason_string_map[i].string_id);
    815           comma = true;
    816         }
    817       }
    818       rv += '\n';
    819     }
    820     if (point->crlIssuer) {
    821       rv += l10n_util::GetStringFUTF8(
    822           IDS_CERT_ISSUER_FORMAT,
    823           base::UTF8ToUTF16(
    824               ProcessGeneralNames(arena.get(), point->crlIssuer)));
    825     }
    826   }
    827   return rv;
    828 }
    829 
    830 std::string ProcessAuthInfoAccess(SECItem* extension_data) {
    831   std::string rv;
    832   CERTAuthInfoAccess** aia;
    833   CERTAuthInfoAccess* desc;
    834   crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
    835   CHECK(arena.get());
    836 
    837   aia = CERT_DecodeAuthInfoAccessExtension(arena.get(), extension_data);
    838   if (aia == NULL)
    839     return l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_DUMP_ERROR);
    840 
    841   while (*aia != NULL) {
    842     desc = *aia++;
    843     base::string16 location_str =
    844         base::UTF8ToUTF16(ProcessGeneralName(arena.get(), desc->location));
    845     switch (SECOID_FindOIDTag(&desc->method)) {
    846     case SEC_OID_PKIX_OCSP:
    847       rv += l10n_util::GetStringFUTF8(IDS_CERT_OCSP_RESPONDER_FORMAT,
    848                                       location_str);
    849       break;
    850     case SEC_OID_PKIX_CA_ISSUERS:
    851       rv += l10n_util::GetStringFUTF8(IDS_CERT_CA_ISSUERS_FORMAT,
    852                                       location_str);
    853       break;
    854     default:
    855       rv += l10n_util::GetStringFUTF8(IDS_CERT_UNKNOWN_OID_INFO_FORMAT,
    856                                       base::UTF8ToUTF16(
    857                                           GetOIDText(&desc->method)),
    858                                       location_str);
    859       break;
    860     }
    861   }
    862   return rv;
    863 }
    864 
    865 std::string ProcessIA5String(SECItem* extension_data) {
    866   SECItem item;
    867   if (SEC_ASN1DecodeItem(NULL, &item, SEC_ASN1_GET(SEC_IA5StringTemplate),
    868                          extension_data) != SECSuccess)
    869     return l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_DUMP_ERROR);
    870   std::string rv((char*)item.data, item.len);  // ASCII data.
    871   PORT_Free(item.data);
    872   return rv;
    873 }
    874 
    875 std::string ProcessBMPString(SECItem* extension_data) {
    876   std::string rv;
    877   SECItem item;
    878   crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
    879   CHECK(arena.get());
    880 
    881   if (SEC_ASN1DecodeItem(arena.get(), &item,
    882                          SEC_ASN1_GET(SEC_BMPStringTemplate), extension_data) ==
    883       SECSuccess)
    884     rv = BMPtoUTF8(arena.get(), item.data, item.len);
    885   return rv;
    886 }
    887 
    888 struct MaskIdPair {
    889   unsigned int mask;
    890   int string_id;
    891 };
    892 
    893 static std::string ProcessBitField(SECItem* bitfield,
    894                                    const MaskIdPair* string_map,
    895                                    size_t len,
    896                                    char separator) {
    897   unsigned int bits = 0;
    898   std::string rv;
    899   for (size_t i = 0; i * 8 < bitfield->len && i < sizeof(bits); ++i)
    900     bits |= bitfield->data[i] << (i * 8);
    901   for (size_t i = 0; i < len; ++i) {
    902     if (bits & string_map[i].mask) {
    903       if (!rv.empty())
    904         rv += separator;
    905       rv += l10n_util::GetStringUTF8(string_map[i].string_id);
    906     }
    907   }
    908   return rv;
    909 }
    910 
    911 static std::string ProcessBitStringExtension(SECItem* extension_data,
    912                                              const MaskIdPair* string_map,
    913                                              size_t len,
    914                                              char separator) {
    915   SECItem decoded;
    916   decoded.type = siBuffer;
    917   decoded.data = NULL;
    918   decoded.len  = 0;
    919   if (SEC_ASN1DecodeItem(NULL, &decoded, SEC_ASN1_GET(SEC_BitStringTemplate),
    920                          extension_data) != SECSuccess)
    921     return l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_DUMP_ERROR);
    922   std::string rv = ProcessBitField(&decoded, string_map, len, separator);
    923   PORT_Free(decoded.data);
    924   return rv;
    925 }
    926 
    927 std::string ProcessNSCertTypeExtension(SECItem* extension_data) {
    928   static const MaskIdPair usage_string_map[] = {
    929     {NS_CERT_TYPE_SSL_CLIENT, IDS_CERT_USAGE_SSL_CLIENT},
    930     {NS_CERT_TYPE_SSL_SERVER, IDS_CERT_USAGE_SSL_SERVER},
    931     {NS_CERT_TYPE_EMAIL, IDS_CERT_EXT_NS_CERT_TYPE_EMAIL},
    932     {NS_CERT_TYPE_OBJECT_SIGNING, IDS_CERT_USAGE_OBJECT_SIGNER},
    933     {NS_CERT_TYPE_SSL_CA, IDS_CERT_USAGE_SSL_CA},
    934     {NS_CERT_TYPE_EMAIL_CA, IDS_CERT_EXT_NS_CERT_TYPE_EMAIL_CA},
    935     {NS_CERT_TYPE_OBJECT_SIGNING_CA, IDS_CERT_USAGE_OBJECT_SIGNER},
    936   };
    937   return ProcessBitStringExtension(extension_data, usage_string_map,
    938                                    ARRAYSIZE_UNSAFE(usage_string_map), '\n');
    939 }
    940 
    941 static const MaskIdPair key_usage_string_map[] = {
    942   {KU_DIGITAL_SIGNATURE, IDS_CERT_X509_KEY_USAGE_SIGNING},
    943   {KU_NON_REPUDIATION, IDS_CERT_X509_KEY_USAGE_NONREP},
    944   {KU_KEY_ENCIPHERMENT, IDS_CERT_X509_KEY_USAGE_ENCIPHERMENT},
    945   {KU_DATA_ENCIPHERMENT, IDS_CERT_X509_KEY_USAGE_DATA_ENCIPHERMENT},
    946   {KU_KEY_AGREEMENT, IDS_CERT_X509_KEY_USAGE_KEY_AGREEMENT},
    947   {KU_KEY_CERT_SIGN, IDS_CERT_X509_KEY_USAGE_CERT_SIGNER},
    948   {KU_CRL_SIGN, IDS_CERT_X509_KEY_USAGE_CRL_SIGNER},
    949   {KU_ENCIPHER_ONLY, IDS_CERT_X509_KEY_USAGE_ENCIPHER_ONLY},
    950   // NSS is missing a flag for dechiperOnly, see:
    951   // https://bugzilla.mozilla.org/show_bug.cgi?id=549952
    952 };
    953 
    954 std::string ProcessKeyUsageBitString(SECItem* bitstring, char sep) {
    955   return ProcessBitField(bitstring, key_usage_string_map,
    956                          arraysize(key_usage_string_map), sep);
    957 }
    958 
    959 std::string ProcessKeyUsageExtension(SECItem* extension_data) {
    960   return ProcessBitStringExtension(extension_data, key_usage_string_map,
    961                                    arraysize(key_usage_string_map), '\n');
    962 }
    963 
    964 std::string ProcessExtKeyUsage(SECItem* extension_data) {
    965   std::string rv;
    966   CERTOidSequence* extension_key_usage = NULL;
    967   extension_key_usage = CERT_DecodeOidSequence(extension_data);
    968   if (extension_key_usage == NULL)
    969     return l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_DUMP_ERROR);
    970 
    971   SECItem** oids;
    972   SECItem* oid;
    973   for (oids = extension_key_usage->oids; oids != NULL && *oids != NULL;
    974        ++oids) {
    975     oid = *oids;
    976     std::string oid_dump = DumpOidString(oid);
    977     std::string oid_text = GetOIDText(oid);
    978 
    979     // If oid is one we recognize, oid_text will have a text description of the
    980     // OID, which we display along with the oid_dump.  If we don't recognize the
    981     // OID, GetOIDText will return the same value as DumpOidString, so just
    982     // display the OID alone.
    983     if (oid_dump == oid_text)
    984       rv += oid_dump;
    985     else
    986       rv += l10n_util::GetStringFUTF8(IDS_CERT_EXT_KEY_USAGE_FORMAT,
    987                                       base::UTF8ToUTF16(oid_text),
    988                                       base::UTF8ToUTF16(oid_dump));
    989     rv += '\n';
    990   }
    991   CERT_DestroyOidSequence(extension_key_usage);
    992   return rv;
    993 }
    994 
    995 std::string ProcessExtensionData(CERTCertExtension* extension) {
    996   g_dynamic_oid_registerer.Get();
    997   SECOidTag oid_tag = SECOID_FindOIDTag(&extension->id);
    998   SECItem* extension_data = &extension->value;
    999 
   1000   // This (and its sub-functions) are based on the same-named functions in
   1001   // security/manager/ssl/src/nsNSSCertHelper.cpp.
   1002   switch (oid_tag) {
   1003     case SEC_OID_NS_CERT_EXT_CERT_TYPE:
   1004       return ProcessNSCertTypeExtension(extension_data);
   1005     case SEC_OID_X509_KEY_USAGE:
   1006       return ProcessKeyUsageExtension(extension_data);
   1007     case SEC_OID_X509_BASIC_CONSTRAINTS:
   1008       return ProcessBasicConstraints(extension_data);
   1009     case SEC_OID_X509_EXT_KEY_USAGE:
   1010       return ProcessExtKeyUsage(extension_data);
   1011     case SEC_OID_X509_ISSUER_ALT_NAME:
   1012     case SEC_OID_X509_SUBJECT_ALT_NAME:
   1013       return ProcessAltName(extension_data);
   1014     case SEC_OID_X509_SUBJECT_KEY_ID:
   1015       return ProcessSubjectKeyId(extension_data);
   1016     case SEC_OID_X509_AUTH_KEY_ID:
   1017       return ProcessAuthKeyId(extension_data);
   1018     case SEC_OID_X509_CERTIFICATE_POLICIES:
   1019       return ProcessCertificatePolicies(extension_data);
   1020     case SEC_OID_X509_CRL_DIST_POINTS:
   1021       return ProcessCrlDistPoints(extension_data);
   1022     case SEC_OID_X509_AUTH_INFO_ACCESS:
   1023       return ProcessAuthInfoAccess(extension_data);
   1024     case SEC_OID_NS_CERT_EXT_BASE_URL:
   1025     case SEC_OID_NS_CERT_EXT_REVOCATION_URL:
   1026     case SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL:
   1027     case SEC_OID_NS_CERT_EXT_CA_CERT_URL:
   1028     case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL:
   1029     case SEC_OID_NS_CERT_EXT_CA_POLICY_URL:
   1030     case SEC_OID_NS_CERT_EXT_HOMEPAGE_URL:
   1031     case SEC_OID_NS_CERT_EXT_COMMENT:
   1032     case SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME:
   1033     case SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL:
   1034       return ProcessIA5String(extension_data);
   1035     default:
   1036       if (oid_tag == ms_cert_ext_certtype)
   1037         return ProcessBMPString(extension_data);
   1038       return ProcessRawBytes(extension_data);
   1039   }
   1040 }
   1041 
   1042 std::string ProcessSubjectPublicKeyInfo(CERTSubjectPublicKeyInfo* spki) {
   1043   std::string rv;
   1044   SECKEYPublicKey* key = SECKEY_ExtractPublicKey(spki);
   1045   if (key) {
   1046     switch (key->keyType) {
   1047       case rsaKey: {
   1048         rv = l10n_util::GetStringFUTF8(
   1049             IDS_CERT_RSA_PUBLIC_KEY_DUMP_FORMAT,
   1050             base::UintToString16(key->u.rsa.modulus.len * 8),
   1051             base::UTF8ToUTF16(ProcessRawBytes(&key->u.rsa.modulus)),
   1052             base::UintToString16(key->u.rsa.publicExponent.len * 8),
   1053             base::UTF8ToUTF16(ProcessRawBytes(&key->u.rsa.publicExponent)));
   1054         break;
   1055       }
   1056       default:
   1057         rv = x509_certificate_model::ProcessRawBits(
   1058             spki->subjectPublicKey.data, spki->subjectPublicKey.len);
   1059         break;
   1060     }
   1061     SECKEY_DestroyPublicKey(key);
   1062   }
   1063   return rv;
   1064 }
   1065 
   1066 net::CertType GetCertType(CERTCertificate *cert) {
   1067   CERTCertTrust trust = {0};
   1068   CERT_GetCertTrust(cert, &trust);
   1069 
   1070   unsigned all_flags = trust.sslFlags | trust.emailFlags |
   1071       trust.objectSigningFlags;
   1072 
   1073   if (cert->nickname && (all_flags & CERTDB_USER))
   1074     return net::USER_CERT;
   1075   if ((all_flags & CERTDB_VALID_CA) || CERT_IsCACert(cert, NULL))
   1076     return net::CA_CERT;
   1077   // TODO(mattm): http://crbug.com/128633.
   1078   if (trust.sslFlags & CERTDB_TERMINAL_RECORD)
   1079     return net::SERVER_CERT;
   1080   return net::OTHER_CERT;
   1081 }
   1082 
   1083 }  // namespace mozilla_security_manager
   1084