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