| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "net/base/ssl_client_socket_win.h" | |
| 6 | |
| 7 #include <schnlsp.h> | |
| 8 | |
| 9 #include "base/lock.h" | |
| 10 #include "base/singleton.h" | |
| 11 #include "base/stl_util-inl.h" | |
| 12 #include "base/string_util.h" | |
| 13 #include "net/base/connection_type_histograms.h" | |
| 14 #include "net/base/io_buffer.h" | |
| 15 #include "net/base/net_errors.h" | |
| 16 #include "net/base/ssl_cert_request_info.h" | |
| 17 #include "net/base/ssl_info.h" | |
| 18 | |
| 19 #pragma comment(lib, "secur32.lib") | |
| 20 | |
| 21 namespace net { | |
| 22 | |
| 23 //----------------------------------------------------------------------------- | |
| 24 | |
| 25 // TODO(wtc): See http://msdn.microsoft.com/en-us/library/aa377188(VS.85).aspx | |
| 26 // for the other error codes we may need to map. | |
| 27 static int MapSecurityError(SECURITY_STATUS err) { | |
| 28 // There are numerous security error codes, but these are the ones we thus | |
| 29 // far find interesting. | |
| 30 switch (err) { | |
| 31 case SEC_E_WRONG_PRINCIPAL: // Schannel | |
| 32 case CERT_E_CN_NO_MATCH: // CryptoAPI | |
| 33 return ERR_CERT_COMMON_NAME_INVALID; | |
| 34 case SEC_E_UNTRUSTED_ROOT: // Schannel | |
| 35 case CERT_E_UNTRUSTEDROOT: // CryptoAPI | |
| 36 return ERR_CERT_AUTHORITY_INVALID; | |
| 37 case SEC_E_CERT_EXPIRED: // Schannel | |
| 38 case CERT_E_EXPIRED: // CryptoAPI | |
| 39 return ERR_CERT_DATE_INVALID; | |
| 40 case CRYPT_E_NO_REVOCATION_CHECK: | |
| 41 return ERR_CERT_NO_REVOCATION_MECHANISM; | |
| 42 case CRYPT_E_REVOCATION_OFFLINE: | |
| 43 return ERR_CERT_UNABLE_TO_CHECK_REVOCATION; | |
| 44 case CRYPT_E_REVOKED: // Schannel and CryptoAPI | |
| 45 return ERR_CERT_REVOKED; | |
| 46 case SEC_E_CERT_UNKNOWN: | |
| 47 case CERT_E_ROLE: | |
| 48 return ERR_CERT_INVALID; | |
| 49 // We received an unexpected_message or illegal_parameter alert message | |
| 50 // from the server. | |
| 51 case SEC_E_ILLEGAL_MESSAGE: | |
| 52 return ERR_SSL_PROTOCOL_ERROR; | |
| 53 case SEC_E_ALGORITHM_MISMATCH: | |
| 54 return ERR_SSL_VERSION_OR_CIPHER_MISMATCH; | |
| 55 case SEC_E_INVALID_HANDLE: | |
| 56 return ERR_UNEXPECTED; | |
| 57 case SEC_E_OK: | |
| 58 return OK; | |
| 59 default: | |
| 60 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; | |
| 61 return ERR_FAILED; | |
| 62 } | |
| 63 } | |
| 64 | |
| 65 // Returns true if the two CERT_CONTEXTs contain the same certificate. | |
| 66 bool SameCert(PCCERT_CONTEXT a, PCCERT_CONTEXT b) { | |
| 67 return a == b || | |
| 68 (a->cbCertEncoded == b->cbCertEncoded && | |
| 69 memcmp(a->pbCertEncoded, b->pbCertEncoded, b->cbCertEncoded) == 0); | |
| 70 } | |
| 71 | |
| 72 //----------------------------------------------------------------------------- | |
| 73 | |
| 74 // A bitmask consisting of these bit flags encodes which versions of the SSL | |
| 75 // protocol (SSL 2.0, SSL 3.0, and TLS 1.0) are enabled. | |
| 76 enum { | |
| 77 SSL2 = 1 << 0, | |
| 78 SSL3 = 1 << 1, | |
| 79 TLS1 = 1 << 2, | |
| 80 SSL_VERSION_MASKS = 1 << 3 // The number of SSL version bitmasks. | |
| 81 }; | |
| 82 | |
| 83 // CredHandleClass simply gives a default constructor and a destructor to | |
| 84 // SSPI's CredHandle type (a C struct). | |
| 85 class CredHandleClass : public CredHandle { | |
| 86 public: | |
| 87 CredHandleClass() { | |
| 88 dwLower = 0; | |
| 89 dwUpper = 0; | |
| 90 } | |
| 91 | |
| 92 ~CredHandleClass() { | |
| 93 if (dwLower || dwUpper) { | |
| 94 SECURITY_STATUS status = FreeCredentialsHandle(this); | |
| 95 DCHECK(status == SEC_E_OK); | |
| 96 } | |
| 97 } | |
| 98 }; | |
| 99 | |
| 100 // A table of CredHandles. | |
| 101 class CredHandleTable { | |
| 102 public: | |
| 103 CredHandleTable() {} | |
| 104 | |
| 105 ~CredHandleTable() { | |
| 106 STLDeleteContainerPairSecondPointers(client_cert_creds_.begin(), | |
| 107 client_cert_creds_.end()); | |
| 108 } | |
| 109 | |
| 110 CredHandle* GetHandle(PCCERT_CONTEXT client_cert, int ssl_version_mask) { | |
| 111 DCHECK(0 < ssl_version_mask && | |
| 112 ssl_version_mask < arraysize(anonymous_creds_)); | |
| 113 CredHandleClass* handle; | |
| 114 AutoLock lock(lock_); | |
| 115 if (client_cert) { | |
| 116 CredHandleMapKey key = std::make_pair(client_cert, ssl_version_mask); | |
| 117 CredHandleMap::const_iterator it = client_cert_creds_.find(key); | |
| 118 if (it == client_cert_creds_.end()) { | |
| 119 handle = new CredHandleClass; | |
| 120 client_cert_creds_[key] = handle; | |
| 121 } else { | |
| 122 handle = it->second; | |
| 123 } | |
| 124 } else { | |
| 125 handle = &anonymous_creds_[ssl_version_mask]; | |
| 126 } | |
| 127 if (!handle->dwLower && !handle->dwUpper) | |
| 128 InitializeHandle(handle, client_cert, ssl_version_mask); | |
| 129 return handle; | |
| 130 } | |
| 131 | |
| 132 private: | |
| 133 // CredHandleMapKey is a std::pair consisting of these two components: | |
| 134 // PCCERT_CONTEXT client_cert | |
| 135 // int ssl_version_mask | |
| 136 typedef std::pair<PCCERT_CONTEXT, int> CredHandleMapKey; | |
| 137 | |
| 138 typedef std::map<CredHandleMapKey, CredHandleClass*> CredHandleMap; | |
| 139 | |
| 140 static void InitializeHandle(CredHandle* handle, | |
| 141 PCCERT_CONTEXT client_cert, | |
| 142 int ssl_version_mask); | |
| 143 | |
| 144 Lock lock_; | |
| 145 | |
| 146 // Anonymous (no client certificate) CredHandles for all possible | |
| 147 // combinations of SSL versions. Defined as an array for fast lookup. | |
| 148 CredHandleClass anonymous_creds_[SSL_VERSION_MASKS]; | |
| 149 | |
| 150 // CredHandles that use a client certificate. | |
| 151 CredHandleMap client_cert_creds_; | |
| 152 }; | |
| 153 | |
| 154 // static | |
| 155 void CredHandleTable::InitializeHandle(CredHandle* handle, | |
| 156 PCCERT_CONTEXT client_cert, | |
| 157 int ssl_version_mask) { | |
| 158 SCHANNEL_CRED schannel_cred = {0}; | |
| 159 schannel_cred.dwVersion = SCHANNEL_CRED_VERSION; | |
| 160 if (client_cert) { | |
| 161 schannel_cred.cCreds = 1; | |
| 162 schannel_cred.paCred = &client_cert; | |
| 163 // Schannel will make its own copy of client_cert. | |
| 164 } | |
| 165 | |
| 166 // The global system registry settings take precedence over the value of | |
| 167 // schannel_cred.grbitEnabledProtocols. | |
| 168 schannel_cred.grbitEnabledProtocols = 0; | |
| 169 if (ssl_version_mask & SSL2) | |
| 170 schannel_cred.grbitEnabledProtocols |= SP_PROT_SSL2; | |
| 171 if (ssl_version_mask & SSL3) | |
| 172 schannel_cred.grbitEnabledProtocols |= SP_PROT_SSL3; | |
| 173 if (ssl_version_mask & TLS1) | |
| 174 schannel_cred.grbitEnabledProtocols |= SP_PROT_TLS1; | |
| 175 | |
| 176 // The default session lifetime is 36000000 milliseconds (ten hours). Set | |
| 177 // schannel_cred.dwSessionLifespan to change the number of milliseconds that | |
| 178 // Schannel keeps the session in its session cache. | |
| 179 | |
| 180 // We can set the key exchange algorithms (RSA or DH) in | |
| 181 // schannel_cred.{cSupportedAlgs,palgSupportedAlgs}. | |
| 182 | |
| 183 // Although SCH_CRED_AUTO_CRED_VALIDATION is convenient, we have to use | |
| 184 // SCH_CRED_MANUAL_CRED_VALIDATION for three reasons. | |
| 185 // 1. SCH_CRED_AUTO_CRED_VALIDATION doesn't allow us to get the certificate | |
| 186 // context if the certificate validation fails. | |
| 187 // 2. SCH_CRED_AUTO_CRED_VALIDATION returns only one error even if the | |
| 188 // certificate has multiple errors. | |
| 189 // 3. SCH_CRED_AUTO_CRED_VALIDATION doesn't allow us to ignore untrusted CA | |
| 190 // and expired certificate errors. There are only flags to ignore the | |
| 191 // name mismatch and unable-to-check-revocation errors. | |
| 192 // | |
| 193 // TODO(wtc): Look into undocumented or poorly documented flags: | |
| 194 // SCH_CRED_RESTRICTED_ROOTS | |
| 195 // SCH_CRED_REVOCATION_CHECK_CACHE_ONLY | |
| 196 // SCH_CRED_CACHE_ONLY_URL_RETRIEVAL | |
| 197 // SCH_CRED_MEMORY_STORE_CERT | |
| 198 schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS | | |
| 199 SCH_CRED_MANUAL_CRED_VALIDATION; | |
| 200 TimeStamp expiry; | |
| 201 SECURITY_STATUS status; | |
| 202 | |
| 203 status = AcquireCredentialsHandle( | |
| 204 NULL, // Not used | |
| 205 UNISP_NAME, // Microsoft Unified Security Protocol Provider | |
| 206 SECPKG_CRED_OUTBOUND, | |
| 207 NULL, // Not used | |
| 208 &schannel_cred, | |
| 209 NULL, // Not used | |
| 210 NULL, // Not used | |
| 211 handle, | |
| 212 &expiry); // Optional | |
| 213 if (status != SEC_E_OK) { | |
| 214 DLOG(ERROR) << "AcquireCredentialsHandle failed: " << status; | |
| 215 // GetHandle will return a pointer to an uninitialized CredHandle, which | |
| 216 // will cause InitializeSecurityContext to fail with SEC_E_INVALID_HANDLE. | |
| 217 } | |
| 218 } | |
| 219 | |
| 220 // For the SSL sockets to share SSL sessions by session resumption handshakes, | |
| 221 // they need to use the same CredHandle. The GetCredHandle function creates | |
| 222 // and returns a shared CredHandle. | |
| 223 // | |
| 224 // The versions of the SSL protocol enabled are a property of the CredHandle. | |
| 225 // So we need a separate CredHandle for each combination of SSL versions. | |
| 226 // Most of the time Chromium will use only one or two combinations of SSL | |
| 227 // versions (for example, SSL3 | TLS1 for normal use, plus SSL3 when visiting | |
| 228 // TLS-intolerant servers). These CredHandles are initialized only when | |
| 229 // needed. | |
| 230 | |
| 231 static CredHandle* GetCredHandle(PCCERT_CONTEXT client_cert, | |
| 232 int ssl_version_mask) { | |
| 233 // It doesn't matter whether GetCredHandle returns NULL or a pointer to an | |
| 234 // uninitialized CredHandle on failure. Both of them cause | |
| 235 // InitializeSecurityContext to fail with SEC_E_INVALID_HANDLE. | |
| 236 if (ssl_version_mask <= 0 || ssl_version_mask >= SSL_VERSION_MASKS) { | |
| 237 NOTREACHED(); | |
| 238 return NULL; | |
| 239 } | |
| 240 return Singleton<CredHandleTable>::get()->GetHandle(client_cert, | |
| 241 ssl_version_mask); | |
| 242 } | |
| 243 | |
| 244 //----------------------------------------------------------------------------- | |
| 245 | |
| 246 // A memory certificate store for client certificates. This allows us to | |
| 247 // close the "MY" system certificate store when we finish searching for | |
| 248 // client certificates. | |
| 249 class ClientCertStore { | |
| 250 public: | |
| 251 ClientCertStore() { | |
| 252 store_ = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, 0, NULL); | |
| 253 } | |
| 254 | |
| 255 ~ClientCertStore() { | |
| 256 if (store_) { | |
| 257 BOOL ok = CertCloseStore(store_, CERT_CLOSE_STORE_CHECK_FLAG); | |
| 258 DCHECK(ok); | |
| 259 } | |
| 260 } | |
| 261 | |
| 262 PCCERT_CONTEXT CopyCertContext(PCCERT_CONTEXT client_cert) { | |
| 263 PCCERT_CONTEXT copy; | |
| 264 BOOL ok = CertAddCertificateContextToStore(store_, client_cert, | |
| 265 CERT_STORE_ADD_USE_EXISTING, | |
| 266 ©); | |
| 267 DCHECK(ok); | |
| 268 return ok ? copy : NULL; | |
| 269 } | |
| 270 | |
| 271 private: | |
| 272 HCERTSTORE store_; | |
| 273 }; | |
| 274 | |
| 275 //----------------------------------------------------------------------------- | |
| 276 | |
| 277 // Size of recv_buffer_ | |
| 278 // | |
| 279 // Ciphertext is decrypted one SSL record at a time, so recv_buffer_ needs to | |
| 280 // have room for a full SSL record, with the header and trailer. Here is the | |
| 281 // breakdown of the size: | |
| 282 // 5: SSL record header | |
| 283 // 16K: SSL record maximum size | |
| 284 // 64: >= SSL record trailer (16 or 20 have been observed) | |
| 285 static const int kRecvBufferSize = (5 + 16*1024 + 64); | |
| 286 | |
| 287 SSLClientSocketWin::SSLClientSocketWin(ClientSocket* transport_socket, | |
| 288 const std::string& hostname, | |
| 289 const SSLConfig& ssl_config) | |
| 290 #pragma warning(suppress: 4355) | |
| 291 : io_callback_(this, &SSLClientSocketWin::OnIOComplete), | |
| 292 transport_(transport_socket), | |
| 293 hostname_(hostname), | |
| 294 ssl_config_(ssl_config), | |
| 295 user_callback_(NULL), | |
| 296 user_buf_len_(0), | |
| 297 next_state_(STATE_NONE), | |
| 298 creds_(NULL), | |
| 299 isc_status_(SEC_E_OK), | |
| 300 payload_send_buffer_len_(0), | |
| 301 bytes_sent_(0), | |
| 302 decrypted_ptr_(NULL), | |
| 303 bytes_decrypted_(0), | |
| 304 received_ptr_(NULL), | |
| 305 bytes_received_(0), | |
| 306 writing_first_token_(false), | |
| 307 completed_handshake_(false), | |
| 308 ignore_ok_result_(false), | |
| 309 renegotiating_(false) { | |
| 310 memset(&stream_sizes_, 0, sizeof(stream_sizes_)); | |
| 311 memset(in_buffers_, 0, sizeof(in_buffers_)); | |
| 312 memset(&send_buffer_, 0, sizeof(send_buffer_)); | |
| 313 memset(&ctxt_, 0, sizeof(ctxt_)); | |
| 314 } | |
| 315 | |
| 316 SSLClientSocketWin::~SSLClientSocketWin() { | |
| 317 Disconnect(); | |
| 318 } | |
| 319 | |
| 320 void SSLClientSocketWin::GetSSLInfo(SSLInfo* ssl_info) { | |
| 321 if (!server_cert_) | |
| 322 return; | |
| 323 | |
| 324 ssl_info->cert = server_cert_; | |
| 325 ssl_info->cert_status = server_cert_verify_result_.cert_status; | |
| 326 SecPkgContext_ConnectionInfo connection_info; | |
| 327 SECURITY_STATUS status = QueryContextAttributes( | |
| 328 &ctxt_, SECPKG_ATTR_CONNECTION_INFO, &connection_info); | |
| 329 if (status == SEC_E_OK) { | |
| 330 // TODO(wtc): compute the overall security strength, taking into account | |
| 331 // dwExchStrength and dwHashStrength. dwExchStrength needs to be | |
| 332 // normalized. | |
| 333 ssl_info->security_bits = connection_info.dwCipherStrength; | |
| 334 } | |
| 335 } | |
| 336 | |
| 337 void SSLClientSocketWin::GetSSLCertRequestInfo( | |
| 338 SSLCertRequestInfo* cert_request_info) { | |
| 339 cert_request_info->host_and_port = hostname_; // TODO(wtc): no port! | |
| 340 cert_request_info->client_certs.clear(); | |
| 341 | |
| 342 // Get the certificate_authorities field of the CertificateRequest message. | |
| 343 // Schannel doesn't return the certificate_types field of the | |
| 344 // CertificateRequest message to us, so we can't filter the client | |
| 345 // certificates properly. :-( | |
| 346 SecPkgContext_IssuerListInfoEx issuer_list; | |
| 347 SECURITY_STATUS status = QueryContextAttributes( | |
| 348 &ctxt_, SECPKG_ATTR_ISSUER_LIST_EX, &issuer_list); | |
| 349 if (status != SEC_E_OK) { | |
| 350 DLOG(ERROR) << "QueryContextAttributes (issuer list) failed: " << status; | |
| 351 return; | |
| 352 } | |
| 353 | |
| 354 // Client certificates of the user are in the "MY" system certificate store. | |
| 355 HCERTSTORE my_cert_store = CertOpenSystemStore(NULL, L"MY"); | |
| 356 if (!my_cert_store) { | |
| 357 FreeContextBuffer(issuer_list.aIssuers); | |
| 358 return; | |
| 359 } | |
| 360 | |
| 361 // Enumerate the client certificates. | |
| 362 CERT_CHAIN_FIND_BY_ISSUER_PARA find_by_issuer_para; | |
| 363 memset(&find_by_issuer_para, 0, sizeof(find_by_issuer_para)); | |
| 364 find_by_issuer_para.cbSize = sizeof(find_by_issuer_para); | |
| 365 find_by_issuer_para.pszUsageIdentifier = szOID_PKIX_KP_CLIENT_AUTH; | |
| 366 find_by_issuer_para.cIssuer = issuer_list.cIssuers; | |
| 367 find_by_issuer_para.rgIssuer = issuer_list.aIssuers; | |
| 368 | |
| 369 PCCERT_CHAIN_CONTEXT chain_context = NULL; | |
| 370 | |
| 371 for (;;) { | |
| 372 // Find a certificate chain. | |
| 373 chain_context = CertFindChainInStore(my_cert_store, | |
| 374 X509_ASN_ENCODING, | |
| 375 0, | |
| 376 CERT_CHAIN_FIND_BY_ISSUER, | |
| 377 &find_by_issuer_para, | |
| 378 chain_context); | |
| 379 if (!chain_context) { | |
| 380 DWORD err = GetLastError(); | |
| 381 if (err != CRYPT_E_NOT_FOUND) | |
| 382 DLOG(ERROR) << "CertFindChainInStore failed: " << err; | |
| 383 break; | |
| 384 } | |
| 385 | |
| 386 // Get the leaf certificate. | |
| 387 PCCERT_CONTEXT cert_context = | |
| 388 chain_context->rgpChain[0]->rgpElement[0]->pCertContext; | |
| 389 // Copy it to our own certificate store, so that we can close the "MY" | |
| 390 // certificate store before returning from this function. | |
| 391 PCCERT_CONTEXT cert_context2 = | |
| 392 Singleton<ClientCertStore>::get()->CopyCertContext(cert_context); | |
| 393 if (!cert_context2) { | |
| 394 NOTREACHED(); | |
| 395 continue; | |
| 396 } | |
| 397 scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle( | |
| 398 cert_context2, X509Certificate::SOURCE_LONE_CERT_IMPORT); | |
| 399 cert_request_info->client_certs.push_back(cert); | |
| 400 } | |
| 401 | |
| 402 FreeContextBuffer(issuer_list.aIssuers); | |
| 403 | |
| 404 BOOL ok = CertCloseStore(my_cert_store, CERT_CLOSE_STORE_CHECK_FLAG); | |
| 405 DCHECK(ok); | |
| 406 } | |
| 407 | |
| 408 int SSLClientSocketWin::Connect(CompletionCallback* callback) { | |
| 409 DCHECK(transport_.get()); | |
| 410 DCHECK(next_state_ == STATE_NONE); | |
| 411 DCHECK(!user_callback_); | |
| 412 | |
| 413 int ssl_version_mask = 0; | |
| 414 if (ssl_config_.ssl2_enabled) | |
| 415 ssl_version_mask |= SSL2; | |
| 416 if (ssl_config_.ssl3_enabled) | |
| 417 ssl_version_mask |= SSL3; | |
| 418 if (ssl_config_.tls1_enabled) | |
| 419 ssl_version_mask |= TLS1; | |
| 420 // If we pass 0 to GetCredHandle, we will let Schannel select the protocols, | |
| 421 // rather than enabling no protocols. So we have to fail here. | |
| 422 if (ssl_version_mask == 0) | |
| 423 return ERR_NO_SSL_VERSIONS_ENABLED; | |
| 424 PCCERT_CONTEXT cert_context = NULL; | |
| 425 if (ssl_config_.client_cert) | |
| 426 cert_context = ssl_config_.client_cert->os_cert_handle(); | |
| 427 creds_ = GetCredHandle(cert_context, ssl_version_mask); | |
| 428 | |
| 429 memset(&ctxt_, 0, sizeof(ctxt_)); | |
| 430 | |
| 431 SecBufferDesc buffer_desc; | |
| 432 DWORD out_flags; | |
| 433 DWORD flags = ISC_REQ_SEQUENCE_DETECT | | |
| 434 ISC_REQ_REPLAY_DETECT | | |
| 435 ISC_REQ_CONFIDENTIALITY | | |
| 436 ISC_RET_EXTENDED_ERROR | | |
| 437 ISC_REQ_ALLOCATE_MEMORY | | |
| 438 ISC_REQ_STREAM; | |
| 439 | |
| 440 send_buffer_.pvBuffer = NULL; | |
| 441 send_buffer_.BufferType = SECBUFFER_TOKEN; | |
| 442 send_buffer_.cbBuffer = 0; | |
| 443 | |
| 444 buffer_desc.cBuffers = 1; | |
| 445 buffer_desc.pBuffers = &send_buffer_; | |
| 446 buffer_desc.ulVersion = SECBUFFER_VERSION; | |
| 447 | |
| 448 TimeStamp expiry; | |
| 449 SECURITY_STATUS status; | |
| 450 | |
| 451 status = InitializeSecurityContext( | |
| 452 creds_, | |
| 453 NULL, // NULL on the first call | |
| 454 const_cast<wchar_t*>(ASCIIToWide(hostname_).c_str()), | |
| 455 flags, | |
| 456 0, // Reserved | |
| 457 SECURITY_NATIVE_DREP, // TODO(wtc): MSDN says this should be set to 0. | |
| 458 NULL, // NULL on the first call | |
| 459 0, // Reserved | |
| 460 &ctxt_, // Receives the new context handle | |
| 461 &buffer_desc, | |
| 462 &out_flags, | |
| 463 &expiry); | |
| 464 if (status != SEC_I_CONTINUE_NEEDED) { | |
| 465 DLOG(ERROR) << "InitializeSecurityContext failed: " << status; | |
| 466 return MapSecurityError(status); | |
| 467 } | |
| 468 | |
| 469 writing_first_token_ = true; | |
| 470 next_state_ = STATE_HANDSHAKE_WRITE; | |
| 471 int rv = DoLoop(OK); | |
| 472 if (rv == ERR_IO_PENDING) | |
| 473 user_callback_ = callback; | |
| 474 return rv; | |
| 475 } | |
| 476 | |
| 477 void SSLClientSocketWin::Disconnect() { | |
| 478 // TODO(wtc): Send SSL close_notify alert. | |
| 479 completed_handshake_ = false; | |
| 480 transport_->Disconnect(); | |
| 481 | |
| 482 if (send_buffer_.pvBuffer) | |
| 483 FreeSendBuffer(); | |
| 484 if (ctxt_.dwLower || ctxt_.dwUpper) { | |
| 485 DeleteSecurityContext(&ctxt_); | |
| 486 memset(&ctxt_, 0, sizeof(ctxt_)); | |
| 487 } | |
| 488 if (server_cert_) | |
| 489 server_cert_ = NULL; | |
| 490 | |
| 491 // TODO(wtc): reset more members? | |
| 492 bytes_decrypted_ = 0; | |
| 493 bytes_received_ = 0; | |
| 494 writing_first_token_ = false; | |
| 495 renegotiating_ = false; | |
| 496 } | |
| 497 | |
| 498 bool SSLClientSocketWin::IsConnected() const { | |
| 499 // Ideally, we should also check if we have received the close_notify alert | |
| 500 // message from the server, and return false in that case. We're not doing | |
| 501 // that, so this function may return a false positive. Since the upper | |
| 502 // layer (HttpNetworkTransaction) needs to handle a persistent connection | |
| 503 // closed by the server when we send a request anyway, a false positive in | |
| 504 // exchange for simpler code is a good trade-off. | |
| 505 return completed_handshake_ && transport_->IsConnected(); | |
| 506 } | |
| 507 | |
| 508 bool SSLClientSocketWin::IsConnectedAndIdle() const { | |
| 509 // Unlike IsConnected, this method doesn't return a false positive. | |
| 510 // | |
| 511 // Strictly speaking, we should check if we have received the close_notify | |
| 512 // alert message from the server, and return false in that case. Although | |
| 513 // the close_notify alert message means EOF in the SSL layer, it is just | |
| 514 // bytes to the transport layer below, so transport_->IsConnectedAndIdle() | |
| 515 // returns the desired false when we receive close_notify. | |
| 516 return completed_handshake_ && transport_->IsConnectedAndIdle(); | |
| 517 } | |
| 518 | |
| 519 int SSLClientSocketWin::Read(IOBuffer* buf, int buf_len, | |
| 520 CompletionCallback* callback) { | |
| 521 DCHECK(completed_handshake_); | |
| 522 DCHECK(next_state_ == STATE_NONE); | |
| 523 DCHECK(!user_callback_); | |
| 524 | |
| 525 // If we have surplus decrypted plaintext, satisfy the Read with it without | |
| 526 // reading more ciphertext from the transport socket. | |
| 527 if (bytes_decrypted_ != 0) { | |
| 528 int len = std::min(buf_len, bytes_decrypted_); | |
| 529 memcpy(buf->data(), decrypted_ptr_, len); | |
| 530 decrypted_ptr_ += len; | |
| 531 bytes_decrypted_ -= len; | |
| 532 if (bytes_decrypted_ == 0) { | |
| 533 decrypted_ptr_ = NULL; | |
| 534 if (bytes_received_ != 0) { | |
| 535 memmove(recv_buffer_.get(), received_ptr_, bytes_received_); | |
| 536 received_ptr_ = recv_buffer_.get(); | |
| 537 } | |
| 538 } | |
| 539 return len; | |
| 540 } | |
| 541 | |
| 542 DCHECK(!user_buf_); | |
| 543 user_buf_ = buf; | |
| 544 user_buf_len_ = buf_len; | |
| 545 | |
| 546 SetNextStateForRead(); | |
| 547 int rv = DoLoop(OK); | |
| 548 if (rv == ERR_IO_PENDING) { | |
| 549 user_callback_ = callback; | |
| 550 } else { | |
| 551 user_buf_ = NULL; | |
| 552 } | |
| 553 return rv; | |
| 554 } | |
| 555 | |
| 556 int SSLClientSocketWin::Write(IOBuffer* buf, int buf_len, | |
| 557 CompletionCallback* callback) { | |
| 558 DCHECK(completed_handshake_); | |
| 559 DCHECK(next_state_ == STATE_NONE); | |
| 560 DCHECK(!user_callback_); | |
| 561 | |
| 562 DCHECK(!user_buf_); | |
| 563 user_buf_ = buf; | |
| 564 user_buf_len_ = buf_len; | |
| 565 | |
| 566 next_state_ = STATE_PAYLOAD_ENCRYPT; | |
| 567 int rv = DoLoop(OK); | |
| 568 if (rv == ERR_IO_PENDING) { | |
| 569 user_callback_ = callback; | |
| 570 } else { | |
| 571 user_buf_ = NULL; | |
| 572 } | |
| 573 return rv; | |
| 574 } | |
| 575 | |
| 576 void SSLClientSocketWin::DoCallback(int rv) { | |
| 577 DCHECK(rv != ERR_IO_PENDING); | |
| 578 DCHECK(user_callback_); | |
| 579 | |
| 580 // since Run may result in Read being called, clear user_callback_ up front. | |
| 581 CompletionCallback* c = user_callback_; | |
| 582 user_callback_ = NULL; | |
| 583 user_buf_ = NULL; | |
| 584 c->Run(rv); | |
| 585 } | |
| 586 | |
| 587 void SSLClientSocketWin::OnIOComplete(int result) { | |
| 588 int rv = DoLoop(result); | |
| 589 if (rv != ERR_IO_PENDING) | |
| 590 DoCallback(rv); | |
| 591 } | |
| 592 | |
| 593 int SSLClientSocketWin::DoLoop(int last_io_result) { | |
| 594 DCHECK(next_state_ != STATE_NONE); | |
| 595 int rv = last_io_result; | |
| 596 do { | |
| 597 State state = next_state_; | |
| 598 next_state_ = STATE_NONE; | |
| 599 switch (state) { | |
| 600 case STATE_HANDSHAKE_READ: | |
| 601 rv = DoHandshakeRead(); | |
| 602 break; | |
| 603 case STATE_HANDSHAKE_READ_COMPLETE: | |
| 604 rv = DoHandshakeReadComplete(rv); | |
| 605 break; | |
| 606 case STATE_HANDSHAKE_WRITE: | |
| 607 rv = DoHandshakeWrite(); | |
| 608 break; | |
| 609 case STATE_HANDSHAKE_WRITE_COMPLETE: | |
| 610 rv = DoHandshakeWriteComplete(rv); | |
| 611 break; | |
| 612 case STATE_VERIFY_CERT: | |
| 613 rv = DoVerifyCert(); | |
| 614 break; | |
| 615 case STATE_VERIFY_CERT_COMPLETE: | |
| 616 rv = DoVerifyCertComplete(rv); | |
| 617 break; | |
| 618 case STATE_PAYLOAD_READ: | |
| 619 rv = DoPayloadRead(); | |
| 620 break; | |
| 621 case STATE_PAYLOAD_READ_COMPLETE: | |
| 622 rv = DoPayloadReadComplete(rv); | |
| 623 break; | |
| 624 case STATE_PAYLOAD_ENCRYPT: | |
| 625 rv = DoPayloadEncrypt(); | |
| 626 break; | |
| 627 case STATE_PAYLOAD_WRITE: | |
| 628 rv = DoPayloadWrite(); | |
| 629 break; | |
| 630 case STATE_PAYLOAD_WRITE_COMPLETE: | |
| 631 rv = DoPayloadWriteComplete(rv); | |
| 632 break; | |
| 633 default: | |
| 634 rv = ERR_UNEXPECTED; | |
| 635 NOTREACHED() << "unexpected state"; | |
| 636 break; | |
| 637 } | |
| 638 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); | |
| 639 return rv; | |
| 640 } | |
| 641 | |
| 642 int SSLClientSocketWin::DoHandshakeRead() { | |
| 643 next_state_ = STATE_HANDSHAKE_READ_COMPLETE; | |
| 644 | |
| 645 if (!recv_buffer_.get()) | |
| 646 recv_buffer_.reset(new char[kRecvBufferSize]); | |
| 647 | |
| 648 int buf_len = kRecvBufferSize - bytes_received_; | |
| 649 | |
| 650 if (buf_len <= 0) { | |
| 651 NOTREACHED() << "Receive buffer is too small!"; | |
| 652 return ERR_UNEXPECTED; | |
| 653 } | |
| 654 | |
| 655 DCHECK(!transport_buf_); | |
| 656 transport_buf_ = new IOBuffer(buf_len); | |
| 657 | |
| 658 return transport_->Read(transport_buf_, buf_len, &io_callback_); | |
| 659 } | |
| 660 | |
| 661 int SSLClientSocketWin::DoHandshakeReadComplete(int result) { | |
| 662 if (result < 0) { | |
| 663 transport_buf_ = NULL; | |
| 664 return result; | |
| 665 } | |
| 666 | |
| 667 if (transport_buf_) { | |
| 668 // A transition to STATE_HANDSHAKE_READ_COMPLETE is set in multiple places, | |
| 669 // not only in DoHandshakeRead(), so we may not have a transport_buf_. | |
| 670 DCHECK_LE(result, kRecvBufferSize - bytes_received_); | |
| 671 char* buf = recv_buffer_.get() + bytes_received_; | |
| 672 memcpy(buf, transport_buf_->data(), result); | |
| 673 transport_buf_ = NULL; | |
| 674 } | |
| 675 | |
| 676 if (result == 0 && !ignore_ok_result_) | |
| 677 return ERR_SSL_PROTOCOL_ERROR; // Incomplete response :( | |
| 678 | |
| 679 ignore_ok_result_ = false; | |
| 680 | |
| 681 bytes_received_ += result; | |
| 682 | |
| 683 // Process the contents of recv_buffer_. | |
| 684 TimeStamp expiry; | |
| 685 DWORD out_flags; | |
| 686 | |
| 687 DWORD flags = ISC_REQ_SEQUENCE_DETECT | | |
| 688 ISC_REQ_REPLAY_DETECT | | |
| 689 ISC_REQ_CONFIDENTIALITY | | |
| 690 ISC_RET_EXTENDED_ERROR | | |
| 691 ISC_REQ_ALLOCATE_MEMORY | | |
| 692 ISC_REQ_STREAM; | |
| 693 | |
| 694 if (ssl_config_.send_client_cert) | |
| 695 flags |= ISC_REQ_USE_SUPPLIED_CREDS; | |
| 696 | |
| 697 SecBufferDesc in_buffer_desc, out_buffer_desc; | |
| 698 | |
| 699 in_buffer_desc.cBuffers = 2; | |
| 700 in_buffer_desc.pBuffers = in_buffers_; | |
| 701 in_buffer_desc.ulVersion = SECBUFFER_VERSION; | |
| 702 | |
| 703 in_buffers_[0].pvBuffer = recv_buffer_.get(); | |
| 704 in_buffers_[0].cbBuffer = bytes_received_; | |
| 705 in_buffers_[0].BufferType = SECBUFFER_TOKEN; | |
| 706 | |
| 707 in_buffers_[1].pvBuffer = NULL; | |
| 708 in_buffers_[1].cbBuffer = 0; | |
| 709 in_buffers_[1].BufferType = SECBUFFER_EMPTY; | |
| 710 | |
| 711 out_buffer_desc.cBuffers = 1; | |
| 712 out_buffer_desc.pBuffers = &send_buffer_; | |
| 713 out_buffer_desc.ulVersion = SECBUFFER_VERSION; | |
| 714 | |
| 715 send_buffer_.pvBuffer = NULL; | |
| 716 send_buffer_.BufferType = SECBUFFER_TOKEN; | |
| 717 send_buffer_.cbBuffer = 0; | |
| 718 | |
| 719 isc_status_ = InitializeSecurityContext( | |
| 720 creds_, | |
| 721 &ctxt_, | |
| 722 NULL, | |
| 723 flags, | |
| 724 0, | |
| 725 SECURITY_NATIVE_DREP, | |
| 726 &in_buffer_desc, | |
| 727 0, | |
| 728 NULL, | |
| 729 &out_buffer_desc, | |
| 730 &out_flags, | |
| 731 &expiry); | |
| 732 | |
| 733 if (send_buffer_.cbBuffer != 0 && | |
| 734 (isc_status_ == SEC_E_OK || | |
| 735 isc_status_ == SEC_I_CONTINUE_NEEDED || | |
| 736 (FAILED(isc_status_) && (out_flags & ISC_RET_EXTENDED_ERROR)))) { | |
| 737 next_state_ = STATE_HANDSHAKE_WRITE; | |
| 738 return OK; | |
| 739 } | |
| 740 return DidCallInitializeSecurityContext(); | |
| 741 } | |
| 742 | |
| 743 int SSLClientSocketWin::DidCallInitializeSecurityContext() { | |
| 744 if (isc_status_ == SEC_E_INCOMPLETE_MESSAGE) { | |
| 745 next_state_ = STATE_HANDSHAKE_READ; | |
| 746 return OK; | |
| 747 } | |
| 748 | |
| 749 if (isc_status_ == SEC_E_OK) { | |
| 750 if (in_buffers_[1].BufferType == SECBUFFER_EXTRA) { | |
| 751 // Save this data for later. | |
| 752 memmove(recv_buffer_.get(), | |
| 753 recv_buffer_.get() + (bytes_received_ - in_buffers_[1].cbBuffer), | |
| 754 in_buffers_[1].cbBuffer); | |
| 755 bytes_received_ = in_buffers_[1].cbBuffer; | |
| 756 } else { | |
| 757 bytes_received_ = 0; | |
| 758 } | |
| 759 return DidCompleteHandshake(); | |
| 760 } | |
| 761 | |
| 762 if (FAILED(isc_status_)) { | |
| 763 int result = MapSecurityError(isc_status_); | |
| 764 // We told Schannel to not verify the server certificate | |
| 765 // (SCH_CRED_MANUAL_CRED_VALIDATION), so any certificate error returned by | |
| 766 // InitializeSecurityContext must be referring to the bad or missing | |
| 767 // client certificate. | |
| 768 if (IsCertificateError(result)) { | |
| 769 // TODO(wtc): Add new error codes for client certificate errors reported | |
| 770 // by the server using SSL/TLS alert messages. See the MSDN page | |
| 771 // "Schannel Error Codes for TLS and SSL Alerts", which maps TLS alert | |
| 772 // messages to Windows error codes: | |
| 773 // http://msdn.microsoft.com/en-us/library/dd721886%28VS.85%29.aspx | |
| 774 return ERR_BAD_SSL_CLIENT_AUTH_CERT; | |
| 775 } | |
| 776 return result; | |
| 777 } | |
| 778 | |
| 779 if (isc_status_ == SEC_I_INCOMPLETE_CREDENTIALS) | |
| 780 return ERR_SSL_CLIENT_AUTH_CERT_NEEDED; | |
| 781 | |
| 782 DCHECK(isc_status_ == SEC_I_CONTINUE_NEEDED); | |
| 783 if (in_buffers_[1].BufferType == SECBUFFER_EXTRA) { | |
| 784 memmove(recv_buffer_.get(), | |
| 785 recv_buffer_.get() + (bytes_received_ - in_buffers_[1].cbBuffer), | |
| 786 in_buffers_[1].cbBuffer); | |
| 787 bytes_received_ = in_buffers_[1].cbBuffer; | |
| 788 next_state_ = STATE_HANDSHAKE_READ_COMPLETE; | |
| 789 ignore_ok_result_ = true; // OK doesn't mean EOF. | |
| 790 return OK; | |
| 791 } | |
| 792 | |
| 793 bytes_received_ = 0; | |
| 794 next_state_ = STATE_HANDSHAKE_READ; | |
| 795 return OK; | |
| 796 } | |
| 797 | |
| 798 int SSLClientSocketWin::DoHandshakeWrite() { | |
| 799 next_state_ = STATE_HANDSHAKE_WRITE_COMPLETE; | |
| 800 | |
| 801 // We should have something to send. | |
| 802 DCHECK(send_buffer_.pvBuffer); | |
| 803 DCHECK(send_buffer_.cbBuffer > 0); | |
| 804 DCHECK(!transport_buf_); | |
| 805 | |
| 806 const char* buf = static_cast<char*>(send_buffer_.pvBuffer) + bytes_sent_; | |
| 807 int buf_len = send_buffer_.cbBuffer - bytes_sent_; | |
| 808 transport_buf_ = new IOBuffer(buf_len); | |
| 809 memcpy(transport_buf_->data(), buf, buf_len); | |
| 810 | |
| 811 return transport_->Write(transport_buf_, buf_len, &io_callback_); | |
| 812 } | |
| 813 | |
| 814 int SSLClientSocketWin::DoHandshakeWriteComplete(int result) { | |
| 815 DCHECK(transport_buf_); | |
| 816 transport_buf_ = NULL; | |
| 817 if (result < 0) | |
| 818 return result; | |
| 819 | |
| 820 DCHECK(result != 0); | |
| 821 | |
| 822 bytes_sent_ += result; | |
| 823 DCHECK(bytes_sent_ <= static_cast<int>(send_buffer_.cbBuffer)); | |
| 824 | |
| 825 if (bytes_sent_ >= static_cast<int>(send_buffer_.cbBuffer)) { | |
| 826 bool overflow = (bytes_sent_ > static_cast<int>(send_buffer_.cbBuffer)); | |
| 827 FreeSendBuffer(); | |
| 828 bytes_sent_ = 0; | |
| 829 if (overflow) // Bug! | |
| 830 return ERR_UNEXPECTED; | |
| 831 if (writing_first_token_) { | |
| 832 writing_first_token_ = false; | |
| 833 DCHECK(bytes_received_ == 0); | |
| 834 next_state_ = STATE_HANDSHAKE_READ; | |
| 835 return OK; | |
| 836 } | |
| 837 return DidCallInitializeSecurityContext(); | |
| 838 } | |
| 839 | |
| 840 // Send the remaining bytes. | |
| 841 next_state_ = STATE_HANDSHAKE_WRITE; | |
| 842 return OK; | |
| 843 } | |
| 844 | |
| 845 // Set server_cert_status_ and return OK or a network error. | |
| 846 int SSLClientSocketWin::DoVerifyCert() { | |
| 847 next_state_ = STATE_VERIFY_CERT_COMPLETE; | |
| 848 | |
| 849 DCHECK(server_cert_); | |
| 850 | |
| 851 return verifier_.Verify(server_cert_, hostname_, | |
| 852 ssl_config_.rev_checking_enabled, | |
| 853 &server_cert_verify_result_, &io_callback_); | |
| 854 } | |
| 855 | |
| 856 int SSLClientSocketWin::DoVerifyCertComplete(int result) { | |
| 857 // If we have been explicitly told to accept this certificate, override the | |
| 858 // result of verifier_.Verify. | |
| 859 // Eventually, we should cache the cert verification results so that we don't | |
| 860 // need to call verifier_.Verify repeatedly. But for now we need to do this. | |
| 861 // Alternatively, we might be able to store the cert's status along with | |
| 862 // the cert in the allowed_bad_certs_ set. | |
| 863 if (IsCertificateError(result) && | |
| 864 ssl_config_.allowed_bad_certs_.count(server_cert_)) | |
| 865 result = OK; | |
| 866 | |
| 867 LogConnectionTypeMetrics(); | |
| 868 if (renegotiating_) { | |
| 869 DidCompleteRenegotiation(result); | |
| 870 } else { | |
| 871 // The initial handshake, kicked off by a Connect, has completed. | |
| 872 completed_handshake_ = true; | |
| 873 // Exit DoLoop and return the result to the caller of Connect. | |
| 874 DCHECK(next_state_ == STATE_NONE); | |
| 875 } | |
| 876 return result; | |
| 877 } | |
| 878 | |
| 879 int SSLClientSocketWin::DoPayloadRead() { | |
| 880 next_state_ = STATE_PAYLOAD_READ_COMPLETE; | |
| 881 | |
| 882 DCHECK(recv_buffer_.get()); | |
| 883 | |
| 884 int buf_len = kRecvBufferSize - bytes_received_; | |
| 885 | |
| 886 if (buf_len <= 0) { | |
| 887 NOTREACHED() << "Receive buffer is too small!"; | |
| 888 return ERR_FAILED; | |
| 889 } | |
| 890 | |
| 891 DCHECK(!transport_buf_); | |
| 892 transport_buf_ = new IOBuffer(buf_len); | |
| 893 | |
| 894 return transport_->Read(transport_buf_, buf_len, &io_callback_); | |
| 895 } | |
| 896 | |
| 897 int SSLClientSocketWin::DoPayloadReadComplete(int result) { | |
| 898 if (result < 0) { | |
| 899 transport_buf_ = NULL; | |
| 900 return result; | |
| 901 } | |
| 902 if (transport_buf_) { | |
| 903 // This method is called after a state transition following DoPayloadRead(), | |
| 904 // or if SetNextStateForRead() was called. We have a transport_buf_ only | |
| 905 // in the first case, and we have to transfer the data from transport_buf_ | |
| 906 // to recv_buffer_. | |
| 907 DCHECK_LE(result, kRecvBufferSize - bytes_received_); | |
| 908 char* buf = recv_buffer_.get() + bytes_received_; | |
| 909 memcpy(buf, transport_buf_->data(), result); | |
| 910 transport_buf_ = NULL; | |
| 911 } | |
| 912 | |
| 913 if (result == 0 && !ignore_ok_result_) { | |
| 914 // TODO(wtc): Unless we have received the close_notify alert, we need to | |
| 915 // return an error code indicating that the SSL connection ended | |
| 916 // uncleanly, a potential truncation attack. | |
| 917 if (bytes_received_ != 0) | |
| 918 return ERR_FAILED; | |
| 919 return OK; | |
| 920 } | |
| 921 | |
| 922 ignore_ok_result_ = false; | |
| 923 | |
| 924 bytes_received_ += result; | |
| 925 | |
| 926 // Process the contents of recv_buffer_. | |
| 927 SecBuffer buffers[4]; | |
| 928 buffers[0].pvBuffer = recv_buffer_.get(); | |
| 929 buffers[0].cbBuffer = bytes_received_; | |
| 930 buffers[0].BufferType = SECBUFFER_DATA; | |
| 931 | |
| 932 buffers[1].BufferType = SECBUFFER_EMPTY; | |
| 933 buffers[2].BufferType = SECBUFFER_EMPTY; | |
| 934 buffers[3].BufferType = SECBUFFER_EMPTY; | |
| 935 | |
| 936 SecBufferDesc buffer_desc; | |
| 937 buffer_desc.cBuffers = 4; | |
| 938 buffer_desc.pBuffers = buffers; | |
| 939 buffer_desc.ulVersion = SECBUFFER_VERSION; | |
| 940 | |
| 941 SECURITY_STATUS status; | |
| 942 status = DecryptMessage(&ctxt_, &buffer_desc, 0, NULL); | |
| 943 | |
| 944 if (status == SEC_E_INCOMPLETE_MESSAGE) { | |
| 945 next_state_ = STATE_PAYLOAD_READ; | |
| 946 return OK; | |
| 947 } | |
| 948 | |
| 949 if (status == SEC_I_CONTEXT_EXPIRED) { | |
| 950 // Received the close_notify alert. | |
| 951 bytes_received_ = 0; | |
| 952 return OK; | |
| 953 } | |
| 954 | |
| 955 if (status != SEC_E_OK && status != SEC_I_RENEGOTIATE) { | |
| 956 DCHECK(status != SEC_E_MESSAGE_ALTERED); | |
| 957 return MapSecurityError(status); | |
| 958 } | |
| 959 | |
| 960 // The received ciphertext was decrypted in place in recv_buffer_. Remember | |
| 961 // the location and length of the decrypted plaintext and any unused | |
| 962 // ciphertext. | |
| 963 decrypted_ptr_ = NULL; | |
| 964 bytes_decrypted_ = 0; | |
| 965 received_ptr_ = NULL; | |
| 966 bytes_received_ = 0; | |
| 967 for (int i = 1; i < 4; i++) { | |
| 968 if (!decrypted_ptr_ && buffers[i].BufferType == SECBUFFER_DATA) { | |
| 969 decrypted_ptr_ = static_cast<char*>(buffers[i].pvBuffer); | |
| 970 bytes_decrypted_ = buffers[i].cbBuffer; | |
| 971 } | |
| 972 if (!received_ptr_ && buffers[i].BufferType == SECBUFFER_EXTRA) { | |
| 973 received_ptr_ = static_cast<char*>(buffers[i].pvBuffer); | |
| 974 bytes_received_ = buffers[i].cbBuffer; | |
| 975 } | |
| 976 } | |
| 977 | |
| 978 int len = 0; | |
| 979 if (bytes_decrypted_ != 0) { | |
| 980 len = std::min(user_buf_len_, bytes_decrypted_); | |
| 981 memcpy(user_buf_->data(), decrypted_ptr_, len); | |
| 982 decrypted_ptr_ += len; | |
| 983 bytes_decrypted_ -= len; | |
| 984 } | |
| 985 if (bytes_decrypted_ == 0) { | |
| 986 decrypted_ptr_ = NULL; | |
| 987 if (bytes_received_ != 0) { | |
| 988 memmove(recv_buffer_.get(), received_ptr_, bytes_received_); | |
| 989 received_ptr_ = recv_buffer_.get(); | |
| 990 } | |
| 991 } | |
| 992 | |
| 993 if (status == SEC_I_RENEGOTIATE) { | |
| 994 if (bytes_received_ != 0) { | |
| 995 // The server requested renegotiation, but there are some data yet to | |
| 996 // be decrypted. The Platform SDK WebClient.c sample doesn't handle | |
| 997 // this, so we don't know how to handle this. Assume this cannot | |
| 998 // happen. | |
| 999 LOG(ERROR) << "DecryptMessage returned SEC_I_RENEGOTIATE with a buffer " | |
| 1000 << "of type SECBUFFER_EXTRA."; | |
| 1001 return ERR_SSL_RENEGOTIATION_REQUESTED; | |
| 1002 } | |
| 1003 if (len != 0) { | |
| 1004 // The server requested renegotiation, but there are some decrypted | |
| 1005 // data. We can't start renegotiation until we have returned all | |
| 1006 // decrypted data to the caller. | |
| 1007 // | |
| 1008 // This hasn't happened during testing. Assume this cannot happen even | |
| 1009 // though we know how to handle this. | |
| 1010 LOG(ERROR) << "DecryptMessage returned SEC_I_RENEGOTIATE with a buffer " | |
| 1011 << "of type SECBUFFER_DATA."; | |
| 1012 return ERR_SSL_RENEGOTIATION_REQUESTED; | |
| 1013 } | |
| 1014 // Jump to the handshake sequence. Will come back when the rehandshake is | |
| 1015 // done. | |
| 1016 renegotiating_ = true; | |
| 1017 next_state_ = STATE_HANDSHAKE_READ_COMPLETE; | |
| 1018 ignore_ok_result_ = true; // OK doesn't mean EOF. | |
| 1019 return len; | |
| 1020 } | |
| 1021 | |
| 1022 // If we decrypted 0 bytes, don't report 0 bytes read, which would be | |
| 1023 // mistaken for EOF. Continue decrypting or read more. | |
| 1024 if (len == 0) | |
| 1025 SetNextStateForRead(); | |
| 1026 return len; | |
| 1027 } | |
| 1028 | |
| 1029 int SSLClientSocketWin::DoPayloadEncrypt() { | |
| 1030 DCHECK(user_buf_); | |
| 1031 DCHECK(user_buf_len_ > 0); | |
| 1032 | |
| 1033 ULONG message_len = std::min( | |
| 1034 stream_sizes_.cbMaximumMessage, static_cast<ULONG>(user_buf_len_)); | |
| 1035 ULONG alloc_len = | |
| 1036 message_len + stream_sizes_.cbHeader + stream_sizes_.cbTrailer; | |
| 1037 user_buf_len_ = message_len; | |
| 1038 | |
| 1039 payload_send_buffer_.reset(new char[alloc_len]); | |
| 1040 memcpy(&payload_send_buffer_[stream_sizes_.cbHeader], | |
| 1041 user_buf_->data(), message_len); | |
| 1042 | |
| 1043 SecBuffer buffers[4]; | |
| 1044 buffers[0].pvBuffer = payload_send_buffer_.get(); | |
| 1045 buffers[0].cbBuffer = stream_sizes_.cbHeader; | |
| 1046 buffers[0].BufferType = SECBUFFER_STREAM_HEADER; | |
| 1047 | |
| 1048 buffers[1].pvBuffer = &payload_send_buffer_[stream_sizes_.cbHeader]; | |
| 1049 buffers[1].cbBuffer = message_len; | |
| 1050 buffers[1].BufferType = SECBUFFER_DATA; | |
| 1051 | |
| 1052 buffers[2].pvBuffer = &payload_send_buffer_[stream_sizes_.cbHeader + | |
| 1053 message_len]; | |
| 1054 buffers[2].cbBuffer = stream_sizes_.cbTrailer; | |
| 1055 buffers[2].BufferType = SECBUFFER_STREAM_TRAILER; | |
| 1056 | |
| 1057 buffers[3].BufferType = SECBUFFER_EMPTY; | |
| 1058 | |
| 1059 SecBufferDesc buffer_desc; | |
| 1060 buffer_desc.cBuffers = 4; | |
| 1061 buffer_desc.pBuffers = buffers; | |
| 1062 buffer_desc.ulVersion = SECBUFFER_VERSION; | |
| 1063 | |
| 1064 SECURITY_STATUS status = EncryptMessage(&ctxt_, 0, &buffer_desc, 0); | |
| 1065 | |
| 1066 if (FAILED(status)) | |
| 1067 return MapSecurityError(status); | |
| 1068 | |
| 1069 payload_send_buffer_len_ = buffers[0].cbBuffer + | |
| 1070 buffers[1].cbBuffer + | |
| 1071 buffers[2].cbBuffer; | |
| 1072 DCHECK(bytes_sent_ == 0); | |
| 1073 | |
| 1074 next_state_ = STATE_PAYLOAD_WRITE; | |
| 1075 return OK; | |
| 1076 } | |
| 1077 | |
| 1078 int SSLClientSocketWin::DoPayloadWrite() { | |
| 1079 next_state_ = STATE_PAYLOAD_WRITE_COMPLETE; | |
| 1080 | |
| 1081 // We should have something to send. | |
| 1082 DCHECK(payload_send_buffer_.get()); | |
| 1083 DCHECK(payload_send_buffer_len_ > 0); | |
| 1084 DCHECK(!transport_buf_); | |
| 1085 | |
| 1086 const char* buf = payload_send_buffer_.get() + bytes_sent_; | |
| 1087 int buf_len = payload_send_buffer_len_ - bytes_sent_; | |
| 1088 transport_buf_ = new IOBuffer(buf_len); | |
| 1089 memcpy(transport_buf_->data(), buf, buf_len); | |
| 1090 | |
| 1091 return transport_->Write(transport_buf_, buf_len, &io_callback_); | |
| 1092 } | |
| 1093 | |
| 1094 int SSLClientSocketWin::DoPayloadWriteComplete(int result) { | |
| 1095 DCHECK(transport_buf_); | |
| 1096 transport_buf_ = NULL; | |
| 1097 if (result < 0) | |
| 1098 return result; | |
| 1099 | |
| 1100 DCHECK(result != 0); | |
| 1101 | |
| 1102 bytes_sent_ += result; | |
| 1103 DCHECK(bytes_sent_ <= payload_send_buffer_len_); | |
| 1104 | |
| 1105 if (bytes_sent_ >= payload_send_buffer_len_) { | |
| 1106 bool overflow = (bytes_sent_ > payload_send_buffer_len_); | |
| 1107 payload_send_buffer_.reset(); | |
| 1108 payload_send_buffer_len_ = 0; | |
| 1109 bytes_sent_ = 0; | |
| 1110 if (overflow) // Bug! | |
| 1111 return ERR_UNEXPECTED; | |
| 1112 // Done | |
| 1113 return user_buf_len_; | |
| 1114 } | |
| 1115 | |
| 1116 // Send the remaining bytes. | |
| 1117 next_state_ = STATE_PAYLOAD_WRITE; | |
| 1118 return OK; | |
| 1119 } | |
| 1120 | |
| 1121 int SSLClientSocketWin::DidCompleteHandshake() { | |
| 1122 SECURITY_STATUS status = QueryContextAttributes( | |
| 1123 &ctxt_, SECPKG_ATTR_STREAM_SIZES, &stream_sizes_); | |
| 1124 if (status != SEC_E_OK) { | |
| 1125 DLOG(ERROR) << "QueryContextAttributes (stream sizes) failed: " << status; | |
| 1126 return MapSecurityError(status); | |
| 1127 } | |
| 1128 DCHECK(!server_cert_ || renegotiating_); | |
| 1129 PCCERT_CONTEXT server_cert_handle = NULL; | |
| 1130 status = QueryContextAttributes( | |
| 1131 &ctxt_, SECPKG_ATTR_REMOTE_CERT_CONTEXT, &server_cert_handle); | |
| 1132 if (status != SEC_E_OK) { | |
| 1133 DLOG(ERROR) << "QueryContextAttributes (remote cert) failed: " << status; | |
| 1134 return MapSecurityError(status); | |
| 1135 } | |
| 1136 if (renegotiating_ && | |
| 1137 SameCert(server_cert_->os_cert_handle(), server_cert_handle)) { | |
| 1138 // We already verified the server certificate. Either it is good or the | |
| 1139 // user has accepted the certificate error. | |
| 1140 CertFreeCertificateContext(server_cert_handle); | |
| 1141 DidCompleteRenegotiation(OK); | |
| 1142 } else { | |
| 1143 server_cert_ = X509Certificate::CreateFromHandle( | |
| 1144 server_cert_handle, X509Certificate::SOURCE_FROM_NETWORK); | |
| 1145 | |
| 1146 next_state_ = STATE_VERIFY_CERT; | |
| 1147 } | |
| 1148 return OK; | |
| 1149 } | |
| 1150 | |
| 1151 // Called when a renegotiation is completed. |result| is the verification | |
| 1152 // result of the server certificate received during renegotiation. | |
| 1153 void SSLClientSocketWin::DidCompleteRenegotiation(int result) { | |
| 1154 // A rehandshake, started in the middle of a Read, has completed. | |
| 1155 renegotiating_ = false; | |
| 1156 // Pick up where we left off. Go back to reading data. | |
| 1157 if (result == OK) | |
| 1158 SetNextStateForRead(); | |
| 1159 } | |
| 1160 | |
| 1161 void SSLClientSocketWin::LogConnectionTypeMetrics() const { | |
| 1162 UpdateConnectionTypeHistograms(CONNECTION_SSL); | |
| 1163 if (server_cert_verify_result_.has_md5) | |
| 1164 UpdateConnectionTypeHistograms(CONNECTION_SSL_MD5); | |
| 1165 if (server_cert_verify_result_.has_md2) | |
| 1166 UpdateConnectionTypeHistograms(CONNECTION_SSL_MD2); | |
| 1167 if (server_cert_verify_result_.has_md4) | |
| 1168 UpdateConnectionTypeHistograms(CONNECTION_SSL_MD4); | |
| 1169 if (server_cert_verify_result_.has_md5_ca) | |
| 1170 UpdateConnectionTypeHistograms(CONNECTION_SSL_MD5_CA); | |
| 1171 if (server_cert_verify_result_.has_md2_ca) | |
| 1172 UpdateConnectionTypeHistograms(CONNECTION_SSL_MD2_CA); | |
| 1173 } | |
| 1174 | |
| 1175 void SSLClientSocketWin::SetNextStateForRead() { | |
| 1176 if (bytes_received_ == 0) { | |
| 1177 next_state_ = STATE_PAYLOAD_READ; | |
| 1178 } else { | |
| 1179 next_state_ = STATE_PAYLOAD_READ_COMPLETE; | |
| 1180 ignore_ok_result_ = true; // OK doesn't mean EOF. | |
| 1181 } | |
| 1182 } | |
| 1183 | |
| 1184 void SSLClientSocketWin::FreeSendBuffer() { | |
| 1185 SECURITY_STATUS status = FreeContextBuffer(send_buffer_.pvBuffer); | |
| 1186 DCHECK(status == SEC_E_OK); | |
| 1187 memset(&send_buffer_, 0, sizeof(send_buffer_)); | |
| 1188 } | |
| 1189 | |
| 1190 } // namespace net | |
| OLD | NEW |