Home | History | Annotate | Download | only in ssl
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/ssl/ssl_error_info.h"
      6 
      7 #include "base/i18n/time_formatting.h"
      8 #include "base/strings/utf_string_conversions.h"
      9 #include "content/public/browser/cert_store.h"
     10 #include "grit/chromium_strings.h"
     11 #include "grit/generated_resources.h"
     12 #include "net/base/escape.h"
     13 #include "net/base/net_errors.h"
     14 #include "net/cert/cert_status_flags.h"
     15 #include "net/ssl/ssl_info.h"
     16 #include "ui/base/l10n/l10n_util.h"
     17 #include "url/gurl.h"
     18 
     19 using base::UTF8ToUTF16;
     20 
     21 SSLErrorInfo::SSLErrorInfo(const base::string16& title,
     22                            const base::string16& details,
     23                            const base::string16& short_description,
     24                            const std::vector<base::string16>& extra_info)
     25     : title_(title),
     26       details_(details),
     27       short_description_(short_description),
     28       extra_information_(extra_info) {
     29 }
     30 
     31 // static
     32 SSLErrorInfo SSLErrorInfo::CreateError(ErrorType error_type,
     33                                        net::X509Certificate* cert,
     34                                        const GURL& request_url) {
     35   base::string16 title, details, short_description;
     36   std::vector<base::string16> extra_info;
     37   switch (error_type) {
     38     case CERT_COMMON_NAME_INVALID: {
     39       title =
     40           l10n_util::GetStringUTF16(IDS_CERT_ERROR_COMMON_NAME_INVALID_TITLE);
     41       // If the certificate contains multiple DNS names, we choose the most
     42       // representative one -- either the DNS name that's also in the subject
     43       // field, or the first one.  If this heuristic turns out to be
     44       // inadequate, we can consider choosing the DNS name that is the
     45       // "closest match" to the host name in the request URL, or listing all
     46       // the DNS names with an HTML <ul>.
     47       std::vector<std::string> dns_names;
     48       cert->GetDNSNames(&dns_names);
     49       DCHECK(!dns_names.empty());
     50       size_t i = 0;
     51       for (; i < dns_names.size(); ++i) {
     52         if (dns_names[i] == cert->subject().common_name)
     53           break;
     54       }
     55       if (i == dns_names.size())
     56         i = 0;
     57       details =
     58           l10n_util::GetStringFUTF16(IDS_CERT_ERROR_COMMON_NAME_INVALID_DETAILS,
     59                                      UTF8ToUTF16(request_url.host()),
     60                                      net::EscapeForHTML(
     61                                          UTF8ToUTF16(dns_names[i])),
     62                                      UTF8ToUTF16(request_url.host()));
     63       short_description = l10n_util::GetStringUTF16(
     64           IDS_CERT_ERROR_COMMON_NAME_INVALID_DESCRIPTION);
     65       extra_info.push_back(
     66           l10n_util::GetStringUTF16(IDS_CERT_ERROR_EXTRA_INFO_1));
     67       extra_info.push_back(
     68           l10n_util::GetStringFUTF16(
     69               IDS_CERT_ERROR_COMMON_NAME_INVALID_EXTRA_INFO_2,
     70               net::EscapeForHTML(UTF8ToUTF16(cert->subject().common_name)),
     71               UTF8ToUTF16(request_url.host())));
     72       break;
     73     }
     74     case CERT_DATE_INVALID:
     75       extra_info.push_back(
     76           l10n_util::GetStringUTF16(IDS_CERT_ERROR_EXTRA_INFO_1));
     77       if (cert->HasExpired()) {
     78         title = l10n_util::GetStringUTF16(IDS_CERT_ERROR_EXPIRED_TITLE);
     79         details = l10n_util::GetStringFUTF16(
     80             IDS_CERT_ERROR_EXPIRED_DETAILS,
     81             UTF8ToUTF16(request_url.host()),
     82             UTF8ToUTF16(request_url.host()),
     83             base::TimeFormatFriendlyDateAndTime(base::Time::Now()));
     84         short_description =
     85             l10n_util::GetStringUTF16(IDS_CERT_ERROR_EXPIRED_DESCRIPTION);
     86         extra_info.push_back(l10n_util::GetStringUTF16(
     87             IDS_CERT_ERROR_EXPIRED_DETAILS_EXTRA_INFO_2));
     88       } else {
     89         // Then it must be not yet valid.  We don't check that it is not yet
     90         // valid as there is still a very unlikely chance that the cert might
     91         // have become valid since the error occurred.
     92         title = l10n_util::GetStringUTF16(IDS_CERT_ERROR_NOT_YET_VALID_TITLE);
     93         details = l10n_util::GetStringFUTF16(
     94             IDS_CERT_ERROR_NOT_YET_VALID_DETAILS,
     95             UTF8ToUTF16(request_url.host()),
     96             UTF8ToUTF16(request_url.host()),
     97             base::TimeFormatFriendlyDateAndTime(base::Time::Now()));
     98         short_description =
     99             l10n_util::GetStringUTF16(IDS_CERT_ERROR_NOT_YET_VALID_DESCRIPTION);
    100         extra_info.push_back(
    101             l10n_util::GetStringUTF16(
    102                 IDS_CERT_ERROR_NOT_YET_VALID_DETAILS_EXTRA_INFO_2));
    103       }
    104       break;
    105     case CERT_AUTHORITY_INVALID:
    106       title = l10n_util::GetStringUTF16(IDS_CERT_ERROR_AUTHORITY_INVALID_TITLE);
    107       details = l10n_util::GetStringFUTF16(
    108           IDS_CERT_ERROR_AUTHORITY_INVALID_DETAILS,
    109           UTF8ToUTF16(request_url.host()));
    110       short_description = l10n_util::GetStringUTF16(
    111           IDS_CERT_ERROR_AUTHORITY_INVALID_DESCRIPTION);
    112       extra_info.push_back(
    113           l10n_util::GetStringUTF16(IDS_CERT_ERROR_EXTRA_INFO_1));
    114       extra_info.push_back(l10n_util::GetStringFUTF16(
    115           IDS_CERT_ERROR_AUTHORITY_INVALID_EXTRA_INFO_2,
    116           UTF8ToUTF16(request_url.host()),
    117           UTF8ToUTF16(request_url.host())));
    118 #if !defined(OS_IOS)
    119       // The third paragraph advises users to install a private trust anchor,
    120       // but that is not possible in Chrome for iOS at this time.
    121       extra_info.push_back(l10n_util::GetStringUTF16(
    122           IDS_CERT_ERROR_AUTHORITY_INVALID_EXTRA_INFO_3));
    123 #endif
    124       break;
    125     case CERT_CONTAINS_ERRORS:
    126       title = l10n_util::GetStringUTF16(IDS_CERT_ERROR_CONTAINS_ERRORS_TITLE);
    127       details = l10n_util::GetStringFUTF16(
    128           IDS_CERT_ERROR_CONTAINS_ERRORS_DETAILS,
    129           UTF8ToUTF16(request_url.host()));
    130       short_description =
    131           l10n_util::GetStringUTF16(IDS_CERT_ERROR_CONTAINS_ERRORS_DESCRIPTION);
    132       extra_info.push_back(
    133           l10n_util::GetStringFUTF16(IDS_CERT_ERROR_EXTRA_INFO_1,
    134                                      UTF8ToUTF16(request_url.host())));
    135       extra_info.push_back(l10n_util::GetStringUTF16(
    136           IDS_CERT_ERROR_CONTAINS_ERRORS_EXTRA_INFO_2));
    137       break;
    138     case CERT_NO_REVOCATION_MECHANISM:
    139       title = l10n_util::GetStringUTF16(
    140           IDS_CERT_ERROR_NO_REVOCATION_MECHANISM_TITLE);
    141       details = l10n_util::GetStringUTF16(
    142           IDS_CERT_ERROR_NO_REVOCATION_MECHANISM_DETAILS);
    143       short_description = l10n_util::GetStringUTF16(
    144           IDS_CERT_ERROR_NO_REVOCATION_MECHANISM_DESCRIPTION);
    145       break;
    146     case CERT_UNABLE_TO_CHECK_REVOCATION:
    147       title = l10n_util::GetStringUTF16(
    148           IDS_CERT_ERROR_UNABLE_TO_CHECK_REVOCATION_TITLE);
    149       details = l10n_util::GetStringUTF16(
    150           IDS_CERT_ERROR_UNABLE_TO_CHECK_REVOCATION_DETAILS);
    151       short_description = l10n_util::GetStringUTF16(
    152           IDS_CERT_ERROR_UNABLE_TO_CHECK_REVOCATION_DESCRIPTION);
    153       break;
    154     case CERT_REVOKED:
    155       title = l10n_util::GetStringUTF16(IDS_CERT_ERROR_REVOKED_CERT_TITLE);
    156       details = l10n_util::GetStringFUTF16(IDS_CERT_ERROR_REVOKED_CERT_DETAILS,
    157                                            UTF8ToUTF16(request_url.host()));
    158       short_description =
    159           l10n_util::GetStringUTF16(IDS_CERT_ERROR_REVOKED_CERT_DESCRIPTION);
    160       extra_info.push_back(
    161           l10n_util::GetStringUTF16(IDS_CERT_ERROR_EXTRA_INFO_1));
    162       extra_info.push_back(
    163           l10n_util::GetStringUTF16(IDS_CERT_ERROR_REVOKED_CERT_EXTRA_INFO_2));
    164       break;
    165     case CERT_INVALID:
    166       title = l10n_util::GetStringUTF16(IDS_CERT_ERROR_INVALID_CERT_TITLE);
    167       details = l10n_util::GetStringFUTF16(
    168           IDS_CERT_ERROR_INVALID_CERT_DETAILS,
    169           UTF8ToUTF16(request_url.host()));
    170       short_description =
    171           l10n_util::GetStringUTF16(IDS_CERT_ERROR_INVALID_CERT_DESCRIPTION);
    172       extra_info.push_back(
    173           l10n_util::GetStringUTF16(IDS_CERT_ERROR_EXTRA_INFO_1));
    174       extra_info.push_back(l10n_util::GetStringUTF16(
    175           IDS_CERT_ERROR_INVALID_CERT_EXTRA_INFO_2));
    176       break;
    177     case CERT_WEAK_SIGNATURE_ALGORITHM:
    178       title = l10n_util::GetStringUTF16(
    179           IDS_CERT_ERROR_WEAK_SIGNATURE_ALGORITHM_TITLE);
    180       details = l10n_util::GetStringFUTF16(
    181           IDS_CERT_ERROR_WEAK_SIGNATURE_ALGORITHM_DETAILS,
    182           UTF8ToUTF16(request_url.host()));
    183       short_description = l10n_util::GetStringUTF16(
    184           IDS_CERT_ERROR_WEAK_SIGNATURE_ALGORITHM_DESCRIPTION);
    185       extra_info.push_back(
    186           l10n_util::GetStringUTF16(IDS_CERT_ERROR_EXTRA_INFO_1));
    187       extra_info.push_back(
    188           l10n_util::GetStringUTF16(
    189               IDS_CERT_ERROR_WEAK_SIGNATURE_ALGORITHM_EXTRA_INFO_2));
    190       break;
    191     case CERT_WEAK_KEY:
    192       title = l10n_util::GetStringUTF16(IDS_CERT_ERROR_WEAK_KEY_TITLE);
    193       details = l10n_util::GetStringFUTF16(
    194           IDS_CERT_ERROR_WEAK_KEY_DETAILS, UTF8ToUTF16(request_url.host()));
    195       short_description = l10n_util::GetStringUTF16(
    196           IDS_CERT_ERROR_WEAK_KEY_DESCRIPTION);
    197       extra_info.push_back(
    198           l10n_util::GetStringUTF16(IDS_CERT_ERROR_EXTRA_INFO_1));
    199       extra_info.push_back(
    200           l10n_util::GetStringUTF16(
    201               IDS_CERT_ERROR_WEAK_KEY_EXTRA_INFO_2));
    202       break;
    203     case CERT_WEAK_KEY_DH:
    204       title = l10n_util::GetStringUTF16(
    205           IDS_ERRORPAGES_HEADING_WEAK_SERVER_EPHEMERAL_DH_KEY);
    206       details = l10n_util::GetStringFUTF16(
    207           IDS_CERT_ERROR_WEAK_KEY_DETAILS, UTF8ToUTF16(request_url.host()));
    208       short_description = l10n_util::GetStringUTF16(
    209           IDS_CERT_ERROR_WEAK_KEY_DESCRIPTION);
    210       extra_info.push_back(
    211           l10n_util::GetStringUTF16(
    212               IDS_ERRORPAGES_SUMMARY_WEAK_SERVER_EPHEMERAL_DH_KEY));
    213     case CERT_NAME_CONSTRAINT_VIOLATION:
    214       title = l10n_util::GetStringUTF16(
    215           IDS_CERT_ERROR_NAME_CONSTRAINT_VIOLATION_TITLE);
    216       details = l10n_util::GetStringFUTF16(
    217           IDS_CERT_ERROR_NAME_CONSTRAINT_VIOLATION_DETAILS,
    218           UTF8ToUTF16(request_url.host()));
    219       short_description = l10n_util::GetStringUTF16(
    220           IDS_CERT_ERROR_NAME_CONSTRAINT_VIOLATION_DESCRIPTION);
    221       break;
    222     case CERT_PINNED_KEY_MISSING:
    223       title = l10n_util::GetStringUTF16(
    224           IDS_ERRORPAGES_HEADING_PINNING_FAILURE);
    225       details = l10n_util::GetStringUTF16(
    226           IDS_ERRORPAGES_SUMMARY_PINNING_FAILURE);
    227       short_description = l10n_util::GetStringUTF16(
    228           IDS_ERRORPAGES_DETAILS_PINNING_FAILURE);
    229     case UNKNOWN:
    230       title = l10n_util::GetStringUTF16(IDS_CERT_ERROR_UNKNOWN_ERROR_TITLE);
    231       details = l10n_util::GetStringUTF16(IDS_CERT_ERROR_UNKNOWN_ERROR_DETAILS);
    232       short_description =
    233           l10n_util::GetStringUTF16(IDS_CERT_ERROR_UNKNOWN_ERROR_DESCRIPTION);
    234       break;
    235     default:
    236       NOTREACHED();
    237   }
    238   return SSLErrorInfo(title, details, short_description, extra_info);
    239 }
    240 
    241 SSLErrorInfo::~SSLErrorInfo() {
    242 }
    243 
    244 // static
    245 SSLErrorInfo::ErrorType SSLErrorInfo::NetErrorToErrorType(int net_error) {
    246   switch (net_error) {
    247     case net::ERR_CERT_COMMON_NAME_INVALID:
    248       return CERT_COMMON_NAME_INVALID;
    249     case net::ERR_CERT_DATE_INVALID:
    250       return CERT_DATE_INVALID;
    251     case net::ERR_CERT_AUTHORITY_INVALID:
    252       return CERT_AUTHORITY_INVALID;
    253     case net::ERR_CERT_CONTAINS_ERRORS:
    254       return CERT_CONTAINS_ERRORS;
    255     case net::ERR_CERT_NO_REVOCATION_MECHANISM:
    256       return CERT_NO_REVOCATION_MECHANISM;
    257     case net::ERR_CERT_UNABLE_TO_CHECK_REVOCATION:
    258       return CERT_UNABLE_TO_CHECK_REVOCATION;
    259     case net::ERR_CERT_REVOKED:
    260       return CERT_REVOKED;
    261     case net::ERR_CERT_INVALID:
    262       return CERT_INVALID;
    263     case net::ERR_CERT_WEAK_SIGNATURE_ALGORITHM:
    264       return CERT_WEAK_SIGNATURE_ALGORITHM;
    265     case net::ERR_CERT_WEAK_KEY:
    266       return CERT_WEAK_KEY;
    267     case net::ERR_CERT_NAME_CONSTRAINT_VIOLATION:
    268       return CERT_NAME_CONSTRAINT_VIOLATION;
    269     case net::ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY:
    270       return CERT_WEAK_KEY_DH;
    271     case net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN:
    272       return CERT_PINNED_KEY_MISSING;
    273     default:
    274       NOTREACHED();
    275       return UNKNOWN;
    276     }
    277 }
    278 
    279 // static
    280 int SSLErrorInfo::GetErrorsForCertStatus(int cert_id,
    281                                          net::CertStatus cert_status,
    282                                          const GURL& url,
    283                                          std::vector<SSLErrorInfo>* errors) {
    284   const net::CertStatus kErrorFlags[] = {
    285     net::CERT_STATUS_COMMON_NAME_INVALID,
    286     net::CERT_STATUS_DATE_INVALID,
    287     net::CERT_STATUS_AUTHORITY_INVALID,
    288     net::CERT_STATUS_NO_REVOCATION_MECHANISM,
    289     net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION,
    290     net::CERT_STATUS_REVOKED,
    291     net::CERT_STATUS_INVALID,
    292     net::CERT_STATUS_WEAK_SIGNATURE_ALGORITHM,
    293     net::CERT_STATUS_WEAK_KEY,
    294     net::CERT_STATUS_NAME_CONSTRAINT_VIOLATION,
    295   };
    296 
    297   const ErrorType kErrorTypes[] = {
    298     CERT_COMMON_NAME_INVALID,
    299     CERT_DATE_INVALID,
    300     CERT_AUTHORITY_INVALID,
    301     CERT_NO_REVOCATION_MECHANISM,
    302     CERT_UNABLE_TO_CHECK_REVOCATION,
    303     CERT_REVOKED,
    304     CERT_INVALID,
    305     CERT_WEAK_SIGNATURE_ALGORITHM,
    306     CERT_WEAK_KEY,
    307     CERT_NAME_CONSTRAINT_VIOLATION,
    308   };
    309   DCHECK(arraysize(kErrorFlags) == arraysize(kErrorTypes));
    310 
    311   scoped_refptr<net::X509Certificate> cert = NULL;
    312   int count = 0;
    313   for (size_t i = 0; i < arraysize(kErrorFlags); ++i) {
    314     if (cert_status & kErrorFlags[i]) {
    315       count++;
    316       if (!cert.get()) {
    317         bool r = content::CertStore::GetInstance()->RetrieveCert(
    318             cert_id, &cert);
    319         DCHECK(r);
    320       }
    321       if (errors)
    322         errors->push_back(
    323             SSLErrorInfo::CreateError(kErrorTypes[i], cert.get(), url));
    324     }
    325   }
    326   return count;
    327 }
    328