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