summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/nss_init.cc49
-rw-r--r--chrome/browser/ssl_uitest.cc216
-rw-r--r--chrome/browser/url_fetcher_unittest.cc8
-rw-r--r--net/base/ssl_client_socket_nss.cc196
-rw-r--r--net/base/ssl_client_socket_nss.h2
-rw-r--r--net/base/ssl_test_util.cc148
-rw-r--r--net/base/ssl_test_util.h53
-rw-r--r--net/build/net.vcproj4
-rw-r--r--net/data/ssl/certificates/expired_cert.pem (renamed from chrome/test/data/ssl/certificates/expired_cert.pem)0
-rw-r--r--net/data/ssl/certificates/invalid_cert.pem (renamed from chrome/test/data/ssl/certificates/invalid_cert.pem)0
-rw-r--r--net/data/ssl/certificates/ok_cert.pem (renamed from chrome/test/data/ssl/certificates/ok_cert.pem)0
-rw-r--r--net/data/ssl/certificates/root_ca_cert.crt (renamed from chrome/test/data/ssl/certificates/root_ca_cert.crt)0
-rw-r--r--net/net.xcodeproj/project.pbxproj16
-rw-r--r--net/net_unittests.scons1
-rw-r--r--net/url_request/url_request_unittest.cc47
15 files changed, 557 insertions, 183 deletions
diff --git a/base/nss_init.cc b/base/nss_init.cc
index c8ba44b..df2beea 100644
--- a/base/nss_init.cc
+++ b/base/nss_init.cc
@@ -9,31 +9,76 @@
// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=455424
// until NSS 3.12.2 comes out and we update to it.
#define Lock FOO_NSS_Lock
+#include <secmod.h>
#include <ssl.h>
#undef Lock
+#include "base/file_util.h"
#include "base/logging.h"
#include "base/singleton.h"
namespace {
+// Load nss's built-in root certs.
+SECMODModule *InitDefaultRootCerts() {
+ const char* kModulePath = "libnssckbi.so";
+ char modparams[1024];
+ snprintf(modparams, sizeof(modparams),
+ "name=\"Root Certs\" library=\"%s\"", kModulePath);
+ SECMODModule *root = SECMOD_LoadUserModule(modparams, NULL, PR_FALSE);
+ if (root)
+ return root;
+
+ // Aw, snap. Can't find/load root cert shared library.
+ // This will make it hard to talk to anybody via https.
+ NOTREACHED();
+ return NULL;
+}
+
class NSSInitSingleton {
public:
NSSInitSingleton() {
+
+ // Initialize without using a persistant database (e.g. ~/.netscape)
CHECK(NSS_NoDB_Init(".") == SECSuccess);
- // Enable ciphers
+
+ root_ = InitDefaultRootCerts();
+
NSS_SetDomesticPolicy();
+
+ // Explicitly enable exactly those ciphers with keys of at least 80 bits
+ for (int i = 0; i < SSL_NumImplementedCiphers; i++) {
+ SSLCipherSuiteInfo info;
+ if (SSL_GetCipherSuiteInfo(SSL_ImplementedCiphers[i], &info,
+ sizeof(info)) == SECSuccess) {
+ SSL_CipherPrefSetDefault(SSL_ImplementedCiphers[i],
+ (info.effectiveKeyBits >= 80));
+ }
+ }
+
// Enable SSL
SSL_OptionSetDefault(SSL_SECURITY, PR_TRUE);
+
+ // All other SSL options are set per-session by SSLClientSocket
}
~NSSInitSingleton() {
+ if (root_) {
+ SECMOD_UnloadUserModule(root_);
+ SECMOD_DestroyModule(root_);
+ root_ = NULL;
+ }
+
// Have to clear the cache, or NSS_Shutdown fails with SEC_ERROR_BUSY
SSL_ClearSessionCache();
SECStatus status = NSS_Shutdown();
- DCHECK(status == SECSuccess);
+ if (status != SECSuccess)
+ LOG(ERROR) << "NSS_Shutdown failed, leak? See "
+ "http://code.google.com/p/chromium/issues/detail?id=4609";
}
+ private:
+ SECMODModule *root_;
};
} // namespace
diff --git a/chrome/browser/ssl_uitest.cc b/chrome/browser/ssl_uitest.cc
index 906c28c..ccef280 100644
--- a/chrome/browser/ssl_uitest.cc
+++ b/chrome/browser/ssl_uitest.cc
@@ -11,28 +11,18 @@
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
+#include "net/base/ssl_test_util.h"
#include "net/url_request/url_request_unittest.h"
namespace {
const wchar_t kDocRoot[] = L"chrome/test/data";
-const char kHostName[] = "127.0.0.1";
-
-const int kOKHTTPSPort = 9443;
-const int kBadHTTPSPort = 9666;
-
-// The issuer name of the cert that should be trusted for the test to work.
-const wchar_t kCertIssuerName[] = L"Test CA";
class SSLUITest : public UITest {
protected:
SSLUITest() {
- CheckCATrusted();
dom_automation_enabled_ = true;
- PathService::Get(base::DIR_SOURCE_ROOT, &cert_dir_);
- cert_dir_ += L"/chrome/test/data/ssl/certificates/";
- std::replace(cert_dir_.begin(), cert_dir_.end(),
- L'/', FilePath::kSeparators[0]);
+ EXPECT_TRUE(util_.CheckCATrusted());
}
TabProxy* GetActiveTabProxy() {
@@ -51,70 +41,34 @@ class SSLUITest : public UITest {
EXPECT_TRUE(browser_proxy->AppendTab(url));
}
- std::wstring GetOKCertPath() {
- std::wstring path(cert_dir_);
- file_util::AppendToPath(&path, L"ok_cert.pem");
- return path;
- }
-
- std::wstring GetInvalidCertPath() {
- std::wstring path(cert_dir_);
- file_util::AppendToPath(&path, L"invalid_cert.pem");
- return path;
- }
-
- std::wstring GetExpiredCertPath() {
- std::wstring path(cert_dir_);
- file_util::AppendToPath(&path, L"expired_cert.pem");
- return path;
+ TestServer* PlainServer() {
+ return new TestServer(kDocRoot);
}
- HTTPSTestServer GoodServer() {
- return HTTPSTestServer(kHostName, kOKHTTPSPort, kDocRoot, GetOKCertPath());
+ HTTPSTestServer* GoodCertServer() {
+ return new HTTPSTestServer(util_.kHostName, util_.kOKHTTPSPort,
+ kDocRoot, util_.GetOKCertPath().ToWStringHack());
}
- HTTPSTestServer BadServer() {
- return HTTPSTestServer(kHostName, kBadHTTPSPort, kDocRoot,
- GetExpiredCertPath());
+ HTTPSTestServer* BadCertServer() {
+ return new HTTPSTestServer(util_.kHostName, util_.kBadHTTPSPort,
+ kDocRoot, util_.GetExpiredCertPath().ToWStringHack());
}
- private:
- void CheckCATrusted() {
- HCERTSTORE cert_store = CertOpenSystemStore(NULL, L"ROOT");
- if (!cert_store) {
- FAIL() << " could not open trusted root CA store";
- return;
- }
- PCCERT_CONTEXT cert =
- CertFindCertificateInStore(cert_store,
- X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
- 0,
- CERT_FIND_ISSUER_STR,
- kCertIssuerName,
- NULL);
- if (cert)
- CertFreeCertificateContext(cert);
- CertCloseStore(cert_store, 0);
-
- if (!cert) {
- FAIL() << " TEST CONFIGURATION ERROR: you need to import the test ca "
- "certificate to your trusted roots for this test to work. For more "
- "info visit:\n"
- "http://wiki.corp.google.com/twiki/bin/view/Main/ChromeUnitUITests\n";
- }
- }
+ protected:
+ SSLTestUtil util_;
- std::wstring cert_dir_;
+ DISALLOW_COPY_AND_ASSIGN(SSLUITest);
};
} // namespace
// Visits a regular page over http.
TEST_F(SSLUITest, TestHTTP) {
- TestServer server(kDocRoot);
+ scoped_ptr<TestServer> server(PlainServer());
scoped_ptr<TabProxy> tab(GetActiveTabProxy());
- NavigateTab(tab.get(), server.TestServerPageW(L"files/ssl/google.html"));
+ NavigateTab(tab.get(), server->TestServerPageW(L"files/ssl/google.html"));
NavigationEntry::PageType page_type;
EXPECT_TRUE(tab->GetPageType(&page_type));
@@ -133,13 +87,12 @@ TEST_F(SSLUITest, TestHTTP) {
// Visits a page over http which includes broken https resources (status should
// be OK).
TEST_F(SSLUITest, TestHTTPWithBrokenHTTPSResource) {
- TestServer http_server(kDocRoot);
- HTTPSTestServer httpsServer(kHostName, kBadHTTPSPort,
- kDocRoot, GetExpiredCertPath());
+ scoped_ptr<TestServer> http_server(PlainServer());
+ scoped_ptr<HTTPSTestServer> bad_https_server(BadCertServer());
scoped_ptr<TabProxy> tab(GetActiveTabProxy());
NavigateTab(tab.get(),
- http_server.TestServerPageW(L"files/ssl/page_with_unsafe_contents.html"));
+ http_server->TestServerPageW(L"files/ssl/page_with_unsafe_contents.html"));
SecurityStyle security_style;
int cert_status;
@@ -153,10 +106,10 @@ TEST_F(SSLUITest, TestHTTPWithBrokenHTTPSResource) {
// Visits a page over OK https:
TEST_F(SSLUITest, TestOKHTTPS) {
- HTTPSTestServer https_server = GoodServer();
+ scoped_ptr<HTTPSTestServer> https_server(GoodCertServer());
scoped_ptr<TabProxy> tab(GetActiveTabProxy());
NavigateTab(tab.get(),
- https_server.TestServerPageW(L"files/ssl/google.html"));
+ https_server->TestServerPageW(L"files/ssl/google.html"));
NavigationEntry::PageType page_type;
EXPECT_TRUE(tab->GetPageType(&page_type));
@@ -174,10 +127,10 @@ TEST_F(SSLUITest, TestOKHTTPS) {
// Visits a page with https error:
TEST_F(SSLUITest, TestHTTPSExpiredCert) {
- HTTPSTestServer https_server = BadServer();
+ scoped_ptr<HTTPSTestServer> bad_https_server(BadCertServer());
scoped_ptr<TabProxy> tab(GetActiveTabProxy());
NavigateTab(tab.get(),
- https_server.TestServerPageW(L"files/ssl/google.html"));
+ bad_https_server->TestServerPageW(L"files/ssl/google.html"));
NavigationEntry::PageType page_type;
EXPECT_TRUE(tab->GetPageType(&page_type));
@@ -210,14 +163,14 @@ TEST_F(SSLUITest, TestHTTPSExpiredCert) {
// Visits a page with mixed content.
TEST_F(SSLUITest, TestMixedContents) {
- HTTPSTestServer https_server = GoodServer();
- TestServer http_server(kDocRoot);
+ scoped_ptr<HTTPSTestServer> https_server(GoodCertServer());
+ scoped_ptr<TestServer> http_server(PlainServer());
// Load a page with mixed-content, the default behavior is to show the mixed
// content.
scoped_ptr<TabProxy> tab(GetActiveTabProxy());
NavigateTab(tab.get(),
- https_server.TestServerPageW(L"files/ssl/page_with_mixed_contents.html"));
+ https_server->TestServerPageW(L"files/ssl/page_with_mixed_contents.html"));
NavigationEntry::PageType page_type;
EXPECT_TRUE(tab->GetPageType(&page_type));
EXPECT_EQ(NavigationEntry::NORMAL_PAGE, page_type);
@@ -282,12 +235,12 @@ TEST_F(SSLUITest, TestMixedContents) {
// - frames content is replaced with warning
// - images and scripts are filtered out entirely
TEST_F(SSLUITest, TestUnsafeContents) {
- HTTPSTestServer good_https_server = GoodServer();
- HTTPSTestServer bad_https_server = BadServer();
+ scoped_ptr<HTTPSTestServer> good_https_server(GoodCertServer());
+ scoped_ptr<HTTPSTestServer> bad_https_server(BadCertServer());
scoped_ptr<TabProxy> tab(GetActiveTabProxy());
NavigateTab(tab.get(),
- good_https_server.TestServerPageW(
+ good_https_server->TestServerPageW(
L"files/ssl/page_with_unsafe_contents.html"));
NavigationEntry::PageType page_type;
EXPECT_TRUE(tab->GetPageType(&page_type));
@@ -332,11 +285,11 @@ TEST_F(SSLUITest, TestUnsafeContents) {
// Visits a page with mixed content loaded by JS (after the initial page load).
TEST_F(SSLUITest, TestMixedContentsLoadedFromJS) {
- HTTPSTestServer https_server = GoodServer();
- TestServer http_server(kDocRoot);
+ scoped_ptr<HTTPSTestServer> https_server(GoodCertServer());
+ scoped_ptr<TestServer> http_server(PlainServer());
scoped_ptr<TabProxy> tab(GetActiveTabProxy());
- NavigateTab(tab.get(), https_server.TestServerPageW(
+ NavigateTab(tab.get(), https_server->TestServerPageW(
L"files/ssl/page_with_dynamic_mixed_contents.html"));
NavigationEntry::PageType page_type;
EXPECT_TRUE(tab->GetPageType(&page_type));
@@ -371,11 +324,11 @@ TEST_F(SSLUITest, TestMixedContentsLoadedFromJS) {
// referencing that same image over http (hoping it is coming from the webcore
// memory cache).
TEST_F(SSLUITest, TestCachedMixedContents) {
- HTTPSTestServer https_server = GoodServer();
- TestServer http_server(kDocRoot);
+ scoped_ptr<HTTPSTestServer> https_server(GoodCertServer());
+ scoped_ptr<TestServer> http_server(PlainServer());
scoped_ptr<TabProxy> tab(GetActiveTabProxy());
- NavigateTab(tab.get(), http_server.TestServerPageW(
+ NavigateTab(tab.get(), http_server->TestServerPageW(
L"files/ssl/page_with_mixed_contents.html"));
NavigationEntry::PageType page_type;
@@ -393,7 +346,7 @@ TEST_F(SSLUITest, TestCachedMixedContents) {
// Load again but over SSL. It should have mixed-contents (even though the
// image comes from the WebCore memory cache).
- NavigateTab(tab.get(), https_server.TestServerPageW(
+ NavigateTab(tab.get(), https_server->TestServerPageW(
L"files/ssl/page_with_mixed_contents.html"));
EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status,
@@ -408,16 +361,17 @@ TEST_F(SSLUITest, TestCachedMixedContents) {
// This test ensures the CN invalid status does not 'stick' to a certificate
// (see bug #1044942) and that it depends on the host-name.
-// TODO (jcampan): this test is flacky and fails sometimes (bug #1065095)
+// TODO(jcampan): this test is flacky and fails sometimes (bug #1065095)
TEST_F(SSLUITest, DISABLED_TestCNInvalidStickiness) {
const std::string kLocalHost = "localhost";
- HTTPSTestServer https_server(kLocalHost, kOKHTTPSPort,
- kDocRoot, GetOKCertPath());
+ scoped_ptr<HTTPSTestServer> https_server(
+ new HTTPSTestServer(kLocalHost, util_.kOKHTTPSPort,
+ kDocRoot, util_.GetOKCertPath().ToWStringHack()));
// First we hit the server with hostname, this generates an invalid policy
// error.
scoped_ptr<TabProxy> tab(GetActiveTabProxy());
- NavigateTab(tab.get(), https_server.TestServerPageW(
+ NavigateTab(tab.get(), https_server->TestServerPageW(
L"files/ssl/google.html"));
// We get an interstitial page as a result.
@@ -443,12 +397,12 @@ TEST_F(SSLUITest, DISABLED_TestCNInvalidStickiness) {
// Now we try again with the right host name this time.
// Let's change the host-name in the url.
- GURL url = https_server.TestServerPageW(L"files/ssl/google.html");
+ GURL url = https_server->TestServerPageW(L"files/ssl/google.html");
std::string::size_type hostname_index = url.spec().find(kLocalHost);
ASSERT_TRUE(hostname_index != std::string::npos); // Test sanity check.
std::string new_url;
new_url.append(url.spec().substr(0, hostname_index));
- new_url.append(kHostName);
+ new_url.append(util_.kHostName);
new_url.append(url.spec().substr(hostname_index + kLocalHost.size()));
NavigateTab(tab.get(), GURL(new_url));
@@ -462,7 +416,7 @@ TEST_F(SSLUITest, DISABLED_TestCNInvalidStickiness) {
EXPECT_EQ(NavigationEntry::SSLStatus::NORMAL_CONTENT, mixed_content_state);
// Now try again the broken one to make sure it is still broken.
- NavigateTab(tab.get(), https_server.TestServerPageW(
+ NavigateTab(tab.get(), https_server->TestServerPageW(
L"files/ssl/google.html"));
EXPECT_TRUE(tab->GetPageType(&page_type));
@@ -478,10 +432,10 @@ TEST_F(SSLUITest, DISABLED_TestCNInvalidStickiness) {
// Test that navigating to a #ref does not change a bad security state.
TEST_F(SSLUITest, TestRefNavigation) {
- HTTPSTestServer https_server = BadServer();
+ scoped_ptr<HTTPSTestServer> bad_https_server(BadCertServer());
scoped_ptr<TabProxy> tab(GetActiveTabProxy());
NavigateTab(tab.get(),
- https_server.TestServerPageW(L"files/ssl/page_with_refs.html"));
+ bad_https_server->TestServerPageW(L"files/ssl/page_with_refs.html"));
NavigationEntry::PageType page_type;
EXPECT_TRUE(tab->GetPageType(&page_type));
@@ -508,7 +462,7 @@ TEST_F(SSLUITest, TestRefNavigation) {
// Now navigate to a ref in the page.
NavigateTab(tab.get(),
- https_server.TestServerPageW(L"files/ssl/page_with_refs.html#jp"));
+ bad_https_server->TestServerPageW(L"files/ssl/page_with_refs.html#jp"));
EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status,
&mixed_content_state));
EXPECT_EQ(SECURITY_STYLE_AUTHENTICATION_BROKEN, security_style);
@@ -521,12 +475,12 @@ TEST_F(SSLUITest, TestRefNavigation) {
// (bug #1966).
// Disabled because flaky (bug #2136).
TEST_F(SSLUITest, DISABLED_TestCloseTabWithUnsafePopup) {
- TestServer http_server(kDocRoot);
- HTTPSTestServer bad_https_server = BadServer();
+ scoped_ptr<TestServer> http_server(PlainServer());
+ scoped_ptr<HTTPSTestServer> bad_https_server(BadCertServer());
scoped_ptr<TabProxy> tab(GetActiveTabProxy());
NavigateTab(tab.get(),
- http_server.TestServerPageW(
+ http_server->TestServerPageW(
L"files/ssl/page_with_unsafe_popup.html"));
int popup_count = 0;
@@ -538,7 +492,7 @@ TEST_F(SSLUITest, DISABLED_TestCloseTabWithUnsafePopup) {
scoped_ptr<BrowserProxy> browser_proxy(automation()->GetBrowserWindow(0));
EXPECT_TRUE(browser_proxy.get());
browser_proxy->AppendTab(
- http_server.TestServerPageW(L"files/ssl/google.html"));
+ http_server->TestServerPageW(L"files/ssl/google.html"));
// Close the first tab.
tab->Close();
@@ -546,12 +500,12 @@ TEST_F(SSLUITest, DISABLED_TestCloseTabWithUnsafePopup) {
// Visit a page over bad https that is a redirect to a page with good https.
TEST_F(SSLUITest, TestRedirectBadToGoodHTTPS) {
- HTTPSTestServer good_https_server = GoodServer();
- HTTPSTestServer bad_https_server = BadServer();
+ scoped_ptr<HTTPSTestServer> good_https_server(GoodCertServer());
+ scoped_ptr<HTTPSTestServer> bad_https_server(BadCertServer());
scoped_ptr<TabProxy> tab(GetActiveTabProxy());
- GURL url1 = bad_https_server.TestServerPageW(L"server-redirect?");
- GURL url2 = good_https_server.TestServerPageW(L"files/ssl/google.html");
+ GURL url1 = bad_https_server->TestServerPageW(L"server-redirect?");
+ GURL url2 = good_https_server->TestServerPageW(L"files/ssl/google.html");
NavigateTab(tab.get(), GURL(url1.spec() + url2.spec()));
NavigationEntry::PageType page_type;
@@ -579,12 +533,12 @@ TEST_F(SSLUITest, TestRedirectBadToGoodHTTPS) {
// Visit a page over good https that is a redirect to a page with bad https.
TEST_F(SSLUITest, TestRedirectGoodToBadHTTPS) {
- HTTPSTestServer good_https_server = GoodServer();
- HTTPSTestServer bad_https_server = BadServer();
+ scoped_ptr<HTTPSTestServer> good_https_server(GoodCertServer());
+ scoped_ptr<HTTPSTestServer> bad_https_server(BadCertServer());
scoped_ptr<TabProxy> tab(GetActiveTabProxy());
- GURL url1 = good_https_server.TestServerPageW(L"server-redirect?");
- GURL url2 = bad_https_server.TestServerPageW(L"files/ssl/google.html");
+ GURL url1 = good_https_server->TestServerPageW(L"server-redirect?");
+ GURL url2 = bad_https_server->TestServerPageW(L"files/ssl/google.html");
NavigateTab(tab.get(), GURL(url1.spec() + url2.spec()));
NavigationEntry::PageType page_type;
@@ -607,15 +561,15 @@ TEST_F(SSLUITest, TestRedirectGoodToBadHTTPS) {
// Visit a page over http that is a redirect to a page with https (good and
// bad).
TEST_F(SSLUITest, TestRedirectHTTPToHTTPS) {
- TestServer http_server(kDocRoot);
- HTTPSTestServer good_https_server = GoodServer();
- HTTPSTestServer bad_https_server = BadServer();
+ scoped_ptr<TestServer> http_server(PlainServer());
+ scoped_ptr<HTTPSTestServer> good_https_server(GoodCertServer());
+ scoped_ptr<HTTPSTestServer> bad_https_server(BadCertServer());
// HTTP redirects to good HTTPS.
scoped_ptr<TabProxy> tab(GetActiveTabProxy());
- GURL http_url = http_server.TestServerPageW(L"server-redirect?");
+ GURL http_url = http_server->TestServerPageW(L"server-redirect?");
GURL good_https_url =
- good_https_server.TestServerPageW(L"files/ssl/google.html");
+ good_https_server->TestServerPageW(L"files/ssl/google.html");
NavigateTab(tab.get(), GURL(http_url.spec() + good_https_url.spec()));
SecurityStyle security_style;
@@ -629,7 +583,7 @@ TEST_F(SSLUITest, TestRedirectHTTPToHTTPS) {
// HTTP redirects to bad HTTPS.
GURL bad_https_url =
- bad_https_server.TestServerPageW(L"files/ssl/google.html");
+ bad_https_server->TestServerPageW(L"files/ssl/google.html");
NavigateTab(tab.get(), GURL(http_url.spec() + bad_https_url.spec()));
NavigationEntry::PageType page_type;
@@ -650,12 +604,12 @@ TEST_F(SSLUITest, TestRedirectHTTPToHTTPS) {
// Visit a page over https that is a redirect to a page with http (to make sure
// we don't keep the secure state).
TEST_F(SSLUITest, TestRedirectHTTPSToHTTP) {
- TestServer http_server(kDocRoot);
- HTTPSTestServer https_server = GoodServer();
+ scoped_ptr<TestServer> http_server(PlainServer());
+ scoped_ptr<HTTPSTestServer> https_server(GoodCertServer());
scoped_ptr<TabProxy> tab(GetActiveTabProxy());
- GURL https_url = https_server.TestServerPageW(L"server-redirect?");
- GURL http_url = http_server.TestServerPageW(L"files/ssl/google.html");
+ GURL https_url = https_server->TestServerPageW(L"server-redirect?");
+ GURL http_url = http_server->TestServerPageW(L"files/ssl/google.html");
NavigateTab(tab.get(), GURL(https_url.spec() + http_url.spec()));
SecurityStyle security_style;
@@ -703,16 +657,16 @@ TEST_F(SSLUITest, TestConnectToBadPort) {
// From a good HTTPS top frame:
// - navigate to an OK HTTPS frame
// - navigate to a bad HTTPS (expect unsafe content and filtered frame), then
-// back
+// back
// - navigate to HTTP (expect mixed content), then back
TEST_F(SSLUITest, TestGoodFrameNavigation) {
- TestServer http_server(kDocRoot);
- HTTPSTestServer good_https_server = GoodServer();
- HTTPSTestServer bad_https_server = BadServer();
-
+ scoped_ptr<TestServer> http_server(PlainServer());
+ scoped_ptr<HTTPSTestServer> good_https_server(GoodCertServer());
+ scoped_ptr<HTTPSTestServer> bad_https_server(BadCertServer());
+
scoped_ptr<TabProxy> tab(GetActiveTabProxy());
NavigateTab(tab.get(),
- good_https_server.TestServerPageW(L"files/ssl/top_frame.html"));
+ good_https_server->TestServerPageW(L"files/ssl/top_frame.html"));
SecurityStyle security_style;
int cert_status;
@@ -802,12 +756,12 @@ TEST_F(SSLUITest, TestGoodFrameNavigation) {
// From a bad HTTPS top frame:
// - navigate to an OK HTTPS frame (expected to be still authentication broken).
TEST_F(SSLUITest, TestBadFrameNavigation) {
- HTTPSTestServer good_https_server = GoodServer();
- HTTPSTestServer bad_https_server = BadServer();
-
+ scoped_ptr<HTTPSTestServer> good_https_server(GoodCertServer());
+ scoped_ptr<HTTPSTestServer> bad_https_server(BadCertServer());
+
scoped_ptr<TabProxy> tab(GetActiveTabProxy());
NavigateTab(tab.get(),
- bad_https_server.TestServerPageW(L"files/ssl/top_frame.html"));
+ bad_https_server->TestServerPageW(L"files/ssl/top_frame.html"));
SecurityStyle security_style;
int cert_status;
@@ -823,7 +777,7 @@ TEST_F(SSLUITest, TestBadFrameNavigation) {
EXPECT_TRUE(tab->TakeActionOnSSLBlockingPage(true));
// Navigate to a good frame.
- bool success = false;
+ bool success = false;
int64 last_nav_time = 0;
EXPECT_TRUE(tab->GetLastNavigationTime(&last_nav_time));
EXPECT_TRUE(tab->ExecuteAndExtractBool(L"",
@@ -844,13 +798,13 @@ TEST_F(SSLUITest, TestBadFrameNavigation) {
// From an HTTP top frame, navigate to good and bad HTTPS (security state should
// stay unauthenticated).
TEST_F(SSLUITest, TestUnauthenticatedFrameNavigation) {
- TestServer http_server(kDocRoot);
- HTTPSTestServer good_https_server = GoodServer();
- HTTPSTestServer bad_https_server = BadServer();
-
+ scoped_ptr<TestServer> http_server(PlainServer());
+ scoped_ptr<HTTPSTestServer> good_https_server(GoodCertServer());
+ scoped_ptr<HTTPSTestServer> bad_https_server(BadCertServer());
+
scoped_ptr<TabProxy> tab(GetActiveTabProxy());
NavigateTab(tab.get(),
- http_server.TestServerPageW(L"files/ssl/top_frame.html"));
+ http_server->TestServerPageW(L"files/ssl/top_frame.html"));
SecurityStyle security_style;
int cert_status;
@@ -906,7 +860,7 @@ TEST_F(SSLUITest, TestUnauthenticatedFrameNavigation) {
}
-// TODO (jcampan): more tests to do below.
+// TODO(jcampan): more tests to do below.
// Visit a page over https that contains a frame with a redirect.
diff --git a/chrome/browser/url_fetcher_unittest.cc b/chrome/browser/url_fetcher_unittest.cc
index b842b762..fe73d3f 100644
--- a/chrome/browser/url_fetcher_unittest.cc
+++ b/chrome/browser/url_fetcher_unittest.cc
@@ -6,6 +6,7 @@
#include "base/time.h"
#include "chrome/browser/url_fetcher.h"
#include "chrome/browser/url_fetcher_protect.h"
+#include "net/base/ssl_test_util.h"
#include "net/url_request/url_request_unittest.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -15,8 +16,6 @@ using base::TimeDelta;
namespace {
const wchar_t kDocRoot[] = L"chrome/test/data";
-const char kHostName[] = "127.0.0.1";
-const int kBadHTTPSPort = 9666;
class URLFetcherTest : public testing::Test, public URLFetcher::Delegate {
public:
@@ -99,6 +98,7 @@ class URLFetcherBadHTTPSTest : public URLFetcherTest {
protected:
std::wstring GetExpiredCertPath();
+ SSLTestUtil util_;
private:
std::wstring cert_dir_;
@@ -408,8 +408,8 @@ TEST_F(URLFetcherProtectTest, ServerUnavailable) {
}
TEST_F(URLFetcherBadHTTPSTest, BadHTTPSTest) {
- HTTPSTestServer server(kHostName, kBadHTTPSPort,
- kDocRoot, GetExpiredCertPath());
+ HTTPSTestServer server(util_.kHostName, util_.kBadHTTPSPort,
+ kDocRoot, util_.GetExpiredCertPath().ToWStringHack());
CreateFetcher(GURL(server.TestServerPage("defaultresponse")));
diff --git a/net/base/ssl_client_socket_nss.cc b/net/base/ssl_client_socket_nss.cc
index c954ec9..ffd1023 100644
--- a/net/base/ssl_client_socket_nss.cc
+++ b/net/base/ssl_client_socket_nss.cc
@@ -6,10 +6,12 @@
#include <nspr.h>
#include <nss.h>
+#include <secerr.h>
// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=455424
// until NSS 3.12.2 comes out and we update to it.
#define Lock FOO_NSS_Lock
#include <ssl.h>
+#include <sslerr.h>
#include <pk11pub.h>
#undef Lock
@@ -21,18 +23,14 @@
static const int kRecvBufferSize = 4096;
-/*
- * nss calls this if an incoming certificate is invalid.
- * TODO(port): expose to app via GetSSLInfo so it can put up
- * the appropriate GUI and retry with override if desired
- */
-static SECStatus
-ownBadCertHandler(void * arg, PRFileDesc * socket)
-{
- PRErrorCode err = PR_GetError();
- LOG(ERROR) << "server certificate is invalid; NSS error code " << err;
- // Return SECSuccess to override the problem, SECFailure to let the original function fail
- return SECSuccess; /* override, say it's OK. */
+// nss calls this if an incoming certificate is invalid.
+static SECStatus ownBadCertHandler(void* arg, PRFileDesc* socket) {
+ PRErrorCode err = PR_GetError();
+ LOG(INFO) << "server certificate is invalid; NSS error code " << err;
+ // Return SECSuccess to override the problem,
+ // or SECFailure to let the original function fail
+ // Chromium wants it to fail here, and may retry it later.
+ return SECFailure;
}
@@ -44,6 +42,7 @@ namespace net {
#define EnterFunction(x)
#define LeaveFunction(x)
#define GotoState(s) next_state_ = s
+#define LogData(s, len)
#else
#define EnterFunction(x) LOG(INFO) << (void *)this << " " << __FUNCTION__ << \
" enter " << x << "; next_state " << next_state_
@@ -51,14 +50,85 @@ namespace net {
" leave " << x << "; next_state " << next_state_
#define GotoState(s) do { LOG(INFO) << (void *)this << " " << __FUNCTION__ << \
" jump to state " << s; next_state_ = s; } while (0)
+#define LogData(s, len) LOG(INFO) << (void *)this << " " << __FUNCTION__ << \
+ " data [" << std::string(s, len) << "]";
+
#endif
+namespace {
+
+int NetErrorFromNSPRError(PRErrorCode err) {
+ // TODO(port): fill this out as we learn what's important
+ switch (err) {
+ case PR_WOULD_BLOCK_ERROR:
+ return ERR_IO_PENDING;
+ case SSL_ERROR_NO_CYPHER_OVERLAP:
+ return ERR_SSL_VERSION_OR_CIPHER_MISMATCH;
+ case SSL_ERROR_BAD_CERT_DOMAIN:
+ return ERR_CERT_COMMON_NAME_INVALID;
+ case SEC_ERROR_EXPIRED_CERTIFICATE:
+ return ERR_CERT_DATE_INVALID;
+ case SEC_ERROR_BAD_SIGNATURE:
+ return ERR_CERT_INVALID;
+ case SSL_ERROR_REVOKED_CERT_ALERT:
+ case SEC_ERROR_REVOKED_CERTIFICATE:
+ case SEC_ERROR_REVOKED_KEY:
+ return ERR_CERT_REVOKED;
+ case SEC_ERROR_UNKNOWN_ISSUER:
+ return ERR_CERT_AUTHORITY_INVALID;
+
+ default: {
+ if (IS_SSL_ERROR(err)) {
+ LOG(WARNING) << "Unknown SSL error " << err <<
+ " mapped to net::ERR_SSL_PROTOCOL_ERROR";
+ return ERR_SSL_PROTOCOL_ERROR;
+ }
+ if (IS_SEC_ERROR(err)) {
+ // TODO(port): Probably not the best mapping
+ LOG(WARNING) << "Unknown SEC error " << err <<
+ " mapped to net::ERR_CERT_INVALID";
+ return ERR_CERT_INVALID;
+ }
+ LOG(WARNING) << "Unknown error " << err <<
+ " mapped to net::ERR_FAILED";
+ return ERR_FAILED;
+ }
+ }
+}
+
+// Shared with the Windows code. TODO(avi): merge to a common place
+int CertStatusFromNetError(int error) {
+ switch (error) {
+ case ERR_CERT_COMMON_NAME_INVALID:
+ return CERT_STATUS_COMMON_NAME_INVALID;
+ case ERR_CERT_DATE_INVALID:
+ return CERT_STATUS_DATE_INVALID;
+ case ERR_CERT_AUTHORITY_INVALID:
+ return CERT_STATUS_AUTHORITY_INVALID;
+ case ERR_CERT_NO_REVOCATION_MECHANISM:
+ return CERT_STATUS_NO_REVOCATION_MECHANISM;
+ case ERR_CERT_UNABLE_TO_CHECK_REVOCATION:
+ return CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
+ case ERR_CERT_REVOKED:
+ return CERT_STATUS_REVOKED;
+ case ERR_CERT_CONTAINS_ERRORS:
+ NOTREACHED();
+ // Falls through.
+ case ERR_CERT_INVALID:
+ return CERT_STATUS_INVALID;
+ default:
+ return 0;
+ }
+}
+
+} // namespace
+
bool SSLClientSocketNSS::nss_options_initialized_ = false;
SSLClientSocketNSS::SSLClientSocketNSS(ClientSocket* transport_socket,
const std::string& hostname,
const SSLConfig& ssl_config)
- :
+ :
buffer_send_callback_(this, &SSLClientSocketNSS::BufferSendComplete),
buffer_recv_callback_(this, &SSLClientSocketNSS::BufferRecvComplete),
transport_send_busy_(false),
@@ -70,6 +140,7 @@ SSLClientSocketNSS::SSLClientSocketNSS(ClientSocket* transport_socket,
user_callback_(NULL),
user_buf_(NULL),
user_buf_len_(0),
+ server_cert_status_(0),
completed_handshake_(false),
next_state_(STATE_NONE),
nss_fd_(NULL),
@@ -107,7 +178,8 @@ int SSLClientSocketNSS::Connect(CompletionCallback* callback) {
return rv;
}
-int SSLClientSocketNSS::ReconnectIgnoringLastError(CompletionCallback* callback) {
+int SSLClientSocketNSS::ReconnectIgnoringLastError(
+ CompletionCallback* callback) {
EnterFunction("");
// TODO(darin): implement me!
LeaveFunction("");
@@ -134,7 +206,7 @@ bool SSLClientSocketNSS::IsConnected() const {
}
int SSLClientSocketNSS::Read(char* buf, int buf_len,
- CompletionCallback* callback) {
+ CompletionCallback* callback) {
EnterFunction(buf_len);
DCHECK(completed_handshake_);
DCHECK(next_state_ == STATE_NONE);
@@ -148,7 +220,7 @@ int SSLClientSocketNSS::Read(char* buf, int buf_len,
int rv = DoLoop(OK);
if (rv == ERR_IO_PENDING)
user_callback_ = callback;
- LeaveFunction("");
+ LeaveFunction(rv);
return rv;
}
@@ -167,14 +239,30 @@ int SSLClientSocketNSS::Write(const char* buf, int buf_len,
int rv = DoLoop(OK);
if (rv == ERR_IO_PENDING)
user_callback_ = callback;
- LeaveFunction("");
+ LeaveFunction(rv);
return rv;
}
void SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) {
EnterFunction("");
- // TODO(port): implement!
ssl_info->Reset();
+ SSLChannelInfo channel_info;
+ SECStatus ok = SSL_GetChannelInfo(nss_fd_,
+ &channel_info, sizeof(channel_info));
+ if (ok == SECSuccess) {
+ SSLCipherSuiteInfo cipher_info;
+ ok = SSL_GetCipherSuiteInfo(channel_info.cipherSuite,
+ &cipher_info, sizeof(cipher_info));
+ if (ok == SECSuccess) {
+ ssl_info->security_bits = cipher_info.effectiveKeyBits;
+ } else {
+ ssl_info->security_bits = -1;
+ NOTREACHED();
+ }
+ }
+ ssl_info->cert_status = server_cert_status_;
+ // TODO(port): implement X509Certificate so we can set the cert field!
+ // CERTCertificate *nssCert = SSL_PeerCertificate(nss_fd_);
LeaveFunction("");
}
@@ -209,9 +297,9 @@ static PRErrorCode MapErrorToNSS(int result) {
return PR_UNKNOWN_ERROR;
}
-/*
+/*
* Do network I/O between the given buffer and the given socket.
- * Return 0 for EOF,
+ * Return 0 for EOF,
* > 0 for bytes transferred immediately,
* < 0 for error (or the non-error ERR_IO_PENDING).
*/
@@ -283,9 +371,9 @@ int SSLClientSocketNSS::DoLoop(int last_io_result) {
do {
network_moved = false;
// Default to STATE_NONE for next state.
- // (This is a quirk carried over from the windows
+ // (This is a quirk carried over from the windows
// implementation. It makes reading the logs a bit harder.)
- // State handlers can and often do call GotoState just
+ // State handlers can and often do call GotoState just
// to stay in the current state.
State state = next_state_;
GotoState(STATE_NONE);
@@ -357,7 +445,7 @@ int SSLClientSocketNSS::DoConnectComplete(int result) {
}
memio_SetPeerName(nss_fd_, &peername);
- // Grab pointer to buffers
+ // Grab pointer to buffers
nss_bufs_ = memio_GetSecret(nss_fd_);
/* Create SSL state machine */
@@ -378,18 +466,37 @@ int SSLClientSocketNSS::DoConnectComplete(int result) {
if (rv != SECSuccess)
return ERR_UNEXPECTED;
+ // SNI is enabled automatically if TLS is enabled -- as long as
+ // SSL_V2_COMPATIBLE_HELLO isn't.
+ // So don't do V2 compatible hellos unless we're really using SSL2,
+ // to avoid errors like
+ // "common name `mail.google.com' != requested host name `gmail.com'"
+ rv = SSL_OptionSet(nss_fd_, SSL_V2_COMPATIBLE_HELLO,
+ ssl_config_.ssl2_enabled);
+ if (rv != SECSuccess)
+ return ERR_UNEXPECTED;
+
rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL3, ssl_config_.ssl3_enabled);
if (rv != SECSuccess)
return ERR_UNEXPECTED;
- rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL3, ssl_config_.tls1_enabled);
+ rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_TLS, ssl_config_.tls1_enabled);
if (rv != SECSuccess)
return ERR_UNEXPECTED;
+#ifdef SSL_ENABLE_SESSION_TICKETS
+ // Support RFC 5077
+ rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SESSION_TICKETS, PR_TRUE);
+ if (rv != SECSuccess)
+ LOG(INFO) << "SSL_ENABLE_SESSION_TICKETS failed. Old system nss?";
+#else
+ #error "You need to install NSS-3.12 or later to build chromium"
+#endif
+
rv = SSL_OptionSet(nss_fd_, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE);
if (rv != SECSuccess)
return ERR_UNEXPECTED;
-
+
rv = SSL_BadCertHook(nss_fd_, ownBadCertHandler, NULL);
if (rv != SECSuccess)
return ERR_UNEXPECTED;
@@ -407,31 +514,39 @@ int SSLClientSocketNSS::DoConnectComplete(int result) {
int SSLClientSocketNSS::DoHandshakeRead() {
EnterFunction("");
+ int net_error;
int rv = SSL_ForceHandshake(nss_fd_);
+
if (rv == SECSuccess) {
+ net_error = OK;
// there's a callback for this, too
completed_handshake_ = true;
// Indicate we're ready to handle I/O. Badly named?
GotoState(STATE_NONE);
- LeaveFunction("");
- return OK;
- }
- PRErrorCode prerr = PR_GetError();
- if (prerr == PR_WOULD_BLOCK_ERROR) {
- // at this point, it should have tried to send some bytes
- GotoState(STATE_HANDSHAKE_READ);
- LeaveFunction("");
- return ERR_IO_PENDING;
+ } else {
+ PRErrorCode prerr = PR_GetError();
+ net_error = NetErrorFromNSPRError(prerr);
+
+ // If not done, stay in this state
+ if (net_error == ERR_IO_PENDING) {
+ GotoState(STATE_HANDSHAKE_READ);
+ } else {
+ server_cert_status_ = CertStatusFromNetError(net_error);
+ LOG(ERROR) << "handshake failed; NSS error code " << prerr
+ << ", net_error " << net_error << ", server_cert_status "
+ << server_cert_status_;
+ }
}
- // TODO: map rv to net error code properly
+
LeaveFunction("");
- return ERR_SSL_PROTOCOL_ERROR;
+ return net_error;
}
-
+
int SSLClientSocketNSS::DoPayloadRead() {
EnterFunction(user_buf_len_);
int rv = PR_Read(nss_fd_, user_buf_, user_buf_len_);
if (rv >= 0) {
+ LogData(user_buf_, rv);
user_buf_ = NULL;
LeaveFunction("");
return rv;
@@ -444,14 +559,14 @@ int SSLClientSocketNSS::DoPayloadRead() {
}
user_buf_ = NULL;
LeaveFunction("");
- // TODO: map rv to net error code properly
- return ERR_SSL_PROTOCOL_ERROR;
+ return NetErrorFromNSPRError(prerr);
}
int SSLClientSocketNSS::DoPayloadWrite() {
EnterFunction(user_buf_len_);
int rv = PR_Write(nss_fd_, user_buf_, user_buf_len_);
if (rv >= 0) {
+ LogData(user_buf_, rv);
user_buf_ = NULL;
LeaveFunction("");
return rv;
@@ -463,8 +578,7 @@ int SSLClientSocketNSS::DoPayloadWrite() {
}
user_buf_ = NULL;
LeaveFunction("");
- // TODO: map rv to net error code properly
- return ERR_SSL_PROTOCOL_ERROR;
+ return NetErrorFromNSPRError(prerr);
}
} // namespace net
diff --git a/net/base/ssl_client_socket_nss.h b/net/base/ssl_client_socket_nss.h
index 41098f3..5015e1e 100644
--- a/net/base/ssl_client_socket_nss.h
+++ b/net/base/ssl_client_socket_nss.h
@@ -76,6 +76,8 @@ class SSLClientSocketNSS : public SSLClientSocket {
char* user_buf_;
int user_buf_len_;
+ int server_cert_status_;
+
bool completed_handshake_;
enum State {
diff --git a/net/base/ssl_test_util.cc b/net/base/ssl_test_util.cc
index e69de29..18e3905 100644
--- a/net/base/ssl_test_util.cc
+++ b/net/base/ssl_test_util.cc
@@ -0,0 +1,148 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+#include <algorithm>
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <wincrypt.h>
+#elif defined(OS_LINUX)
+#include <nspr.h>
+#include <nss.h>
+#include <secerr.h>
+// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=455424
+// until NSS 3.12.2 comes out and we update to it.
+#define Lock FOO_NSS_Lock
+#include <ssl.h>
+#include <sslerr.h>
+#include <pk11pub.h>
+#undef Lock
+#include "base/nss_init.h"
+#endif
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+
+#include "net/base/ssl_test_util.h"
+
+// static
+const char SSLTestUtil::kHostName[] = "127.0.0.1";
+const int SSLTestUtil::kOKHTTPSPort = 9443;
+const int SSLTestUtil::kBadHTTPSPort = 9666;
+
+// The issuer name of the cert that should be trusted for the test to work.
+const wchar_t SSLTestUtil::kCertIssuerName[] = L"Test CA";
+
+#if defined(OS_LINUX)
+static CERTCertificate* LoadTemporaryCert(const FilePath& filename) {
+ base::EnsureNSSInit();
+
+ std::string rawcert;
+ if (!file_util::ReadFileToString(filename.ToWStringHack(), &rawcert)) {
+ LOG(ERROR) << "Can't load certificate " << filename.ToWStringHack();
+ return NULL;
+ }
+
+ CERTCertificate *cert;
+ cert = CERT_DecodeCertFromPackage(const_cast<char *>(rawcert.c_str()),
+ rawcert.length());
+ if (!cert) {
+ LOG(ERROR) << "Can't convert certificate " << filename.ToWStringHack();
+ return NULL;
+ }
+
+ // TODO(port): remove this const_cast after NSS 3.12.3 is released
+ CERTCertTrust trust;
+ int rv = CERT_DecodeTrustString(&trust, const_cast<char *>("TCu,Cu,Tu"));
+ if (rv != SECSuccess) {
+ LOG(ERROR) << "Can't decode trust string";
+ CERT_DestroyCertificate(cert);
+ return NULL;
+ }
+
+ rv = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert, &trust);
+ if (rv != SECSuccess) {
+ LOG(ERROR) << "Can't change trust for certificate "
+ << filename.ToWStringHack();
+ CERT_DestroyCertificate(cert);
+ return NULL;
+ }
+
+ LOG(INFO) << "Loaded temporary certificate " << filename.ToWStringHack();
+ return cert;
+}
+#endif
+
+SSLTestUtil::SSLTestUtil() {
+ PathService::Get(base::DIR_SOURCE_ROOT, &cert_dir_);
+ cert_dir_ = cert_dir_.Append(FILE_PATH_LITERAL("net"));
+ cert_dir_ = cert_dir_.Append(FILE_PATH_LITERAL("data"));
+ cert_dir_ = cert_dir_.Append(FILE_PATH_LITERAL("ssl"));
+ cert_dir_ = cert_dir_.Append(FILE_PATH_LITERAL("certificates"));
+
+#if defined(OS_LINUX)
+ cert_ = reinterpret_cast<PrivateCERTCertificate*>(
+ LoadTemporaryCert(GetRootCertPath()));
+ DCHECK(cert_);
+#endif
+}
+
+SSLTestUtil::~SSLTestUtil() {
+#if defined(OS_LINUX)
+ if (cert_)
+ CERT_DestroyCertificate(reinterpret_cast<CERTCertificate*>(cert_));
+#endif
+}
+
+FilePath SSLTestUtil::GetRootCertPath() {
+ FilePath path(cert_dir_);
+ path = path.Append(FILE_PATH_LITERAL("root_ca_cert.crt"));
+ return path;
+}
+
+FilePath SSLTestUtil::GetOKCertPath() {
+ FilePath path(cert_dir_);
+ path = path.Append(FILE_PATH_LITERAL("ok_cert.pem"));
+ return path;
+}
+
+FilePath SSLTestUtil::GetExpiredCertPath() {
+ FilePath path(cert_dir_);
+ path = path.Append(FILE_PATH_LITERAL("expired_cert.pem"));
+ return path;
+}
+
+bool SSLTestUtil::CheckCATrusted() {
+// TODO(port): Port either this or LoadTemporaryCert to MacOSX.
+#if defined(OS_WIN)
+ HCERTSTORE cert_store = CertOpenSystemStore(NULL, L"ROOT");
+ if (!cert_store) {
+ LOG(ERROR) << " could not open trusted root CA store";
+ return false;
+ }
+ PCCERT_CONTEXT cert =
+ CertFindCertificateInStore(cert_store,
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ 0,
+ CERT_FIND_ISSUER_STR,
+ kCertIssuerName,
+ NULL);
+ if (cert)
+ CertFreeCertificateContext(cert);
+ CertCloseStore(cert_store, 0);
+
+ if (!cert) {
+ LOG(ERROR) << " TEST CONFIGURATION ERROR: you need to import the test ca "
+ "certificate to your trusted roots for this test to work. "
+ "For more info visit:\n"
+ "http://dev.chromium.org/developers/testing\n";
+ return false;
+ }
+#endif
+ return true;
+}
diff --git a/net/base/ssl_test_util.h b/net/base/ssl_test_util.h
index e69de29..9daa4cc 100644
--- a/net/base/ssl_test_util.h
+++ b/net/base/ssl_test_util.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_BASE_SSL_TEST_UTIL_H_
+#define NET_BASE_SSL_TEST_UTIL_H_
+
+#include "build/build_config.h"
+
+#include "base/file_path.h"
+
+// TODO(dkegel): share this between net/base and
+// chrome/browser without putting it in net.lib
+
+class SSLTestUtil {
+ public:
+ SSLTestUtil();
+
+ ~SSLTestUtil();
+
+ FilePath GetRootCertPath();
+
+ FilePath GetOKCertPath();
+
+ FilePath GetExpiredCertPath();
+
+ // Hostname to use for test server
+ static const char kHostName[];
+
+ // Port to use for test server
+ static const int kOKHTTPSPort;
+
+ // Port to use for bad test server
+ static const int kBadHTTPSPort;
+
+ // Issuer name of the cert that should be trusted for the test to work.
+ static const wchar_t kCertIssuerName[];
+
+ // Returns false if our test root certificate is not trusted.
+ bool CheckCATrusted();
+
+ private:
+ FilePath cert_dir_;
+
+#if defined(OS_LINUX)
+ struct PrivateCERTCertificate;
+ PrivateCERTCertificate *cert_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(SSLTestUtil);
+};
+
+#endif // NET_BASE_SSL_TEST_UTIL_H_
diff --git a/net/build/net.vcproj b/net/build/net.vcproj
index fed4d4f..4530a27 100644
--- a/net/build/net.vcproj
+++ b/net/build/net.vcproj
@@ -461,6 +461,10 @@
>
</File>
<File
+ RelativePath="..\base\ssl_test_util.cc"
+ >
+ </File>
+ <File
RelativePath="..\base\tcp_client_socket.h"
>
</File>
diff --git a/chrome/test/data/ssl/certificates/expired_cert.pem b/net/data/ssl/certificates/expired_cert.pem
index 370330d..370330d 100644
--- a/chrome/test/data/ssl/certificates/expired_cert.pem
+++ b/net/data/ssl/certificates/expired_cert.pem
diff --git a/chrome/test/data/ssl/certificates/invalid_cert.pem b/net/data/ssl/certificates/invalid_cert.pem
index 8507299..8507299 100644
--- a/chrome/test/data/ssl/certificates/invalid_cert.pem
+++ b/net/data/ssl/certificates/invalid_cert.pem
diff --git a/chrome/test/data/ssl/certificates/ok_cert.pem b/net/data/ssl/certificates/ok_cert.pem
index 6349b78..6349b78 100644
--- a/chrome/test/data/ssl/certificates/ok_cert.pem
+++ b/net/data/ssl/certificates/ok_cert.pem
diff --git a/chrome/test/data/ssl/certificates/root_ca_cert.crt b/net/data/ssl/certificates/root_ca_cert.crt
index 873b4f7..873b4f7 100644
--- a/chrome/test/data/ssl/certificates/root_ca_cert.crt
+++ b/net/data/ssl/certificates/root_ca_cert.crt
diff --git a/net/net.xcodeproj/project.pbxproj b/net/net.xcodeproj/project.pbxproj
index 11a8199..bb16121 100644
--- a/net/net.xcodeproj/project.pbxproj
+++ b/net/net.xcodeproj/project.pbxproj
@@ -151,6 +151,7 @@
8220FABD0E914ACA008170A9 /* ssl_client_socket_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32950E5A181C00A747DB /* ssl_client_socket_unittest.cc */; };
8220FAFC0E915561008170A9 /* ssl_client_socket_mac.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32970E5A181C00A747DB /* ssl_client_socket_mac.cc */; };
825C2FCC0E5C968B00FDEAB7 /* ev_root_ca_metadata.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32BE0E5A181C00A747DB /* ev_root_ca_metadata.cc */; };
+ 826F15770EE48CEA00D973C7 /* ssl_test_util.cc in Sources */ = {isa = PBXBuildFile; fileRef = 826F15760EE48CEA00D973C7 /* ssl_test_util.cc */; };
827E139D0E81611D00183614 /* x509_certificate_mac.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32800E5A181C00A747DB /* x509_certificate_mac.cc */; };
82ECB3090E5B651D00A913E3 /* mime_sniffer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32AD0E5A181C00A747DB /* mime_sniffer.cc */; };
93D11DCE0E91463000C36437 /* file_stream_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = 93D11DCD0E91463000C36437 /* file_stream_posix.cc */; };
@@ -673,6 +674,8 @@
82113A270E84360200E3848F /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = "<group>"; };
82113BBC0E892E5800E3848F /* x509_certificate.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = x509_certificate.cc; sourceTree = "<group>"; };
8249C4920EA786B100A4A54B /* ssl_client_socket_mac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ssl_client_socket_mac.h; sourceTree = "<group>"; };
+ 826F15750EE48CEA00D973C7 /* ssl_test_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ssl_test_util.h; sourceTree = "<group>"; };
+ 826F15760EE48CEA00D973C7 /* ssl_test_util.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ssl_test_util.cc; sourceTree = "<group>"; };
936882DC0E9154E200043405 /* file_stream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file_stream.h; sourceTree = "<group>"; };
93D11DCD0E91463000C36437 /* file_stream_posix.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file_stream_posix.cc; sourceTree = "<group>"; };
A5AB7BFB0EB7DBA10070A7D3 /* file_stream_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file_stream_unittest.cc; sourceTree = "<group>"; };
@@ -967,6 +970,8 @@
7BED32930E5A181C00A747DB /* ssl_config_service.h */,
7BED32920E5A181C00A747DB /* ssl_config_service_unittest.cc */,
7BED32910E5A181C00A747DB /* ssl_info.h */,
+ 826F15760EE48CEA00D973C7 /* ssl_test_util.cc */,
+ 826F15750EE48CEA00D973C7 /* ssl_test_util.h */,
7BED328F0E5A181C00A747DB /* tcp_client_socket.h */,
E47E933E0E8924DC00CA613E /* tcp_client_socket_libevent.cc */,
7BED328E0E5A181C00A747DB /* tcp_client_socket_unittest.cc */,
@@ -1548,8 +1553,10 @@
7BD8F70E0E65DCE500034DE9 /* disk_cache_test_util.cc in Sources */,
7BD8F70F0E65DCEB00034DE9 /* entry_unittest.cc in Sources */,
7B4DF6B10E5B98ED004D7619 /* escape_unittest.cc in Sources */,
+ A5AB7BFC0EB7DBA10070A7D3 /* file_stream_unittest.cc in Sources */,
7BA0151F0E5A1B9200044150 /* gzip_filter_unittest.cc in Sources */,
7B82FF460E763620008F45CF /* host_resolver_unittest.cc in Sources */,
+ 042A4D480EC4F4500083281F /* http_auth_cache_unittest.cc in Sources */,
04C626D80E8DE3AA0067E92A /* http_auth_handler_basic_unittest.cc in Sources */,
04C626D60E8DE39E0067E92A /* http_auth_handler_digest_unittest.cc in Sources */,
04C626DA0E8DE3BA0067E92A /* http_auth_unittest.cc in Sources */,
@@ -1559,6 +1566,7 @@
821F21320E5CD756003C7E38 /* http_response_headers_unittest.cc in Sources */,
E4CE9C2E0E8C02ED00D5378C /* http_transaction_unittest.cc in Sources */,
821F21130E5CD662003C7E38 /* http_vary_data_unittest.cc in Sources */,
+ A50055C00EBF7CD6007B0A90 /* listen_socket_unittest.cc in Sources */,
7BD8F7100E65DCF000034DE9 /* mapped_file_unittest.cc in Sources */,
7B4DF9AC0E5C906A004D7619 /* mime_sniffer_unittest.cc in Sources */,
048268090E5B3B4800A30786 /* mime_util_unittest.cc in Sources */,
@@ -1568,15 +1576,13 @@
E4AFA6430E5241B400201347 /* run_all_unittests.cc in Sources */,
7BA362B70E8C3D040023C8B9 /* sdch_filter_unittest.cc in Sources */,
8220FABD0E914ACA008170A9 /* ssl_client_socket_unittest.cc in Sources */,
+ 826F15770EE48CEA00D973C7 /* ssl_test_util.cc in Sources */,
7BD8F7110E65DCF500034DE9 /* storage_block_unittest.cc in Sources */,
E47E93430E8924EE00CA613E /* tcp_client_socket_unittest.cc in Sources */,
- 7BA361450E8C341F0023C8B9 /* test_completion_callback_unittest.cc in Sources */,
- 82113A1D0E8434EE00E3848F /* x509_certificate_unittest.cc in Sources */,
- A5AB7BFC0EB7DBA10070A7D3 /* file_stream_unittest.cc in Sources */,
A50055BF0EBF7CB2007B0A90 /* telnet_server_unittest.cc in Sources */,
- A50055C00EBF7CD6007B0A90 /* listen_socket_unittest.cc in Sources */,
- 042A4D480EC4F4500083281F /* http_auth_cache_unittest.cc in Sources */,
+ 7BA361450E8C341F0023C8B9 /* test_completion_callback_unittest.cc in Sources */,
048133550ED27FEF005C5BBC /* url_request_unittest.cc in Sources */,
+ 82113A1D0E8434EE00E3848F /* x509_certificate_unittest.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/net/net_unittests.scons b/net/net_unittests.scons
index 0879dee..3535850 100644
--- a/net/net_unittests.scons
+++ b/net/net_unittests.scons
@@ -54,6 +54,7 @@ input_files = [
'base/net_util_unittest.cc',
'base/registry_controlled_domain_unittest.cc',
'base/run_all_unittests.cc',
+ 'base/ssl_test_util.cc',
'base/ssl_client_socket_unittest.cc',
'base/tcp_client_socket_unittest.cc',
'base/telnet_server_unittest.cc',
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index e2197f8..83d5744 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -4,9 +4,13 @@
#include "net/url_request/url_request_unittest.h"
+#include "build/build_config.h"
+
#if defined(OS_WIN)
#include <windows.h>
#include <shlobj.h>
+#elif defined(OS_LINUX)
+#include "base/nss_init.h"
#endif
#include <algorithm>
@@ -21,6 +25,7 @@
#include "net/base/net_errors.h"
#include "net/base/net_module.h"
#include "net/base/net_util.h"
+#include "net/base/ssl_test_util.h"
#include "net/disk_cache/disk_cache.h"
#include "net/http/http_cache.h"
#include "net/http/http_network_layer.h"
@@ -116,6 +121,48 @@ TEST_F(URLRequestTest, GetTest) {
#endif
}
+class HTTPSRequestTest : public testing::Test {
+ protected:
+ HTTPSRequestTest() : util_() {};
+
+ SSLTestUtil util_;
+};
+
+#if defined(OS_MACOSX)
+// TODO(port): support temporary root cert on mac
+#define MAYBE_HTTPSGetTest DISABLED_HTTPSGetTest
+#else
+#define MAYBE_HTTPSGetTest HTTPSGetTest
+#endif
+
+TEST_F(HTTPSRequestTest, MAYBE_HTTPSGetTest) {
+ // Note: tools/testserver/testserver.py does not need
+ // a working document root to server the pages / and /hello.html,
+ // so this test doesn't really need to specify a document root.
+ // But if it did, a good one would be net/data/ssl.
+ HTTPSTestServer https_server(util_.kHostName, util_.kOKHTTPSPort,
+ L"net/data/ssl",
+ util_.GetOKCertPath().ToWStringHack());
+
+ EXPECT_TRUE(util_.CheckCATrusted());
+ TestDelegate d;
+ {
+ TestURLRequest r(https_server.TestServerPage(""), &d);
+
+ r.Start();
+ EXPECT_TRUE(r.is_pending());
+
+ MessageLoop::current()->Run();
+
+ EXPECT_EQ(1, d.response_started_count());
+ EXPECT_FALSE(d.received_data_before_response());
+ EXPECT_NE(0, d.bytes_received());
+ }
+#ifndef NDEBUG
+ DCHECK_EQ(url_request_metrics.object_count,0);
+#endif
+}
+
TEST_F(URLRequestTest, CancelTest) {
TestDelegate d;
{