blob: b4a2f124c89ef1c727cef7bb16fdcab46476ba41 [file] [log] [blame]
[email protected]03ef4b2a2012-03-06 15:04:201// 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/website_settings_model.h"
6
7#include <string>
8#include <vector>
9
10#include "base/string_number_conversions.h"
11#include "base/utf_string_conversions.h"
12#include "chrome/browser/profiles/profile.h"
13#include "chrome/browser/ssl/ssl_error_info.h"
14#include "content/browser/cert_store.h"
15#include "content/public/common/ssl_status.h"
16#include "content/public/common/url_constants.h"
17#include "grit/chromium_strings.h"
18#include "grit/generated_resources.h"
19#include "net/base/cert_status_flags.h"
20#include "net/base/ssl_cipher_suite_names.h"
21#include "net/base/ssl_connection_status_flags.h"
22#include "net/base/x509_certificate.h"
23#include "ui/base/l10n/l10n_util.h"
24#include "ui/base/resource/resource_bundle.h"
25
26WebsiteSettingsModel::WebsiteSettingsModel(Profile* profile,
27 const GURL& url,
28 const content::SSLStatus& ssl,
29 CertStore* cert_store)
30 : site_identity_status_(SITE_IDENTITY_STATUS_UNKNOWN),
31 site_connection_status_(SITE_CONNECTION_STATUS_UNKNOWN),
32 cert_store_(cert_store) {
33 Init(profile, url, ssl);
34 // After initialization the status about the site's connection
35 // and it's identity must be available.
36 DCHECK_NE(site_identity_status_, SITE_IDENTITY_STATUS_UNKNOWN);
37 DCHECK_NE(site_connection_status_, SITE_CONNECTION_STATUS_UNKNOWN);
38}
39
40WebsiteSettingsModel::~WebsiteSettingsModel() {
41}
42
43void WebsiteSettingsModel::Init(Profile* profile,
44 const GURL& url,
45 const content::SSLStatus& ssl) {
46 if (url.SchemeIs(chrome::kChromeUIScheme)) {
47 site_identity_status_ = SITE_IDENTITY_STATUS_INTERNAL_PAGE;
48 site_identity_details_ =
49 l10n_util::GetStringUTF16(IDS_PAGE_INFO_INTERNAL_PAGE);
50 site_connection_status_ = SITE_CONNECTION_STATUS_INTERNAL_PAGE;
51 return;
52 }
53
54 scoped_refptr<net::X509Certificate> cert;
55
56 // Identity section.
57 string16 subject_name(UTF8ToUTF16(url.host()));
58 bool empty_subject_name = false;
59 if (subject_name.empty()) {
60 subject_name.assign(
61 l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY));
62 empty_subject_name = true;
63 }
64
65 if (ssl.cert_id &&
66 cert_store_->RetrieveCert(ssl.cert_id, &cert) &&
67 (!net::IsCertStatusError(ssl.cert_status) ||
68 net::IsCertStatusMinorError(ssl.cert_status))) {
69 // There are no major errors. Check for minor errors.
70 if (net::IsCertStatusMinorError(ssl.cert_status)) {
71 site_identity_status_ = SITE_IDENTITY_STATUS_CERT_REVOCATION_UNKNOWN;
72 string16 issuer_name(UTF8ToUTF16(cert->issuer().GetDisplayName()));
73 if (issuer_name.empty()) {
74 issuer_name.assign(l10n_util::GetStringUTF16(
75 IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY));
76 }
77 site_identity_details_.assign(l10n_util::GetStringFUTF16(
78 IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY, issuer_name));
79
80 site_identity_details_ += ASCIIToUTF16("\n\n");
81 if (ssl.cert_status & net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION) {
82 site_identity_details_ += l10n_util::GetStringUTF16(
83 IDS_PAGE_INFO_SECURITY_TAB_UNABLE_TO_CHECK_REVOCATION);
84 } else if (ssl.cert_status & net::CERT_STATUS_NO_REVOCATION_MECHANISM) {
85 site_identity_details_ += l10n_util::GetStringUTF16(
86 IDS_PAGE_INFO_SECURITY_TAB_NO_REVOCATION_MECHANISM);
87 } else {
88 NOTREACHED() << "Need to specify string for this warning";
89 }
90 } else if (ssl.cert_status & net::CERT_STATUS_IS_EV) {
91 // EV HTTPS page.
92 site_identity_status_ = SITE_IDENTITY_STATUS_EV_CERT;
93 DCHECK(!cert->subject().organization_names.empty());
94 organization_name_ = UTF8ToUTF16(cert->subject().organization_names[0]);
95 // An EV Cert is required to have a city (localityName) and country but
96 // state is "if any".
97 DCHECK(!cert->subject().locality_name.empty());
98 DCHECK(!cert->subject().country_name.empty());
99 string16 locality;
100 if (!cert->subject().state_or_province_name.empty()) {
101 locality = l10n_util::GetStringFUTF16(
102 IDS_PAGEINFO_ADDRESS,
103 UTF8ToUTF16(cert->subject().locality_name),
104 UTF8ToUTF16(cert->subject().state_or_province_name),
105 UTF8ToUTF16(cert->subject().country_name));
106 } else {
107 locality = l10n_util::GetStringFUTF16(
108 IDS_PAGEINFO_PARTIAL_ADDRESS,
109 UTF8ToUTF16(cert->subject().locality_name),
110 UTF8ToUTF16(cert->subject().country_name));
111 }
112 DCHECK(!cert->subject().organization_names.empty());
113 site_identity_details_.assign(l10n_util::GetStringFUTF16(
114 IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY_EV,
115 UTF8ToUTF16(cert->subject().organization_names[0]),
116 locality,
117 UTF8ToUTF16(cert->issuer().GetDisplayName())));
118 } else if (ssl.cert_status & net::CERT_STATUS_IS_DNSSEC) {
119 // DNSSEC authenticated page.
120 site_identity_status_ = SITE_IDENTITY_STATUS_DNSSEC_CERT;
121 site_identity_details_.assign(l10n_util::GetStringFUTF16(
122 IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY, UTF8ToUTF16("DNSSEC")));
123 } else {
124 // Non-EV OK HTTPS page.
125 site_identity_status_ = SITE_IDENTITY_STATUS_CERT;
126 string16 issuer_name(UTF8ToUTF16(cert->issuer().GetDisplayName()));
127 if (issuer_name.empty()) {
128 issuer_name.assign(l10n_util::GetStringUTF16(
129 IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY));
130 }
131 site_identity_details_.assign(l10n_util::GetStringFUTF16(
132 IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY, issuer_name));
133 }
134 } else {
135 // HTTP or HTTPS with errors (not warnings).
136 site_identity_details_.assign(l10n_util::GetStringUTF16(
137 IDS_PAGE_INFO_SECURITY_TAB_INSECURE_IDENTITY));
138 if (ssl.security_style == content::SECURITY_STYLE_UNAUTHENTICATED)
139 site_identity_status_ = SITE_IDENTITY_STATUS_NO_CERT;
140 else
141 site_identity_status_ = SITE_IDENTITY_STATUS_ERROR;
142
143 const string16 bullet = UTF8ToUTF16("\n • ");
144 std::vector<SSLErrorInfo> errors;
145 SSLErrorInfo::GetErrorsForCertStatus(ssl.cert_id, ssl.cert_status,
146 url, &errors);
147 for (size_t i = 0; i < errors.size(); ++i) {
148 site_identity_details_ += bullet;
149 site_identity_details_ += errors[i].short_description();
150 }
151
152 if (ssl.cert_status & net::CERT_STATUS_NON_UNIQUE_NAME) {
153 site_identity_details_ += ASCIIToUTF16("\n\n");
154 site_identity_details_ += l10n_util::GetStringUTF16(
155 IDS_PAGE_INFO_SECURITY_TAB_NON_UNIQUE_NAME);
156 }
157 }
158
159 // Site Connection
160 // We consider anything less than 80 bits encryption to be weak encryption.
161 // TODO(wtc): Bug 1198735: report mixed/unsafe content for unencrypted and
162 // weakly encrypted connections.
163 site_connection_status_ = SITE_CONNECTION_STATUS_UNKNOWN;
164
165 if (!ssl.cert_id) {
166 // Not HTTPS.
167 DCHECK_EQ(ssl.security_style, content::SECURITY_STYLE_UNAUTHENTICATED);
168 if (ssl.security_style == content::SECURITY_STYLE_UNAUTHENTICATED)
169 site_connection_status_ = SITE_CONNECTION_STATUS_UNENCRYPTED;
170 else
171 site_connection_status_ = SITE_CONNECTION_STATUS_ENCRYPTED_ERROR;
172
173 site_connection_details_.assign(l10n_util::GetStringFUTF16(
174 IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT,
175 subject_name));
176 } else if (ssl.security_bits < 0) {
177 // Security strength is unknown. Say nothing.
178 site_connection_status_ = SITE_CONNECTION_STATUS_ENCRYPTED_ERROR;
179 } else if (ssl.security_bits == 0) {
180 DCHECK_NE(ssl.security_style, content::SECURITY_STYLE_UNAUTHENTICATED);
181 site_connection_status_ = SITE_CONNECTION_STATUS_ENCRYPTED_ERROR;
182 site_connection_details_.assign(l10n_util::GetStringFUTF16(
183 IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT,
184 subject_name));
185 } else if (ssl.security_bits < 80) {
186 site_connection_status_ = SITE_CONNECTION_STATUS_ENCRYPTED_ERROR;
187 site_connection_details_.assign(l10n_util::GetStringFUTF16(
188 IDS_PAGE_INFO_SECURITY_TAB_WEAK_ENCRYPTION_CONNECTION_TEXT,
189 subject_name));
190 } else {
191 site_connection_status_ = SITE_CONNECTION_STATUS_ENCRYPTED;
192 site_connection_details_.assign(l10n_util::GetStringFUTF16(
193 IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_CONNECTION_TEXT,
194 subject_name,
195 base::IntToString16(ssl.security_bits)));
196 if (ssl.content_status) {
197 bool ran_insecure_content =
198 !!(ssl.content_status & content::SSLStatus::RAN_INSECURE_CONTENT);
199 site_connection_status_ = ran_insecure_content ?
200 SITE_CONNECTION_STATUS_ENCRYPTED_ERROR
201 : SITE_CONNECTION_STATUS_MIXED_CONTENT;
202 site_connection_details_.assign(l10n_util::GetStringFUTF16(
203 IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_SENTENCE_LINK,
204 site_connection_details_,
205 l10n_util::GetStringUTF16(ran_insecure_content ?
206 IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_INSECURE_CONTENT_ERROR :
207 IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_INSECURE_CONTENT_WARNING)));
208 }
209 }
210
211 uint16 cipher_suite =
212 net::SSLConnectionStatusToCipherSuite(ssl.connection_status);
213 if (ssl.security_bits > 0 && cipher_suite) {
214 int ssl_version =
215 net::SSLConnectionStatusToVersion(ssl.connection_status);
216 const char* ssl_version_str;
217 net::SSLVersionToString(&ssl_version_str, ssl_version);
218 site_connection_details_ += ASCIIToUTF16("\n\n");
219 site_connection_details_ += l10n_util::GetStringFUTF16(
220 IDS_PAGE_INFO_SECURITY_TAB_SSL_VERSION,
221 ASCIIToUTF16(ssl_version_str));
222
223 bool did_fallback = (ssl.connection_status &
224 net::SSL_CONNECTION_SSL3_FALLBACK) != 0;
225 bool no_renegotiation =
226 (ssl.connection_status &
227 net::SSL_CONNECTION_NO_RENEGOTIATION_EXTENSION) != 0;
228 const char *key_exchange, *cipher, *mac;
229 net::SSLCipherSuiteToStrings(&key_exchange, &cipher, &mac, cipher_suite);
230
231 site_connection_details_ += ASCIIToUTF16("\n\n");
232 site_connection_details_ += l10n_util::GetStringFUTF16(
233 IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTION_DETAILS,
234 ASCIIToUTF16(cipher), ASCIIToUTF16(mac), ASCIIToUTF16(key_exchange));
235
236 site_connection_details_ += ASCIIToUTF16("\n\n");
237 uint8 compression_id =
238 net::SSLConnectionStatusToCompression(ssl.connection_status);
239 if (compression_id) {
240 const char* compression;
241 net::SSLCompressionToString(&compression, compression_id);
242 site_connection_details_ += l10n_util::GetStringFUTF16(
243 IDS_PAGE_INFO_SECURITY_TAB_COMPRESSION_DETAILS,
244 ASCIIToUTF16(compression));
245 } else {
246 site_connection_details_ += l10n_util::GetStringUTF16(
247 IDS_PAGE_INFO_SECURITY_TAB_NO_COMPRESSION);
248 }
249
250 if (did_fallback) {
251 // For now, only SSLv3 fallback will trigger a warning icon.
252 if (site_connection_status_ < SITE_CONNECTION_STATUS_MIXED_CONTENT)
253 site_connection_status_ = SITE_CONNECTION_STATUS_MIXED_CONTENT;
254 site_connection_details_ += ASCIIToUTF16("\n\n");
255 site_connection_details_ += l10n_util::GetStringUTF16(
256 IDS_PAGE_INFO_SECURITY_TAB_FALLBACK_MESSAGE);
257 }
258 if (no_renegotiation) {
259 site_connection_details_ += ASCIIToUTF16("\n\n");
260 site_connection_details_ += l10n_util::GetStringUTF16(
261 IDS_PAGE_INFO_SECURITY_TAB_RENEGOTIATION_MESSAGE);
262 }
263 }
264}