| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/base/ssl_client_socket_win.h" | 5 #include "net/base/ssl_client_socket_win.h" |
| 6 | 6 |
| 7 #include <schnlsp.h> | 7 #include <schnlsp.h> |
| 8 | 8 |
| 9 #include "base/lock.h" | 9 #include "base/lock.h" |
| 10 #include "base/singleton.h" | 10 #include "base/singleton.h" |
| 11 #include "base/string_util.h" | 11 #include "base/string_util.h" |
| 12 #include "net/base/connection_type_histograms.h" | 12 #include "net/base/connection_type_histograms.h" |
| 13 #include "net/base/net_errors.h" | 13 #include "net/base/net_errors.h" |
| 14 #include "net/base/scoped_cert_chain_context.h" | |
| 15 #include "net/base/ssl_info.h" | 14 #include "net/base/ssl_info.h" |
| 16 | 15 |
| 17 #pragma comment(lib, "secur32.lib") | 16 #pragma comment(lib, "secur32.lib") |
| 18 | 17 |
| 19 namespace net { | 18 namespace net { |
| 20 | 19 |
| 21 //----------------------------------------------------------------------------- | 20 //----------------------------------------------------------------------------- |
| 22 | 21 |
| 23 // TODO(wtc): See http://msdn.microsoft.com/en-us/library/aa377188(VS.85).aspx | 22 // TODO(wtc): See http://msdn.microsoft.com/en-us/library/aa377188(VS.85).aspx |
| 24 // for the other error codes we may need to map. | 23 // for the other error codes we may need to map. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 53 case SEC_E_INVALID_HANDLE: | 52 case SEC_E_INVALID_HANDLE: |
| 54 return ERR_UNEXPECTED; | 53 return ERR_UNEXPECTED; |
| 55 case SEC_E_OK: | 54 case SEC_E_OK: |
| 56 return OK; | 55 return OK; |
| 57 default: | 56 default: |
| 58 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; | 57 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; |
| 59 return ERR_FAILED; | 58 return ERR_FAILED; |
| 60 } | 59 } |
| 61 } | 60 } |
| 62 | 61 |
| 63 // Map a network error code to the equivalent certificate status flag. If | |
| 64 // the error code is not a certificate error, it is mapped to 0. | |
| 65 static int MapNetErrorToCertStatus(int error) { | |
| 66 switch (error) { | |
| 67 case ERR_CERT_COMMON_NAME_INVALID: | |
| 68 return CERT_STATUS_COMMON_NAME_INVALID; | |
| 69 case ERR_CERT_DATE_INVALID: | |
| 70 return CERT_STATUS_DATE_INVALID; | |
| 71 case ERR_CERT_AUTHORITY_INVALID: | |
| 72 return CERT_STATUS_AUTHORITY_INVALID; | |
| 73 case ERR_CERT_NO_REVOCATION_MECHANISM: | |
| 74 return CERT_STATUS_NO_REVOCATION_MECHANISM; | |
| 75 case ERR_CERT_UNABLE_TO_CHECK_REVOCATION: | |
| 76 return CERT_STATUS_UNABLE_TO_CHECK_REVOCATION; | |
| 77 case ERR_CERT_REVOKED: | |
| 78 return CERT_STATUS_REVOKED; | |
| 79 case ERR_CERT_CONTAINS_ERRORS: | |
| 80 NOTREACHED(); | |
| 81 // Falls through. | |
| 82 case ERR_CERT_INVALID: | |
| 83 return CERT_STATUS_INVALID; | |
| 84 default: | |
| 85 return 0; | |
| 86 } | |
| 87 } | |
| 88 | |
| 89 static int MapCertStatusToNetError(int cert_status) { | |
| 90 // A certificate may have multiple errors. We report the most | |
| 91 // serious error. | |
| 92 | |
| 93 // Unrecoverable errors | |
| 94 if (cert_status & CERT_STATUS_INVALID) | |
| 95 return ERR_CERT_INVALID; | |
| 96 if (cert_status & CERT_STATUS_REVOKED) | |
| 97 return ERR_CERT_REVOKED; | |
| 98 | |
| 99 // Recoverable errors | |
| 100 if (cert_status & CERT_STATUS_AUTHORITY_INVALID) | |
| 101 return ERR_CERT_AUTHORITY_INVALID; | |
| 102 if (cert_status & CERT_STATUS_COMMON_NAME_INVALID) | |
| 103 return ERR_CERT_COMMON_NAME_INVALID; | |
| 104 if (cert_status & CERT_STATUS_DATE_INVALID) | |
| 105 return ERR_CERT_DATE_INVALID; | |
| 106 | |
| 107 // Unknown status. Give it the benefit of the doubt. | |
| 108 if (cert_status & CERT_STATUS_UNABLE_TO_CHECK_REVOCATION) | |
| 109 return ERR_CERT_UNABLE_TO_CHECK_REVOCATION; | |
| 110 if (cert_status & CERT_STATUS_NO_REVOCATION_MECHANISM) | |
| 111 return ERR_CERT_NO_REVOCATION_MECHANISM; | |
| 112 | |
| 113 NOTREACHED(); | |
| 114 return ERR_UNEXPECTED; | |
| 115 } | |
| 116 | |
| 117 // Map the errors in the chain_context->TrustStatus.dwErrorStatus returned by | |
| 118 // CertGetCertificateChain to our certificate status flags. | |
| 119 static int MapCertChainErrorStatusToCertStatus(DWORD error_status) { | |
| 120 int cert_status = 0; | |
| 121 | |
| 122 // CERT_TRUST_IS_NOT_TIME_NESTED means a subject certificate's time validity | |
| 123 // does not nest correctly within its issuer's time validity. | |
| 124 const DWORD kDateInvalidErrors = CERT_TRUST_IS_NOT_TIME_VALID | | |
| 125 CERT_TRUST_IS_NOT_TIME_NESTED | | |
| 126 CERT_TRUST_CTL_IS_NOT_TIME_VALID; | |
| 127 if (error_status & kDateInvalidErrors) | |
| 128 cert_status |= CERT_STATUS_DATE_INVALID; | |
| 129 | |
| 130 const DWORD kAuthorityInvalidErrors = CERT_TRUST_IS_UNTRUSTED_ROOT | | |
| 131 CERT_TRUST_IS_EXPLICIT_DISTRUST | | |
| 132 CERT_TRUST_IS_PARTIAL_CHAIN; | |
| 133 if (error_status & kAuthorityInvalidErrors) | |
| 134 cert_status |= CERT_STATUS_AUTHORITY_INVALID; | |
| 135 | |
| 136 if ((error_status & CERT_TRUST_REVOCATION_STATUS_UNKNOWN) && | |
| 137 !(error_status & CERT_TRUST_IS_OFFLINE_REVOCATION)) | |
| 138 cert_status |= CERT_STATUS_NO_REVOCATION_MECHANISM; | |
| 139 | |
| 140 if (error_status & CERT_TRUST_IS_OFFLINE_REVOCATION) | |
| 141 cert_status |= CERT_STATUS_UNABLE_TO_CHECK_REVOCATION; | |
| 142 | |
| 143 if (error_status & CERT_TRUST_IS_REVOKED) | |
| 144 cert_status |= CERT_STATUS_REVOKED; | |
| 145 | |
| 146 const DWORD kWrongUsageErrors = CERT_TRUST_IS_NOT_VALID_FOR_USAGE | | |
| 147 CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE; | |
| 148 if (error_status & kWrongUsageErrors) { | |
| 149 // TODO(wtc): Handle these errors. | |
| 150 // cert_status = |= CERT_STATUS_WRONG_USAGE; | |
| 151 } | |
| 152 | |
| 153 // The rest of the errors. | |
| 154 const DWORD kCertInvalidErrors = | |
| 155 CERT_TRUST_IS_NOT_SIGNATURE_VALID | | |
| 156 CERT_TRUST_IS_CYCLIC | | |
| 157 CERT_TRUST_INVALID_EXTENSION | | |
| 158 CERT_TRUST_INVALID_POLICY_CONSTRAINTS | | |
| 159 CERT_TRUST_INVALID_BASIC_CONSTRAINTS | | |
| 160 CERT_TRUST_INVALID_NAME_CONSTRAINTS | | |
| 161 CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID | | |
| 162 CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT | | |
| 163 CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT | | |
| 164 CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT | | |
| 165 CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT | | |
| 166 CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY | | |
| 167 CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT; | |
| 168 if (error_status & kCertInvalidErrors) | |
| 169 cert_status |= CERT_STATUS_INVALID; | |
| 170 | |
| 171 return cert_status; | |
| 172 } | |
| 173 | |
| 174 //----------------------------------------------------------------------------- | 62 //----------------------------------------------------------------------------- |
| 175 | 63 |
| 176 // A bitmask consisting of these bit flags encodes which versions of the SSL | 64 // A bitmask consisting of these bit flags encodes which versions of the SSL |
| 177 // protocol (SSL 2.0, SSL 3.0, and TLS 1.0) are enabled. | 65 // protocol (SSL 2.0, SSL 3.0, and TLS 1.0) are enabled. |
| 178 enum { | 66 enum { |
| 179 SSL2 = 1 << 0, | 67 SSL2 = 1 << 0, |
| 180 SSL3 = 1 << 1, | 68 SSL3 = 1 << 1, |
| 181 TLS1 = 1 << 2, | 69 TLS1 = 1 << 2, |
| 182 SSL_VERSION_MASKS = 1 << 3 // The number of SSL version bitmasks. | 70 SSL_VERSION_MASKS = 1 << 3 // The number of SSL version bitmasks. |
| 183 }; | 71 }; |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 321 #pragma warning(suppress: 4355) | 209 #pragma warning(suppress: 4355) |
| 322 : io_callback_(this, &SSLClientSocketWin::OnIOComplete), | 210 : io_callback_(this, &SSLClientSocketWin::OnIOComplete), |
| 323 transport_(transport_socket), | 211 transport_(transport_socket), |
| 324 hostname_(hostname), | 212 hostname_(hostname), |
| 325 ssl_config_(ssl_config), | 213 ssl_config_(ssl_config), |
| 326 user_callback_(NULL), | 214 user_callback_(NULL), |
| 327 user_buf_(NULL), | 215 user_buf_(NULL), |
| 328 user_buf_len_(0), | 216 user_buf_len_(0), |
| 329 next_state_(STATE_NONE), | 217 next_state_(STATE_NONE), |
| 330 server_cert_(NULL), | 218 server_cert_(NULL), |
| 331 server_cert_status_(0), | |
| 332 creds_(NULL), | 219 creds_(NULL), |
| 333 payload_send_buffer_len_(0), | 220 payload_send_buffer_len_(0), |
| 334 bytes_sent_(0), | 221 bytes_sent_(0), |
| 335 decrypted_ptr_(NULL), | 222 decrypted_ptr_(NULL), |
| 336 bytes_decrypted_(0), | 223 bytes_decrypted_(0), |
| 337 received_ptr_(NULL), | 224 received_ptr_(NULL), |
| 338 bytes_received_(0), | 225 bytes_received_(0), |
| 339 completed_handshake_(false), | 226 completed_handshake_(false), |
| 340 complete_handshake_on_write_complete_(false), | 227 complete_handshake_on_write_complete_(false), |
| 341 ignore_ok_result_(false), | 228 ignore_ok_result_(false), |
| (...skipping 23 matching lines...) Expand all Loading... |
| 365 SecPkgContext_ConnectionInfo connection_info; | 252 SecPkgContext_ConnectionInfo connection_info; |
| 366 status = QueryContextAttributes(&ctxt_, | 253 status = QueryContextAttributes(&ctxt_, |
| 367 SECPKG_ATTR_CONNECTION_INFO, | 254 SECPKG_ATTR_CONNECTION_INFO, |
| 368 &connection_info); | 255 &connection_info); |
| 369 if (status == SEC_E_OK) { | 256 if (status == SEC_E_OK) { |
| 370 // TODO(wtc): compute the overall security strength, taking into account | 257 // TODO(wtc): compute the overall security strength, taking into account |
| 371 // dwExchStrength and dwHashStrength. dwExchStrength needs to be | 258 // dwExchStrength and dwHashStrength. dwExchStrength needs to be |
| 372 // normalized. | 259 // normalized. |
| 373 ssl_info->security_bits = connection_info.dwCipherStrength; | 260 ssl_info->security_bits = connection_info.dwCipherStrength; |
| 374 } | 261 } |
| 375 ssl_info->cert_status = server_cert_status_; | 262 ssl_info->cert_status = server_cert_verify_result_.cert_status; |
| 376 } | 263 } |
| 377 | 264 |
| 378 int SSLClientSocketWin::Connect(CompletionCallback* callback) { | 265 int SSLClientSocketWin::Connect(CompletionCallback* callback) { |
| 379 DCHECK(transport_.get()); | 266 DCHECK(transport_.get()); |
| 380 DCHECK(next_state_ == STATE_NONE); | 267 DCHECK(next_state_ == STATE_NONE); |
| 381 DCHECK(!user_callback_); | 268 DCHECK(!user_callback_); |
| 382 | 269 |
| 383 int ssl_version_mask = 0; | 270 int ssl_version_mask = 0; |
| 384 if (ssl_config_.ssl2_enabled) | 271 if (ssl_config_.ssl2_enabled) |
| 385 ssl_version_mask |= SSL2; | 272 ssl_version_mask |= SSL2; |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 527 break; | 414 break; |
| 528 case STATE_HANDSHAKE_READ_COMPLETE: | 415 case STATE_HANDSHAKE_READ_COMPLETE: |
| 529 rv = DoHandshakeReadComplete(rv); | 416 rv = DoHandshakeReadComplete(rv); |
| 530 break; | 417 break; |
| 531 case STATE_HANDSHAKE_WRITE: | 418 case STATE_HANDSHAKE_WRITE: |
| 532 rv = DoHandshakeWrite(); | 419 rv = DoHandshakeWrite(); |
| 533 break; | 420 break; |
| 534 case STATE_HANDSHAKE_WRITE_COMPLETE: | 421 case STATE_HANDSHAKE_WRITE_COMPLETE: |
| 535 rv = DoHandshakeWriteComplete(rv); | 422 rv = DoHandshakeWriteComplete(rv); |
| 536 break; | 423 break; |
| 424 case STATE_VERIFY_CERT: |
| 425 rv = DoVerifyCert(); |
| 426 break; |
| 427 case STATE_VERIFY_CERT_COMPLETE: |
| 428 rv = DoVerifyCertComplete(rv); |
| 429 break; |
| 537 case STATE_PAYLOAD_READ: | 430 case STATE_PAYLOAD_READ: |
| 538 rv = DoPayloadRead(); | 431 rv = DoPayloadRead(); |
| 539 break; | 432 break; |
| 540 case STATE_PAYLOAD_READ_COMPLETE: | 433 case STATE_PAYLOAD_READ_COMPLETE: |
| 541 rv = DoPayloadReadComplete(rv); | 434 rv = DoPayloadReadComplete(rv); |
| 542 break; | 435 break; |
| 543 case STATE_PAYLOAD_ENCRYPT: | 436 case STATE_PAYLOAD_ENCRYPT: |
| 544 rv = DoPayloadEncrypt(); | 437 rv = DoPayloadEncrypt(); |
| 545 break; | 438 break; |
| 546 case STATE_PAYLOAD_WRITE: | 439 case STATE_PAYLOAD_WRITE: |
| (...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 792 return DidCompleteHandshake(); | 685 return DidCompleteHandshake(); |
| 793 next_state_ = STATE_HANDSHAKE_READ; | 686 next_state_ = STATE_HANDSHAKE_READ; |
| 794 } else { | 687 } else { |
| 795 // Send the remaining bytes. | 688 // Send the remaining bytes. |
| 796 next_state_ = STATE_HANDSHAKE_WRITE; | 689 next_state_ = STATE_HANDSHAKE_WRITE; |
| 797 } | 690 } |
| 798 | 691 |
| 799 return OK; | 692 return OK; |
| 800 } | 693 } |
| 801 | 694 |
| 695 // Set server_cert_status_ and return OK or a network error. |
| 696 int SSLClientSocketWin::DoVerifyCert() { |
| 697 next_state_ = STATE_VERIFY_CERT_COMPLETE; |
| 698 |
| 699 DCHECK(server_cert_); |
| 700 |
| 701 PCCERT_CONTEXT dup_cert = CertDuplicateCertificateContext(server_cert_); |
| 702 scoped_refptr<X509Certificate> cert = |
| 703 X509Certificate::CreateFromHandle(dup_cert, |
| 704 X509Certificate::SOURCE_FROM_NETWORK); |
| 705 return verifier_.Verify(cert, hostname_, ssl_config_.rev_checking_enabled, |
| 706 &server_cert_verify_result_, &io_callback_); |
| 707 } |
| 708 |
| 709 int SSLClientSocketWin::DoVerifyCertComplete(int result) { |
| 710 LogConnectionTypeMetrics(); |
| 711 return result; |
| 712 } |
| 713 |
| 802 int SSLClientSocketWin::DoPayloadRead() { | 714 int SSLClientSocketWin::DoPayloadRead() { |
| 803 next_state_ = STATE_PAYLOAD_READ_COMPLETE; | 715 next_state_ = STATE_PAYLOAD_READ_COMPLETE; |
| 804 | 716 |
| 805 DCHECK(recv_buffer_.get()); | 717 DCHECK(recv_buffer_.get()); |
| 806 | 718 |
| 807 char* buf = recv_buffer_.get() + bytes_received_; | 719 char* buf = recv_buffer_.get() + bytes_received_; |
| 808 int buf_len = kRecvBufferSize - bytes_received_; | 720 int buf_len = kRecvBufferSize - bytes_received_; |
| 809 | 721 |
| 810 if (buf_len <= 0) { | 722 if (buf_len <= 0) { |
| 811 NOTREACHED() << "Receive buffer is too small!"; | 723 NOTREACHED() << "Receive buffer is too small!"; |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1013 } | 925 } |
| 1014 DCHECK(!server_cert_); | 926 DCHECK(!server_cert_); |
| 1015 status = QueryContextAttributes( | 927 status = QueryContextAttributes( |
| 1016 &ctxt_, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &server_cert_); | 928 &ctxt_, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &server_cert_); |
| 1017 if (status != SEC_E_OK) { | 929 if (status != SEC_E_OK) { |
| 1018 DLOG(ERROR) << "QueryContextAttributes failed: " << status; | 930 DLOG(ERROR) << "QueryContextAttributes failed: " << status; |
| 1019 return MapSecurityError(status); | 931 return MapSecurityError(status); |
| 1020 } | 932 } |
| 1021 | 933 |
| 1022 completed_handshake_ = true; | 934 completed_handshake_ = true; |
| 1023 return VerifyServerCert(); | 935 next_state_ = STATE_VERIFY_CERT; |
| 936 return OK; |
| 1024 } | 937 } |
| 1025 | 938 |
| 1026 // static | 939 void SSLClientSocketWin::LogConnectionTypeMetrics() const { |
| 1027 void SSLClientSocketWin::LogConnectionTypeMetrics( | |
| 1028 PCCERT_CHAIN_CONTEXT chain_context) { | |
| 1029 UpdateConnectionTypeHistograms(CONNECTION_SSL); | 940 UpdateConnectionTypeHistograms(CONNECTION_SSL); |
| 1030 | 941 if (server_cert_verify_result_.has_md5) |
| 1031 PCERT_SIMPLE_CHAIN first_chain = chain_context->rgpChain[0]; | |
| 1032 int num_elements = first_chain->cElement; | |
| 1033 PCERT_CHAIN_ELEMENT* element = first_chain->rgpElement; | |
| 1034 bool has_md5 = false; | |
| 1035 bool has_md2 = false; | |
| 1036 bool has_md4 = false; | |
| 1037 bool has_md5_ca = false; | |
| 1038 bool has_md2_ca = false; | |
| 1039 | |
| 1040 // Each chain starts with the end entity certificate (i = 0) and ends with | |
| 1041 // the root CA certificate (i = num_elements - 1). Do not inspect the | |
| 1042 // signature algorithm of the root CA certificate because the signature on | |
| 1043 // the trust anchor is not important. | |
| 1044 for (int i = 0; i < num_elements - 1; ++i) { | |
| 1045 PCCERT_CONTEXT cert = element[i]->pCertContext; | |
| 1046 const char* algorithm = cert->pCertInfo->SignatureAlgorithm.pszObjId; | |
| 1047 if (strcmp(algorithm, szOID_RSA_MD5RSA) == 0) { | |
| 1048 // md5WithRSAEncryption: 1.2.840.113549.1.1.4 | |
| 1049 has_md5 = true; | |
| 1050 if (i != 0) | |
| 1051 has_md5_ca = true; | |
| 1052 } else if (strcmp(algorithm, szOID_RSA_MD2RSA) == 0) { | |
| 1053 // md2WithRSAEncryption: 1.2.840.113549.1.1.2 | |
| 1054 has_md2 = true; | |
| 1055 if (i != 0) | |
| 1056 has_md2_ca = true; | |
| 1057 } else if (strcmp(algorithm, szOID_RSA_MD4RSA) == 0) { | |
| 1058 // md4WithRSAEncryption: 1.2.840.113549.1.1.3 | |
| 1059 has_md4 = true; | |
| 1060 } | |
| 1061 } | |
| 1062 | |
| 1063 if (has_md5) | |
| 1064 UpdateConnectionTypeHistograms(CONNECTION_SSL_MD5); | 942 UpdateConnectionTypeHistograms(CONNECTION_SSL_MD5); |
| 1065 if (has_md2) | 943 if (server_cert_verify_result_.has_md2) |
| 1066 UpdateConnectionTypeHistograms(CONNECTION_SSL_MD2); | 944 UpdateConnectionTypeHistograms(CONNECTION_SSL_MD2); |
| 1067 if (has_md4) | 945 if (server_cert_verify_result_.has_md4) |
| 1068 UpdateConnectionTypeHistograms(CONNECTION_SSL_MD4); | 946 UpdateConnectionTypeHistograms(CONNECTION_SSL_MD4); |
| 1069 if (has_md5_ca) | 947 if (server_cert_verify_result_.has_md5_ca) |
| 1070 UpdateConnectionTypeHistograms(CONNECTION_SSL_MD5_CA); | 948 UpdateConnectionTypeHistograms(CONNECTION_SSL_MD5_CA); |
| 1071 if (has_md2_ca) | 949 if (server_cert_verify_result_.has_md2_ca) |
| 1072 UpdateConnectionTypeHistograms(CONNECTION_SSL_MD2_CA); | 950 UpdateConnectionTypeHistograms(CONNECTION_SSL_MD2_CA); |
| 1073 } | 951 } |
| 1074 | 952 |
| 1075 // Set server_cert_status_ and return OK or a network error. | |
| 1076 int SSLClientSocketWin::VerifyServerCert() { | |
| 1077 DCHECK(server_cert_); | |
| 1078 server_cert_status_ = 0; | |
| 1079 | |
| 1080 // Build and validate certificate chain. | |
| 1081 | |
| 1082 CERT_CHAIN_PARA chain_para; | |
| 1083 memset(&chain_para, 0, sizeof(chain_para)); | |
| 1084 chain_para.cbSize = sizeof(chain_para); | |
| 1085 // TODO(wtc): consider requesting the usage szOID_PKIX_KP_SERVER_AUTH | |
| 1086 // or szOID_SERVER_GATED_CRYPTO or szOID_SGC_NETSCAPE | |
| 1087 chain_para.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND; | |
| 1088 chain_para.RequestedUsage.Usage.cUsageIdentifier = 0; | |
| 1089 chain_para.RequestedUsage.Usage.rgpszUsageIdentifier = NULL; // LPSTR* | |
| 1090 // We can set CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS to get more chains. | |
| 1091 DWORD flags = CERT_CHAIN_CACHE_END_CERT; | |
| 1092 if (ssl_config_.rev_checking_enabled) { | |
| 1093 server_cert_status_ |= CERT_STATUS_REV_CHECKING_ENABLED; | |
| 1094 flags |= CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT; | |
| 1095 } else { | |
| 1096 flags |= CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY; | |
| 1097 } | |
| 1098 PCCERT_CHAIN_CONTEXT chain_context; | |
| 1099 if (!CertGetCertificateChain( | |
| 1100 NULL, // default chain engine, HCCE_CURRENT_USER | |
| 1101 server_cert_, | |
| 1102 NULL, // current system time | |
| 1103 server_cert_->hCertStore, // search this store | |
| 1104 &chain_para, | |
| 1105 flags, | |
| 1106 NULL, // reserved | |
| 1107 &chain_context)) { | |
| 1108 return MapSecurityError(GetLastError()); | |
| 1109 } | |
| 1110 ScopedCertChainContext scoped_chain_context(chain_context); | |
| 1111 | |
| 1112 LogConnectionTypeMetrics(chain_context); | |
| 1113 | |
| 1114 server_cert_status_ |= MapCertChainErrorStatusToCertStatus( | |
| 1115 chain_context->TrustStatus.dwErrorStatus); | |
| 1116 | |
| 1117 std::wstring wstr_hostname = ASCIIToWide(hostname_); | |
| 1118 | |
| 1119 SSL_EXTRA_CERT_CHAIN_POLICY_PARA extra_policy_para; | |
| 1120 memset(&extra_policy_para, 0, sizeof(extra_policy_para)); | |
| 1121 extra_policy_para.cbSize = sizeof(extra_policy_para); | |
| 1122 extra_policy_para.dwAuthType = AUTHTYPE_SERVER; | |
| 1123 extra_policy_para.fdwChecks = 0; | |
| 1124 extra_policy_para.pwszServerName = | |
| 1125 const_cast<wchar_t*>(wstr_hostname.c_str()); | |
| 1126 | |
| 1127 CERT_CHAIN_POLICY_PARA policy_para; | |
| 1128 memset(&policy_para, 0, sizeof(policy_para)); | |
| 1129 policy_para.cbSize = sizeof(policy_para); | |
| 1130 policy_para.dwFlags = 0; | |
| 1131 policy_para.pvExtraPolicyPara = &extra_policy_para; | |
| 1132 | |
| 1133 CERT_CHAIN_POLICY_STATUS policy_status; | |
| 1134 memset(&policy_status, 0, sizeof(policy_status)); | |
| 1135 policy_status.cbSize = sizeof(policy_status); | |
| 1136 | |
| 1137 if (!CertVerifyCertificateChainPolicy( | |
| 1138 CERT_CHAIN_POLICY_SSL, | |
| 1139 chain_context, | |
| 1140 &policy_para, | |
| 1141 &policy_status)) { | |
| 1142 return MapSecurityError(GetLastError()); | |
| 1143 } | |
| 1144 | |
| 1145 if (policy_status.dwError) { | |
| 1146 server_cert_status_ |= MapNetErrorToCertStatus( | |
| 1147 MapSecurityError(policy_status.dwError)); | |
| 1148 | |
| 1149 // CertVerifyCertificateChainPolicy reports only one error (in | |
| 1150 // policy_status.dwError) if the certificate has multiple errors. | |
| 1151 // CertGetCertificateChain doesn't report certificate name mismatch, so | |
| 1152 // CertVerifyCertificateChainPolicy is the only function that can report | |
| 1153 // certificate name mismatch. | |
| 1154 // | |
| 1155 // To prevent a potential certificate name mismatch from being hidden by | |
| 1156 // some other certificate error, if we get any other certificate error, | |
| 1157 // we call CertVerifyCertificateChainPolicy again, ignoring all other | |
| 1158 // certificate errors. Both extra_policy_para.fdwChecks and | |
| 1159 // policy_para.dwFlags allow us to ignore certificate errors, so we set | |
| 1160 // them both. | |
| 1161 if (policy_status.dwError != CERT_E_CN_NO_MATCH) { | |
| 1162 const DWORD extra_ignore_flags = | |
| 1163 0x00000080 | // SECURITY_FLAG_IGNORE_REVOCATION | |
| 1164 0x00000100 | // SECURITY_FLAG_IGNORE_UNKNOWN_CA | |
| 1165 0x00002000 | // SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | |
| 1166 0x00000200; // SECURITY_FLAG_IGNORE_WRONG_USAGE | |
| 1167 extra_policy_para.fdwChecks = extra_ignore_flags; | |
| 1168 const DWORD ignore_flags = | |
| 1169 CERT_CHAIN_POLICY_IGNORE_ALL_NOT_TIME_VALID_FLAGS | | |
| 1170 CERT_CHAIN_POLICY_IGNORE_INVALID_BASIC_CONSTRAINTS_FLAG | | |
| 1171 CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG | | |
| 1172 CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG | | |
| 1173 CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG | | |
| 1174 CERT_CHAIN_POLICY_IGNORE_INVALID_POLICY_FLAG | | |
| 1175 CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS | | |
| 1176 CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG | | |
| 1177 CERT_CHAIN_POLICY_TRUST_TESTROOT_FLAG | | |
| 1178 CERT_CHAIN_POLICY_IGNORE_NOT_SUPPORTED_CRITICAL_EXT_FLAG | | |
| 1179 CERT_CHAIN_POLICY_IGNORE_PEER_TRUST_FLAG; | |
| 1180 policy_para.dwFlags = ignore_flags; | |
| 1181 if (!CertVerifyCertificateChainPolicy( | |
| 1182 CERT_CHAIN_POLICY_SSL, | |
| 1183 chain_context, | |
| 1184 &policy_para, | |
| 1185 &policy_status)) { | |
| 1186 return MapSecurityError(GetLastError()); | |
| 1187 } | |
| 1188 if (policy_status.dwError) { | |
| 1189 server_cert_status_ |= MapNetErrorToCertStatus( | |
| 1190 MapSecurityError(policy_status.dwError)); | |
| 1191 } | |
| 1192 } | |
| 1193 } | |
| 1194 | |
| 1195 // TODO(wtc): Suppress CERT_STATUS_NO_REVOCATION_MECHANISM for now to be | |
| 1196 // compatible with WinHTTP, which doesn't report this error (bug 3004). | |
| 1197 server_cert_status_ &= ~CERT_STATUS_NO_REVOCATION_MECHANISM; | |
| 1198 | |
| 1199 if (IsCertStatusError(server_cert_status_)) | |
| 1200 return MapCertStatusToNetError(server_cert_status_); | |
| 1201 return OK; | |
| 1202 } | |
| 1203 | |
| 1204 } // namespace net | 953 } // namespace net |
| 1205 | 954 |
| OLD | NEW |