ssl_error_info.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
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 "content/public/browser/cert_store.h" 11#include "grit/chromium_strings.h" 12#include "grit/generated_resources.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 20using base::UTF8ToUTF16; 21 22SSLErrorInfo::SSLErrorInfo(const base::string16& details, 23 const base::string16& short_description) 24 : details_(details), 25 short_description_(short_description) { 26} 27 28// static 29SSLErrorInfo 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 { 71 // Then it must be not yet valid. We don't check that it is not yet 72 // valid as there is still a very unlikely chance that the cert might 73 // have become valid since the error occurred. 74 details = l10n_util::GetStringFUTF16( 75 IDS_CERT_ERROR_NOT_YET_VALID_DETAILS, 76 UTF8ToUTF16(request_url.host()), 77 base::IntToString16( 78 (cert->valid_start() - base::Time::Now()).InDays())); 79 short_description = 80 l10n_util::GetStringUTF16(IDS_CERT_ERROR_NOT_YET_VALID_DESCRIPTION); 81 } 82 break; 83 case CERT_AUTHORITY_INVALID: 84 details = l10n_util::GetStringFUTF16( 85 IDS_CERT_ERROR_AUTHORITY_INVALID_DETAILS, 86 UTF8ToUTF16(request_url.host())); 87 short_description = l10n_util::GetStringUTF16( 88 IDS_CERT_ERROR_AUTHORITY_INVALID_DESCRIPTION); 89 break; 90 case CERT_CONTAINS_ERRORS: 91 details = l10n_util::GetStringFUTF16( 92 IDS_CERT_ERROR_CONTAINS_ERRORS_DETAILS, 93 UTF8ToUTF16(request_url.host())); 94 short_description = 95 l10n_util::GetStringUTF16(IDS_CERT_ERROR_CONTAINS_ERRORS_DESCRIPTION); 96 break; 97 case CERT_NO_REVOCATION_MECHANISM: 98 details = l10n_util::GetStringUTF16( 99 IDS_CERT_ERROR_NO_REVOCATION_MECHANISM_DETAILS); 100 short_description = l10n_util::GetStringUTF16( 101 IDS_CERT_ERROR_NO_REVOCATION_MECHANISM_DESCRIPTION); 102 break; 103 case CERT_REVOKED: 104 details = l10n_util::GetStringFUTF16(IDS_CERT_ERROR_REVOKED_CERT_DETAILS, 105 UTF8ToUTF16(request_url.host())); 106 short_description = 107 l10n_util::GetStringUTF16(IDS_CERT_ERROR_REVOKED_CERT_DESCRIPTION); 108 break; 109 case CERT_INVALID: 110 details = l10n_util::GetStringFUTF16( 111 IDS_CERT_ERROR_INVALID_CERT_DETAILS, 112 UTF8ToUTF16(request_url.host())); 113 short_description = 114 l10n_util::GetStringUTF16(IDS_CERT_ERROR_INVALID_CERT_DESCRIPTION); 115 break; 116 case CERT_WEAK_SIGNATURE_ALGORITHM: 117 details = l10n_util::GetStringFUTF16( 118 IDS_CERT_ERROR_WEAK_SIGNATURE_ALGORITHM_DETAILS, 119 UTF8ToUTF16(request_url.host())); 120 short_description = l10n_util::GetStringUTF16( 121 IDS_CERT_ERROR_WEAK_SIGNATURE_ALGORITHM_DESCRIPTION); 122 break; 123 case CERT_WEAK_KEY: 124 details = l10n_util::GetStringFUTF16( 125 IDS_CERT_ERROR_WEAK_KEY_DETAILS, UTF8ToUTF16(request_url.host())); 126 short_description = l10n_util::GetStringUTF16( 127 IDS_CERT_ERROR_WEAK_KEY_DESCRIPTION); 128 break; 129 case CERT_WEAK_KEY_DH: 130 details = l10n_util::GetStringFUTF16( 131 IDS_CERT_ERROR_WEAK_KEY_DETAILS, UTF8ToUTF16(request_url.host())); 132 short_description = l10n_util::GetStringUTF16( 133 IDS_CERT_ERROR_WEAK_KEY_DESCRIPTION); 134 case CERT_NAME_CONSTRAINT_VIOLATION: 135 details = l10n_util::GetStringFUTF16( 136 IDS_CERT_ERROR_NAME_CONSTRAINT_VIOLATION_DETAILS, 137 UTF8ToUTF16(request_url.host())); 138 short_description = l10n_util::GetStringUTF16( 139 IDS_CERT_ERROR_NAME_CONSTRAINT_VIOLATION_DESCRIPTION); 140 break; 141 case CERT_PINNED_KEY_MISSING: 142 details = l10n_util::GetStringUTF16( 143 IDS_ERRORPAGES_SUMMARY_PINNING_FAILURE); 144 short_description = l10n_util::GetStringUTF16( 145 IDS_ERRORPAGES_DETAILS_PINNING_FAILURE); 146 case UNKNOWN: 147 details = l10n_util::GetStringUTF16(IDS_CERT_ERROR_UNKNOWN_ERROR_DETAILS); 148 short_description = 149 l10n_util::GetStringUTF16(IDS_CERT_ERROR_UNKNOWN_ERROR_DESCRIPTION); 150 break; 151 case CERT_UNABLE_TO_CHECK_REVOCATION: // Deprecated. 152 default: 153 NOTREACHED(); 154 } 155 return SSLErrorInfo(details, short_description); 156} 157 158SSLErrorInfo::~SSLErrorInfo() { 159} 160 161// static 162SSLErrorInfo::ErrorType SSLErrorInfo::NetErrorToErrorType(int net_error) { 163 switch (net_error) { 164 case net::ERR_CERT_COMMON_NAME_INVALID: 165 return CERT_COMMON_NAME_INVALID; 166 case net::ERR_CERT_DATE_INVALID: 167 return CERT_DATE_INVALID; 168 case net::ERR_CERT_AUTHORITY_INVALID: 169 return CERT_AUTHORITY_INVALID; 170 case net::ERR_CERT_CONTAINS_ERRORS: 171 return CERT_CONTAINS_ERRORS; 172 case net::ERR_CERT_NO_REVOCATION_MECHANISM: 173 return CERT_NO_REVOCATION_MECHANISM; 174 case net::ERR_CERT_UNABLE_TO_CHECK_REVOCATION: 175 return CERT_UNABLE_TO_CHECK_REVOCATION; 176 case net::ERR_CERT_REVOKED: 177 return CERT_REVOKED; 178 case net::ERR_CERT_INVALID: 179 return CERT_INVALID; 180 case net::ERR_CERT_WEAK_SIGNATURE_ALGORITHM: 181 return CERT_WEAK_SIGNATURE_ALGORITHM; 182 case net::ERR_CERT_WEAK_KEY: 183 return CERT_WEAK_KEY; 184 case net::ERR_CERT_NAME_CONSTRAINT_VIOLATION: 185 return CERT_NAME_CONSTRAINT_VIOLATION; 186 case net::ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY: 187 return CERT_WEAK_KEY_DH; 188 case net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN: 189 return CERT_PINNED_KEY_MISSING; 190 default: 191 NOTREACHED(); 192 return UNKNOWN; 193 } 194} 195 196// static 197int SSLErrorInfo::GetErrorsForCertStatus(int cert_id, 198 net::CertStatus cert_status, 199 const GURL& url, 200 std::vector<SSLErrorInfo>* errors) { 201 const net::CertStatus kErrorFlags[] = { 202 net::CERT_STATUS_COMMON_NAME_INVALID, 203 net::CERT_STATUS_DATE_INVALID, 204 net::CERT_STATUS_AUTHORITY_INVALID, 205 net::CERT_STATUS_NO_REVOCATION_MECHANISM, 206 net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION, 207 net::CERT_STATUS_REVOKED, 208 net::CERT_STATUS_INVALID, 209 net::CERT_STATUS_WEAK_SIGNATURE_ALGORITHM, 210 net::CERT_STATUS_WEAK_KEY, 211 net::CERT_STATUS_NAME_CONSTRAINT_VIOLATION, 212 }; 213 214 const ErrorType kErrorTypes[] = { 215 CERT_COMMON_NAME_INVALID, 216 CERT_DATE_INVALID, 217 CERT_AUTHORITY_INVALID, 218 CERT_NO_REVOCATION_MECHANISM, 219 CERT_UNABLE_TO_CHECK_REVOCATION, 220 CERT_REVOKED, 221 CERT_INVALID, 222 CERT_WEAK_SIGNATURE_ALGORITHM, 223 CERT_WEAK_KEY, 224 CERT_NAME_CONSTRAINT_VIOLATION, 225 }; 226 DCHECK(arraysize(kErrorFlags) == arraysize(kErrorTypes)); 227 228 scoped_refptr<net::X509Certificate> cert = NULL; 229 int count = 0; 230 for (size_t i = 0; i < arraysize(kErrorFlags); ++i) { 231 if (cert_status & kErrorFlags[i]) { 232 count++; 233 if (!cert.get()) { 234 bool r = content::CertStore::GetInstance()->RetrieveCert( 235 cert_id, &cert); 236 DCHECK(r); 237 } 238 if (errors) 239 errors->push_back( 240 SSLErrorInfo::CreateError(kErrorTypes[i], cert.get(), url)); 241 } 242 } 243 return count; 244} 245