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/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
68namespace {
69
70std::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
83SECOidTag 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.
104std::string ProcessRawBytes(SECItem* data) {
105  return x509_certificate_model::ProcessRawBytes(data->data, data->len);
106}
107
108SECOidTag ms_cert_ext_certtype = SEC_OID_UNKNOWN;
109SECOidTag ms_certsrv_ca_version = SEC_OID_UNKNOWN;
110SECOidTag ms_nt_principal_name = SEC_OID_UNKNOWN;
111SECOidTag ms_ntds_replication = SEC_OID_UNKNOWN;
112SECOidTag eku_ms_individual_code_signing = SEC_OID_UNKNOWN;
113SECOidTag eku_ms_commercial_code_signing = SEC_OID_UNKNOWN;
114SECOidTag eku_ms_trust_list_signing = SEC_OID_UNKNOWN;
115SECOidTag eku_ms_time_stamping = SEC_OID_UNKNOWN;
116SECOidTag eku_ms_server_gated_crypto = SEC_OID_UNKNOWN;
117SECOidTag eku_ms_encrypting_file_system = SEC_OID_UNKNOWN;
118SECOidTag eku_ms_file_recovery = SEC_OID_UNKNOWN;
119SECOidTag eku_ms_windows_hardware_driver_verification = SEC_OID_UNKNOWN;
120SECOidTag eku_ms_qualified_subordination = SEC_OID_UNKNOWN;
121SECOidTag eku_ms_key_recovery = SEC_OID_UNKNOWN;
122SECOidTag eku_ms_document_signing = SEC_OID_UNKNOWN;
123SECOidTag eku_ms_lifetime_signing = SEC_OID_UNKNOWN;
124SECOidTag eku_ms_smart_card_logon = SEC_OID_UNKNOWN;
125SECOidTag eku_ms_key_recovery_agent = SEC_OID_UNKNOWN;
126SECOidTag eku_netscape_international_step_up = SEC_OID_UNKNOWN;
127SECOidTag cert_attribute_business_category = SEC_OID_UNKNOWN;
128SECOidTag cert_attribute_ev_incorporation_country = SEC_OID_UNKNOWN;
129
130class 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
166static base::LazyInstance<DynamicOidRegisterer>::Leaky
167    g_dynamic_oid_registerer = LAZY_INSTANCE_INITIALIZER;
168
169}  // namespace
170
171namespace mozilla_security_manager {
172
173std::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
184std::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.
406std::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
429std::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
442std::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
468std::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
572std::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
587std::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
600std::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
618std::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
652std::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
707std::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
765std::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
830std::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
865std::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
875std::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
888struct MaskIdPair {
889  unsigned int mask;
890  int string_id;
891};
892
893static 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
911static 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
927std::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
941static 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
954std::string ProcessKeyUsageBitString(SECItem* bitstring, char sep) {
955  return ProcessBitField(bitstring, key_usage_string_map,
956                         arraysize(key_usage_string_map), sep);
957}
958
959std::string ProcessKeyUsageExtension(SECItem* extension_data) {
960  return ProcessBitStringExtension(extension_data, key_usage_string_map,
961                                   arraysize(key_usage_string_map), '\n');
962}
963
964std::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
995std::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
1042std::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
1066net::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