diff options
-rw-r--r-- | base/nss_init.cc | 49 | ||||
-rw-r--r-- | chrome/browser/ssl_uitest.cc | 216 | ||||
-rw-r--r-- | chrome/browser/url_fetcher_unittest.cc | 8 | ||||
-rw-r--r-- | net/base/ssl_client_socket_nss.cc | 196 | ||||
-rw-r--r-- | net/base/ssl_client_socket_nss.h | 2 | ||||
-rw-r--r-- | net/base/ssl_test_util.cc | 148 | ||||
-rw-r--r-- | net/base/ssl_test_util.h | 53 | ||||
-rw-r--r-- | net/build/net.vcproj | 4 | ||||
-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.pbxproj | 16 | ||||
-rw-r--r-- | net/net_unittests.scons | 1 | ||||
-rw-r--r-- | net/url_request/url_request_unittest.cc | 47 |
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; { |