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