1f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch/* 2f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * libjingle 3f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * Copyright 2004--2005, Google Inc. 4f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 5f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * Redistribution and use in source and binary forms, with or without 6f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * modification, are permitted provided that the following conditions are met: 7f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 8f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 1. Redistributions of source code must retain the above copyright notice, 9f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * this list of conditions and the following disclaimer. 10f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 2. Redistributions in binary form must reproduce the above copyright notice, 11f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * this list of conditions and the following disclaimer in the documentation 12f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * and/or other materials provided with the distribution. 13f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 3. The name of the author may not be used to endorse or promote products 14f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * derived from this software without specific prior written permission. 15f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * 16f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch */ 27f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 28f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/win32.h" 29f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#define SECURITY_WIN32 30f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include <security.h> 31f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include <schannel.h> 32f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 33f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include <iomanip> 34f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include <vector> 35f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 36f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/common.h" 37f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/logging.h" 38f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/schanneladapter.h" 39f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/sec_buffer.h" 40f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/thread.h" 41f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 42f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochnamespace talk_base { 43f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 44f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch///////////////////////////////////////////////////////////////////////////// 45f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// SChannelAdapter 46f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch///////////////////////////////////////////////////////////////////////////// 47f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 48f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochextern const ConstantLabel SECURITY_ERRORS[]; 49f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 50f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst ConstantLabel SCHANNEL_BUFFER_TYPES[] = { 51f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch KLABEL(SECBUFFER_EMPTY), // 0 52f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch KLABEL(SECBUFFER_DATA), // 1 53f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch KLABEL(SECBUFFER_TOKEN), // 2 54f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch KLABEL(SECBUFFER_PKG_PARAMS), // 3 55f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch KLABEL(SECBUFFER_MISSING), // 4 56f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch KLABEL(SECBUFFER_EXTRA), // 5 57f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch KLABEL(SECBUFFER_STREAM_TRAILER), // 6 58f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch KLABEL(SECBUFFER_STREAM_HEADER), // 7 59f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch KLABEL(SECBUFFER_MECHLIST), // 11 60f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch KLABEL(SECBUFFER_MECHLIST_SIGNATURE), // 12 61f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch KLABEL(SECBUFFER_TARGET), // 13 62f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch KLABEL(SECBUFFER_CHANNEL_BINDINGS), // 14 63f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LASTLABEL 64f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}; 65f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 66f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid DescribeBuffer(LoggingSeverity severity, const char* prefix, 67f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const SecBuffer& sb) { 68f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG_V(severity) 69f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << prefix 70f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << "(" << sb.cbBuffer 71f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << ", " << FindLabel(sb.BufferType & ~SECBUFFER_ATTRMASK, 72f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SCHANNEL_BUFFER_TYPES) 73f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << ", " << sb.pvBuffer << ")"; 74f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 75f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 76f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid DescribeBuffers(LoggingSeverity severity, const char* prefix, 77f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const SecBufferDesc* sbd) { 78f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!LOG_CHECK_LEVEL_V(severity)) 79f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 80f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG_V(severity) << prefix << "("; 81f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch for (size_t i=0; i<sbd->cBuffers; ++i) { 82f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch DescribeBuffer(severity, " ", sbd->pBuffers[i]); 83f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 84f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG_V(severity) << ")"; 85f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 86f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 87f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochconst ULONG SSL_FLAGS_DEFAULT = ISC_REQ_ALLOCATE_MEMORY 88f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch | ISC_REQ_CONFIDENTIALITY 89f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch | ISC_REQ_EXTENDED_ERROR 90f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch | ISC_REQ_INTEGRITY 91f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch | ISC_REQ_REPLAY_DETECT 92f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch | ISC_REQ_SEQUENCE_DETECT 93f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch | ISC_REQ_STREAM; 94f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch //| ISC_REQ_USE_SUPPLIED_CREDS; 95f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 96f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochtypedef std::vector<char> SChannelBuffer; 97f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 98f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochstruct SChannelAdapter::SSLImpl { 99f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch CredHandle cred; 100f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch CtxtHandle ctx; 101f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch bool cred_init, ctx_init; 102f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SChannelBuffer inbuf, outbuf, readable; 103f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SecPkgContext_StreamSizes sizes; 104f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 105f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SSLImpl() : cred_init(false), ctx_init(false) { } 106f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}; 107f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 108f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochSChannelAdapter::SChannelAdapter(AsyncSocket* socket) 109f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch : SSLAdapter(socket), state_(SSL_NONE), 110f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch restartable_(false), signal_close_(false), message_pending_(false), 111f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch impl_(new SSLImpl) { 112f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 113f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 114f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochSChannelAdapter::~SChannelAdapter() { 115f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch Cleanup(); 116f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 117f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 118f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint 119f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochSChannelAdapter::StartSSL(const char* hostname, bool restartable) { 120f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (state_ != SSL_NONE) 121f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return ERROR_ALREADY_INITIALIZED; 122f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 123f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ssl_host_name_ = hostname; 124f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch restartable_ = restartable; 125f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 126f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (socket_->GetState() != Socket::CS_CONNECTED) { 127f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch state_ = SSL_WAIT; 128f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return 0; 129f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 130f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 131f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch state_ = SSL_CONNECTING; 132f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (int err = BeginSSL()) { 133f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch Error("BeginSSL", err, false); 134f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return err; 135f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 136f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 137f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return 0; 138f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 139f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 140f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint 141f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochSChannelAdapter::BeginSSL() { 142f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_VERBOSE) << "BeginSSL: " << ssl_host_name_; 143f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(state_ == SSL_CONNECTING); 144f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 145f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SECURITY_STATUS ret; 146f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 147f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SCHANNEL_CRED sc_cred = { 0 }; 148f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch sc_cred.dwVersion = SCHANNEL_CRED_VERSION; 149f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch //sc_cred.dwMinimumCipherStrength = 128; // Note: use system default 150f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch sc_cred.dwFlags = SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_AUTO_CRED_VALIDATION; 151f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 152f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ret = AcquireCredentialsHandle(NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, 153f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch &sc_cred, NULL, NULL, &impl_->cred, NULL); 154f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (ret != SEC_E_OK) { 155f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_ERROR) << "AcquireCredentialsHandle error: " 156f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << ErrorName(ret, SECURITY_ERRORS); 157f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return ret; 158f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 159f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch impl_->cred_init = true; 160f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 161f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (LOG_CHECK_LEVEL(LS_VERBOSE)) { 162f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SecPkgCred_CipherStrengths cipher_strengths = { 0 }; 163f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ret = QueryCredentialsAttributes(&impl_->cred, 164f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SECPKG_ATTR_CIPHER_STRENGTHS, 165f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch &cipher_strengths); 166f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (SUCCEEDED(ret)) { 167f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_VERBOSE) << "SChannel cipher strength: " 168f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << cipher_strengths.dwMinimumCipherStrength << " - " 169f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << cipher_strengths.dwMaximumCipherStrength; 170f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 171f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 172f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SecPkgCred_SupportedAlgs supported_algs = { 0 }; 173f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ret = QueryCredentialsAttributes(&impl_->cred, 174f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SECPKG_ATTR_SUPPORTED_ALGS, 175f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch &supported_algs); 176f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (SUCCEEDED(ret)) { 177f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_VERBOSE) << "SChannel supported algorithms:"; 178f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch for (DWORD i=0; i<supported_algs.cSupportedAlgs; ++i) { 179f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ALG_ID alg_id = supported_algs.palgSupportedAlgs[i]; 180f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch PCCRYPT_OID_INFO oinfo = CryptFindOIDInfo(CRYPT_OID_INFO_ALGID_KEY, 181f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch &alg_id, 0); 182f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LPCWSTR alg_name = (NULL != oinfo) ? oinfo->pwszName : L"Unknown"; 183f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_VERBOSE) << " " << ToUtf8(alg_name) << " (" << alg_id << ")"; 184f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 185f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch CSecBufferBase::FreeSSPI(supported_algs.palgSupportedAlgs); 186f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 187f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 188f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 189f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ULONG flags = SSL_FLAGS_DEFAULT, ret_flags = 0; 190f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (ignore_bad_cert()) 191f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch flags |= ISC_REQ_MANUAL_CRED_VALIDATION; 192f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 193f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch CSecBufferBundle<2, CSecBufferBase::FreeSSPI> sb_out; 194f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ret = InitializeSecurityContextA(&impl_->cred, NULL, 195f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const_cast<char*>(ssl_host_name_.c_str()), 196f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch flags, 0, 0, NULL, 0, 197f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch &impl_->ctx, sb_out.desc(), 198f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch &ret_flags, NULL); 199f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (SUCCEEDED(ret)) 200f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch impl_->ctx_init = true; 201f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return ProcessContext(ret, NULL, sb_out.desc()); 202f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 203f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 204f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint 205f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochSChannelAdapter::ContinueSSL() { 206f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_VERBOSE) << "ContinueSSL"; 207f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(state_ == SSL_CONNECTING); 208f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 209f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SECURITY_STATUS ret; 210f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 211f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch CSecBufferBundle<2> sb_in; 212f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch sb_in[0].BufferType = SECBUFFER_TOKEN; 213f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch sb_in[0].cbBuffer = static_cast<unsigned long>(impl_->inbuf.size()); 214f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch sb_in[0].pvBuffer = &impl_->inbuf[0]; 215f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch //DescribeBuffers(LS_VERBOSE, "Input Buffer ", sb_in.desc()); 216f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 217f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ULONG flags = SSL_FLAGS_DEFAULT, ret_flags = 0; 218f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (ignore_bad_cert()) 219f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch flags |= ISC_REQ_MANUAL_CRED_VALIDATION; 220f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 221f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch CSecBufferBundle<2, CSecBufferBase::FreeSSPI> sb_out; 222f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ret = InitializeSecurityContextA(&impl_->cred, &impl_->ctx, 223f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const_cast<char*>(ssl_host_name_.c_str()), 224f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch flags, 0, 0, sb_in.desc(), 0, 225f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch NULL, sb_out.desc(), 226f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch &ret_flags, NULL); 227f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return ProcessContext(ret, sb_in.desc(), sb_out.desc()); 228f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 229f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 230f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint 231f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochSChannelAdapter::ProcessContext(long int status, _SecBufferDesc* sbd_in, 232f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch _SecBufferDesc* sbd_out) { 233f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LoggingSeverity level = LS_ERROR; 234f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if ((status == SEC_E_OK) 235f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch || (status != SEC_I_CONTINUE_NEEDED) 236f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch || (status != SEC_E_INCOMPLETE_MESSAGE)) { 237f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch level = LS_VERBOSE; // Expected messages 238f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 239f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG_V(level) 240f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << "InitializeSecurityContext error: " 241f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << ErrorName(status, SECURITY_ERRORS); 242f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch //if (sbd_in) 243f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // DescribeBuffers(LS_VERBOSE, "Input Buffer ", sbd_in); 244f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch //if (sbd_out) 245f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // DescribeBuffers(LS_VERBOSE, "Output Buffer ", sbd_out); 246f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 247f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (status == SEC_E_INCOMPLETE_MESSAGE) { 248f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Wait for more input from server. 249f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return Flush(); 250f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 251f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 252f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (FAILED(status)) { 253f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // We can't continue. Common errors: 254f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // SEC_E_CERT_EXPIRED - Typically, this means the computer clock is wrong. 255f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return status; 256f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 257f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 258f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Note: we check both input and output buffers for SECBUFFER_EXTRA. 259f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Experience shows it appearing in the input, but the documentation claims 260f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // it should appear in the output. 261f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch size_t extra = 0; 262f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (sbd_in) { 263f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch for (size_t i=0; i<sbd_in->cBuffers; ++i) { 264f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SecBuffer& buffer = sbd_in->pBuffers[i]; 265f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (buffer.BufferType == SECBUFFER_EXTRA) { 266f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch extra += buffer.cbBuffer; 267f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 268f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 269f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 270f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (sbd_out) { 271f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch for (size_t i=0; i<sbd_out->cBuffers; ++i) { 272f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SecBuffer& buffer = sbd_out->pBuffers[i]; 273f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (buffer.BufferType == SECBUFFER_EXTRA) { 274f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch extra += buffer.cbBuffer; 275f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (buffer.BufferType == SECBUFFER_TOKEN) { 276f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch impl_->outbuf.insert(impl_->outbuf.end(), 277f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch reinterpret_cast<char*>(buffer.pvBuffer), 278f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch reinterpret_cast<char*>(buffer.pvBuffer) + buffer.cbBuffer); 279f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 280f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 281f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 282f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 283f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (extra) { 284f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(extra <= impl_->inbuf.size()); 285f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch size_t consumed = impl_->inbuf.size() - extra; 286f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch memmove(&impl_->inbuf[0], &impl_->inbuf[consumed], extra); 287f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch impl_->inbuf.resize(extra); 288f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 289f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch impl_->inbuf.clear(); 290f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 291f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 292f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (SEC_I_CONTINUE_NEEDED == status) { 293f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Send data to server and wait for response. 294f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Note: ContinueSSL will result in a Flush, anyway. 295f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return impl_->inbuf.empty() ? Flush() : ContinueSSL(); 296f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 297f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 298f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (SEC_E_OK == status) { 299f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_VERBOSE) << "QueryContextAttributes"; 300f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch status = QueryContextAttributes(&impl_->ctx, SECPKG_ATTR_STREAM_SIZES, 301f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch &impl_->sizes); 302f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (FAILED(status)) { 303f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_ERROR) << "QueryContextAttributes error: " 304f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << ErrorName(status, SECURITY_ERRORS); 305f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return status; 306f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 307f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 308f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch state_ = SSL_CONNECTED; 309f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 310f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (int err = DecryptData()) { 311f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return err; 312f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (int err = Flush()) { 313f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return err; 314f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 315f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // If we decrypted any data, queue up a notification here 316f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch PostEvent(); 317f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Signal our connectedness 318f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch AsyncSocketAdapter::OnConnectEvent(this); 319f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 320f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return 0; 321f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 322f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 323f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (SEC_I_INCOMPLETE_CREDENTIALS == status) { 324f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // We don't support client authentication in schannel. 325f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return status; 326f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 327f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 328f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // We don't expect any other codes 329f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(false); 330f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return status; 331f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 332f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 333f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint 334f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochSChannelAdapter::DecryptData() { 335f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SChannelBuffer& inbuf = impl_->inbuf; 336f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SChannelBuffer& readable = impl_->readable; 337f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 338f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch while (!inbuf.empty()) { 339f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch CSecBufferBundle<4> in_buf; 340f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch in_buf[0].BufferType = SECBUFFER_DATA; 341f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch in_buf[0].cbBuffer = static_cast<unsigned long>(inbuf.size()); 342f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch in_buf[0].pvBuffer = &inbuf[0]; 343f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 344f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch //DescribeBuffers(LS_VERBOSE, "Decrypt In ", in_buf.desc()); 345f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SECURITY_STATUS status = DecryptMessage(&impl_->ctx, in_buf.desc(), 0, 0); 346f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch //DescribeBuffers(LS_VERBOSE, "Decrypt Out ", in_buf.desc()); 347f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 348f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Note: We are explicitly treating SEC_E_OK, SEC_I_CONTEXT_EXPIRED, and 349f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // any other successful results as continue. 350f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (SUCCEEDED(status)) { 351f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch size_t data_len = 0, extra_len = 0; 352f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch for (size_t i=0; i<in_buf.desc()->cBuffers; ++i) { 353f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (in_buf[i].BufferType == SECBUFFER_DATA) { 354f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch data_len += in_buf[i].cbBuffer; 355f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch readable.insert(readable.end(), 356f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch reinterpret_cast<char*>(in_buf[i].pvBuffer), 357f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch reinterpret_cast<char*>(in_buf[i].pvBuffer) + in_buf[i].cbBuffer); 358f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (in_buf[i].BufferType == SECBUFFER_EXTRA) { 359f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch extra_len += in_buf[i].cbBuffer; 360f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 361f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 362f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // There is a bug on Win2K where SEC_I_CONTEXT_EXPIRED is misclassified. 363f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if ((data_len == 0) && (inbuf[0] == 0x15)) { 364f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch status = SEC_I_CONTEXT_EXPIRED; 365f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 366f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (extra_len) { 367f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch size_t consumed = inbuf.size() - extra_len; 368f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch memmove(&inbuf[0], &inbuf[consumed], extra_len); 369f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch inbuf.resize(extra_len); 370f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 371f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch inbuf.clear(); 372f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 373f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // TODO: Handle SEC_I_CONTEXT_EXPIRED to do clean shutdown 374f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (status != SEC_E_OK) { 375f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_INFO) << "DecryptMessage returned continuation code: " 376f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << ErrorName(status, SECURITY_ERRORS); 377f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 378f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch continue; 379f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 380f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 381f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (status == SEC_E_INCOMPLETE_MESSAGE) { 382f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; 383f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 384f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return status; 385f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 386f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 387f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 388f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return 0; 389f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 390f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 391f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid 392f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochSChannelAdapter::Cleanup() { 393f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (impl_->ctx_init) 394f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch DeleteSecurityContext(&impl_->ctx); 395f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (impl_->cred_init) 396f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch FreeCredentialsHandle(&impl_->cred); 397f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch delete impl_; 398f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 399f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 400f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid 401f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochSChannelAdapter::PostEvent() { 402f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Check if there's anything notable to signal 403f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (impl_->readable.empty() && !signal_close_) 404f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 405f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 406f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Only one post in the queue at a time 407f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (message_pending_) 408f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 409f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 410f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (Thread* thread = Thread::Current()) { 411f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch message_pending_ = true; 412f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch thread->Post(this); 413f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 414f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_ERROR) << "No thread context available for SChannelAdapter"; 415f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(false); 416f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 417f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 418f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 419f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid 420f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochSChannelAdapter::Error(const char* context, int err, bool signal) { 421f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_WARNING) << "SChannelAdapter::Error(" 422f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << context << ", " 423f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch << ErrorName(err, SECURITY_ERRORS) << ")"; 424f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch state_ = SSL_ERROR; 425f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SetError(err); 426f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (signal) 427f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch AsyncSocketAdapter::OnCloseEvent(this, err); 428f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 429f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 430f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint 431f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochSChannelAdapter::Read() { 432f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch char buffer[4096]; 433f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SChannelBuffer& inbuf = impl_->inbuf; 434f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch while (true) { 435f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int ret = AsyncSocketAdapter::Recv(buffer, sizeof(buffer)); 436f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (ret > 0) { 437f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch inbuf.insert(inbuf.end(), buffer, buffer + ret); 438f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (GetError() == EWOULDBLOCK) { 439f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return 0; // Blocking 440f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 441f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return GetError(); 442f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 443f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 444f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 445f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 446f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint 447f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochSChannelAdapter::Flush() { 448f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int result = 0; 449f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch size_t pos = 0; 450f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SChannelBuffer& outbuf = impl_->outbuf; 451f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch while (pos < outbuf.size()) { 452f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch int sent = AsyncSocketAdapter::Send(&outbuf[pos], outbuf.size() - pos); 453f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (sent > 0) { 454f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch pos += sent; 455f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (GetError() == EWOULDBLOCK) { 456f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; // Blocking 457f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 458f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch result = GetError(); 459f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; 460f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 461f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 462f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (int remainder = outbuf.size() - pos) { 463f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch memmove(&outbuf[0], &outbuf[pos], remainder); 464f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch outbuf.resize(remainder); 465f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 466f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch outbuf.clear(); 467f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 468f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return result; 469f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 470f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 471f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// 472f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// AsyncSocket Implementation 473f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch// 474f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 475f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint 476f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochSChannelAdapter::Send(const void* pv, size_t cb) { 477f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch switch (state_) { 478f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case SSL_NONE: 479f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return AsyncSocketAdapter::Send(pv, cb); 480f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 481f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case SSL_WAIT: 482f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case SSL_CONNECTING: 483f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SetError(EWOULDBLOCK); 484f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return SOCKET_ERROR; 485f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 486f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case SSL_CONNECTED: 487f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; 488f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 489f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case SSL_ERROR: 490f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch default: 491f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return SOCKET_ERROR; 492f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 493f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 494f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch size_t written = 0; 495f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SChannelBuffer& outbuf = impl_->outbuf; 496f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch while (written < cb) { 497f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch const size_t encrypt_len = std::min<size_t>(cb - written, 498f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch impl_->sizes.cbMaximumMessage); 499f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 500f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch CSecBufferBundle<4> out_buf; 501f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch out_buf[0].BufferType = SECBUFFER_STREAM_HEADER; 502f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch out_buf[0].cbBuffer = impl_->sizes.cbHeader; 503f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch out_buf[1].BufferType = SECBUFFER_DATA; 504f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch out_buf[1].cbBuffer = static_cast<unsigned long>(encrypt_len); 505f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch out_buf[2].BufferType = SECBUFFER_STREAM_TRAILER; 506f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch out_buf[2].cbBuffer = impl_->sizes.cbTrailer; 507f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 508f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch size_t packet_len = out_buf[0].cbBuffer 509f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch + out_buf[1].cbBuffer 510f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch + out_buf[2].cbBuffer; 511f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 512f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SChannelBuffer message; 513f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch message.resize(packet_len); 514f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch out_buf[0].pvBuffer = &message[0]; 515f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch out_buf[1].pvBuffer = &message[out_buf[0].cbBuffer]; 516f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch out_buf[2].pvBuffer = &message[out_buf[0].cbBuffer + out_buf[1].cbBuffer]; 517f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 518f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch memcpy(out_buf[1].pvBuffer, 519f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch static_cast<const char*>(pv) + written, 520f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch encrypt_len); 521f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 522f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch //DescribeBuffers(LS_VERBOSE, "Encrypt In ", out_buf.desc()); 523f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SECURITY_STATUS res = EncryptMessage(&impl_->ctx, 0, out_buf.desc(), 0); 524f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch //DescribeBuffers(LS_VERBOSE, "Encrypt Out ", out_buf.desc()); 525f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 526f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (FAILED(res)) { 527f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch Error("EncryptMessage", res, false); 528f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return SOCKET_ERROR; 529f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 530f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 531f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // We assume that the header and data segments do not change length, 532f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // or else encrypting the concatenated packet in-place is wrong. 533f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(out_buf[0].cbBuffer == impl_->sizes.cbHeader); 534f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(out_buf[1].cbBuffer == static_cast<unsigned long>(encrypt_len)); 535f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 536f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // However, the length of the trailer may change due to padding. 537f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(out_buf[2].cbBuffer <= impl_->sizes.cbTrailer); 538f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 539f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch packet_len = out_buf[0].cbBuffer 540f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch + out_buf[1].cbBuffer 541f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch + out_buf[2].cbBuffer; 542f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 543f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch written += encrypt_len; 544f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch outbuf.insert(outbuf.end(), &message[0], &message[packet_len-1]+1); 545f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 546f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 547f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (int err = Flush()) { 548f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch state_ = SSL_ERROR; 549f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SetError(err); 550f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return SOCKET_ERROR; 551f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 552f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 553f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return static_cast<int>(written); 554f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 555f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 556f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint 557f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochSChannelAdapter::Recv(void* pv, size_t cb) { 558f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch switch (state_) { 559f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case SSL_NONE: 560f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return AsyncSocketAdapter::Recv(pv, cb); 561f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 562f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case SSL_WAIT: 563f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case SSL_CONNECTING: 564f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SetError(EWOULDBLOCK); 565f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return SOCKET_ERROR; 566f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 567f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case SSL_CONNECTED: 568f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch break; 569f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 570f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch case SSL_ERROR: 571f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch default: 572f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return SOCKET_ERROR; 573f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 574f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 575f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SChannelBuffer& readable = impl_->readable; 576f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (readable.empty()) { 577f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch SetError(EWOULDBLOCK); 578f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return SOCKET_ERROR; 579f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 580f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch size_t read = _min(cb, readable.size()); 581f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch memcpy(pv, &readable[0], read); 582f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (size_t remaining = readable.size() - read) { 583f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch memmove(&readable[0], &readable[read], remaining); 584f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch readable.resize(remaining); 585f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else { 586f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch readable.clear(); 587f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 588f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 589f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch PostEvent(); 590f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return static_cast<int>(read); 591f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 592f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 593f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochint 594f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochSChannelAdapter::Close() { 595f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!impl_->readable.empty()) { 596f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(WARNING) << "SChannelAdapter::Close with readable data"; 597f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Note: this isn't strictly an error, but we're using it temporarily to 598f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // track bugs. 599f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch //ASSERT(false); 600f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 601f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (state_ == SSL_CONNECTED) { 602f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch DWORD token = SCHANNEL_SHUTDOWN; 603f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch CSecBufferBundle<1> sb_in; 604f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch sb_in[0].BufferType = SECBUFFER_TOKEN; 605f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch sb_in[0].cbBuffer = sizeof(token); 606f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch sb_in[0].pvBuffer = &token; 607f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ApplyControlToken(&impl_->ctx, sb_in.desc()); 608f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // TODO: In theory, to do a nice shutdown, we need to begin shutdown 609f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // negotiation with more calls to InitializeSecurityContext. Since the 610f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // socket api doesn't support nice shutdown at this point, we don't bother. 611f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 612f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch Cleanup(); 613f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch impl_ = new SSLImpl; 614f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch state_ = restartable_ ? SSL_WAIT : SSL_NONE; 615f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch signal_close_ = false; 616f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch message_pending_ = false; 617f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return AsyncSocketAdapter::Close(); 618f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 619f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 620f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochSocket::ConnState 621f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochSChannelAdapter::GetState() const { 622f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (signal_close_) 623f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return CS_CONNECTED; 624f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ConnState state = socket_->GetState(); 625f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if ((state == CS_CONNECTED) 626f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch && ((state_ == SSL_WAIT) || (state_ == SSL_CONNECTING))) 627f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch state = CS_CONNECTING; 628f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return state; 629f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 630f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 631f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid 632f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochSChannelAdapter::OnConnectEvent(AsyncSocket* socket) { 633f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch LOG(LS_VERBOSE) << "SChannelAdapter::OnConnectEvent"; 634f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (state_ != SSL_WAIT) { 635f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch ASSERT(state_ == SSL_NONE); 636f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch AsyncSocketAdapter::OnConnectEvent(socket); 637f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 638f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 639f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 640f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch state_ = SSL_CONNECTING; 641f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (int err = BeginSSL()) { 642f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch Error("BeginSSL", err); 643f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 644f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 645f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 646f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid 647f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochSChannelAdapter::OnReadEvent(AsyncSocket* socket) { 648f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (state_ == SSL_NONE) { 649f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch AsyncSocketAdapter::OnReadEvent(socket); 650f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 651f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 652f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 653f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (int err = Read()) { 654f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch Error("Read", err); 655f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 656f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 657f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 658f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (impl_->inbuf.empty()) 659f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 660f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 661f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (state_ == SSL_CONNECTED) { 662f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (int err = DecryptData()) { 663f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch Error("DecryptData", err); 664f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (!impl_->readable.empty()) { 665f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch AsyncSocketAdapter::OnReadEvent(this); 666f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 667f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (state_ == SSL_CONNECTING) { 668f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (int err = ContinueSSL()) { 669f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch Error("ContinueSSL", err); 670f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 671f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 672f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 673f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 674f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid 675f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochSChannelAdapter::OnWriteEvent(AsyncSocket* socket) { 676f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (state_ == SSL_NONE) { 677f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch AsyncSocketAdapter::OnWriteEvent(socket); 678f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 679f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 680f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 681f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (int err = Flush()) { 682f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch Error("Flush", err); 683f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 684f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 685f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 686f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // See if we have more data to write 687f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!impl_->outbuf.empty()) 688f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 689f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 690f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // Buffer is empty, submit notification 691f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (state_ == SSL_CONNECTED) { 692f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch AsyncSocketAdapter::OnWriteEvent(socket); 693f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 694f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 695f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 696f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid 697f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochSChannelAdapter::OnCloseEvent(AsyncSocket* socket, int err) { 698f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if ((state_ == SSL_NONE) || impl_->readable.empty()) { 699f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch AsyncSocketAdapter::OnCloseEvent(socket, err); 700f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; 701f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 702f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 703f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // If readable is non-empty, then we have a pending Message 704f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch // that will allow us to signal close (eventually). 705f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch signal_close_ = true; 706f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 707f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 708f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid 709f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochSChannelAdapter::OnMessage(Message* pmsg) { 710f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!message_pending_) 711f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch return; // This occurs when socket is closed 712f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 713f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch message_pending_ = false; 714f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch if (!impl_->readable.empty()) { 715f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch AsyncSocketAdapter::OnReadEvent(this); 716f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } else if (signal_close_) { 717f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch signal_close_ = false; 718f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch AsyncSocketAdapter::OnCloseEvent(this, 0); // TODO: cache this error? 719f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch } 720f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} 721f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch 722f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch} // namespace talk_base 723