diff options
author | wtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-03 16:51:15 +0000 |
---|---|---|
committer | wtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-03 16:51:15 +0000 |
commit | dedb594391d9ec31a6eac1eccbdd754ac2ce5ed7 (patch) | |
tree | cac5603ceb1a8dd526624c428d6ffd6eafaf3de5 | |
parent | 7f969d6b73d925d306032565179d6b2109646ee0 (diff) | |
download | chromium_src-dedb594391d9ec31a6eac1eccbdd754ac2ce5ed7.zip chromium_src-dedb594391d9ec31a6eac1eccbdd754ac2ce5ed7.tar.gz chromium_src-dedb594391d9ec31a6eac1eccbdd754ac2ce5ed7.tar.bz2 |
Move certificate verification off the IO thread.
Move the MapNetErrorToCertStatus and MapCertStatusToNetError
functions to cert_status_flags.h so they can be shared with
Mac and Linux code.
Move the certificate verification function to the
X509Certificate class. Right now X509Certificate::Verify is
only implemented on Windows.
R=eroman
BUG=3592
Review URL: http://codereview.chromium.org/14915
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@9084 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | net/base/cert_status_flags.cc | 67 | ||||
-rw-r--r-- | net/base/cert_status_flags.h | 8 | ||||
-rw-r--r-- | net/base/cert_verifier.cc | 23 | ||||
-rw-r--r-- | net/base/cert_verifier.h | 10 | ||||
-rw-r--r-- | net/base/cert_verify_result.h | 31 | ||||
-rw-r--r-- | net/base/ssl_client_socket_mac.cc | 27 | ||||
-rw-r--r-- | net/base/ssl_client_socket_nss.cc | 27 | ||||
-rw-r--r-- | net/base/ssl_client_socket_win.cc | 319 | ||||
-rw-r--r-- | net/base/ssl_client_socket_win.h | 12 | ||||
-rw-r--r-- | net/base/x509_certificate.h | 32 | ||||
-rw-r--r-- | net/base/x509_certificate_win.cc | 271 | ||||
-rw-r--r-- | net/build/net.vcproj | 16 | ||||
-rw-r--r-- | net/net.xcodeproj/project.pbxproj | 16 | ||||
-rw-r--r-- | net/net_lib.scons | 4 |
14 files changed, 499 insertions, 364 deletions
diff --git a/net/base/cert_status_flags.cc b/net/base/cert_status_flags.cc new file mode 100644 index 0000000..a0ddc13 --- /dev/null +++ b/net/base/cert_status_flags.cc @@ -0,0 +1,67 @@ +// Copyright (c) 2009 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 "net/base/cert_status_flags.h" + +#include "base/logging.h" +#include "net/base/net_errors.h" + +namespace net { + +int MapNetErrorToCertStatus(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; + // We added the ERR_CERT_CONTAINS_ERRORS error code when we were using + // WinInet, but we never figured out how it differs from ERR_CERT_INVALID. + // We should not use ERR_CERT_CONTAINS_ERRORS in new code. + case ERR_CERT_CONTAINS_ERRORS: + NOTREACHED(); + // Falls through. + case ERR_CERT_INVALID: + return CERT_STATUS_INVALID; + default: + return 0; + } +} + +int MapCertStatusToNetError(int cert_status) { + // A certificate may have multiple errors. We report the most + // serious error. + + // Unrecoverable errors + if (cert_status & CERT_STATUS_INVALID) + return ERR_CERT_INVALID; + if (cert_status & CERT_STATUS_REVOKED) + return ERR_CERT_REVOKED; + + // Recoverable errors + if (cert_status & CERT_STATUS_AUTHORITY_INVALID) + return ERR_CERT_AUTHORITY_INVALID; + if (cert_status & CERT_STATUS_COMMON_NAME_INVALID) + return ERR_CERT_COMMON_NAME_INVALID; + if (cert_status & CERT_STATUS_DATE_INVALID) + return ERR_CERT_DATE_INVALID; + + // Unknown status. Give it the benefit of the doubt. + if (cert_status & CERT_STATUS_UNABLE_TO_CHECK_REVOCATION) + return ERR_CERT_UNABLE_TO_CHECK_REVOCATION; + if (cert_status & CERT_STATUS_NO_REVOCATION_MECHANISM) + return ERR_CERT_NO_REVOCATION_MECHANISM; + + NOTREACHED(); + return ERR_UNEXPECTED; +} + +} // namespace net diff --git a/net/base/cert_status_flags.h b/net/base/cert_status_flags.h index fcd03f0..02381cc 100644 --- a/net/base/cert_status_flags.h +++ b/net/base/cert_status_flags.h @@ -33,6 +33,14 @@ static inline bool IsCertStatusError(int status) { return (CERT_STATUS_ALL_ERRORS & status) != 0; } +// Maps a network error code to the equivalent certificate status flag. If +// the error code is not a certificate error, it is mapped to 0. +int MapNetErrorToCertStatus(int error); + +// Maps the most serious certificate error in the certificate status flags +// to the equivalent network error code. +int MapCertStatusToNetError(int cert_status); + } // namespace net #endif // NET_BASE_CERT_STATUS_FLAGS_H_ diff --git a/net/base/cert_verifier.cc b/net/base/cert_verifier.cc index 8163690..567ea38 100644 --- a/net/base/cert_verifier.cc +++ b/net/base/cert_verifier.cc @@ -6,6 +6,7 @@ #include "base/message_loop.h" #include "base/worker_pool.h" +#include "net/base/cert_verify_result.h" #include "net/base/net_errors.h" #include "net/base/x509_certificate.h" @@ -18,17 +19,16 @@ class CertVerifier::Request : X509Certificate* cert, const std::string& hostname, bool rev_checking_enabled, - int* cert_status, + CertVerifyResult* verify_result, CompletionCallback* callback) : cert_(cert), hostname_(hostname), rev_checking_enabled_(rev_checking_enabled), verifier_(verifier), - cert_status_(cert_status), + verify_result_(verify_result), callback_(callback), origin_loop_(MessageLoop::current()), - error_(OK), - result_(0) { + error_(OK) { } ~Request() {} @@ -55,13 +55,12 @@ class CertVerifier::Request : void DoCallback() { // Running on the origin thread. - DCHECK(error_ || result_); // We may have been cancelled! if (!verifier_) return; - *cert_status_ = result_; + *verify_result_ = result_; // Drop the verifier's reference to us. Do this before running the // callback since the callback might result in the verifier being @@ -86,7 +85,7 @@ class CertVerifier::Request : // Only used on the origin thread (where Verify was called). CertVerifier* verifier_; - int* cert_status_; + CertVerifyResult* verify_result_; CompletionCallback* callback_; // Used to post ourselves onto the origin thread. @@ -95,7 +94,7 @@ class CertVerifier::Request : // Assigned on the worker thread, read on the origin thread. int error_; - int result_; + CertVerifyResult result_; }; //----------------------------------------------------------------------------- @@ -111,20 +110,20 @@ CertVerifier::~CertVerifier() { int CertVerifier::Verify(X509Certificate* cert, const std::string& hostname, bool rev_checking_enabled, - int* cert_status, + CertVerifyResult* verify_result, CompletionCallback* callback) { DCHECK(!request_) << "verifier already in use"; // Do a synchronous verification. if (!callback) { - int result; + CertVerifyResult result; int rv = cert->Verify(hostname, rev_checking_enabled, &result); - *cert_status = result; + *verify_result = result; return rv; } request_ = new Request(this, cert, hostname, rev_checking_enabled, - cert_status, callback); + verify_result, callback); // Dispatch to worker thread... if (!WorkerPool::PostTask(FROM_HERE, diff --git a/net/base/cert_verifier.h b/net/base/cert_verifier.h index 06f7cef..051bc25 100644 --- a/net/base/cert_verifier.h +++ b/net/base/cert_verifier.h @@ -13,6 +13,7 @@ namespace net { +class CertVerifyResult; class X509Certificate; // This class represents the task of verifying a certificate. It can only @@ -35,9 +36,10 @@ class CertVerifier { // Verifies the given certificate against the given hostname. Returns OK if // successful or an error code upon failure. // - // The |cert_status| bitmask is always filled out regardless of the return - // value. If the certificate has multiple errors, the corresponding status - // flags are set in |cert_status|, and the error code for the most serious + // The |*verify_result| structure, including the |verify_result->cert_status| + // bitmask, is always filled out regardless of the return value. If the + // certificate has multiple errors, the corresponding status flags are set in + // |verify_result->cert_status|, and the error code for the most serious // error is returned. // // If |rev_checking_enabled| is true, certificate revocation checking is @@ -50,7 +52,7 @@ class CertVerifier { // be passed to the callback when available. // int Verify(X509Certificate* cert, const std::string& hostname, - bool rev_checking_enabled, int* cert_status, + bool rev_checking_enabled, CertVerifyResult* verify_result, CompletionCallback* callback); private: diff --git a/net/base/cert_verify_result.h b/net/base/cert_verify_result.h new file mode 100644 index 0000000..825ce4c --- /dev/null +++ b/net/base/cert_verify_result.h @@ -0,0 +1,31 @@ +// Copyright (c) 2009 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_CERT_VERIFY_RESULT_H_ +#define NET_BASE_CERT_VERIFY_RESULT_H_ + +namespace net { + +// The result of certificate verification. +class CertVerifyResult { + public: + CertVerifyResult() + : cert_status(0), has_md5(false), has_md2(false), has_md4(false), + has_md5_ca(false), has_md2_ca(false) { + } + + int cert_status; + + // Properties of the certificate chain. + bool has_md5; + bool has_md2; + bool has_md4; + bool has_md5_ca; + bool has_md2_ca; +}; + +} // namespace net + +#endif // NET_BASE_CERT_VERIFY_RESULT_H_ + diff --git a/net/base/ssl_client_socket_mac.cc b/net/base/ssl_client_socket_mac.cc index 24d33e5..a84929b 100644 --- a/net/base/ssl_client_socket_mac.cc +++ b/net/base/ssl_client_socket_mac.cc @@ -159,31 +159,6 @@ OSStatus OSStatusFromNetError(int net_error) { } } -// 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; - } -} - // Converts from a cipher suite to its key size. If the suite is marked with a // **, it's not actually implemented in Secure Transport and won't be returned // (but we'll code for it anyway). The reference here is @@ -534,7 +509,7 @@ int SSLClientSocketMac::DoHandshake() { // TODO(wtc): for now, always check revocation. server_cert_status_ = CERT_STATUS_REV_CHECKING_ENABLED; if (net_error) - server_cert_status_ |= CertStatusFromNetError(net_error); + server_cert_status_ |= MapNetErrorToCertStatus(net_error); return net_error; } diff --git a/net/base/ssl_client_socket_nss.cc b/net/base/ssl_client_socket_nss.cc index 62e348b..5c33dc8 100644 --- a/net/base/ssl_client_socket_nss.cc +++ b/net/base/ssl_client_socket_nss.cc @@ -100,31 +100,6 @@ int NetErrorFromNSPRError(PRErrorCode err) { } } -// 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; @@ -538,7 +513,7 @@ int SSLClientSocketNSS::DoHandshakeRead() { if (net_error == ERR_IO_PENDING) { GotoState(STATE_HANDSHAKE_READ); } else { - server_cert_status_ = CertStatusFromNetError(net_error); + server_cert_status_ = MapNetErrorToCertStatus(net_error); LOG(ERROR) << "handshake failed; NSS error code " << prerr << ", net_error " << net_error << ", server_cert_status " << server_cert_status_; diff --git a/net/base/ssl_client_socket_win.cc b/net/base/ssl_client_socket_win.cc index f946f72..dc3ccf3 100644 --- a/net/base/ssl_client_socket_win.cc +++ b/net/base/ssl_client_socket_win.cc @@ -11,7 +11,6 @@ #include "base/string_util.h" #include "net/base/connection_type_histograms.h" #include "net/base/net_errors.h" -#include "net/base/scoped_cert_chain_context.h" #include "net/base/ssl_info.h" #pragma comment(lib, "secur32.lib") @@ -60,117 +59,6 @@ static int MapSecurityError(SECURITY_STATUS err) { } } -// Map a network error code to the equivalent certificate status flag. If -// the error code is not a certificate error, it is mapped to 0. -static int MapNetErrorToCertStatus(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; - } -} - -static int MapCertStatusToNetError(int cert_status) { - // A certificate may have multiple errors. We report the most - // serious error. - - // Unrecoverable errors - if (cert_status & CERT_STATUS_INVALID) - return ERR_CERT_INVALID; - if (cert_status & CERT_STATUS_REVOKED) - return ERR_CERT_REVOKED; - - // Recoverable errors - if (cert_status & CERT_STATUS_AUTHORITY_INVALID) - return ERR_CERT_AUTHORITY_INVALID; - if (cert_status & CERT_STATUS_COMMON_NAME_INVALID) - return ERR_CERT_COMMON_NAME_INVALID; - if (cert_status & CERT_STATUS_DATE_INVALID) - return ERR_CERT_DATE_INVALID; - - // Unknown status. Give it the benefit of the doubt. - if (cert_status & CERT_STATUS_UNABLE_TO_CHECK_REVOCATION) - return ERR_CERT_UNABLE_TO_CHECK_REVOCATION; - if (cert_status & CERT_STATUS_NO_REVOCATION_MECHANISM) - return ERR_CERT_NO_REVOCATION_MECHANISM; - - NOTREACHED(); - return ERR_UNEXPECTED; -} - -// Map the errors in the chain_context->TrustStatus.dwErrorStatus returned by -// CertGetCertificateChain to our certificate status flags. -static int MapCertChainErrorStatusToCertStatus(DWORD error_status) { - int cert_status = 0; - - // CERT_TRUST_IS_NOT_TIME_NESTED means a subject certificate's time validity - // does not nest correctly within its issuer's time validity. - const DWORD kDateInvalidErrors = CERT_TRUST_IS_NOT_TIME_VALID | - CERT_TRUST_IS_NOT_TIME_NESTED | - CERT_TRUST_CTL_IS_NOT_TIME_VALID; - if (error_status & kDateInvalidErrors) - cert_status |= CERT_STATUS_DATE_INVALID; - - const DWORD kAuthorityInvalidErrors = CERT_TRUST_IS_UNTRUSTED_ROOT | - CERT_TRUST_IS_EXPLICIT_DISTRUST | - CERT_TRUST_IS_PARTIAL_CHAIN; - if (error_status & kAuthorityInvalidErrors) - cert_status |= CERT_STATUS_AUTHORITY_INVALID; - - if ((error_status & CERT_TRUST_REVOCATION_STATUS_UNKNOWN) && - !(error_status & CERT_TRUST_IS_OFFLINE_REVOCATION)) - cert_status |= CERT_STATUS_NO_REVOCATION_MECHANISM; - - if (error_status & CERT_TRUST_IS_OFFLINE_REVOCATION) - cert_status |= CERT_STATUS_UNABLE_TO_CHECK_REVOCATION; - - if (error_status & CERT_TRUST_IS_REVOKED) - cert_status |= CERT_STATUS_REVOKED; - - const DWORD kWrongUsageErrors = CERT_TRUST_IS_NOT_VALID_FOR_USAGE | - CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE; - if (error_status & kWrongUsageErrors) { - // TODO(wtc): Handle these errors. - // cert_status = |= CERT_STATUS_WRONG_USAGE; - } - - // The rest of the errors. - const DWORD kCertInvalidErrors = - CERT_TRUST_IS_NOT_SIGNATURE_VALID | - CERT_TRUST_IS_CYCLIC | - CERT_TRUST_INVALID_EXTENSION | - CERT_TRUST_INVALID_POLICY_CONSTRAINTS | - CERT_TRUST_INVALID_BASIC_CONSTRAINTS | - CERT_TRUST_INVALID_NAME_CONSTRAINTS | - CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID | - CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT | - CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT | - CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT | - CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT | - CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY | - CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT; - if (error_status & kCertInvalidErrors) - cert_status |= CERT_STATUS_INVALID; - - return cert_status; -} - //----------------------------------------------------------------------------- // A bitmask consisting of these bit flags encodes which versions of the SSL @@ -328,7 +216,6 @@ SSLClientSocketWin::SSLClientSocketWin(ClientSocket* transport_socket, user_buf_len_(0), next_state_(STATE_NONE), server_cert_(NULL), - server_cert_status_(0), creds_(NULL), payload_send_buffer_len_(0), bytes_sent_(0), @@ -372,7 +259,7 @@ void SSLClientSocketWin::GetSSLInfo(SSLInfo* ssl_info) { // normalized. ssl_info->security_bits = connection_info.dwCipherStrength; } - ssl_info->cert_status = server_cert_status_; + ssl_info->cert_status = server_cert_verify_result_.cert_status; } int SSLClientSocketWin::Connect(CompletionCallback* callback) { @@ -534,6 +421,12 @@ int SSLClientSocketWin::DoLoop(int last_io_result) { case STATE_HANDSHAKE_WRITE_COMPLETE: rv = DoHandshakeWriteComplete(rv); break; + case STATE_VERIFY_CERT: + rv = DoVerifyCert(); + break; + case STATE_VERIFY_CERT_COMPLETE: + rv = DoVerifyCertComplete(rv); + break; case STATE_PAYLOAD_READ: rv = DoPayloadRead(); break; @@ -799,6 +692,25 @@ int SSLClientSocketWin::DoHandshakeWriteComplete(int result) { return OK; } +// Set server_cert_status_ and return OK or a network error. +int SSLClientSocketWin::DoVerifyCert() { + next_state_ = STATE_VERIFY_CERT_COMPLETE; + + DCHECK(server_cert_); + + PCCERT_CONTEXT dup_cert = CertDuplicateCertificateContext(server_cert_); + scoped_refptr<X509Certificate> cert = + X509Certificate::CreateFromHandle(dup_cert, + X509Certificate::SOURCE_FROM_NETWORK); + return verifier_.Verify(cert, hostname_, ssl_config_.rev_checking_enabled, + &server_cert_verify_result_, &io_callback_); +} + +int SSLClientSocketWin::DoVerifyCertComplete(int result) { + LogConnectionTypeMetrics(); + return result; +} + int SSLClientSocketWin::DoPayloadRead() { next_state_ = STATE_PAYLOAD_READ_COMPLETE; @@ -1020,186 +932,23 @@ int SSLClientSocketWin::DidCompleteHandshake() { } completed_handshake_ = true; - return VerifyServerCert(); + next_state_ = STATE_VERIFY_CERT; + return OK; } -// static -void SSLClientSocketWin::LogConnectionTypeMetrics( - PCCERT_CHAIN_CONTEXT chain_context) { +void SSLClientSocketWin::LogConnectionTypeMetrics() const { UpdateConnectionTypeHistograms(CONNECTION_SSL); - - PCERT_SIMPLE_CHAIN first_chain = chain_context->rgpChain[0]; - int num_elements = first_chain->cElement; - PCERT_CHAIN_ELEMENT* element = first_chain->rgpElement; - bool has_md5 = false; - bool has_md2 = false; - bool has_md4 = false; - bool has_md5_ca = false; - bool has_md2_ca = false; - - // Each chain starts with the end entity certificate (i = 0) and ends with - // the root CA certificate (i = num_elements - 1). Do not inspect the - // signature algorithm of the root CA certificate because the signature on - // the trust anchor is not important. - for (int i = 0; i < num_elements - 1; ++i) { - PCCERT_CONTEXT cert = element[i]->pCertContext; - const char* algorithm = cert->pCertInfo->SignatureAlgorithm.pszObjId; - if (strcmp(algorithm, szOID_RSA_MD5RSA) == 0) { - // md5WithRSAEncryption: 1.2.840.113549.1.1.4 - has_md5 = true; - if (i != 0) - has_md5_ca = true; - } else if (strcmp(algorithm, szOID_RSA_MD2RSA) == 0) { - // md2WithRSAEncryption: 1.2.840.113549.1.1.2 - has_md2 = true; - if (i != 0) - has_md2_ca = true; - } else if (strcmp(algorithm, szOID_RSA_MD4RSA) == 0) { - // md4WithRSAEncryption: 1.2.840.113549.1.1.3 - has_md4 = true; - } - } - - if (has_md5) + if (server_cert_verify_result_.has_md5) UpdateConnectionTypeHistograms(CONNECTION_SSL_MD5); - if (has_md2) + if (server_cert_verify_result_.has_md2) UpdateConnectionTypeHistograms(CONNECTION_SSL_MD2); - if (has_md4) + if (server_cert_verify_result_.has_md4) UpdateConnectionTypeHistograms(CONNECTION_SSL_MD4); - if (has_md5_ca) + if (server_cert_verify_result_.has_md5_ca) UpdateConnectionTypeHistograms(CONNECTION_SSL_MD5_CA); - if (has_md2_ca) + if (server_cert_verify_result_.has_md2_ca) UpdateConnectionTypeHistograms(CONNECTION_SSL_MD2_CA); } -// Set server_cert_status_ and return OK or a network error. -int SSLClientSocketWin::VerifyServerCert() { - DCHECK(server_cert_); - server_cert_status_ = 0; - - // Build and validate certificate chain. - - CERT_CHAIN_PARA chain_para; - memset(&chain_para, 0, sizeof(chain_para)); - chain_para.cbSize = sizeof(chain_para); - // TODO(wtc): consider requesting the usage szOID_PKIX_KP_SERVER_AUTH - // or szOID_SERVER_GATED_CRYPTO or szOID_SGC_NETSCAPE - chain_para.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND; - chain_para.RequestedUsage.Usage.cUsageIdentifier = 0; - chain_para.RequestedUsage.Usage.rgpszUsageIdentifier = NULL; // LPSTR* - // We can set CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS to get more chains. - DWORD flags = CERT_CHAIN_CACHE_END_CERT; - if (ssl_config_.rev_checking_enabled) { - server_cert_status_ |= CERT_STATUS_REV_CHECKING_ENABLED; - flags |= CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT; - } else { - flags |= CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY; - } - PCCERT_CHAIN_CONTEXT chain_context; - if (!CertGetCertificateChain( - NULL, // default chain engine, HCCE_CURRENT_USER - server_cert_, - NULL, // current system time - server_cert_->hCertStore, // search this store - &chain_para, - flags, - NULL, // reserved - &chain_context)) { - return MapSecurityError(GetLastError()); - } - ScopedCertChainContext scoped_chain_context(chain_context); - - LogConnectionTypeMetrics(chain_context); - - server_cert_status_ |= MapCertChainErrorStatusToCertStatus( - chain_context->TrustStatus.dwErrorStatus); - - std::wstring wstr_hostname = ASCIIToWide(hostname_); - - SSL_EXTRA_CERT_CHAIN_POLICY_PARA extra_policy_para; - memset(&extra_policy_para, 0, sizeof(extra_policy_para)); - extra_policy_para.cbSize = sizeof(extra_policy_para); - extra_policy_para.dwAuthType = AUTHTYPE_SERVER; - extra_policy_para.fdwChecks = 0; - extra_policy_para.pwszServerName = - const_cast<wchar_t*>(wstr_hostname.c_str()); - - CERT_CHAIN_POLICY_PARA policy_para; - memset(&policy_para, 0, sizeof(policy_para)); - policy_para.cbSize = sizeof(policy_para); - policy_para.dwFlags = 0; - policy_para.pvExtraPolicyPara = &extra_policy_para; - - CERT_CHAIN_POLICY_STATUS policy_status; - memset(&policy_status, 0, sizeof(policy_status)); - policy_status.cbSize = sizeof(policy_status); - - if (!CertVerifyCertificateChainPolicy( - CERT_CHAIN_POLICY_SSL, - chain_context, - &policy_para, - &policy_status)) { - return MapSecurityError(GetLastError()); - } - - if (policy_status.dwError) { - server_cert_status_ |= MapNetErrorToCertStatus( - MapSecurityError(policy_status.dwError)); - - // CertVerifyCertificateChainPolicy reports only one error (in - // policy_status.dwError) if the certificate has multiple errors. - // CertGetCertificateChain doesn't report certificate name mismatch, so - // CertVerifyCertificateChainPolicy is the only function that can report - // certificate name mismatch. - // - // To prevent a potential certificate name mismatch from being hidden by - // some other certificate error, if we get any other certificate error, - // we call CertVerifyCertificateChainPolicy again, ignoring all other - // certificate errors. Both extra_policy_para.fdwChecks and - // policy_para.dwFlags allow us to ignore certificate errors, so we set - // them both. - if (policy_status.dwError != CERT_E_CN_NO_MATCH) { - const DWORD extra_ignore_flags = - 0x00000080 | // SECURITY_FLAG_IGNORE_REVOCATION - 0x00000100 | // SECURITY_FLAG_IGNORE_UNKNOWN_CA - 0x00002000 | // SECURITY_FLAG_IGNORE_CERT_DATE_INVALID - 0x00000200; // SECURITY_FLAG_IGNORE_WRONG_USAGE - extra_policy_para.fdwChecks = extra_ignore_flags; - const DWORD ignore_flags = - CERT_CHAIN_POLICY_IGNORE_ALL_NOT_TIME_VALID_FLAGS | - CERT_CHAIN_POLICY_IGNORE_INVALID_BASIC_CONSTRAINTS_FLAG | - CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG | - CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG | - CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG | - CERT_CHAIN_POLICY_IGNORE_INVALID_POLICY_FLAG | - CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS | - CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG | - CERT_CHAIN_POLICY_TRUST_TESTROOT_FLAG | - CERT_CHAIN_POLICY_IGNORE_NOT_SUPPORTED_CRITICAL_EXT_FLAG | - CERT_CHAIN_POLICY_IGNORE_PEER_TRUST_FLAG; - policy_para.dwFlags = ignore_flags; - if (!CertVerifyCertificateChainPolicy( - CERT_CHAIN_POLICY_SSL, - chain_context, - &policy_para, - &policy_status)) { - return MapSecurityError(GetLastError()); - } - if (policy_status.dwError) { - server_cert_status_ |= MapNetErrorToCertStatus( - MapSecurityError(policy_status.dwError)); - } - } - } - - // TODO(wtc): Suppress CERT_STATUS_NO_REVOCATION_MECHANISM for now to be - // compatible with WinHTTP, which doesn't report this error (bug 3004). - server_cert_status_ &= ~CERT_STATUS_NO_REVOCATION_MECHANISM; - - if (IsCertStatusError(server_cert_status_)) - return MapCertStatusToNetError(server_cert_status_); - return OK; -} - } // namespace net diff --git a/net/base/ssl_client_socket_win.h b/net/base/ssl_client_socket_win.h index 58a035e..c0b5243 100644 --- a/net/base/ssl_client_socket_win.h +++ b/net/base/ssl_client_socket_win.h @@ -14,6 +14,8 @@ #include <string> #include "base/scoped_ptr.h" +#include "net/base/cert_verifier.h" +#include "net/base/cert_verify_result.h" #include "net/base/completion_callback.h" #include "net/base/ssl_client_socket.h" #include "net/base/ssl_config_service.h" @@ -56,6 +58,8 @@ class SSLClientSocketWin : public SSLClientSocket { int DoHandshakeReadComplete(int result); int DoHandshakeWrite(); int DoHandshakeWriteComplete(int result); + int DoVerifyCert(); + int DoVerifyCertComplete(int result); int DoPayloadRead(); int DoPayloadReadComplete(int result); int DoPayloadEncrypt(); @@ -63,8 +67,7 @@ class SSLClientSocketWin : public SSLClientSocket { int DoPayloadWriteComplete(int result); int DidCompleteHandshake(); - static void LogConnectionTypeMetrics(PCCERT_CHAIN_CONTEXT chain_context); - int VerifyServerCert(); + void LogConnectionTypeMetrics() const; CompletionCallbackImpl<SSLClientSocketWin> io_callback_; scoped_ptr<ClientSocket> transport_; @@ -85,6 +88,8 @@ class SSLClientSocketWin : public SSLClientSocket { STATE_HANDSHAKE_READ_COMPLETE, STATE_HANDSHAKE_WRITE, STATE_HANDSHAKE_WRITE_COMPLETE, + STATE_VERIFY_CERT, + STATE_VERIFY_CERT_COMPLETE, STATE_PAYLOAD_ENCRYPT, STATE_PAYLOAD_WRITE, STATE_PAYLOAD_WRITE_COMPLETE, @@ -95,7 +100,8 @@ class SSLClientSocketWin : public SSLClientSocket { SecPkgContext_StreamSizes stream_sizes_; PCCERT_CONTEXT server_cert_; - int server_cert_status_; + CertVerifier verifier_; + CertVerifyResult server_cert_verify_result_; CredHandle* creds_; CtxtHandle ctxt_; diff --git a/net/base/x509_certificate.h b/net/base/x509_certificate.h index 9127cc6..dceb52f 100644 --- a/net/base/x509_certificate.h +++ b/net/base/x509_certificate.h @@ -29,6 +29,8 @@ class Pickle; namespace net { +class CertVerifyResult; + // X509Certificate represents an X.509 certificate used by SSL. class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { public: @@ -50,6 +52,9 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { bool operator() (X509Certificate* lhs, X509Certificate* rhs) const; }; + // A handle to the certificate object in the underlying crypto library. + // We assume that OSCertHandle is a pointer type on all platforms and + // NULL is an invalid OSCertHandle. #if defined(OS_WIN) typedef PCCERT_CONTEXT OSCertHandle; #elif defined(OS_MACOSX) @@ -60,7 +65,7 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { // TODO(ericroman): not implemented typedef void* OSCertHandle; #endif - + // Principal represent an X.509 principal. struct Principal { Principal() { } @@ -181,6 +186,21 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { // now. bool HasExpired() const; + // Verifies the certificate against the given hostname. Returns OK if + // successful or an error code upon failure. + // + // The |*verify_result| structure, including the |verify_result->cert_status| + // bitmask, is always filled out regardless of the return value. If the + // certificate has multiple errors, the corresponding status flags are set in + // |verify_result->cert_status|, and the error code for the most serious + // error is returned. + // + // If |rev_checking_enabled| is true, certificate revocation checking is + // performed. + int Verify(const std::string& hostname, + bool rev_checking_enabled, + CertVerifyResult* verify_result) const; + // Returns true if the certificate is an extended-validation (EV) // certificate. bool IsEV(int cert_status) const; @@ -198,22 +218,22 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> { void Insert(X509Certificate* cert); void Remove(X509Certificate* cert); X509Certificate* Find(const Fingerprint& fingerprint); - + private: typedef std::map<Fingerprint, X509Certificate*, FingerprintLessThan> CertMap; - + // Obtain an instance of X509Certificate::Cache via GetInstance(). Cache() { } friend struct DefaultSingletonTraits<Cache>; - + // You must acquire this lock before using any private data of this object. // You must not block while holding this lock. Lock lock_; - + // The certificate cache. You must acquire |lock_| before using |cache_|. CertMap cache_; - + DISALLOW_COPY_AND_ASSIGN(Cache); }; diff --git a/net/base/x509_certificate_win.cc b/net/base/x509_certificate_win.cc index 57ce947..4c2cf2c 100644 --- a/net/base/x509_certificate_win.cc +++ b/net/base/x509_certificate_win.cc @@ -9,7 +9,9 @@ #include "base/string_tokenizer.h" #include "base/string_util.h" #include "net/base/cert_status_flags.h" +#include "net/base/cert_verify_result.h" #include "net/base/ev_root_ca_metadata.h" +#include "net/base/net_errors.h" #include "net/base/scoped_cert_chain_context.h" #pragma comment(lib, "crypt32.lib") @@ -20,6 +22,109 @@ namespace net { namespace { +//----------------------------------------------------------------------------- + +// TODO(wtc): This is a copy of the MapSecurityError function in +// ssl_client_socket_win.cc. Another function that maps Windows error codes +// to our network error codes is WinInetUtil::OSErrorToNetError. We should +// eliminate the code duplication. +int MapSecurityError(SECURITY_STATUS err) { + // There are numerous security error codes, but these are the ones we thus + // far find interesting. + switch (err) { + case SEC_E_WRONG_PRINCIPAL: // Schannel + case CERT_E_CN_NO_MATCH: // CryptoAPI + return ERR_CERT_COMMON_NAME_INVALID; + case SEC_E_UNTRUSTED_ROOT: // Schannel + case CERT_E_UNTRUSTEDROOT: // CryptoAPI + return ERR_CERT_AUTHORITY_INVALID; + case SEC_E_CERT_EXPIRED: // Schannel + case CERT_E_EXPIRED: // CryptoAPI + return ERR_CERT_DATE_INVALID; + case CRYPT_E_NO_REVOCATION_CHECK: + return ERR_CERT_NO_REVOCATION_MECHANISM; + case CRYPT_E_REVOCATION_OFFLINE: + return ERR_CERT_UNABLE_TO_CHECK_REVOCATION; + case CRYPT_E_REVOKED: // Schannel and CryptoAPI + return ERR_CERT_REVOKED; + case SEC_E_CERT_UNKNOWN: + case CERT_E_ROLE: + return ERR_CERT_INVALID; + // We received an unexpected_message or illegal_parameter alert message + // from the server. + case SEC_E_ILLEGAL_MESSAGE: + return ERR_SSL_PROTOCOL_ERROR; + case SEC_E_ALGORITHM_MISMATCH: + return ERR_SSL_VERSION_OR_CIPHER_MISMATCH; + case SEC_E_INVALID_HANDLE: + return ERR_UNEXPECTED; + case SEC_E_OK: + return OK; + default: + LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; + return ERR_FAILED; + } +} + +// Map the errors in the chain_context->TrustStatus.dwErrorStatus returned by +// CertGetCertificateChain to our certificate status flags. +int MapCertChainErrorStatusToCertStatus(DWORD error_status) { + int cert_status = 0; + + // CERT_TRUST_IS_NOT_TIME_NESTED means a subject certificate's time validity + // does not nest correctly within its issuer's time validity. + const DWORD kDateInvalidErrors = CERT_TRUST_IS_NOT_TIME_VALID | + CERT_TRUST_IS_NOT_TIME_NESTED | + CERT_TRUST_CTL_IS_NOT_TIME_VALID; + if (error_status & kDateInvalidErrors) + cert_status |= CERT_STATUS_DATE_INVALID; + + const DWORD kAuthorityInvalidErrors = CERT_TRUST_IS_UNTRUSTED_ROOT | + CERT_TRUST_IS_EXPLICIT_DISTRUST | + CERT_TRUST_IS_PARTIAL_CHAIN; + if (error_status & kAuthorityInvalidErrors) + cert_status |= CERT_STATUS_AUTHORITY_INVALID; + + if ((error_status & CERT_TRUST_REVOCATION_STATUS_UNKNOWN) && + !(error_status & CERT_TRUST_IS_OFFLINE_REVOCATION)) + cert_status |= CERT_STATUS_NO_REVOCATION_MECHANISM; + + if (error_status & CERT_TRUST_IS_OFFLINE_REVOCATION) + cert_status |= CERT_STATUS_UNABLE_TO_CHECK_REVOCATION; + + if (error_status & CERT_TRUST_IS_REVOKED) + cert_status |= CERT_STATUS_REVOKED; + + const DWORD kWrongUsageErrors = CERT_TRUST_IS_NOT_VALID_FOR_USAGE | + CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE; + if (error_status & kWrongUsageErrors) { + // TODO(wtc): Handle these errors. + // cert_status = |= CERT_STATUS_WRONG_USAGE; + } + + // The rest of the errors. + const DWORD kCertInvalidErrors = + CERT_TRUST_IS_NOT_SIGNATURE_VALID | + CERT_TRUST_IS_CYCLIC | + CERT_TRUST_INVALID_EXTENSION | + CERT_TRUST_INVALID_POLICY_CONSTRAINTS | + CERT_TRUST_INVALID_BASIC_CONSTRAINTS | + CERT_TRUST_INVALID_NAME_CONSTRAINTS | + CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID | + CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT | + CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT | + CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT | + CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT | + CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY | + CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT; + if (error_status & kCertInvalidErrors) + cert_status |= CERT_STATUS_INVALID; + + return cert_status; +} + +//----------------------------------------------------------------------------- + // Wrappers of malloc and free for CRYPT_DECODE_PARA, which requires the // WINAPI calling convention. void* WINAPI MyCryptAlloc(size_t size) { @@ -59,6 +164,38 @@ void GetCertSubjectAltName(PCCERT_CONTEXT cert, output->reset(alt_name_info); } +// Saves some information about the certificate chain chain_context in +// *verify_result. +void GetCertChainInfo(PCCERT_CHAIN_CONTEXT chain_context, + CertVerifyResult* verify_result) { + PCERT_SIMPLE_CHAIN first_chain = chain_context->rgpChain[0]; + int num_elements = first_chain->cElement; + PCERT_CHAIN_ELEMENT* element = first_chain->rgpElement; + + // Each chain starts with the end entity certificate (i = 0) and ends with + // the root CA certificate (i = num_elements - 1). Do not inspect the + // signature algorithm of the root CA certificate because the signature on + // the trust anchor is not important. + for (int i = 0; i < num_elements - 1; ++i) { + PCCERT_CONTEXT cert = element[i]->pCertContext; + const char* algorithm = cert->pCertInfo->SignatureAlgorithm.pszObjId; + if (strcmp(algorithm, szOID_RSA_MD5RSA) == 0) { + // md5WithRSAEncryption: 1.2.840.113549.1.1.4 + verify_result->has_md5 = true; + if (i != 0) + verify_result->has_md5_ca = true; + } else if (strcmp(algorithm, szOID_RSA_MD2RSA) == 0) { + // md2WithRSAEncryption: 1.2.840.113549.1.1.2 + verify_result->has_md2 = true; + if (i != 0) + verify_result->has_md2_ca = true; + } else if (strcmp(algorithm, szOID_RSA_MD4RSA) == 0) { + // md4WithRSAEncryption: 1.2.840.113549.1.1.3 + verify_result->has_md4 = true; + } + } +} + /////////////////////////////////////////////////////////////////////////// // // Functions used by X509Certificate::IsEV @@ -293,6 +430,140 @@ bool X509Certificate::HasExpired() const { return Time::Now() > valid_expiry(); } +int X509Certificate::Verify(const std::string& hostname, + bool rev_checking_enabled, + CertVerifyResult* verify_result) const { + verify_result->cert_status = 0; + verify_result->has_md5 = false; + verify_result->has_md2 = false; + verify_result->has_md4 = false; + verify_result->has_md5_ca = false; + verify_result->has_md2_ca = false; + + // Build and validate certificate chain. + + CERT_CHAIN_PARA chain_para; + memset(&chain_para, 0, sizeof(chain_para)); + chain_para.cbSize = sizeof(chain_para); + // TODO(wtc): consider requesting the usage szOID_PKIX_KP_SERVER_AUTH + // or szOID_SERVER_GATED_CRYPTO or szOID_SGC_NETSCAPE + chain_para.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND; + chain_para.RequestedUsage.Usage.cUsageIdentifier = 0; + chain_para.RequestedUsage.Usage.rgpszUsageIdentifier = NULL; // LPSTR* + // We can set CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS to get more chains. + DWORD flags = CERT_CHAIN_CACHE_END_CERT; + if (rev_checking_enabled) { + verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; + flags |= CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT; + } else { + flags |= CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY; + } + PCCERT_CHAIN_CONTEXT chain_context; + if (!CertGetCertificateChain( + NULL, // default chain engine, HCCE_CURRENT_USER + cert_handle_, + NULL, // current system time + cert_handle_->hCertStore, // search this store + &chain_para, + flags, + NULL, // reserved + &chain_context)) { + return MapSecurityError(GetLastError()); + } + ScopedCertChainContext scoped_chain_context(chain_context); + + GetCertChainInfo(chain_context, verify_result); + + verify_result->cert_status |= MapCertChainErrorStatusToCertStatus( + chain_context->TrustStatus.dwErrorStatus); + + std::wstring wstr_hostname = ASCIIToWide(hostname); + + SSL_EXTRA_CERT_CHAIN_POLICY_PARA extra_policy_para; + memset(&extra_policy_para, 0, sizeof(extra_policy_para)); + extra_policy_para.cbSize = sizeof(extra_policy_para); + extra_policy_para.dwAuthType = AUTHTYPE_SERVER; + extra_policy_para.fdwChecks = 0; + extra_policy_para.pwszServerName = + const_cast<wchar_t*>(wstr_hostname.c_str()); + + CERT_CHAIN_POLICY_PARA policy_para; + memset(&policy_para, 0, sizeof(policy_para)); + policy_para.cbSize = sizeof(policy_para); + policy_para.dwFlags = 0; + policy_para.pvExtraPolicyPara = &extra_policy_para; + + CERT_CHAIN_POLICY_STATUS policy_status; + memset(&policy_status, 0, sizeof(policy_status)); + policy_status.cbSize = sizeof(policy_status); + + if (!CertVerifyCertificateChainPolicy( + CERT_CHAIN_POLICY_SSL, + chain_context, + &policy_para, + &policy_status)) { + return MapSecurityError(GetLastError()); + } + + if (policy_status.dwError) { + verify_result->cert_status |= MapNetErrorToCertStatus( + MapSecurityError(policy_status.dwError)); + + // CertVerifyCertificateChainPolicy reports only one error (in + // policy_status.dwError) if the certificate has multiple errors. + // CertGetCertificateChain doesn't report certificate name mismatch, so + // CertVerifyCertificateChainPolicy is the only function that can report + // certificate name mismatch. + // + // To prevent a potential certificate name mismatch from being hidden by + // some other certificate error, if we get any other certificate error, + // we call CertVerifyCertificateChainPolicy again, ignoring all other + // certificate errors. Both extra_policy_para.fdwChecks and + // policy_para.dwFlags allow us to ignore certificate errors, so we set + // them both. + if (policy_status.dwError != CERT_E_CN_NO_MATCH) { + const DWORD extra_ignore_flags = + 0x00000080 | // SECURITY_FLAG_IGNORE_REVOCATION + 0x00000100 | // SECURITY_FLAG_IGNORE_UNKNOWN_CA + 0x00002000 | // SECURITY_FLAG_IGNORE_CERT_DATE_INVALID + 0x00000200; // SECURITY_FLAG_IGNORE_WRONG_USAGE + extra_policy_para.fdwChecks = extra_ignore_flags; + const DWORD ignore_flags = + CERT_CHAIN_POLICY_IGNORE_ALL_NOT_TIME_VALID_FLAGS | + CERT_CHAIN_POLICY_IGNORE_INVALID_BASIC_CONSTRAINTS_FLAG | + CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG | + CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG | + CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG | + CERT_CHAIN_POLICY_IGNORE_INVALID_POLICY_FLAG | + CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS | + CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG | + CERT_CHAIN_POLICY_TRUST_TESTROOT_FLAG | + CERT_CHAIN_POLICY_IGNORE_NOT_SUPPORTED_CRITICAL_EXT_FLAG | + CERT_CHAIN_POLICY_IGNORE_PEER_TRUST_FLAG; + policy_para.dwFlags = ignore_flags; + if (!CertVerifyCertificateChainPolicy( + CERT_CHAIN_POLICY_SSL, + chain_context, + &policy_para, + &policy_status)) { + return MapSecurityError(GetLastError()); + } + if (policy_status.dwError) { + verify_result->cert_status |= MapNetErrorToCertStatus( + MapSecurityError(policy_status.dwError)); + } + } + } + + // TODO(wtc): Suppress CERT_STATUS_NO_REVOCATION_MECHANISM for now to be + // compatible with WinHTTP, which doesn't report this error (bug 3004). + verify_result->cert_status &= ~CERT_STATUS_NO_REVOCATION_MECHANISM; + + if (IsCertStatusError(verify_result->cert_status)) + return MapCertStatusToNetError(verify_result->cert_status); + return OK; +} + // Returns true if the certificate is an extended-validation certificate. // // The certificate has already been verified by the HTTP library. cert_status diff --git a/net/build/net.vcproj b/net/build/net.vcproj index 811eb1b..4721309 100644 --- a/net/build/net.vcproj +++ b/net/build/net.vcproj @@ -165,10 +165,26 @@ > </File> <File + RelativePath="..\base\cert_status_flags.cc" + > + </File> + <File RelativePath="..\base\cert_status_flags.h" > </File> <File + RelativePath="..\base\cert_verifier.cc" + > + </File> + <File + RelativePath="..\base\cert_verifier.h" + > + </File> + <File + RelativePath="..\base\cert_verify_result.h" + > + </File> + <File RelativePath="..\base\client_socket.h" > </File> diff --git a/net/net.xcodeproj/project.pbxproj b/net/net.xcodeproj/project.pbxproj index e0bce49..37df32e 100644 --- a/net/net.xcodeproj/project.pbxproj +++ b/net/net.xcodeproj/project.pbxproj @@ -124,6 +124,7 @@ 7BA362B60E8C3D020023C8B9 /* sdch_filter.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BA3615E0E8C35A50023C8B9 /* sdch_filter.cc */; }; 7BA362B70E8C3D040023C8B9 /* sdch_filter_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BA361600E8C35A50023C8B9 /* sdch_filter_unittest.cc */; }; 7BA362C40E8C3D4C0023C8B9 /* libsdch.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BA362C10E8C3D2B0023C8B9 /* libsdch.a */; }; + 7BCF4CF2ECABD68C18FA59F7 /* cert_status_flags.cc in Sources */ = {isa = PBXBuildFile; fileRef = C081BA94B2F59669BFAFD808 /* cert_status_flags.cc */; }; 7BD8F70C0E65DCD800034DE9 /* block_files_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32F90E5A190600A747DB /* block_files_unittest.cc */; }; 7BD8F70D0E65DCE000034DE9 /* disk_cache_test_base.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32D50E5A190600A747DB /* disk_cache_test_base.cc */; }; 7BD8F70E0E65DCE500034DE9 /* disk_cache_test_util.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32FA0E5A190600A747DB /* disk_cache_test_util.cc */; }; @@ -163,6 +164,7 @@ A50055FE0EBF800D007B0A90 /* telnet_server.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED328D0E5A181C00A747DB /* telnet_server.cc */; }; A50055FF0EBF8018007B0A90 /* listen_socket.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED32B30E5A181C00A747DB /* listen_socket.cc */; }; A5AB7BFC0EB7DBA10070A7D3 /* file_stream_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = A5AB7BFB0EB7DBA10070A7D3 /* file_stream_unittest.cc */; }; + B07E3550EFE4B6C6680D49BE /* cert_verifier.cc in Sources */ = {isa = PBXBuildFile; fileRef = B87DD6154A7A9ED60F28F016 /* cert_verifier.cc */; }; B4DD1C3523B3890B287055E6 /* connection_type_histograms.cc in Sources */ = {isa = PBXBuildFile; fileRef = F17062083BCE6F0A42F4C479 /* connection_type_histograms.cc */; }; B5F622260E805FC40076681A /* url_request_job_manager.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED33A30E5A198600A747DB /* url_request_job_manager.cc */; }; BAA46E3B0E5CE99A00E77460 /* net_util_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED329F0E5A181C00A747DB /* net_util_unittest.cc */; }; @@ -442,10 +444,9 @@ 15C6370BF6FE62308A559648 /* ftp_auth_cache_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ftp_auth_cache_unittest.cc; path = ftp/ftp_auth_cache_unittest.cc; sourceTree = SOURCE_ROOT; }; 4D4C5C050EF1B8C5002CA805 /* filter_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = filter_unittest.cc; sourceTree = "<group>"; }; 533102E60E5E3EBF00FF8E32 /* net_util_posix.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = net_util_posix.cc; sourceTree = "<group>"; }; + 58586B4C2F020D851B930BF2 /* cert_verify_result.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cert_verify_result.h; sourceTree = "<group>"; }; 7B2630600E82F282001CE27F /* libevent.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = libevent.xcodeproj; path = third_party/libevent/libevent.xcodeproj; sourceTree = "<group>"; }; 7B82FF450E763620008F45CF /* host_resolver_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = host_resolver_unittest.cc; sourceTree = "<group>"; }; - 7BA3615D0E8C35A50023C8B9 /* host_resolver_unittest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = host_resolver_unittest.h; sourceTree = "<group>"; }; - 7BA3615E0E8C35A50023C8B9 /* sdch_filter.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sdch_filter.cc; sourceTree = "<group>"; }; 7B8501F10E5A372500730B43 /* googleurl.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = googleurl.xcodeproj; path = build/googleurl.xcodeproj; sourceTree = "<group>"; }; 7B8502620E5A38BB00730B43 /* modp_b64.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = modp_b64.xcodeproj; path = third_party/modp_b64/modp_b64.xcodeproj; sourceTree = "<group>"; }; 7BA015570E5A1C3E00044150 /* icu.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = icu.xcodeproj; path = third_party/icu38/icu.xcodeproj; sourceTree = "<group>"; }; @@ -454,6 +455,8 @@ 7BA016930E5A1E8700044150 /* zlib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = zlib.xcodeproj; path = third_party/zlib/zlib.xcodeproj; sourceTree = "<group>"; }; 7BA357A60E8990260023C8B9 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = "<group>"; }; 7BA361440E8C341F0023C8B9 /* test_completion_callback_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = test_completion_callback_unittest.cc; sourceTree = "<group>"; }; + 7BA3615D0E8C35A50023C8B9 /* host_resolver_unittest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = host_resolver_unittest.h; sourceTree = "<group>"; }; + 7BA3615E0E8C35A50023C8B9 /* sdch_filter.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sdch_filter.cc; sourceTree = "<group>"; }; 7BA3615F0E8C35A50023C8B9 /* sdch_filter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sdch_filter.h; sourceTree = "<group>"; }; 7BA361600E8C35A50023C8B9 /* sdch_filter_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sdch_filter_unittest.cc; sourceTree = "<group>"; }; 7BA361EB0E8C38C60023C8B9 /* http_version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = http_version.h; sourceTree = "<group>"; }; @@ -686,7 +689,10 @@ 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>"; }; ACAB6D5C0F43A727D039E138 /* ftp_auth_cache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ftp_auth_cache.h; path = ftp/ftp_auth_cache.h; sourceTree = SOURCE_ROOT; }; + B87DD6154A7A9ED60F28F016 /* cert_verifier.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cert_verifier.cc; sourceTree = "<group>"; }; + C081BA94B2F59669BFAFD808 /* cert_status_flags.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cert_status_flags.cc; sourceTree = "<group>"; }; D4726BC70CCE10F4FF2A5E12 /* connection_type_histograms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = connection_type_histograms.h; sourceTree = "<group>"; }; + DD0B3349460AB0703FCE0C7A /* cert_verifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cert_verifier.h; sourceTree = "<group>"; }; DFC96EF80EF9BC5D003C335B /* eviction.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eviction.cc; sourceTree = "<group>"; }; DFC96EF90EF9BC5D003C335B /* eviction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eviction.h; sourceTree = "<group>"; }; DFEE18250E882E3600666107 /* stats_histogram.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = stats_histogram.cc; sourceTree = "<group>"; }; @@ -893,7 +899,11 @@ 7BED32750E5A181C00A747DB /* bzip2_filter.cc */, 7BED32740E5A181C00A747DB /* bzip2_filter.h */, 7BED32730E5A181C00A747DB /* bzip2_filter_unittest.cc */, + C081BA94B2F59669BFAFD808 /* cert_status_flags.cc */, 7BED32720E5A181C00A747DB /* cert_status_flags.h */, + B87DD6154A7A9ED60F28F016 /* cert_verifier.cc */, + DD0B3349460AB0703FCE0C7A /* cert_verifier.h */, + 58586B4C2F020D851B930BF2 /* cert_verify_result.h */, 7BED32710E5A181C00A747DB /* client_socket.h */, 7BED32700E5A181C00A747DB /* client_socket_factory.cc */, 7BED326F0E5A181C00A747DB /* client_socket_factory.h */, @@ -1467,6 +1477,8 @@ 7B8503FC0E5B2DA200730B43 /* block_files.cc in Sources */, 7BA0172F0E5A244D00044150 /* bzip2_filter.cc in Sources */, 7B8504050E5B2DBD00730B43 /* cache_util_posix.cc in Sources */, + 7BCF4CF2ECABD68C18FA59F7 /* cert_status_flags.cc in Sources */, + B07E3550EFE4B6C6680D49BE /* cert_verifier.cc in Sources */, E4CE9C0D0E8BFFFA00D5378C /* client_socket_factory.cc in Sources */, 7B8504080E5B2DD800730B43 /* client_socket_handle.cc in Sources */, 7B8504090E5B2DD800730B43 /* client_socket_pool.cc in Sources */, diff --git a/net/net_lib.scons b/net/net_lib.scons index 099c46b..4eb6639 100644 --- a/net/net_lib.scons +++ b/net/net_lib.scons @@ -26,7 +26,11 @@ input_files = ChromeFileList([ 'base/base64.h', 'base/bzip2_filter.cc', 'base/bzip2_filter.h', + 'base/cert_status_flags.cc', 'base/cert_status_flags.h', + 'base/cert_verifier.cc', + 'base/cert_verifier.h', + 'base/cert_verify_result.h', 'base/client_socket.h', 'base/client_socket_factory.cc', 'base/client_socket_factory.h', |