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/string_number_conversions.h" 9 #include "base/strings/utf_string_conversions.h" 10 #include "chrome/grit/chromium_strings.h" 11 #include "chrome/grit/generated_resources.h" 12 #include "content/public/browser/cert_store.h" 13 #include "net/base/escape.h" 14 #include "net/base/net_errors.h" 15 #include "net/cert/cert_status_flags.h" 16 #include "net/ssl/ssl_info.h" 17 #include "ui/base/l10n/l10n_util.h" 18 #include "url/gurl.h" 19 20 using base::UTF8ToUTF16; 21 22 SSLErrorInfo::SSLErrorInfo(const base::string16& details, 23 const base::string16& short_description) 24 : details_(details), 25 short_description_(short_description) { 26 } 27 28 // static 29 SSLErrorInfo SSLErrorInfo::CreateError(ErrorType error_type, 30 net::X509Certificate* cert, 31 const GURL& request_url) { 32 base::string16 details, short_description; 33 switch (error_type) { 34 case CERT_COMMON_NAME_INVALID: { 35 // If the certificate contains multiple DNS names, we choose the most 36 // representative one -- either the DNS name that's also in the subject 37 // field, or the first one. If this heuristic turns out to be 38 // inadequate, we can consider choosing the DNS name that is the 39 // "closest match" to the host name in the request URL, or listing all 40 // the DNS names with an HTML <ul>. 41 std::vector<std::string> dns_names; 42 cert->GetDNSNames(&dns_names); 43 DCHECK(!dns_names.empty()); 44 size_t i = 0; 45 for (; i < dns_names.size(); ++i) { 46 if (dns_names[i] == cert->subject().common_name) 47 break; 48 } 49 if (i == dns_names.size()) 50 i = 0; 51 details = 52 l10n_util::GetStringFUTF16(IDS_CERT_ERROR_COMMON_NAME_INVALID_DETAILS, 53 UTF8ToUTF16(request_url.host()), 54 net::EscapeForHTML( 55 UTF8ToUTF16(dns_names[i]))); 56 short_description = l10n_util::GetStringUTF16( 57 IDS_CERT_ERROR_COMMON_NAME_INVALID_DESCRIPTION); 58 break; 59 } 60 case CERT_DATE_INVALID: 61 if (cert->HasExpired()) { 62 details = l10n_util::GetStringFUTF16( 63 IDS_CERT_ERROR_EXPIRED_DETAILS, 64 UTF8ToUTF16(request_url.host()), 65 base::IntToString16( 66 (base::Time::Now() - cert->valid_expiry()).InDays()), 67 base::TimeFormatFriendlyDate(base::Time::Now())); 68 short_description = 69 l10n_util::GetStringUTF16(IDS_CERT_ERROR_EXPIRED_DESCRIPTION); 70 } else if (base::Time::Now() < cert->valid_start()) { 71 details = l10n_util::GetStringFUTF16( 72 IDS_CERT_ERROR_NOT_YET_VALID_DETAILS, 73 UTF8ToUTF16(request_url.host()), 74 base::IntToString16( 75 (cert->valid_start() - base::Time::Now()).InDays())); 76 short_description = 77 l10n_util::GetStringUTF16(IDS_CERT_ERROR_NOT_YET_VALID_DESCRIPTION); 78 } else { 79 // Two possibilities: (1) an intermediate or root certificate has 80 // expired, or (2) the certificate has become valid since the error 81 // occurred. Since (1) is more likely, assume that's the case. 82 details = l10n_util::GetStringFUTF16( 83 IDS_CERT_ERROR_CHAIN_EXPIRED_DETAILS, 84 UTF8ToUTF16(request_url.host()), 85 base::TimeFormatFriendlyDate(base::Time::Now())); 86 short_description = 87 l10n_util::GetStringUTF16(IDS_CERT_ERROR_CHAIN_EXPIRED_DESCRIPTION); 88 } 89 break; 90 case CERT_AUTHORITY_INVALID: 91 details = l10n_util::GetStringFUTF16( 92 IDS_CERT_ERROR_AUTHORITY_INVALID_DETAILS, 93 UTF8ToUTF16(request_url.host())); 94 short_description = l10n_util::GetStringUTF16( 95 IDS_CERT_ERROR_AUTHORITY_INVALID_DESCRIPTION); 96 break; 97 case CERT_CONTAINS_ERRORS: 98 details = l10n_util::GetStringFUTF16( 99 IDS_CERT_ERROR_CONTAINS_ERRORS_DETAILS, 100 UTF8ToUTF16(request_url.host())); 101 short_description = 102 l10n_util::GetStringUTF16(IDS_CERT_ERROR_CONTAINS_ERRORS_DESCRIPTION); 103 break; 104 case CERT_NO_REVOCATION_MECHANISM: 105 details = l10n_util::GetStringUTF16( 106 IDS_CERT_ERROR_NO_REVOCATION_MECHANISM_DETAILS); 107 short_description = l10n_util::GetStringUTF16( 108 IDS_CERT_ERROR_NO_REVOCATION_MECHANISM_DESCRIPTION); 109 break; 110 case CERT_REVOKED: 111 details = l10n_util::GetStringFUTF16(IDS_CERT_ERROR_REVOKED_CERT_DETAILS, 112 UTF8ToUTF16(request_url.host())); 113 short_description = 114 l10n_util::GetStringUTF16(IDS_CERT_ERROR_REVOKED_CERT_DESCRIPTION); 115 break; 116 case CERT_INVALID: 117 details = l10n_util::GetStringFUTF16( 118 IDS_CERT_ERROR_INVALID_CERT_DETAILS, 119 UTF8ToUTF16(request_url.host())); 120 short_description = 121 l10n_util::GetStringUTF16(IDS_CERT_ERROR_INVALID_CERT_DESCRIPTION); 122 break; 123 case CERT_WEAK_SIGNATURE_ALGORITHM: 124 details = l10n_util::GetStringFUTF16( 125 IDS_CERT_ERROR_WEAK_SIGNATURE_ALGORITHM_DETAILS, 126 UTF8ToUTF16(request_url.host())); 127 short_description = l10n_util::GetStringUTF16( 128 IDS_CERT_ERROR_WEAK_SIGNATURE_ALGORITHM_DESCRIPTION); 129 break; 130 case CERT_WEAK_KEY: 131 details = l10n_util::GetStringFUTF16( 132 IDS_CERT_ERROR_WEAK_KEY_DETAILS, UTF8ToUTF16(request_url.host())); 133 short_description = l10n_util::GetStringUTF16( 134 IDS_CERT_ERROR_WEAK_KEY_DESCRIPTION); 135 break; 136 case CERT_WEAK_KEY_DH: 137 details = l10n_util::GetStringFUTF16( 138 IDS_CERT_ERROR_WEAK_KEY_DETAILS, UTF8ToUTF16(request_url.host())); 139 short_description = l10n_util::GetStringUTF16( 140 IDS_CERT_ERROR_WEAK_KEY_DESCRIPTION); 141 case CERT_NAME_CONSTRAINT_VIOLATION: 142 details = l10n_util::GetStringFUTF16( 143 IDS_CERT_ERROR_NAME_CONSTRAINT_VIOLATION_DETAILS, 144 UTF8ToUTF16(request_url.host())); 145 short_description = l10n_util::GetStringUTF16( 146 IDS_CERT_ERROR_NAME_CONSTRAINT_VIOLATION_DESCRIPTION); 147 break; 148 case CERT_PINNED_KEY_MISSING: 149 details = l10n_util::GetStringUTF16( 150 IDS_ERRORPAGES_SUMMARY_PINNING_FAILURE); 151 short_description = l10n_util::GetStringUTF16( 152 IDS_ERRORPAGES_DETAILS_PINNING_FAILURE); 153 break; 154 case UNKNOWN: 155 details = l10n_util::GetStringUTF16(IDS_CERT_ERROR_UNKNOWN_ERROR_DETAILS); 156 short_description = 157 l10n_util::GetStringUTF16(IDS_CERT_ERROR_UNKNOWN_ERROR_DESCRIPTION); 158 break; 159 case CERT_UNABLE_TO_CHECK_REVOCATION: // Deprecated. 160 default: 161 NOTREACHED(); 162 } 163 return SSLErrorInfo(details, short_description); 164 } 165 166 SSLErrorInfo::~SSLErrorInfo() { 167 } 168 169 // static 170 SSLErrorInfo::ErrorType SSLErrorInfo::NetErrorToErrorType(int net_error) { 171 switch (net_error) { 172 case net::ERR_CERT_COMMON_NAME_INVALID: 173 return CERT_COMMON_NAME_INVALID; 174 case net::ERR_CERT_DATE_INVALID: 175 return CERT_DATE_INVALID; 176 case net::ERR_CERT_AUTHORITY_INVALID: 177 return CERT_AUTHORITY_INVALID; 178 case net::ERR_CERT_CONTAINS_ERRORS: 179 return CERT_CONTAINS_ERRORS; 180 case net::ERR_CERT_NO_REVOCATION_MECHANISM: 181 return CERT_NO_REVOCATION_MECHANISM; 182 case net::ERR_CERT_UNABLE_TO_CHECK_REVOCATION: 183 return CERT_UNABLE_TO_CHECK_REVOCATION; 184 case net::ERR_CERT_REVOKED: 185 return CERT_REVOKED; 186 case net::ERR_CERT_INVALID: 187 return CERT_INVALID; 188 case net::ERR_CERT_WEAK_SIGNATURE_ALGORITHM: 189 return CERT_WEAK_SIGNATURE_ALGORITHM; 190 case net::ERR_CERT_WEAK_KEY: 191 return CERT_WEAK_KEY; 192 case net::ERR_CERT_NAME_CONSTRAINT_VIOLATION: 193 return CERT_NAME_CONSTRAINT_VIOLATION; 194 case net::ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY: 195 return CERT_WEAK_KEY_DH; 196 case net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN: 197 return CERT_PINNED_KEY_MISSING; 198 default: 199 NOTREACHED(); 200 return UNKNOWN; 201 } 202 } 203 204 // static 205 int SSLErrorInfo::GetErrorsForCertStatus(int cert_id, 206 net::CertStatus cert_status, 207 const GURL& url, 208 std::vector<SSLErrorInfo>* errors) { 209 const net::CertStatus kErrorFlags[] = { 210 net::CERT_STATUS_COMMON_NAME_INVALID, 211 net::CERT_STATUS_DATE_INVALID, 212 net::CERT_STATUS_AUTHORITY_INVALID, 213 net::CERT_STATUS_NO_REVOCATION_MECHANISM, 214 net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION, 215 net::CERT_STATUS_REVOKED, 216 net::CERT_STATUS_INVALID, 217 net::CERT_STATUS_WEAK_SIGNATURE_ALGORITHM, 218 net::CERT_STATUS_WEAK_KEY, 219 net::CERT_STATUS_NAME_CONSTRAINT_VIOLATION, 220 }; 221 222 const ErrorType kErrorTypes[] = { 223 CERT_COMMON_NAME_INVALID, 224 CERT_DATE_INVALID, 225 CERT_AUTHORITY_INVALID, 226 CERT_NO_REVOCATION_MECHANISM, 227 CERT_UNABLE_TO_CHECK_REVOCATION, 228 CERT_REVOKED, 229 CERT_INVALID, 230 CERT_WEAK_SIGNATURE_ALGORITHM, 231 CERT_WEAK_KEY, 232 CERT_NAME_CONSTRAINT_VIOLATION, 233 }; 234 DCHECK(arraysize(kErrorFlags) == arraysize(kErrorTypes)); 235 236 scoped_refptr<net::X509Certificate> cert = NULL; 237 int count = 0; 238 for (size_t i = 0; i < arraysize(kErrorFlags); ++i) { 239 if (cert_status & kErrorFlags[i]) { 240 count++; 241 if (!cert.get()) { 242 bool r = content::CertStore::GetInstance()->RetrieveCert( 243 cert_id, &cert); 244 DCHECK(r); 245 } 246 if (errors) 247 errors->push_back( 248 SSLErrorInfo::CreateError(kErrorTypes[i], cert.get(), url)); 249 } 250 } 251 return count; 252 } 253