diff options
-rw-r--r-- | base/base.gypi | 8 | ||||
-rw-r--r-- | base/crypto/rsa_private_key_nss.cc | 2 | ||||
-rw-r--r-- | base/crypto/signature_creator_nss.cc | 2 | ||||
-rw-r--r-- | base/crypto/signature_verifier_nss.cc | 3 | ||||
-rw-r--r-- | base/hmac_nss.cc | 2 | ||||
-rw-r--r-- | base/nss_util.cc (renamed from base/nss_init.cc) | 24 | ||||
-rw-r--r-- | base/nss_util.h (renamed from base/nss_init.h) | 16 | ||||
-rw-r--r-- | base/test/test_suite.h | 2 | ||||
-rw-r--r-- | chrome/app/chrome_dll_main.cc | 2 | ||||
-rw-r--r-- | chrome/app/generated_resources.grd | 203 | ||||
-rw-r--r-- | chrome/browser/gtk/certificate_viewer.cc | 898 | ||||
-rw-r--r-- | chrome/browser/gtk/certificate_viewer.h | 12 | ||||
-rw-r--r-- | chrome/browser/gtk/page_info_window_gtk.cc | 46 | ||||
-rw-r--r-- | chrome/browser/importer/nss_decryptor_linux.cc | 2 | ||||
-rwxr-xr-x | chrome/chrome_browser.gypi | 2 | ||||
-rw-r--r-- | net/base/cert_database_nss.cc | 2 | ||||
-rw-r--r-- | net/base/keygen_handler_nss.cc | 2 | ||||
-rw-r--r-- | net/base/x509_certificate_nss.cc | 22 | ||||
-rw-r--r-- | net/http/des.cc | 2 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_nss.cc | 2 | ||||
-rw-r--r-- | net/socket/ssl_test_util.cc | 2 | ||||
-rw-r--r-- | net/url_request/url_request_unittest.cc | 2 |
22 files changed, 1208 insertions, 50 deletions
diff --git a/base/base.gypi b/base/base.gypi index f7584c4..ecdc0a0 100644 --- a/base/base.gypi +++ b/base/base.gypi @@ -287,8 +287,8 @@ 'directory_watcher_inotify.cc', 'linux_util.cc', 'message_pump_glib.cc', - 'nss_init.cc', - 'nss_init.h', + 'nss_util.cc', + 'nss_util.h', ], },], [ 'OS != "linux"', { @@ -547,8 +547,8 @@ 'message_pump_mac.mm', 'nsimage_cache_mac.h', 'nsimage_cache_mac.mm', - 'nss_init.cc', - 'nss_init.h', + 'nss_util.cc', + 'nss_util.h', 'pe_image.cc', 'pe_image.h', 'setproctitle_linux.c', diff --git a/base/crypto/rsa_private_key_nss.cc b/base/crypto/rsa_private_key_nss.cc index 7e10b36..26bb10cc 100644 --- a/base/crypto/rsa_private_key_nss.cc +++ b/base/crypto/rsa_private_key_nss.cc @@ -12,7 +12,7 @@ #include <list> #include "base/logging.h" -#include "base/nss_init.h" +#include "base/nss_util.h" #include "base/scoped_ptr.h" #include "base/string_util.h" diff --git a/base/crypto/signature_creator_nss.cc b/base/crypto/signature_creator_nss.cc index e0de4b7..ff1d271 100644 --- a/base/crypto/signature_creator_nss.cc +++ b/base/crypto/signature_creator_nss.cc @@ -9,7 +9,7 @@ #include <stdlib.h> #include "base/logging.h" -#include "base/nss_init.h" +#include "base/nss_util.h" #include "base/scoped_ptr.h" namespace base { diff --git a/base/crypto/signature_verifier_nss.cc b/base/crypto/signature_verifier_nss.cc index 901f1fc..369f275 100644 --- a/base/crypto/signature_verifier_nss.cc +++ b/base/crypto/signature_verifier_nss.cc @@ -9,7 +9,7 @@ #include <stdlib.h> #include "base/logging.h" -#include "base/nss_init.h" +#include "base/nss_util.h" namespace base { @@ -111,4 +111,3 @@ void SignatureVerifier::Reset() { } } // namespace base - diff --git a/base/hmac_nss.cc b/base/hmac_nss.cc index ce705c5..d55bc64 100644 --- a/base/hmac_nss.cc +++ b/base/hmac_nss.cc @@ -8,7 +8,7 @@ #include <pk11pub.h> #include "base/logging.h" -#include "base/nss_init.h" +#include "base/nss_util.h" #include "base/scoped_ptr.h" namespace { diff --git a/base/nss_init.cc b/base/nss_util.cc index 7f65504..757b437 100644 --- a/base/nss_init.cc +++ b/base/nss_util.cc @@ -1,14 +1,15 @@ -// Copyright (c) 2008-2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2008-2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/nss_init.h" +#include "base/nss_util.h" #include <dlfcn.h> #include <nss.h> #include <plarena.h> #include <prerror.h> #include <prinit.h> +#include <prtime.h> #include <pk11pub.h> #include <secmod.h> #include <ssl.h> @@ -177,4 +178,23 @@ void EnsureNSSInit() { Singleton<NSSInitSingleton>::get(); } +// TODO(port): Implement this more simply. We can convert by subtracting an +// offset (the difference between NSPR's and base::Time's epochs). +Time PRTimeToBaseTime(PRTime prtime) { + PRExplodedTime prxtime; + PR_ExplodeTime(prtime, PR_GMTParameters, &prxtime); + + base::Time::Exploded exploded; + exploded.year = prxtime.tm_year; + exploded.month = prxtime.tm_month + 1; + exploded.day_of_week = prxtime.tm_wday; + exploded.day_of_month = prxtime.tm_mday; + exploded.hour = prxtime.tm_hour; + exploded.minute = prxtime.tm_min; + exploded.second = prxtime.tm_sec; + exploded.millisecond = prxtime.tm_usec / 1000; + + return Time::FromUTCExploded(exploded); +} + } // namespace base diff --git a/base/nss_init.h b/base/nss_util.h index cd8ee77..f766228 100644 --- a/base/nss_init.h +++ b/base/nss_util.h @@ -1,12 +1,16 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef BASE_NSS_INIT_H_ -#define BASE_NSS_INIT_H_ +#ifndef BASE_NSS_UTIL_H_ +#define BASE_NSS_UTIL_H_ + +#include "base/basictypes.h" namespace base { +class Time; + // Initialize NRPR if it isn't already initialized. This function is // thread-safe, and NSPR will only ever be initialized once. NSPR will be // properly shut down on program exit. @@ -17,6 +21,10 @@ void EnsureNSPRInit(); // ever be initialized once. NSS will be properly shut down on program exit. void EnsureNSSInit(); +// Convert a NSS PRTime value into a base::Time object. +// We use a int64 instead of PRTime here to avoid depending on NSPR headers. +Time PRTimeToBaseTime(int64 prtime); + } // namespace base -#endif // BASE_NSS_INIT_H_ +#endif // BASE_NSS_UTIL_H_ diff --git a/base/test/test_suite.h b/base/test/test_suite.h index aa006fc..c738518 100644 --- a/base/test/test_suite.h +++ b/base/test/test_suite.h @@ -14,7 +14,7 @@ #include "base/debug_on_start.h" #include "base/i18n/icu_util.h" #include "base/multiprocess_test.h" -#include "base/nss_init.h" +#include "base/nss_util.h" #include "base/path_service.h" #include "base/process_util.h" #include "base/scoped_nsautorelease_pool.h" diff --git a/chrome/app/chrome_dll_main.cc b/chrome/app/chrome_dll_main.cc index b15e044..a43f0e2 100644 --- a/chrome/app/chrome_dll_main.cc +++ b/chrome/app/chrome_dll_main.cc @@ -58,7 +58,7 @@ #include "ipc/ipc_switches.h" #if defined(OS_LINUX) -#include "base/nss_init.h" +#include "base/nss_util.h" #include "chrome/browser/renderer_host/render_sandbox_host_linux.h" #include "chrome/browser/zygote_host_linux.h" #endif diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 70becd3..df97fa2 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -2416,6 +2416,209 @@ each locale. --> Unknown server certificate error </message> + <!-- Certificate viewer dialog strings. These are only used on platforms that don't have a native certificate info dialog, such as Linux. --> + <message name="IDS_CERT_INFO_DIALOG_TITLE" desc="Title of dialog displaying info about a certificate"> + Certificate Viewer: <ph name="CERTIFICATE_NAME">$1<ex>www.google.com</ex></ph> + </message> + <message name="IDS_CERT_INFO_GENERAL_TAB_LABEL" desc="Title of the notebook page displaying the basic info about the certificate"> + &General + </message> + <message name="IDS_CERT_INFO_DETAILS_TAB_LABEL" desc="Title of the notebook page displaying the details about the certificate"> + &Details + </message> + <message name="IDS_CERT_INFO_VERIFIED_USAGES_GROUP" desc="The label of the group in the general page of the certificate info dialog which lists the usages that the certificate is verified for"> + This certificate has been verified for the following usages: + </message> + <message name="IDS_CERT_USAGE_SSL_CLIENT" desc="The description of a certificate that is verified for use as an SSL client"> + SSL Client Certificate + </message> + <message name="IDS_CERT_USAGE_SSL_SERVER" desc="The description of a certificate that is verified for use as an SSL server"> + SSL Server Certificate + </message> + <message name="IDS_CERT_USAGE_SSL_SERVER_WITH_STEPUP" desc="The description of a certificate that is verified for use as an SSL server with step up"> + SSL Server with Step-up + </message> + <message name="IDS_CERT_USAGE_EMAIL_SIGNER" desc="The description of a certificate that is verified for signing emails"> + Email Signer Certificate + </message> + <message name="IDS_CERT_USAGE_EMAIL_RECEIVER" desc="The description of a + certificate that is verified for encrypting email"> + Email Encryption Certificate + </message> + <message name="IDS_CERT_USAGE_OBJECT_SIGNER" desc="The description of a certificate that is verified for signing objects"> + Object Signer + </message> + <message name="IDS_CERT_USAGE_SSL_CA" desc="The description of a certificate that is verified for use by an SSL certification authority"> + SSL Certification Authority + </message> + <message name="IDS_CERT_USAGE_STATUS_RESPONDER" desc="The description of a certificate that is verified for use as a status responder"> + Status Responder Certificate + </message> + <message name="IDS_CERT_INFO_SUBJECT_GROUP" desc="The label of the Issued To group in the general page of the certificate info dialog"> + Issued To + </message> + <message name="IDS_CERT_INFO_ISSUER_GROUP" desc="The label of the Issued By group in the general page of the certificate info dialog"> + Issued By + </message> + <message name="IDS_CERT_INFO_COMMON_NAME_LABEL" desc="The label of the Common Name field in the general page of the certificate info dialog. (CN) is the name of this field in the standard"> + Common Name (CN) + </message> + <message name="IDS_CERT_INFO_ORGANIZATION_LABEL" desc="The label of the Organization field in the general page of the certificate info dialog. (O) is the name of this field in the standard"> + Organization (O) + </message> + <message name="IDS_CERT_INFO_ORGANIZATIONAL_UNIT_LABEL" desc="The label of the Organizational Unit field in the general page of the certificate info dialog. (OU) is the name of this field in the standard"> + Organizational Unit (OU) + </message> + <message name="IDS_CERT_INFO_SERIAL_NUMBER_LABEL" desc="The label of the Serial Number field in the general page of the certificate info dialog."> + Serial Number + </message> + <message name="IDS_CERT_INFO_VALIDITY_GROUP" desc="The label of the group showing the validity (issued and expired dates) in the general page of the certificate info dialog"> + Validity Period + </message> + <message name="IDS_CERT_INFO_ISSUED_ON_LABEL" desc="The label of the Issued On field in the general page of the certificate info dialog"> + Issued On + </message> + <message name="IDS_CERT_INFO_EXPIRES_ON_LABEL" desc="The label of the Issued On field in the general page of the certificate info dialog"> + Expires On + </message> + <message name="IDS_CERT_INFO_FINGERPRINTS_GROUP" desc="The label of the group showing the certificate fingerprints in the general page of the certificate info dialog"> + Fingerprints + </message> + <message name="IDS_CERT_INFO_SHA1_FINGERPRINT_LABEL" desc="The label of the SHA1 Fingerprint field in the general page of the certificate info dialog"> + SHA-1 Fingerprint + </message> + <message name="IDS_CERT_INFO_MD5_FINGERPRINT_LABEL" desc="The label of the MD5 Fingerprint field in the general page of the certificate info dialog"> + MD5 Fingerprint + </message> + <message name="IDS_CERT_INFO_FIELD_NOT_PRESENT" desc="The text displayed in the certificate info dialog for a given field when the certificate does not contain that field"> + <Not Part Of Certificate> + </message> + + <message name="IDS_CERT_DETAILS_CERTIFICATE_HIERARCHY_LABEL" desc="The label of the Certificate Hierarchy tree in the details page of the certificate info dialog."> + Certificate Hierarchy + </message> + <message name="IDS_CERT_DETAILS_CERTIFICATE_FIELDS_LABEL" desc="The label of the Certificate Fields tree in the details page of the certificate info dialog."> + Certificate Fields + </message> + <message name="IDS_CERT_DETAILS_CERTIFICATE_FIELD_VALUE_LABEL" desc="The label of the Certificate Field Value text in the details page of the certificate info dialog."> + Field Value + </message> + <message name="IDS_CERT_DETAILS_CERTIFICATE" desc="The label of the Certificate element in the details page of the certificate info dialog."> + Certificate + </message> + <message name="IDS_CERT_DETAILS_VERSION" desc="The label of the Version element in the details page of the certificate info dialog."> + Version + </message> + <message name="IDS_CERT_DETAILS_VERSION_FORMAT" desc="The format of the Version field value in the details page of the certificate info dialog."> + Version <ph name="NUMBER">$1<ex>3</ex></ph> + </message> + <message name="IDS_CERT_DETAILS_SERIAL_NUMBER" desc="The label of the Serial Number element in the details page of the certificate info dialog."> + Serial Number + </message> + <message name="IDS_CERT_DETAILS_CERTIFICATE_SIG_ALG" desc="The label of the Certificate Signature Algorithm element in the details page of the certificate info dialog."> + Certificate Signature Algorithm + </message> + <message name="IDS_CERT_DETAILS_ISSUER" desc="The label of the Issuer element in the details page of the certificate info dialog."> + Issuer + </message> + <message name="IDS_CERT_DETAILS_VALIDITY" desc="The label of the Validity element in the details page of the certificate info dialog."> + Validity + </message> + <message name="IDS_CERT_DETAILS_NOT_BEFORE" desc="The label of the Validity->Not Before element in the details page of the certificate info dialog."> + Not Before + </message> + <message name="IDS_CERT_DETAILS_NOT_AFTER" desc="The label of the Validity->Not After element in the details page of the certificate info dialog."> + Not After + </message> + <message name="IDS_CERT_DETAILS_SUBJECT" desc="The label of the Subject element in the details page of the certificate info dialog. (In this case, subject refers to the entity the certificate was issued to.)"> + Subject + </message> + <message name="IDS_CERT_DETAILS_SUBJECT_KEY_INFO" desc="The label of the Subject Public Key Info element in the details page of the certificate info dialog. (In this case, subject refers to the entity the certificate was issued to.)"> + Subject Public Key Info + </message> + <message name="IDS_CERT_DETAILS_SUBJECT_KEY_ALG" desc="The label of the Subject Public Key Algorithm element in the details page of the certificate info dialog. (In this case, subject refers to the entity the certificate was issued to.)"> + Subject Public Key Algorithm + </message> + <message name="IDS_CERT_DETAILS_SUBJECT_KEY" desc="The label of the Subject's Public Key element in the details page of the certificate info dialog. (In this case, subject refers to the entity the certificate was issued to.)"> + Subject's Public Key + </message> + <message name="IDS_CERT_DETAILS_EXTENSIONS" desc="The label of the Extensions element in the details page of the certificate info dialog."> + Extensions + </message> + <message name="IDS_CERT_DETAILS_CERTIFICATE_SIG_VALUE" desc="The label of the Certificate Signature Value element in the details page of the certificate info dialog."> + Certificate Signature Value + </message> + + <message translateable="false" name="IDS_CERT_OID_AVA_COMMON_NAME" desc=""> + CN + </message> + <message translateable="false" name="IDS_CERT_OID_AVA_STATE_OR_PROVINCE" desc=""> + ST + </message> + <message translateable="false" name="IDS_CERT_OID_AVA_ORGANIZATION_NAME" desc=""> + O + </message> + <message translateable="false" name="IDS_CERT_OID_AVA_ORGANIZATIONAL_UNIT_NAME" desc=""> + OU + </message> + <message translateable="false" name="IDS_CERT_OID_AVA_DN_QUALIFIER" desc=""> + dnQualifier + </message> + <message translateable="false" name="IDS_CERT_OID_AVA_COUNTRY_NAME" desc=""> + C + </message> + <message translateable="false" name="IDS_CERT_OID_AVA_SERIAL_NUMBER" desc=""> + serialNumber + </message> + <message translateable="false" name="IDS_CERT_OID_AVA_LOCALITY" desc=""> + L + </message> + <message translateable="false" name="IDS_CERT_OID_AVA_DC" desc=""> + DC + </message> + <message translateable="false" name="IDS_CERT_OID_RFC1274_MAIL" desc=""> + MAIL + </message> + <message translateable="false" name="IDS_CERT_OID_RFC1274_UID" desc=""> + UID + </message> + <message translateable="false" name="IDS_CERT_OID_PKCS9_EMAIL_ADDRESS" desc=""> + E + </message> + + <message name="IDS_CERT_OID_PKCS1_RSA_ENCRYPTION" desc="description of public key algorithm SEC_OID_PKCS1_RSA_ENCRYPTION"> + PKCS #1 RSA Encryption + </message> + <message name="IDS_CERT_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION" desc="description of public key algorithm SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION"> + PKCS #1 MD2 With RSA Encryption + </message> + <message name="IDS_CERT_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION" desc="description of public key algorithm SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION"> + PKCS #1 MD4 With RSA Encryption + </message> + <message name="IDS_CERT_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION" desc="description of public key algorithm SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION"> + PKCS #1 MD5 With RSA Encryption + </message> + <message name="IDS_CERT_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION" desc="description of public key algorithm SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION"> + PKCS #1 SHA-1 With RSA Encryption + </message> + <message name="IDS_CERT_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION" desc="description of public key algorithm SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION"> + PKCS #1 SHA-256 With RSA Encryption + </message> + <message name="IDS_CERT_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION" desc="description of public key algorithm SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION"> + PKCS #1 SHA-384 With RSA Encryption + </message> + <message name="IDS_CERT_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION" desc="description of public key algorithm SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION"> + PKCS #1 SHA-512 With RSA Encryption + </message> + + <message name="IDS_CERT_EXTENSION_CRITICAL" desc="The text displayed in the certificate details dialog for a given extension which is critical"> + Critical + </message> + <message name="IDS_CERT_EXTENSION_NON_CRITICAL" desc="The text displayed in the certificate details dialog for a given extension which is not critical"> + Not Critical + </message> + + <!-- General wizard strings --> <message name="IDS_WIZARD_NEXT" desc="The wizard next button label"> Next diff --git a/chrome/browser/gtk/certificate_viewer.cc b/chrome/browser/gtk/certificate_viewer.cc new file mode 100644 index 0000000..65c24e3 --- /dev/null +++ b/chrome/browser/gtk/certificate_viewer.cc @@ -0,0 +1,898 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/gtk/certificate_viewer.h" + +#include <cert.h> +#include <gtk/gtk.h> +#include <hasht.h> +#include <prprf.h> +#include <sechash.h> + +#include <algorithm> + +#include "app/l10n_util.h" +#include "base/i18n/time_formatting.h" +#include "base/nss_util.h" +#include "base/string_util.h" +#include "base/time.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/cert_store.h" +#include "chrome/common/gtk_util.h" +#include "grit/generated_resources.h" + +namespace { + +//////////////////////////////////////////////////////////////////////////////// +// NSS utility functions. + +// Convert a char* return value from NSS into a std::string and free the NSS +// memory. If the arg is NULL, a "Field Not Present" string will be returned +// instead. +std::string Stringize(char* nss_text) { + std::string s; + if (nss_text) { + s = nss_text; + PORT_Free(nss_text); + } else { + s = l10n_util::GetStringUTF8(IDS_CERT_INFO_FIELD_NOT_PRESENT); + } + return s; +} + +// Hash a certificate using the given algorithm, return the result as a +// colon-seperated hex string. The len specified is the number of bytes +// required for storing the raw fingerprint. +// (It's a bit redundant that the caller needs to specify len in addition to the +// algorithm, but given the limited uses, not worth fixing.) +std::string HashCert(CERTCertificate* cert, HASH_HashType algorithm, int len) { + unsigned char fingerprint[HASH_LENGTH_MAX]; + SECItem fingerprint_item; + + DCHECK(NULL != cert->derCert.data); + DCHECK(0 != cert->derCert.len); + DCHECK(len <= HASH_LENGTH_MAX); + memset(fingerprint, 0, len); + SECStatus rv = HASH_HashBuf(algorithm, fingerprint, cert->derCert.data, + cert->derCert.len); + DCHECK(rv == SECSuccess); + fingerprint_item.data = fingerprint; + fingerprint_item.len = len; + return Stringize(CERT_Hexify(&fingerprint_item, TRUE)); +} + +// Format a SECItem as a space separated string, with 16 bytes on each line. +std::string ProcessRawBytes(SECItem* data) { + static const char kHexChars[] = "0123456789ABCDEF"; + + // Each input byte creates two output hex characters + a space or newline, + // except for the last byte. + std::string ret(std::max(0u, data->len * 3 - 1), '\0'); + + for (size_t i = 0; i < data->len; ++i) { + unsigned char b = data->data[i]; + ret[i * 3] = kHexChars[(b >> 4) & 0xf]; + ret[i * 3 + 1] = kHexChars[b & 0xf]; + if (i + 1 < data->len) { + if ((i + 1) % 16 == 0) + ret[i * 3 + 2] = '\n'; + else + ret[i * 3 + 2] = ' '; + } + } + return ret; +} + +// For fields which have the length specified in bits, rather than bytes. +std::string ProcessRawBits(SECItem* data) { + SECItem bytedata; + bytedata.data = data->data; + bytedata.len = data->len / 8; + return ProcessRawBytes(&bytedata); +} + +// Based on mozilla/source/security/manager/ssl/src/nsNSSCertificate.cpp: +// nsNSSCertificate::GetWindowTitle. +std::string GetCertTitle(CERTCertificate* cert) { + std::string rv; + if (cert->nickname) { + rv = cert->nickname; + } else { + char* cn = CERT_GetCommonName(&cert->subject); + if (cn) { + rv = Stringize(cn); + } else if (cert->subjectName) { + rv = cert->subjectName; + } else if (cert->emailAddr) { + rv = cert->emailAddr; + } + } + // TODO(mattm): Should we return something other than an empty string when all + // the checks fail? + return rv; +} + +std::string GetOIDText(SECItem* oid) { + int string_id; + switch (SECOID_FindOIDTag(oid)) { + case SEC_OID_AVA_COMMON_NAME: + string_id = IDS_CERT_OID_AVA_COMMON_NAME; + break; + case SEC_OID_AVA_STATE_OR_PROVINCE: + string_id = IDS_CERT_OID_AVA_STATE_OR_PROVINCE; + break; + case SEC_OID_AVA_ORGANIZATION_NAME: + string_id = IDS_CERT_OID_AVA_ORGANIZATION_NAME; + break; + case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME: + string_id = IDS_CERT_OID_AVA_ORGANIZATIONAL_UNIT_NAME; + break; + case SEC_OID_AVA_DN_QUALIFIER: + string_id = IDS_CERT_OID_AVA_DN_QUALIFIER; + break; + case SEC_OID_AVA_COUNTRY_NAME: + string_id = IDS_CERT_OID_AVA_COUNTRY_NAME; + break; + case SEC_OID_AVA_SERIAL_NUMBER: + string_id = IDS_CERT_OID_AVA_SERIAL_NUMBER; + break; + case SEC_OID_AVA_LOCALITY: + string_id = IDS_CERT_OID_AVA_LOCALITY; + break; + case SEC_OID_AVA_DC: + string_id = IDS_CERT_OID_AVA_DC; + break; + case SEC_OID_RFC1274_MAIL: + string_id = IDS_CERT_OID_RFC1274_MAIL; + break; + case SEC_OID_RFC1274_UID: + string_id = IDS_CERT_OID_RFC1274_UID; + break; + case SEC_OID_PKCS9_EMAIL_ADDRESS: + string_id = IDS_CERT_OID_PKCS9_EMAIL_ADDRESS; + break; + case SEC_OID_PKCS1_RSA_ENCRYPTION: + string_id = IDS_CERT_OID_PKCS1_RSA_ENCRYPTION; + break; + case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: + string_id = IDS_CERT_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION; + break; + case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: + string_id = IDS_CERT_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION; + break; + case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: + string_id = IDS_CERT_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; + break; + case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: + string_id = IDS_CERT_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; + break; + case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: + string_id = IDS_CERT_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; + break; + case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: + string_id = IDS_CERT_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; + break; + case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: + string_id = IDS_CERT_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; + break; + // There are a billionty other OIDs we could add here. I tried to get the + // important ones... + default: + string_id = -1; + break; + } + if (string_id >= 0) + return l10n_util::GetStringUTF8(string_id); + + char* pr_string = CERT_GetOidString(oid); + if (pr_string) { + std::string rv = pr_string; + PR_smprintf_free(pr_string); + return rv; + } + + return ProcessRawBytes(oid); +} + +// Get a display string from a Relative Distinguished Name. +std::string ProcessRDN(CERTRDN* rdn) { + std::string rv; + + CERTAVA** avas = rdn->avas; + for (size_t i = 0; avas[i] != NULL; ++i) { + rv += GetOIDText(&avas[i]->type); + SECItem* decode_item = CERT_DecodeAVAValue(&avas[i]->value); + if (decode_item) { + // TODO(mattm): Pass decode_item to CERT_RFC1485_EscapeAndQuote. + rv += " = "; + std::string value(reinterpret_cast<char*>(decode_item->data), + decode_item->len); + rv += value; + SECITEM_FreeItem(decode_item, PR_TRUE); + } + rv += '\n'; + } + + return rv; +} + +std::string ProcessName(CERTName* name) { + std::string rv; + CERTRDN** last_rdn; + + // Find last non-NULL rdn. + for (last_rdn = name->rdns; last_rdn[0]; last_rdn++) {} + last_rdn--; + + for (CERTRDN** rdn = last_rdn; rdn >= name->rdns; rdn--) + rv += ProcessRDN(*rdn); + return rv; +} + +std::string ProcessSecAlgorithm(SECAlgorithmID* algorithm_id) { + return GetOIDText(&algorithm_id->algorithm); +} + +std::string ProcessExtensionData(SECItem* extension_data) { + // TODO(mattm): should display extension-specific info here (see + // ProcessExtensionData in nsNSSCertHelper.cpp) + return ProcessRawBytes(extension_data); +} + +std::string ProcessExtension(CERTCertExtension* extension) { + std::string rv; + int criticality = IDS_CERT_EXTENSION_NON_CRITICAL; + if (extension->critical.data && extension->critical.data[0]) + criticality = IDS_CERT_EXTENSION_CRITICAL; + rv = l10n_util::GetStringUTF8(criticality) + "\n" + + ProcessExtensionData(&extension->value); + return rv; +} + +std::string ProcessSubjectPublicKeyInfo(CERTSubjectPublicKeyInfo* spki) { + // TODO(mattm): firefox decodes the key and displays modulus and exponent. + return ProcessRawBits(&spki->subjectPublicKey); +} + +//////////////////////////////////////////////////////////////////////////////// +// Gtk utility functions. + +GtkWidget* LeftAlign(GtkWidget* label) { + gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + return label; +} + +const char kOptionGroupTitleMarkup[] = "<span weight='bold'>%s</span>"; + +GtkWidget* BoldLabel(const std::string& text) { + GtkWidget* label = gtk_label_new(NULL); + char* markup = g_markup_printf_escaped(kOptionGroupTitleMarkup, + text.c_str()); + gtk_label_set_markup(GTK_LABEL(label), markup); + g_free(markup); + + return LeftAlign(label); +} + +void AddTitle(GtkTable* table, int row, const std::string& text) { + gtk_table_attach_defaults(table, + BoldLabel(text), + 0, 2, + row, row + 1); +} + +void AddKeyValue(GtkTable* table, int row, const std::string& text, + const std::string& value) { + gtk_table_attach_defaults( + table, + gtk_util::IndentWidget(LeftAlign(gtk_label_new(text.c_str()))), + 0, 1, row, row + 1); + gtk_table_attach_defaults( + table, + LeftAlign(gtk_label_new(value.c_str())), + 1, 2, row, row + 1); +} + +//////////////////////////////////////////////////////////////////////////////// +// CertificateViewer class definition. + +class CertificateViewer { + public: + CertificateViewer(gfx::NativeWindow parent, CERTCertList* cert_chain_list); + ~CertificateViewer(); + + void InitGeneralPage(); + void InitDetailsPage(); + + void Show(); + + private: + // Indices and column count for the certificate chain hierarchy tree store. + enum { + HIERARCHY_NAME, + HIERARCHY_OBJECT, + HIERARCHY_COLUMNS + }; + + // Indices and column count for the certificate fields tree store. + enum { + FIELDS_NAME, + FIELDS_VALUE, + FIELDS_COLUMNS + }; + + // Fill the tree store with the certificate hierarchy, and set |leaf| to the + // iter of the leaf node. + void FillHierarchyStore(GtkTreeStore* hierarchy_store, + GtkTreeIter* leaf) const; + + // Fill the tree store with the details of the given certificate. + static void FillTreeStoreWithCertFields(GtkTreeStore* store, + CERTCertificate* cert); + + // Create a tree store filled with the details of the given certificate. + static GtkTreeStore* CreateFieldsTreeStore(CERTCertificate* cert); + + // Callbacks for user selecting elements in the trees. + static void OnHierarchySelectionChanged(GtkTreeSelection *selection, + CertificateViewer* viewer); + static void OnFieldsSelectionChanged(GtkTreeSelection *selection, + CertificateViewer* viewer); + + // The certificate hierarchy (leaf cert first). + CERTCertList* cert_chain_list_; + // The same contents of cert_chain_list_ in a vector for easier access. + typedef std::vector<CERTCertificate*> CertificateVector; + CertificateVector cert_chain_; + + GtkWidget* dialog_; + GtkWidget* notebook_; + GtkWidget* general_page_vbox_; + GtkWidget* details_page_vbox_; + GtkWidget* fields_tree_; + GtkTextBuffer* field_value_buffer_; + + DISALLOW_COPY_AND_ASSIGN(CertificateViewer); +}; + +//////////////////////////////////////////////////////////////////////////////// +// CertificateViewer implementation. + +// Close button callback. +void OnDialogResponse(GtkDialog* dialog, gint response_id, + gpointer user_data) { + // "Close" was clicked. + gtk_widget_destroy(GTK_WIDGET(dialog)); +} + +void OnDestroy(GtkDialog* dialog, CertificateViewer* cert_viewer) { + delete cert_viewer; +} + +CertificateViewer::CertificateViewer(gfx::NativeWindow parent, + CERTCertList* cert_chain_list) + : cert_chain_list_(cert_chain_list) { + CERTCertListNode *node; + for (node = CERT_LIST_HEAD(cert_chain_list_); + !CERT_LIST_END(node, cert_chain_list_); + node = CERT_LIST_NEXT(node)) { + cert_chain_.push_back(node->cert); + } + + dialog_ = gtk_dialog_new_with_buttons( + l10n_util::GetStringFUTF8( + IDS_CERT_INFO_DIALOG_TITLE, + UTF8ToUTF16(GetCertTitle(cert_chain_.front()))).c_str(), + parent, + // Non-modal. + GTK_DIALOG_NO_SEPARATOR, + GTK_STOCK_CLOSE, + GTK_RESPONSE_CLOSE, + NULL); + gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog_)->vbox), + gtk_util::kContentAreaSpacing); + + InitGeneralPage(); + InitDetailsPage(); + + notebook_ = gtk_notebook_new(); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog_)->vbox), notebook_); + + gtk_notebook_append_page( + GTK_NOTEBOOK(notebook_), + general_page_vbox_, + gtk_label_new_with_mnemonic( + gtk_util::ConvertAcceleratorsFromWindowsStyle( + l10n_util::GetStringUTF8( + IDS_CERT_INFO_GENERAL_TAB_LABEL)).c_str())); + + gtk_notebook_append_page( + GTK_NOTEBOOK(notebook_), + details_page_vbox_, + gtk_label_new_with_mnemonic( + gtk_util::ConvertAcceleratorsFromWindowsStyle( + l10n_util::GetStringUTF8( + IDS_CERT_INFO_DETAILS_TAB_LABEL)).c_str())); + + g_signal_connect(dialog_, "response", G_CALLBACK(OnDialogResponse), NULL); + g_signal_connect(dialog_, "destroy", G_CALLBACK(OnDestroy), this); +} + +CertificateViewer::~CertificateViewer() { + CERT_DestroyCertList(cert_chain_list_); +} + +void CertificateViewer::InitGeneralPage() { + CERTCertificate* cert = cert_chain_.front(); + general_page_vbox_ = gtk_vbox_new(FALSE, gtk_util::kContentAreaSpacing); + gtk_container_set_border_width(GTK_CONTAINER(general_page_vbox_), + gtk_util::kContentAreaBorder); + + GtkWidget* uses_vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); + gtk_box_pack_start(GTK_BOX(general_page_vbox_), uses_vbox, FALSE, FALSE, 0); + gtk_box_pack_start( + GTK_BOX(uses_vbox), + BoldLabel(l10n_util::GetStringUTF8(IDS_CERT_INFO_VERIFIED_USAGES_GROUP)), + FALSE, FALSE, 0); + + SECCertificateUsage usages = 0; + // TODO(wtc): See if we should use X509Certificate::Verify instead. + if (CERT_VerifyCertificateNow(CERT_GetDefaultCertDB(), cert, PR_TRUE, + certificateUsageCheckAllUsages, + NULL, &usages) == SECSuccess) { + // List of usages to display is borrowed from + // mozilla/source/security/manager/ssl/src/nsUsageArrayHelper.cpp + struct { + SECCertificateUsage usage; + int string_id; + } usageStringMap[] = { + {certificateUsageSSLClient, IDS_CERT_USAGE_SSL_CLIENT}, + {certificateUsageSSLServer, IDS_CERT_USAGE_SSL_SERVER}, + {certificateUsageSSLServerWithStepUp, + IDS_CERT_USAGE_SSL_SERVER_WITH_STEPUP}, + {certificateUsageEmailSigner, IDS_CERT_USAGE_EMAIL_SIGNER}, + {certificateUsageEmailRecipient, IDS_CERT_USAGE_EMAIL_RECEIVER}, + {certificateUsageObjectSigner, IDS_CERT_USAGE_OBJECT_SIGNER}, + {certificateUsageSSLCA, IDS_CERT_USAGE_SSL_CA}, + {certificateUsageStatusResponder, IDS_CERT_USAGE_STATUS_RESPONDER}, + }; + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(usageStringMap); ++i) { + if (usages & usageStringMap[i].usage) + gtk_box_pack_start( + GTK_BOX(uses_vbox), + gtk_util::IndentWidget(LeftAlign(gtk_label_new( + l10n_util::GetStringUTF8( + usageStringMap[i].string_id).c_str()))), + FALSE, FALSE, 0); + } + } + + gtk_box_pack_start(GTK_BOX(general_page_vbox_), gtk_hseparator_new(), + FALSE, FALSE, 0); + + const int num_rows = 21; + GtkTable* table = GTK_TABLE(gtk_table_new(num_rows, 2, FALSE)); + gtk_table_set_col_spacing(table, 0, gtk_util::kLabelSpacing); + gtk_table_set_row_spacings(table, gtk_util::kControlSpacing); + + gtk_box_pack_start(GTK_BOX(general_page_vbox_), GTK_WIDGET(table), + FALSE, FALSE, 0); + int row = 0; + AddTitle(table, row++, + l10n_util::GetStringUTF8(IDS_CERT_INFO_SUBJECT_GROUP)); + AddKeyValue(table, row++, + l10n_util::GetStringUTF8(IDS_CERT_INFO_COMMON_NAME_LABEL), + Stringize(CERT_GetCommonName(&cert->subject))); + AddKeyValue(table, row++, + l10n_util::GetStringUTF8(IDS_CERT_INFO_ORGANIZATION_LABEL), + Stringize(CERT_GetOrgName(&cert->subject))); + AddKeyValue(table, row++, + l10n_util::GetStringUTF8(IDS_CERT_INFO_ORGANIZATIONAL_UNIT_LABEL), + Stringize(CERT_GetOrgUnitName(&cert->subject))); + AddKeyValue(table, row++, + l10n_util::GetStringUTF8(IDS_CERT_INFO_SERIAL_NUMBER_LABEL), + Stringize(CERT_Hexify(&cert->serialNumber, TRUE))); + + row += 2; // Add spacing (kControlSpacing * 3 == kContentAreaSpacing). + + AddTitle(table, row++, + l10n_util::GetStringUTF8(IDS_CERT_INFO_ISSUER_GROUP)); + AddKeyValue(table, row++, + l10n_util::GetStringUTF8(IDS_CERT_INFO_COMMON_NAME_LABEL), + Stringize(CERT_GetCommonName(&cert->issuer))); + AddKeyValue(table, row++, + l10n_util::GetStringUTF8(IDS_CERT_INFO_ORGANIZATION_LABEL), + Stringize(CERT_GetOrgName(&cert->issuer))); + AddKeyValue(table, row++, + l10n_util::GetStringUTF8(IDS_CERT_INFO_ORGANIZATIONAL_UNIT_LABEL), + Stringize(CERT_GetOrgUnitName(&cert->issuer))); + + row += 2; // Add spacing (kControlSpacing * 3 == kContentAreaSpacing). + + PRTime issued, expires; + std::string issued_str, expires_str; + if (CERT_GetCertTimes(cert, &issued, &expires) == SECSuccess) { + issued_str = WideToUTF8( + base::TimeFormatShortDateNumeric(base::PRTimeToBaseTime(issued))); + expires_str = WideToUTF8( + base::TimeFormatShortDateNumeric(base::PRTimeToBaseTime(expires))); + } else { + issued_str = l10n_util::GetStringUTF8(IDS_CERT_INFO_FIELD_NOT_PRESENT); + expires_str = l10n_util::GetStringUTF8(IDS_CERT_INFO_FIELD_NOT_PRESENT); + } + AddTitle(table, row++, + l10n_util::GetStringUTF8(IDS_CERT_INFO_VALIDITY_GROUP)); + AddKeyValue(table, row++, + l10n_util::GetStringUTF8(IDS_CERT_INFO_ISSUED_ON_LABEL), + issued_str); + AddKeyValue(table, row++, + l10n_util::GetStringUTF8(IDS_CERT_INFO_EXPIRES_ON_LABEL), + expires_str); + + row += 2; // Add spacing (kControlSpacing * 3 == kContentAreaSpacing). + + AddTitle(table, row++, + l10n_util::GetStringUTF8(IDS_CERT_INFO_FINGERPRINTS_GROUP)); + AddKeyValue(table, row++, + l10n_util::GetStringUTF8(IDS_CERT_INFO_SHA1_FINGERPRINT_LABEL), + HashCert(cert, HASH_AlgSHA1, SHA1_LENGTH)); + AddKeyValue(table, row++, + l10n_util::GetStringUTF8(IDS_CERT_INFO_MD5_FINGERPRINT_LABEL), + HashCert(cert, HASH_AlgMD5, MD5_LENGTH)); + + DCHECK_EQ(row, num_rows); +} + +void CertificateViewer::FillHierarchyStore(GtkTreeStore* hierarchy_store, + GtkTreeIter* leaf) const { + GtkTreeIter parent; + GtkTreeIter* parent_ptr = NULL; + GtkTreeIter iter; + for (CertificateVector::const_reverse_iterator i = cert_chain_.rbegin(); + i != cert_chain_.rend(); ++i) { + gtk_tree_store_append(hierarchy_store, &iter, parent_ptr); + GtkTreeStore* fields_store = CreateFieldsTreeStore(*i); + gtk_tree_store_set( + hierarchy_store, &iter, + HIERARCHY_NAME, GetCertTitle(*i).c_str(), + HIERARCHY_OBJECT, fields_store, + -1); + g_object_unref(fields_store); + parent = iter; + parent_ptr = &parent; + } + *leaf = iter; +} + +// static +void CertificateViewer::FillTreeStoreWithCertFields(GtkTreeStore* store, + CERTCertificate* cert) { + GtkTreeIter top; + gtk_tree_store_append(store, &top, NULL); + gtk_tree_store_set( + store, &top, + FIELDS_NAME, GetCertTitle(cert).c_str(), + FIELDS_VALUE, "", + -1); + + GtkTreeIter cert_iter; + gtk_tree_store_append(store, &cert_iter, &top); + gtk_tree_store_set( + store, &cert_iter, + FIELDS_NAME, + l10n_util::GetStringUTF8(IDS_CERT_DETAILS_CERTIFICATE).c_str(), + FIELDS_VALUE, "", + -1); + + unsigned long version = ULONG_MAX; + std::string version_str; + if (SEC_ASN1DecodeInteger(&cert->version, &version) == SECSuccess && + version != ULONG_MAX) + version_str = l10n_util::GetStringFUTF8(IDS_CERT_DETAILS_VERSION_FORMAT, + UintToString16(version + 1)); + GtkTreeIter iter; + gtk_tree_store_append(store, &iter, &cert_iter); + gtk_tree_store_set( + store, &iter, + FIELDS_NAME, + l10n_util::GetStringUTF8(IDS_CERT_DETAILS_VERSION).c_str(), + FIELDS_VALUE, version_str.c_str(), + -1); + + gtk_tree_store_append(store, &iter, &cert_iter); + gtk_tree_store_set( + store, &iter, + FIELDS_NAME, + l10n_util::GetStringUTF8(IDS_CERT_DETAILS_SERIAL_NUMBER).c_str(), + FIELDS_VALUE, Stringize(CERT_Hexify(&cert->serialNumber, TRUE)).c_str(), + -1); + + gtk_tree_store_append(store, &iter, &cert_iter); + gtk_tree_store_set( + store, &iter, + FIELDS_NAME, + l10n_util::GetStringUTF8(IDS_CERT_DETAILS_CERTIFICATE_SIG_ALG).c_str(), + FIELDS_VALUE, ProcessSecAlgorithm(&cert->signature).c_str(), + -1); + + gtk_tree_store_append(store, &iter, &cert_iter); + gtk_tree_store_set( + store, &iter, + FIELDS_NAME, + l10n_util::GetStringUTF8(IDS_CERT_DETAILS_ISSUER).c_str(), + FIELDS_VALUE, ProcessName(&cert->issuer).c_str(), + -1); + + GtkTreeIter validity_iter; + gtk_tree_store_append(store, &validity_iter, &cert_iter); + gtk_tree_store_set( + store, &validity_iter, + FIELDS_NAME, + l10n_util::GetStringUTF8(IDS_CERT_DETAILS_VALIDITY).c_str(), + FIELDS_VALUE, "", + -1); + + PRTime issued, expires; + std::string issued_str, expires_str; + if (CERT_GetCertTimes(cert, &issued, &expires) == SECSuccess) { + issued_str = WideToUTF8( + base::TimeFormatShortDateAndTime(base::PRTimeToBaseTime(issued))); + expires_str = WideToUTF8( + base::TimeFormatShortDateAndTime(base::PRTimeToBaseTime(expires))); + } + gtk_tree_store_append(store, &iter, &validity_iter); + gtk_tree_store_set( + store, &iter, + FIELDS_NAME, + l10n_util::GetStringUTF8(IDS_CERT_DETAILS_NOT_BEFORE).c_str(), + FIELDS_VALUE, issued_str.c_str(), + -1); + gtk_tree_store_append(store, &iter, &validity_iter); + gtk_tree_store_set( + store, &iter, + FIELDS_NAME, + l10n_util::GetStringUTF8(IDS_CERT_DETAILS_NOT_AFTER).c_str(), + FIELDS_VALUE, expires_str.c_str(), + -1); + + gtk_tree_store_append(store, &iter, &cert_iter); + gtk_tree_store_set( + store, &iter, + FIELDS_NAME, + l10n_util::GetStringUTF8(IDS_CERT_DETAILS_SUBJECT).c_str(), + FIELDS_VALUE, ProcessName(&cert->subject).c_str(), + -1); + + GtkTreeIter subject_public_key_iter; + gtk_tree_store_append(store, &subject_public_key_iter, &cert_iter); + gtk_tree_store_set( + store, &subject_public_key_iter, + FIELDS_NAME, + l10n_util::GetStringUTF8(IDS_CERT_DETAILS_SUBJECT_KEY_INFO).c_str(), + FIELDS_VALUE, "", + -1); + + gtk_tree_store_append(store, &iter, &subject_public_key_iter); + gtk_tree_store_set( + store, &iter, + FIELDS_NAME, + l10n_util::GetStringUTF8(IDS_CERT_DETAILS_SUBJECT_KEY_ALG).c_str(), + FIELDS_VALUE, + ProcessSecAlgorithm(&cert->subjectPublicKeyInfo.algorithm).c_str(), + -1); + + gtk_tree_store_append(store, &iter, &subject_public_key_iter); + gtk_tree_store_set( + store, &iter, + FIELDS_NAME, + l10n_util::GetStringUTF8(IDS_CERT_DETAILS_SUBJECT_KEY).c_str(), + FIELDS_VALUE, + ProcessSubjectPublicKeyInfo(&cert->subjectPublicKeyInfo).c_str(), + -1); + + if (cert->extensions) { + GtkTreeIter extensions_iter; + gtk_tree_store_append(store, &extensions_iter, &cert_iter); + gtk_tree_store_set( + store, &extensions_iter, + FIELDS_NAME, + l10n_util::GetStringUTF8(IDS_CERT_DETAILS_EXTENSIONS).c_str(), + FIELDS_VALUE, "", + -1); + + for (size_t i = 0; cert->extensions[i] != NULL; ++i) { + gtk_tree_store_append(store, &iter, &extensions_iter); + gtk_tree_store_set( + store, &iter, + FIELDS_NAME, GetOIDText(&cert->extensions[i]->id).c_str(), + FIELDS_VALUE, ProcessExtension(cert->extensions[i]).c_str(), + -1); + } + } + + gtk_tree_store_append(store, &iter, &top); + gtk_tree_store_set( + store, &iter, + FIELDS_NAME, + l10n_util::GetStringUTF8(IDS_CERT_DETAILS_CERTIFICATE_SIG_ALG).c_str(), + FIELDS_VALUE, + ProcessSecAlgorithm(&cert->signatureWrap.signatureAlgorithm).c_str(), + -1); + + gtk_tree_store_append(store, &iter, &top); + gtk_tree_store_set( + store, &iter, + FIELDS_NAME, + l10n_util::GetStringUTF8(IDS_CERT_DETAILS_CERTIFICATE_SIG_VALUE).c_str(), + FIELDS_VALUE, ProcessRawBits(&cert->signatureWrap.signature).c_str(), + -1); +} + +// static +GtkTreeStore* CertificateViewer::CreateFieldsTreeStore(CERTCertificate* cert) { + GtkTreeStore* fields_store = gtk_tree_store_new(FIELDS_COLUMNS, G_TYPE_STRING, + G_TYPE_STRING); + FillTreeStoreWithCertFields(fields_store, cert); + return fields_store; +} + +void CertificateViewer::InitDetailsPage() { + details_page_vbox_ = gtk_vbox_new(FALSE, gtk_util::kContentAreaSpacing); + gtk_container_set_border_width(GTK_CONTAINER(details_page_vbox_), + gtk_util::kContentAreaBorder); + + GtkWidget* hierarchy_vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); + gtk_box_pack_start(GTK_BOX(details_page_vbox_), hierarchy_vbox, + FALSE, FALSE, 0); + + gtk_box_pack_start(GTK_BOX(hierarchy_vbox), + BoldLabel(l10n_util::GetStringUTF8( + IDS_CERT_DETAILS_CERTIFICATE_HIERARCHY_LABEL)), + FALSE, FALSE, 0); + + GtkTreeStore* hierarchy_store = gtk_tree_store_new(HIERARCHY_COLUMNS, + G_TYPE_STRING, + G_TYPE_OBJECT); + GtkTreeIter hierarchy_leaf_iter; + FillHierarchyStore(hierarchy_store, &hierarchy_leaf_iter); + GtkWidget* hierarchy_tree = gtk_tree_view_new_with_model( + GTK_TREE_MODEL(hierarchy_store)); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(hierarchy_tree), FALSE); + gtk_tree_view_append_column( + GTK_TREE_VIEW(hierarchy_tree), + gtk_tree_view_column_new_with_attributes("", gtk_cell_renderer_text_new(), + "text", HIERARCHY_NAME, + NULL)); + gtk_tree_view_expand_all(GTK_TREE_VIEW(hierarchy_tree)); + GtkTreeSelection* hierarchy_selection = gtk_tree_view_get_selection( + GTK_TREE_VIEW(hierarchy_tree)); + gtk_tree_selection_set_mode(hierarchy_selection, GTK_SELECTION_SINGLE); + g_signal_connect(G_OBJECT(hierarchy_selection), "changed", + G_CALLBACK(OnHierarchySelectionChanged), this); + GtkWidget* hierarchy_scroll_window = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(hierarchy_scroll_window), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_NEVER); + gtk_scrolled_window_set_shadow_type( + GTK_SCROLLED_WINDOW(hierarchy_scroll_window), GTK_SHADOW_ETCHED_IN); + gtk_container_add(GTK_CONTAINER(hierarchy_scroll_window), hierarchy_tree); + gtk_box_pack_start(GTK_BOX(hierarchy_vbox), + hierarchy_scroll_window, FALSE, FALSE, 0); + + GtkWidget* fields_vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); + gtk_box_pack_start(GTK_BOX(details_page_vbox_), fields_vbox, + TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(fields_vbox), + BoldLabel(l10n_util::GetStringUTF8( + IDS_CERT_DETAILS_CERTIFICATE_FIELDS_LABEL)), + FALSE, FALSE, 0); + + fields_tree_ = gtk_tree_view_new(); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(fields_tree_), FALSE); + gtk_tree_view_append_column( + GTK_TREE_VIEW(fields_tree_), + gtk_tree_view_column_new_with_attributes("", gtk_cell_renderer_text_new(), + "text", FIELDS_NAME, + NULL)); + GtkTreeSelection* fields_selection = gtk_tree_view_get_selection( + GTK_TREE_VIEW(fields_tree_)); + gtk_tree_selection_set_mode(fields_selection, GTK_SELECTION_SINGLE); + g_signal_connect(G_OBJECT(fields_selection), "changed", + G_CALLBACK(OnFieldsSelectionChanged), this); + GtkWidget* fields_scroll_window = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(fields_scroll_window), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type( + GTK_SCROLLED_WINDOW(fields_scroll_window), GTK_SHADOW_ETCHED_IN); + gtk_container_add(GTK_CONTAINER(fields_scroll_window), fields_tree_); + gtk_box_pack_start(GTK_BOX(fields_vbox), + fields_scroll_window, TRUE, TRUE, 0); + + GtkWidget* value_vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); + gtk_box_pack_start(GTK_BOX(details_page_vbox_), value_vbox, + TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(value_vbox), + BoldLabel(l10n_util::GetStringUTF8( + IDS_CERT_DETAILS_CERTIFICATE_FIELD_VALUE_LABEL)), + FALSE, FALSE, 0); + + // TODO(mattm): fix text view coloring (should have grey background). + // TODO(mattm): use fixed width font in field value text box. + GtkWidget* field_value_view = gtk_text_view_new(); + gtk_text_view_set_editable(GTK_TEXT_VIEW(field_value_view), FALSE); + gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(field_value_view), GTK_WRAP_NONE); + field_value_buffer_ = gtk_text_view_get_buffer( + GTK_TEXT_VIEW(field_value_view)); + GtkWidget* value_scroll_window = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(value_scroll_window), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type( + GTK_SCROLLED_WINDOW(value_scroll_window), GTK_SHADOW_ETCHED_IN); + gtk_container_add(GTK_CONTAINER(value_scroll_window), field_value_view); + gtk_box_pack_start(GTK_BOX(value_vbox), + value_scroll_window, TRUE, TRUE, 0); + + // TODO(mattm): export certificate button. + + // Select the initial certificate in the hierarchy. + gtk_tree_selection_select_iter(hierarchy_selection, &hierarchy_leaf_iter); +} + +// static +void CertificateViewer::OnHierarchySelectionChanged( + GtkTreeSelection *selection, CertificateViewer* viewer) { + GtkTreeIter iter; + GtkTreeModel* model; + if (gtk_tree_selection_get_selected(selection, &model, &iter)) { + GtkTreeStore* fields_store = NULL; + gtk_tree_model_get(model, &iter, HIERARCHY_OBJECT, &fields_store, -1); + gtk_tree_view_set_model(GTK_TREE_VIEW(viewer->fields_tree_), + GTK_TREE_MODEL(fields_store)); + gtk_tree_view_expand_all(GTK_TREE_VIEW(viewer->fields_tree_)); + } else { + gtk_tree_view_set_model(GTK_TREE_VIEW(viewer->fields_tree_), NULL); + } +} + +// static +void CertificateViewer::OnFieldsSelectionChanged(GtkTreeSelection *selection, + CertificateViewer* viewer) { + GtkTreeIter iter; + GtkTreeModel* model; + if (gtk_tree_selection_get_selected(selection, &model, &iter)) { + gchar* value_string = NULL; + gtk_tree_model_get(model, &iter, FIELDS_VALUE, &value_string, -1); + if (value_string) { + gtk_text_buffer_set_text(viewer->field_value_buffer_, value_string, -1); + g_free(value_string); + } else { + gtk_text_buffer_set_text(viewer->field_value_buffer_, "", 0); + } + } else { + gtk_text_buffer_set_text(viewer->field_value_buffer_, "", 0); + } +} + +void CertificateViewer::Show() { + gtk_widget_show_all(dialog_); +} + +} // namespace + +void ShowCertificateViewer(gfx::NativeWindow parent, int cert_id) { + scoped_refptr<net::X509Certificate> cert; + CertStore::GetSharedInstance()->RetrieveCert(cert_id, &cert); + if (!cert.get()) { + // The certificate was not found. Could be that the renderer crashed before + // we displayed the page info. + return; + } + + CERTCertList* cert_chain = CERT_GetCertChainFromCert( + cert->os_cert_handle(), PR_Now(), certUsageSSLServer); + DCHECK(cert_chain); + (new CertificateViewer(parent, cert_chain))->Show(); +} diff --git a/chrome/browser/gtk/certificate_viewer.h b/chrome/browser/gtk/certificate_viewer.h new file mode 100644 index 0000000..f5ebf44 --- /dev/null +++ b/chrome/browser/gtk/certificate_viewer.h @@ -0,0 +1,12 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_GTK_CERTIFICATE_VIEWER_H_ +#define CHROME_BROWSER_GTK_CERTIFICATE_VIEWER_H_ + +#include "app/gfx/native_widget_types.h" + +void ShowCertificateViewer(gfx::NativeWindow parent, int cert_id); + +#endif // CHROME_BROWSER_GTK_CERTIFICATE_VIEWER_H_ diff --git a/chrome/browser/gtk/page_info_window_gtk.cc b/chrome/browser/gtk/page_info_window_gtk.cc index d6cb526..81ab056 100644 --- a/chrome/browser/gtk/page_info_window_gtk.cc +++ b/chrome/browser/gtk/page_info_window_gtk.cc @@ -10,6 +10,7 @@ #include "app/resource_bundle.h" #include "base/compiler_specific.h" #include "base/string_util.h" +#include "chrome/browser/gtk/certificate_viewer.h" #include "chrome/browser/page_info_model.h" #include "chrome/browser/page_info_window.h" #include "chrome/common/gtk_util.h" @@ -19,6 +20,10 @@ namespace { +enum { + RESPONSE_SHOW_CERT_INFO = 0, +}; + class PageInfoWindowGtk : public PageInfoModel::PageInfoModelObserver { public: PageInfoWindowGtk(gfx::NativeWindow parent, @@ -34,6 +39,9 @@ class PageInfoWindowGtk : public PageInfoModel::PageInfoModelObserver { // Shows the page info window. void Show(); + // Shows the certificate info window. + void ShowCertDialog(); + private: // Layouts the different sections retrieved from the model. void InitContents(); @@ -50,13 +58,21 @@ class PageInfoWindowGtk : public PageInfoModel::PageInfoModelObserver { // The virtual box containing the sections. GtkWidget* contents_; + // The id of the certificate for this page. + int cert_id_; + DISALLOW_COPY_AND_ASSIGN(PageInfoWindowGtk); }; -// Close button callback. -void OnDialogResponse(GtkDialog* dialog, gpointer data) { - // "Close" was clicked. - gtk_widget_destroy(GTK_WIDGET(dialog)); +// Button callbacks. +void OnDialogResponse(GtkDialog* dialog, gint response_id, + PageInfoWindowGtk* page_info) { + if (response_id == RESPONSE_SHOW_CERT_INFO) { + page_info->ShowCertDialog(); + } else { + // "Close" was clicked. + gtk_widget_destroy(GTK_WIDGET(dialog)); + } } void OnDestroy(GtkDialog* dialog, PageInfoWindowGtk* page_info) { @@ -72,7 +88,8 @@ PageInfoWindowGtk::PageInfoWindowGtk(gfx::NativeWindow parent, bool show_history) : ALLOW_THIS_IN_INITIALIZER_LIST(model_(profile, url, ssl, show_history, this)), - contents_(NULL) { + contents_(NULL), + cert_id_(ssl.cert_id()) { dialog_ = gtk_dialog_new_with_buttons( l10n_util::GetStringUTF8(IDS_PAGEINFO_WINDOW_TITLE).c_str(), parent, @@ -81,9 +98,22 @@ PageInfoWindowGtk::PageInfoWindowGtk(gfx::NativeWindow parent, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); + gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_CLOSE); + + if (cert_id_) { + GtkWidget* cert_info_button = gtk_dialog_add_button( + GTK_DIALOG(dialog_), + l10n_util::GetStringUTF8(IDS_PAGEINFO_CERT_INFO_BUTTON).c_str(), + RESPONSE_SHOW_CERT_INFO); + gtk_button_box_set_child_secondary( + GTK_BUTTON_BOX(GTK_DIALOG(dialog_)->action_area), + cert_info_button, + TRUE); + } + gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog_)->vbox), gtk_util::kContentAreaSpacing); - g_signal_connect(dialog_, "response", G_CALLBACK(OnDialogResponse), NULL); + g_signal_connect(dialog_, "response", G_CALLBACK(OnDialogResponse), this); g_signal_connect(dialog_, "destroy", G_CALLBACK(OnDestroy), this); InitContents(); @@ -152,6 +182,10 @@ void PageInfoWindowGtk::Show() { gtk_widget_show(dialog_); } +void PageInfoWindowGtk::ShowCertDialog() { + ShowCertificateViewer(GTK_WINDOW(dialog_), cert_id_); +} + } // namespace namespace browser { diff --git a/chrome/browser/importer/nss_decryptor_linux.cc b/chrome/browser/importer/nss_decryptor_linux.cc index a8e8d44..2fc083e 100644 --- a/chrome/browser/importer/nss_decryptor_linux.cc +++ b/chrome/browser/importer/nss_decryptor_linux.cc @@ -8,7 +8,7 @@ #include <pk11sdr.h> #include "base/basictypes.h" -#include "base/nss_init.h" +#include "base/nss_util.h" #include "base/string_util.h" #include "base/sys_string_conversions.h" diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 103177e..e3d3db3 100755 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -856,6 +856,8 @@ 'browser/gtk/browser_window_gtk.h', 'browser/gtk/cairo_cached_surface.cc', 'browser/gtk/cairo_cached_surface.h', + 'browser/gtk/certificate_viewer.cc', + 'browser/gtk/certificate_viewer.h', 'browser/gtk/clear_browsing_data_dialog_gtk.cc', 'browser/gtk/clear_browsing_data_dialog_gtk.h', 'browser/gtk/constrained_window_gtk.cc', diff --git a/net/base/cert_database_nss.cc b/net/base/cert_database_nss.cc index 605c556..e3c1a09 100644 --- a/net/base/cert_database_nss.cc +++ b/net/base/cert_database_nss.cc @@ -14,7 +14,7 @@ #include "base/logging.h" #include "base/scoped_ptr.h" -#include "base/nss_init.h" +#include "base/nss_util.h" namespace net { diff --git a/net/base/keygen_handler_nss.cc b/net/base/keygen_handler_nss.cc index d68ba0d..6c17298 100644 --- a/net/base/keygen_handler_nss.cc +++ b/net/base/keygen_handler_nss.cc @@ -12,7 +12,7 @@ #include <cryptohi.h> // SEC_DerSignData() #include <keyhi.h> // SECKEY_CreateSubjectPublicKeyInfo() -#include "base/nss_init.h" +#include "base/nss_util.h" #include "base/logging.h" namespace net { diff --git a/net/base/x509_certificate_nss.cc b/net/base/x509_certificate_nss.cc index 5f7075e..f7dbd71 100644 --- a/net/base/x509_certificate_nss.cc +++ b/net/base/x509_certificate_nss.cc @@ -16,7 +16,7 @@ #include "base/logging.h" #include "base/pickle.h" #include "base/time.h" -#include "base/nss_init.h" +#include "base/nss_util.h" #include "net/base/cert_status_flags.h" #include "net/base/cert_verify_result.h" #include "net/base/ev_root_ca_metadata.h" @@ -211,24 +211,6 @@ void GetCertChainInfo(CERTCertList* cert_list, } } -// TODO(port): Implement this more simply, and put it in the right place -base::Time PRTimeToBaseTime(PRTime prtime) { - PRExplodedTime prxtime; - PR_ExplodeTime(prtime, PR_GMTParameters, &prxtime); - - base::Time::Exploded exploded; - exploded.year = prxtime.tm_year; - exploded.month = prxtime.tm_month + 1; - exploded.day_of_week = prxtime.tm_wday; - exploded.day_of_month = prxtime.tm_mday; - exploded.hour = prxtime.tm_hour; - exploded.minute = prxtime.tm_min; - exploded.second = prxtime.tm_sec; - exploded.millisecond = prxtime.tm_usec / 1000; - - return base::Time::FromUTCExploded(exploded); -} - typedef char* (*CERTGetNameFunc)(CERTName* name); void ParsePrincipal(CERTName* name, @@ -292,7 +274,7 @@ void ParseDate(SECItem* der_date, base::Time* result) { PRTime prtime; SECStatus rv = DER_DecodeTimeChoice(&prtime, der_date); DCHECK(rv == SECSuccess); - *result = PRTimeToBaseTime(prtime); + *result = base::PRTimeToBaseTime(prtime); } void GetCertSubjectAltNamesOfType(X509Certificate::OSCertHandle cert_handle, diff --git a/net/http/des.cc b/net/http/des.cc index 0f89029..9e56a70 100644 --- a/net/http/des.cc +++ b/net/http/des.cc @@ -16,7 +16,7 @@ #include "base/logging.h" #if defined(OS_LINUX) -#include "base/nss_init.h" +#include "base/nss_util.h" #endif // The Mac and Windows (CryptoAPI) versions of DESEncrypt are our own code. diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc index bcb57f1..13f02ae 100644 --- a/net/socket/ssl_client_socket_nss.cc +++ b/net/socket/ssl_client_socket_nss.cc @@ -58,7 +58,7 @@ #include "base/compiler_specific.h" #include "base/logging.h" -#include "base/nss_init.h" +#include "base/nss_util.h" #include "base/string_util.h" #include "net/base/cert_verifier.h" #include "net/base/io_buffer.h" diff --git a/net/socket/ssl_test_util.cc b/net/socket/ssl_test_util.cc index becb322..cde21f3 100644 --- a/net/socket/ssl_test_util.cc +++ b/net/socket/ssl_test_util.cc @@ -20,7 +20,7 @@ #include <ssl.h> #include <sslerr.h> #include <pk11pub.h> -#include "base/nss_init.h" +#include "base/nss_util.h" #elif defined(OS_MACOSX) #include <Security/Security.h> #include "base/scoped_cftyperef.h" diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index 9936643..d0ee197 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc @@ -10,7 +10,7 @@ #include <windows.h> #include <shlobj.h> #elif defined(OS_LINUX) -#include "base/nss_init.h" +#include "base/nss_util.h" #endif #include <algorithm> |