Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. | 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 | 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/io_buffer.h" | 13 #include "net/base/io_buffer.h" |
| 14 #include "net/base/net_errors.h" | 14 #include "net/base/net_errors.h" |
| 15 #include "net/base/ssl_cert_request_info.h" | |
| 15 #include "net/base/ssl_info.h" | 16 #include "net/base/ssl_info.h" |
| 16 | 17 |
| 17 #pragma comment(lib, "secur32.lib") | 18 #pragma comment(lib, "secur32.lib") |
| 18 | 19 |
| 19 namespace net { | 20 namespace net { |
| 20 | 21 |
| 21 //----------------------------------------------------------------------------- | 22 //----------------------------------------------------------------------------- |
| 22 | 23 |
| 23 // TODO(wtc): See http://msdn.microsoft.com/en-us/library/aa377188(VS.85).aspx | 24 // 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. | 25 // for the other error codes we may need to map. |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 55 case SEC_E_OK: | 56 case SEC_E_OK: |
| 56 return OK; | 57 return OK; |
| 57 default: | 58 default: |
| 58 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; | 59 LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED"; |
| 59 return ERR_FAILED; | 60 return ERR_FAILED; |
| 60 } | 61 } |
| 61 } | 62 } |
| 62 | 63 |
| 63 // Returns true if the two CERT_CONTEXTs contain the same certificate. | 64 // Returns true if the two CERT_CONTEXTs contain the same certificate. |
| 64 bool SameCert(PCCERT_CONTEXT a, PCCERT_CONTEXT b) { | 65 bool SameCert(PCCERT_CONTEXT a, PCCERT_CONTEXT b) { |
| 65 return a->cbCertEncoded == b->cbCertEncoded && | 66 return a == b || |
| 66 memcmp(a->pbCertEncoded, b->pbCertEncoded, b->cbCertEncoded) == 0; | 67 (a->cbCertEncoded == b->cbCertEncoded && |
| 68 memcmp(a->pbCertEncoded, b->pbCertEncoded, b->cbCertEncoded) == 0); | |
| 67 } | 69 } |
| 68 | 70 |
| 69 //----------------------------------------------------------------------------- | 71 //----------------------------------------------------------------------------- |
| 70 | 72 |
| 71 // A bitmask consisting of these bit flags encodes which versions of the SSL | 73 // A bitmask consisting of these bit flags encodes which versions of the SSL |
| 72 // protocol (SSL 2.0, SSL 3.0, and TLS 1.0) are enabled. | 74 // protocol (SSL 2.0, SSL 3.0, and TLS 1.0) are enabled. |
| 73 enum { | 75 enum { |
| 74 SSL2 = 1 << 0, | 76 SSL2 = 1 << 0, |
| 75 SSL3 = 1 << 1, | 77 SSL3 = 1 << 1, |
| 76 TLS1 = 1 << 2, | 78 TLS1 = 1 << 2, |
| 77 SSL_VERSION_MASKS = 1 << 3 // The number of SSL version bitmasks. | 79 SSL_VERSION_MASKS = 1 << 3 // The number of SSL version bitmasks. |
| 78 }; | 80 }; |
| 79 | 81 |
| 80 // A table of CredHandles for all possible combinations of SSL versions. | 82 // CredHandleClass simply gives a default constructor and a destructor to |
| 83 // SSPI's CredHandle type (a C struct). The default constuctor is required | |
| 84 // by STL containers. | |
| 85 class CredHandleClass : public CredHandle { | |
| 86 public: | |
| 87 CredHandleClass() { | |
| 88 dwLower = 0; | |
| 89 dwUpper = 0; | |
| 90 } | |
| 91 | |
| 92 ~CredHandleClass() { | |
| 93 if (dwLower || dwUpper) { | |
|
eroman
2009/06/19 21:42:24
heh, been a while since i seen hungarian notation
| |
| 94 SECURITY_STATUS status = FreeCredentialsHandle(this); | |
| 95 DCHECK(status == SEC_E_OK); | |
| 96 } | |
| 97 } | |
| 98 }; | |
| 99 | |
| 100 // A table of CredHandles. | |
| 81 class CredHandleTable { | 101 class CredHandleTable { |
| 82 public: | 102 public: |
| 83 CredHandleTable() { | 103 CredHandleTable() {} |
| 84 memset(creds_, 0, sizeof(creds_)); | |
| 85 } | |
| 86 | 104 |
| 87 // Frees the CredHandles. | 105 ~CredHandleTable() {} |
| 88 ~CredHandleTable() { | 106 |
| 89 for (int i = 0; i < arraysize(creds_); ++i) { | 107 CredHandle* GetHandle(PCCERT_CONTEXT client_cert, int ssl_version_mask) { |
| 90 if (creds_[i].dwLower || creds_[i].dwUpper) | 108 DCHECK(0 < ssl_version_mask && |
|
eroman
2009/06/19 21:42:24
nit: I would suggest writing this as two DCHECKs:
wtc
2009/06/19 23:11:53
I didn't make this change because the second DCHEC
| |
| 91 FreeCredentialsHandle(&creds_[i]); | 109 ssl_version_mask < arraysize(anonymous_creds_)); |
| 110 CredHandle* handle; | |
| 111 AutoLock lock(lock_); | |
| 112 if (client_cert) { | |
| 113 handle = &client_cert_creds_[ | |
| 114 std::make_pair(client_cert, ssl_version_mask)]; | |
| 115 } else { | |
| 116 handle = &anonymous_creds_[ssl_version_mask]; | |
| 92 } | 117 } |
| 93 } | 118 if (!handle->dwLower && !handle->dwUpper) |
| 94 | 119 InitializeHandle(handle, client_cert, ssl_version_mask); |
| 95 CredHandle* GetHandle(int ssl_version_mask) { | |
| 96 DCHECK(0 < ssl_version_mask && ssl_version_mask < arraysize(creds_)); | |
| 97 CredHandle* handle = &creds_[ssl_version_mask]; | |
| 98 { | |
| 99 AutoLock lock(lock_); | |
| 100 if (!handle->dwLower && !handle->dwUpper) | |
| 101 InitializeHandle(handle, ssl_version_mask); | |
| 102 } | |
| 103 return handle; | 120 return handle; |
| 104 } | 121 } |
| 105 | 122 |
| 106 private: | 123 private: |
| 107 static void InitializeHandle(CredHandle* handle, int ssl_version_mask); | 124 // CredHandleMapKey is a std::pair consisting of these two components: |
| 125 // PCCERT_CONTEXT client_cert | |
| 126 // int ssl_version_mask | |
| 127 typedef std::pair<PCCERT_CONTEXT, int> CredHandleMapKey; | |
| 128 | |
| 129 typedef std::map<CredHandleMapKey, CredHandleClass> CredHandleMap; | |
|
eroman
2009/06/19 21:42:24
Hmm, I dunno about this...
Most of the STL contai
| |
| 130 | |
| 131 static void InitializeHandle(CredHandle* handle, | |
| 132 PCCERT_CONTEXT client_cert, | |
| 133 int ssl_version_mask); | |
| 108 | 134 |
| 109 Lock lock_; | 135 Lock lock_; |
| 110 CredHandle creds_[SSL_VERSION_MASKS]; | 136 |
| 137 // Anonymous (no client certificate) CredHandles for all possible | |
| 138 // combinations of SSL versions. Defined as an array for fast lookup. | |
| 139 CredHandleClass anonymous_creds_[SSL_VERSION_MASKS]; | |
| 140 | |
| 141 // CredHandles that use a client certificate. | |
| 142 CredHandleMap client_cert_creds_; | |
| 111 }; | 143 }; |
| 112 | 144 |
| 113 // static | 145 // static |
| 114 void CredHandleTable::InitializeHandle(CredHandle* handle, | 146 void CredHandleTable::InitializeHandle(CredHandle* handle, |
| 147 PCCERT_CONTEXT client_cert, | |
| 115 int ssl_version_mask) { | 148 int ssl_version_mask) { |
| 116 SCHANNEL_CRED schannel_cred = {0}; | 149 SCHANNEL_CRED schannel_cred = {0}; |
| 117 schannel_cred.dwVersion = SCHANNEL_CRED_VERSION; | 150 schannel_cred.dwVersion = SCHANNEL_CRED_VERSION; |
| 151 if (client_cert) { | |
| 152 schannel_cred.cCreds = 1; | |
| 153 schannel_cred.paCred = &client_cert; | |
| 154 // Schannel will make its own copy of client_cert. | |
| 155 } | |
| 118 | 156 |
| 119 // The global system registry settings take precedence over the value of | 157 // The global system registry settings take precedence over the value of |
| 120 // schannel_cred.grbitEnabledProtocols. | 158 // schannel_cred.grbitEnabledProtocols. |
| 121 schannel_cred.grbitEnabledProtocols = 0; | 159 schannel_cred.grbitEnabledProtocols = 0; |
| 122 if (ssl_version_mask & SSL2) | 160 if (ssl_version_mask & SSL2) |
| 123 schannel_cred.grbitEnabledProtocols |= SP_PROT_SSL2; | 161 schannel_cred.grbitEnabledProtocols |= SP_PROT_SSL2; |
| 124 if (ssl_version_mask & SSL3) | 162 if (ssl_version_mask & SSL3) |
| 125 schannel_cred.grbitEnabledProtocols |= SP_PROT_SSL3; | 163 schannel_cred.grbitEnabledProtocols |= SP_PROT_SSL3; |
| 126 if (ssl_version_mask & TLS1) | 164 if (ssl_version_mask & TLS1) |
| 127 schannel_cred.grbitEnabledProtocols |= SP_PROT_TLS1; | 165 schannel_cred.grbitEnabledProtocols |= SP_PROT_TLS1; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 173 // For the SSL sockets to share SSL sessions by session resumption handshakes, | 211 // For the SSL sockets to share SSL sessions by session resumption handshakes, |
| 174 // they need to use the same CredHandle. The GetCredHandle function creates | 212 // they need to use the same CredHandle. The GetCredHandle function creates |
| 175 // and returns a shared CredHandle. | 213 // and returns a shared CredHandle. |
| 176 // | 214 // |
| 177 // The versions of the SSL protocol enabled are a property of the CredHandle. | 215 // The versions of the SSL protocol enabled are a property of the CredHandle. |
| 178 // So we need a separate CredHandle for each combination of SSL versions. | 216 // So we need a separate CredHandle for each combination of SSL versions. |
| 179 // Most of the time Chromium will use only one or two combinations of SSL | 217 // Most of the time Chromium will use only one or two combinations of SSL |
| 180 // versions (for example, SSL3 | TLS1 for normal use, plus SSL3 when visiting | 218 // versions (for example, SSL3 | TLS1 for normal use, plus SSL3 when visiting |
| 181 // TLS-intolerant servers). These CredHandles are initialized only when | 219 // TLS-intolerant servers). These CredHandles are initialized only when |
| 182 // needed. | 220 // needed. |
| 183 // | |
| 184 // NOTE: Since the client authentication certificate is also a property of the | |
| 185 // CredHandle, SSL sockets won't be able to use the shared CredHandles when we | |
| 186 // support SSL client authentication. So we will need to refine the way we | |
| 187 // share SSL sessions. For now the simple solution of using shared | |
| 188 // CredHandles is good enough. | |
| 189 | 221 |
| 190 static CredHandle* GetCredHandle(int ssl_version_mask) { | 222 static CredHandle* GetCredHandle(PCCERT_CONTEXT client_cert, |
| 223 int ssl_version_mask) { | |
| 191 // It doesn't matter whether GetCredHandle returns NULL or a pointer to an | 224 // It doesn't matter whether GetCredHandle returns NULL or a pointer to an |
| 192 // uninitialized CredHandle on failure. Both of them cause | 225 // uninitialized CredHandle on failure. Both of them cause |
| 193 // InitializeSecurityContext to fail with SEC_E_INVALID_HANDLE. | 226 // InitializeSecurityContext to fail with SEC_E_INVALID_HANDLE. |
| 194 if (ssl_version_mask <= 0 || ssl_version_mask >= SSL_VERSION_MASKS) { | 227 if (ssl_version_mask <= 0 || ssl_version_mask >= SSL_VERSION_MASKS) { |
| 195 NOTREACHED(); | 228 NOTREACHED(); |
| 196 return NULL; | 229 return NULL; |
| 197 } | 230 } |
| 198 return Singleton<CredHandleTable>::get()->GetHandle(ssl_version_mask); | 231 return Singleton<CredHandleTable>::get()->GetHandle(client_cert, |
| 232 ssl_version_mask); | |
| 199 } | 233 } |
| 200 | 234 |
| 201 //----------------------------------------------------------------------------- | 235 //----------------------------------------------------------------------------- |
| 202 | 236 |
| 237 // A memory certificate store for client certificates. This allows us to | |
| 238 // close the "MY" system certificate store when we finish searching for | |
| 239 // client certificates. | |
| 240 class ClientCertStore { | |
| 241 public: | |
| 242 ClientCertStore() { | |
| 243 store_ = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, 0, NULL); | |
| 244 } | |
| 245 | |
| 246 ~ClientCertStore() { | |
| 247 if (store_) { | |
| 248 BOOL ok = CertCloseStore(store_, CERT_CLOSE_STORE_CHECK_FLAG); | |
| 249 DCHECK(ok); | |
| 250 } | |
| 251 } | |
| 252 | |
| 253 PCCERT_CONTEXT CopyCertContext(PCCERT_CONTEXT client_cert) { | |
| 254 PCCERT_CONTEXT copy; | |
| 255 BOOL ok = CertAddCertificateContextToStore(store_, client_cert, | |
| 256 CERT_STORE_ADD_USE_EXISTING, | |
| 257 ©); | |
| 258 DCHECK(ok); | |
| 259 return ok ? copy : NULL; | |
| 260 } | |
| 261 | |
| 262 private: | |
| 263 HCERTSTORE store_; | |
| 264 }; | |
| 265 | |
| 266 //----------------------------------------------------------------------------- | |
| 267 | |
| 203 // Size of recv_buffer_ | 268 // Size of recv_buffer_ |
| 204 // | 269 // |
| 205 // Ciphertext is decrypted one SSL record at a time, so recv_buffer_ needs to | 270 // Ciphertext is decrypted one SSL record at a time, so recv_buffer_ needs to |
| 206 // have room for a full SSL record, with the header and trailer. Here is the | 271 // have room for a full SSL record, with the header and trailer. Here is the |
| 207 // breakdown of the size: | 272 // breakdown of the size: |
| 208 // 5: SSL record header | 273 // 5: SSL record header |
| 209 // 16K: SSL record maximum size | 274 // 16K: SSL record maximum size |
| 210 // 64: >= SSL record trailer (16 or 20 have been observed) | 275 // 64: >= SSL record trailer (16 or 20 have been observed) |
| 211 static const int kRecvBufferSize = (5 + 16*1024 + 64); | 276 static const int kRecvBufferSize = (5 + 16*1024 + 64); |
| 212 | 277 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 255 if (status == SEC_E_OK) { | 320 if (status == SEC_E_OK) { |
| 256 // TODO(wtc): compute the overall security strength, taking into account | 321 // TODO(wtc): compute the overall security strength, taking into account |
| 257 // dwExchStrength and dwHashStrength. dwExchStrength needs to be | 322 // dwExchStrength and dwHashStrength. dwExchStrength needs to be |
| 258 // normalized. | 323 // normalized. |
| 259 ssl_info->security_bits = connection_info.dwCipherStrength; | 324 ssl_info->security_bits = connection_info.dwCipherStrength; |
| 260 } | 325 } |
| 261 } | 326 } |
| 262 | 327 |
| 263 void SSLClientSocketWin::GetSSLCertRequestInfo( | 328 void SSLClientSocketWin::GetSSLCertRequestInfo( |
| 264 SSLCertRequestInfo* cert_request_info) { | 329 SSLCertRequestInfo* cert_request_info) { |
| 265 // TODO(wtc): implement this. | 330 cert_request_info->host_and_port = hostname_; // TODO(wtc): no port! |
| 331 cert_request_info->client_certs.clear(); | |
| 332 | |
| 333 // Get the certificate_authorities field of the CertificateRequest message. | |
| 334 // Schannel doesn't return the certificate_types field of the | |
| 335 // CertificateRequest message to us, so we can't filter the client | |
| 336 // certificates properly. :-( | |
| 337 SecPkgContext_IssuerListInfoEx issuer_list; | |
| 338 SECURITY_STATUS status = QueryContextAttributes( | |
| 339 &ctxt_, SECPKG_ATTR_ISSUER_LIST_EX, &issuer_list); | |
| 340 if (status != SEC_E_OK) { | |
| 341 DLOG(ERROR) << "QueryContextAttributes (issuer list) failed: " << status; | |
| 342 return; | |
| 343 } | |
| 344 | |
| 345 // Client certificates of the user are in the "MY" system certificate store. | |
| 346 HCERTSTORE my_cert_store = CertOpenSystemStore(NULL, L"MY"); | |
| 347 if (!my_cert_store) { | |
| 348 FreeContextBuffer(issuer_list.aIssuers); | |
| 349 return; | |
| 350 } | |
| 351 | |
| 352 // Enumerate the client certificates. | |
| 353 CERT_CHAIN_FIND_BY_ISSUER_PARA find_by_issuer_para; | |
| 354 memset(&find_by_issuer_para, 0, sizeof(find_by_issuer_para)); | |
| 355 find_by_issuer_para.cbSize = sizeof(find_by_issuer_para); | |
| 356 find_by_issuer_para.pszUsageIdentifier = szOID_PKIX_KP_CLIENT_AUTH; | |
| 357 find_by_issuer_para.cIssuer = issuer_list.cIssuers; | |
| 358 find_by_issuer_para.rgIssuer = issuer_list.aIssuers; | |
| 359 | |
| 360 PCCERT_CHAIN_CONTEXT chain_context = NULL; | |
| 361 | |
| 362 for (;;) { | |
| 363 // Find a certificate chain. | |
| 364 chain_context = CertFindChainInStore(my_cert_store, | |
| 365 X509_ASN_ENCODING, | |
| 366 0, | |
| 367 CERT_CHAIN_FIND_BY_ISSUER, | |
| 368 &find_by_issuer_para, | |
| 369 chain_context); | |
| 370 if (!chain_context) { | |
| 371 DWORD err = GetLastError(); | |
| 372 if (err != CRYPT_E_NOT_FOUND) | |
| 373 DLOG(ERROR) << "CertFindChainInStore failed: " << err; | |
| 374 break; | |
| 375 } | |
| 376 | |
| 377 // Get the leaf certificate. | |
| 378 PCCERT_CONTEXT cert_context = | |
| 379 chain_context->rgpChain[0]->rgpElement[0]->pCertContext; | |
| 380 // Copy it to our own certificate store, so that we can close the "MY" | |
| 381 // certificate store before returning from this function. | |
| 382 PCCERT_CONTEXT cert_context2 = | |
| 383 Singleton<ClientCertStore>::get()->CopyCertContext(cert_context); | |
| 384 if (!cert_context2) { | |
| 385 NOTREACHED(); | |
| 386 continue; | |
| 387 } | |
| 388 scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle( | |
| 389 cert_context2, X509Certificate::SOURCE_LONE_CERT_IMPORT); | |
| 390 cert_request_info->client_certs.push_back(cert); | |
| 391 } | |
| 392 | |
| 393 FreeContextBuffer(issuer_list.aIssuers); | |
| 394 | |
| 395 BOOL ok = CertCloseStore(my_cert_store, CERT_CLOSE_STORE_CHECK_FLAG); | |
| 396 DCHECK(ok); | |
| 266 } | 397 } |
| 267 | 398 |
| 268 int SSLClientSocketWin::Connect(CompletionCallback* callback) { | 399 int SSLClientSocketWin::Connect(CompletionCallback* callback) { |
| 269 DCHECK(transport_.get()); | 400 DCHECK(transport_.get()); |
| 270 DCHECK(next_state_ == STATE_NONE); | 401 DCHECK(next_state_ == STATE_NONE); |
| 271 DCHECK(!user_callback_); | 402 DCHECK(!user_callback_); |
| 272 | 403 |
| 273 int ssl_version_mask = 0; | 404 int ssl_version_mask = 0; |
| 274 if (ssl_config_.ssl2_enabled) | 405 if (ssl_config_.ssl2_enabled) |
| 275 ssl_version_mask |= SSL2; | 406 ssl_version_mask |= SSL2; |
| 276 if (ssl_config_.ssl3_enabled) | 407 if (ssl_config_.ssl3_enabled) |
| 277 ssl_version_mask |= SSL3; | 408 ssl_version_mask |= SSL3; |
| 278 if (ssl_config_.tls1_enabled) | 409 if (ssl_config_.tls1_enabled) |
| 279 ssl_version_mask |= TLS1; | 410 ssl_version_mask |= TLS1; |
| 280 // If we pass 0 to GetCredHandle, we will let Schannel select the protocols, | 411 // If we pass 0 to GetCredHandle, we will let Schannel select the protocols, |
| 281 // rather than enabling no protocols. So we have to fail here. | 412 // rather than enabling no protocols. So we have to fail here. |
| 282 if (ssl_version_mask == 0) | 413 if (ssl_version_mask == 0) |
| 283 return ERR_NO_SSL_VERSIONS_ENABLED; | 414 return ERR_NO_SSL_VERSIONS_ENABLED; |
| 284 creds_ = GetCredHandle(ssl_version_mask); | 415 PCCERT_CONTEXT cert_context = NULL; |
| 416 if (ssl_config_.client_cert) | |
| 417 cert_context = ssl_config_.client_cert->os_cert_handle(); | |
| 418 creds_ = GetCredHandle(cert_context, ssl_version_mask); | |
| 285 | 419 |
| 286 memset(&ctxt_, 0, sizeof(ctxt_)); | 420 memset(&ctxt_, 0, sizeof(ctxt_)); |
| 287 | 421 |
| 288 SecBufferDesc buffer_desc; | 422 SecBufferDesc buffer_desc; |
| 289 DWORD out_flags; | 423 DWORD out_flags; |
| 290 DWORD flags = ISC_REQ_SEQUENCE_DETECT | | 424 DWORD flags = ISC_REQ_SEQUENCE_DETECT | |
| 291 ISC_REQ_REPLAY_DETECT | | 425 ISC_REQ_REPLAY_DETECT | |
| 292 ISC_REQ_CONFIDENTIALITY | | 426 ISC_REQ_CONFIDENTIALITY | |
| 293 ISC_RET_EXTENDED_ERROR | | 427 ISC_RET_EXTENDED_ERROR | |
| 294 ISC_REQ_ALLOCATE_MEMORY | | 428 ISC_REQ_ALLOCATE_MEMORY | |
| (...skipping 743 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1038 } | 1172 } |
| 1039 } | 1173 } |
| 1040 | 1174 |
| 1041 void SSLClientSocketWin::FreeSendBuffer() { | 1175 void SSLClientSocketWin::FreeSendBuffer() { |
| 1042 SECURITY_STATUS status = FreeContextBuffer(send_buffer_.pvBuffer); | 1176 SECURITY_STATUS status = FreeContextBuffer(send_buffer_.pvBuffer); |
| 1043 DCHECK(status == SEC_E_OK); | 1177 DCHECK(status == SEC_E_OK); |
| 1044 memset(&send_buffer_, 0, sizeof(send_buffer_)); | 1178 memset(&send_buffer_, 0, sizeof(send_buffer_)); |
| 1045 } | 1179 } |
| 1046 | 1180 |
| 1047 } // namespace net | 1181 } // namespace net |
| OLD | NEW |