147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org/*
247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *
447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  Use of this source code is governed by a BSD-style license
547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  that can be found in the LICENSE file in the root of the source
647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  tree. An additional intellectual property rights grant can be found
747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  in the file PATENTS.  All contributing project authors may
847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org */
1047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/win32.h"
1247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#define SECURITY_WIN32
1347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <security.h>
1447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <schannel.h>
1547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <iomanip>
1747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <vector>
1847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/common.h"
2047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/logging.h"
2147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/schanneladapter.h"
2247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/sec_buffer.h"
2347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/thread.h"
2447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgnamespace rtc {
2647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org/////////////////////////////////////////////////////////////////////////////
2847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// SChannelAdapter
2947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org/////////////////////////////////////////////////////////////////////////////
3047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
3147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgextern const ConstantLabel SECURITY_ERRORS[];
3247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
3347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgconst ConstantLabel SCHANNEL_BUFFER_TYPES[] = {
3447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  KLABEL(SECBUFFER_EMPTY),              //  0
3547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  KLABEL(SECBUFFER_DATA),               //  1
3647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  KLABEL(SECBUFFER_TOKEN),              //  2
3747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  KLABEL(SECBUFFER_PKG_PARAMS),         //  3
3847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  KLABEL(SECBUFFER_MISSING),            //  4
3947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  KLABEL(SECBUFFER_EXTRA),              //  5
4047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  KLABEL(SECBUFFER_STREAM_TRAILER),     //  6
4147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  KLABEL(SECBUFFER_STREAM_HEADER),      //  7
4247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  KLABEL(SECBUFFER_MECHLIST),           // 11
4347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  KLABEL(SECBUFFER_MECHLIST_SIGNATURE), // 12
4447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  KLABEL(SECBUFFER_TARGET),             // 13
4547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  KLABEL(SECBUFFER_CHANNEL_BINDINGS),   // 14
4647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  LASTLABEL
4747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org};
4847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
4947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid DescribeBuffer(LoggingSeverity severity, const char* prefix,
5047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                    const SecBuffer& sb) {
5147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  LOG_V(severity)
5247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    << prefix
5347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    << "(" << sb.cbBuffer
5447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    << ", " << FindLabel(sb.BufferType & ~SECBUFFER_ATTRMASK,
5547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                          SCHANNEL_BUFFER_TYPES)
5647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    << ", " << sb.pvBuffer << ")";
5747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
5847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
5947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid DescribeBuffers(LoggingSeverity severity, const char* prefix,
6047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                     const SecBufferDesc* sbd) {
6147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!LOG_CHECK_LEVEL_V(severity))
6247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return;
6347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  LOG_V(severity) << prefix << "(";
6447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  for (size_t i=0; i<sbd->cBuffers; ++i) {
6547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    DescribeBuffer(severity, "  ", sbd->pBuffers[i]);
6647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
6747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  LOG_V(severity) << ")";
6847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
6947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
7047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgconst ULONG SSL_FLAGS_DEFAULT = ISC_REQ_ALLOCATE_MEMORY
7147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                              | ISC_REQ_CONFIDENTIALITY
7247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                              | ISC_REQ_EXTENDED_ERROR
7347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                              | ISC_REQ_INTEGRITY
7447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                              | ISC_REQ_REPLAY_DETECT
7547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                              | ISC_REQ_SEQUENCE_DETECT
7647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                              | ISC_REQ_STREAM;
7747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                              //| ISC_REQ_USE_SUPPLIED_CREDS;
7847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
7947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgtypedef std::vector<char> SChannelBuffer;
8047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
8147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstruct SChannelAdapter::SSLImpl {
8247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CredHandle cred;
8347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CtxtHandle ctx;
8447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  bool cred_init, ctx_init;
8547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SChannelBuffer inbuf, outbuf, readable;
8647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SecPkgContext_StreamSizes sizes;
8747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
8847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SSLImpl() : cred_init(false), ctx_init(false) { }
8947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org};
9047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
9147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSChannelAdapter::SChannelAdapter(AsyncSocket* socket)
9247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  : SSLAdapter(socket), state_(SSL_NONE),
9347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    restartable_(false), signal_close_(false), message_pending_(false),
9447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    impl_(new SSLImpl) {
9547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
9647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
9747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSChannelAdapter::~SChannelAdapter() {
9847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  Cleanup();
9947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
10047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
10147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint
10247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSChannelAdapter::StartSSL(const char* hostname, bool restartable) {
10347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (state_ != SSL_NONE)
10447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return ERROR_ALREADY_INITIALIZED;
10547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
10647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ssl_host_name_ = hostname;
10747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  restartable_ = restartable;
10847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
10947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (socket_->GetState() != Socket::CS_CONNECTED) {
11047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    state_ = SSL_WAIT;
11147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return 0;
11247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
11347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
11447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  state_ = SSL_CONNECTING;
11547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (int err = BeginSSL()) {
11647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    Error("BeginSSL", err, false);
11747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return err;
11847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
11947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
12047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return 0;
12147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
12247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
12347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint
12447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSChannelAdapter::BeginSSL() {
12547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  LOG(LS_VERBOSE) << "BeginSSL: " << ssl_host_name_;
12647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(state_ == SSL_CONNECTING);
12747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
12847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SECURITY_STATUS ret;
12947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
13047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SCHANNEL_CRED sc_cred = { 0 };
13147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  sc_cred.dwVersion = SCHANNEL_CRED_VERSION;
13247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  //sc_cred.dwMinimumCipherStrength = 128; // Note: use system default
13347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  sc_cred.dwFlags = SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_AUTO_CRED_VALIDATION;
13447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
135b957cd8adc24f22701221b5755a87a8dccfe0b71sergeyu@chromium.org  ret = AcquireCredentialsHandle(NULL, const_cast<LPTSTR>(UNISP_NAME),
136b957cd8adc24f22701221b5755a87a8dccfe0b71sergeyu@chromium.org                                 SECPKG_CRED_OUTBOUND, NULL, &sc_cred, NULL,
137b957cd8adc24f22701221b5755a87a8dccfe0b71sergeyu@chromium.org                                 NULL, &impl_->cred, NULL);
13847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (ret != SEC_E_OK) {
13947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_ERROR) << "AcquireCredentialsHandle error: "
14047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                  << ErrorName(ret, SECURITY_ERRORS);
14147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return ret;
14247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
14347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  impl_->cred_init = true;
14447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
14547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (LOG_CHECK_LEVEL(LS_VERBOSE)) {
14647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    SecPkgCred_CipherStrengths cipher_strengths = { 0 };
14747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ret = QueryCredentialsAttributes(&impl_->cred,
14847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                     SECPKG_ATTR_CIPHER_STRENGTHS,
14947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                     &cipher_strengths);
15047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (SUCCEEDED(ret)) {
15147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      LOG(LS_VERBOSE) << "SChannel cipher strength: "
15247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                  << cipher_strengths.dwMinimumCipherStrength << " - "
15347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                  << cipher_strengths.dwMaximumCipherStrength;
15447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
15547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
15647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    SecPkgCred_SupportedAlgs supported_algs = { 0 };
15747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ret = QueryCredentialsAttributes(&impl_->cred,
15847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                     SECPKG_ATTR_SUPPORTED_ALGS,
15947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                     &supported_algs);
16047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (SUCCEEDED(ret)) {
16147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      LOG(LS_VERBOSE) << "SChannel supported algorithms:";
16247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      for (DWORD i=0; i<supported_algs.cSupportedAlgs; ++i) {
16347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        ALG_ID alg_id = supported_algs.palgSupportedAlgs[i];
16447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        PCCRYPT_OID_INFO oinfo = CryptFindOIDInfo(CRYPT_OID_INFO_ALGID_KEY,
16547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                                  &alg_id, 0);
16647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        LPCWSTR alg_name = (NULL != oinfo) ? oinfo->pwszName : L"Unknown";
16747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        LOG(LS_VERBOSE) << "  " << ToUtf8(alg_name) << " (" << alg_id << ")";
16847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
16947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      CSecBufferBase::FreeSSPI(supported_algs.palgSupportedAlgs);
17047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
17147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
17247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
17347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ULONG flags = SSL_FLAGS_DEFAULT, ret_flags = 0;
17447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (ignore_bad_cert())
17547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    flags |= ISC_REQ_MANUAL_CRED_VALIDATION;
17647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
17747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CSecBufferBundle<2, CSecBufferBase::FreeSSPI> sb_out;
17847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ret = InitializeSecurityContextA(&impl_->cred, NULL,
17947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                   const_cast<char*>(ssl_host_name_.c_str()),
18047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                   flags, 0, 0, NULL, 0,
18147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                   &impl_->ctx, sb_out.desc(),
18247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                   &ret_flags, NULL);
18347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (SUCCEEDED(ret))
18447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    impl_->ctx_init = true;
18547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return ProcessContext(ret, NULL, sb_out.desc());
18647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
18747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
18847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint
18947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSChannelAdapter::ContinueSSL() {
19047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  LOG(LS_VERBOSE) << "ContinueSSL";
19147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(state_ == SSL_CONNECTING);
19247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
19347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SECURITY_STATUS ret;
19447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
19547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CSecBufferBundle<2> sb_in;
19647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  sb_in[0].BufferType = SECBUFFER_TOKEN;
19747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  sb_in[0].cbBuffer = static_cast<unsigned long>(impl_->inbuf.size());
19847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  sb_in[0].pvBuffer = &impl_->inbuf[0];
19947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  //DescribeBuffers(LS_VERBOSE, "Input Buffer ", sb_in.desc());
20047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
20147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ULONG flags = SSL_FLAGS_DEFAULT, ret_flags = 0;
20247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (ignore_bad_cert())
20347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    flags |= ISC_REQ_MANUAL_CRED_VALIDATION;
20447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
20547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CSecBufferBundle<2, CSecBufferBase::FreeSSPI> sb_out;
20647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ret = InitializeSecurityContextA(&impl_->cred, &impl_->ctx,
20747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                   const_cast<char*>(ssl_host_name_.c_str()),
20847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                   flags, 0, 0, sb_in.desc(), 0,
20947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                   NULL, sb_out.desc(),
21047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                   &ret_flags, NULL);
21147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return ProcessContext(ret, sb_in.desc(), sb_out.desc());
21247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
21347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
21447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint
21547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSChannelAdapter::ProcessContext(long int status, _SecBufferDesc* sbd_in,
21647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                _SecBufferDesc* sbd_out) {
21747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED &&
21847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      status != SEC_E_INCOMPLETE_MESSAGE) {
21947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_ERROR)
22047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      << "InitializeSecurityContext error: "
22147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      << ErrorName(status, SECURITY_ERRORS);
22247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
22347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  //if (sbd_in)
22447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  //  DescribeBuffers(LS_VERBOSE, "Input Buffer ", sbd_in);
22547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  //if (sbd_out)
22647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  //  DescribeBuffers(LS_VERBOSE, "Output Buffer ", sbd_out);
22747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
22847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (status == SEC_E_INCOMPLETE_MESSAGE) {
22947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Wait for more input from server.
23047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return Flush();
23147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
23247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
23347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (FAILED(status)) {
23447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // We can't continue.  Common errors:
23547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // SEC_E_CERT_EXPIRED - Typically, this means the computer clock is wrong.
23647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return status;
23747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
23847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
23947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Note: we check both input and output buffers for SECBUFFER_EXTRA.
24047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Experience shows it appearing in the input, but the documentation claims
24147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // it should appear in the output.
24247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  size_t extra = 0;
24347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (sbd_in) {
24447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    for (size_t i=0; i<sbd_in->cBuffers; ++i) {
24547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      SecBuffer& buffer = sbd_in->pBuffers[i];
24647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      if (buffer.BufferType == SECBUFFER_EXTRA) {
24747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        extra += buffer.cbBuffer;
24847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
24947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
25047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
25147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (sbd_out) {
25247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    for (size_t i=0; i<sbd_out->cBuffers; ++i) {
25347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      SecBuffer& buffer = sbd_out->pBuffers[i];
25447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      if (buffer.BufferType == SECBUFFER_EXTRA) {
25547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        extra += buffer.cbBuffer;
25647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      } else if (buffer.BufferType == SECBUFFER_TOKEN) {
25747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        impl_->outbuf.insert(impl_->outbuf.end(),
25847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          reinterpret_cast<char*>(buffer.pvBuffer),
25947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          reinterpret_cast<char*>(buffer.pvBuffer) + buffer.cbBuffer);
26047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
26147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
26247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
26347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
26447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (extra) {
26547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ASSERT(extra <= impl_->inbuf.size());
26647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    size_t consumed = impl_->inbuf.size() - extra;
26747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    memmove(&impl_->inbuf[0], &impl_->inbuf[consumed], extra);
26847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    impl_->inbuf.resize(extra);
26947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  } else {
27047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    impl_->inbuf.clear();
27147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
27247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
27347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (SEC_I_CONTINUE_NEEDED == status) {
27447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Send data to server and wait for response.
27547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Note: ContinueSSL will result in a Flush, anyway.
27647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return impl_->inbuf.empty() ? Flush() : ContinueSSL();
27747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
27847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
27947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (SEC_E_OK == status) {
28047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_VERBOSE) << "QueryContextAttributes";
28147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    status = QueryContextAttributes(&impl_->ctx, SECPKG_ATTR_STREAM_SIZES,
28247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                    &impl_->sizes);
28347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (FAILED(status)) {
28447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      LOG(LS_ERROR) << "QueryContextAttributes error: "
28547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                    << ErrorName(status, SECURITY_ERRORS);
28647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return status;
28747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
28847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
28947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    state_ = SSL_CONNECTED;
29047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
29147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (int err = DecryptData()) {
29247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return err;
29347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    } else if (int err = Flush()) {
29447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return err;
29547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    } else {
29647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // If we decrypted any data, queue up a notification here
29747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      PostEvent();
29847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // Signal our connectedness
29947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      AsyncSocketAdapter::OnConnectEvent(this);
30047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
30147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return 0;
30247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
30347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
30447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (SEC_I_INCOMPLETE_CREDENTIALS == status) {
30547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // We don't support client authentication in schannel.
30647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return status;
30747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
30847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
30947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // We don't expect any other codes
31047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(false);
31147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return status;
31247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
31347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
31447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint
31547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSChannelAdapter::DecryptData() {
31647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SChannelBuffer& inbuf = impl_->inbuf;
31747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SChannelBuffer& readable = impl_->readable;
31847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
31947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  while (!inbuf.empty()) {
32047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CSecBufferBundle<4> in_buf;
32147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    in_buf[0].BufferType = SECBUFFER_DATA;
32247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    in_buf[0].cbBuffer = static_cast<unsigned long>(inbuf.size());
32347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    in_buf[0].pvBuffer = &inbuf[0];
32447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
32547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    //DescribeBuffers(LS_VERBOSE, "Decrypt In ", in_buf.desc());
32647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    SECURITY_STATUS status = DecryptMessage(&impl_->ctx, in_buf.desc(), 0, 0);
32747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    //DescribeBuffers(LS_VERBOSE, "Decrypt Out ", in_buf.desc());
32847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
32947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Note: We are explicitly treating SEC_E_OK, SEC_I_CONTEXT_EXPIRED, and
33047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // any other successful results as continue.
33147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (SUCCEEDED(status)) {
33247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      size_t data_len = 0, extra_len = 0;
33347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      for (size_t i=0; i<in_buf.desc()->cBuffers; ++i) {
33447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        if (in_buf[i].BufferType == SECBUFFER_DATA) {
33547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          data_len += in_buf[i].cbBuffer;
33647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          readable.insert(readable.end(),
33747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org            reinterpret_cast<char*>(in_buf[i].pvBuffer),
33847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org            reinterpret_cast<char*>(in_buf[i].pvBuffer) + in_buf[i].cbBuffer);
33947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        } else if (in_buf[i].BufferType == SECBUFFER_EXTRA) {
34047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          extra_len += in_buf[i].cbBuffer;
34147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        }
34247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
34347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // There is a bug on Win2K where SEC_I_CONTEXT_EXPIRED is misclassified.
34447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      if ((data_len == 0) && (inbuf[0] == 0x15)) {
34547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        status = SEC_I_CONTEXT_EXPIRED;
34647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
34747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      if (extra_len) {
34847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        size_t consumed = inbuf.size() - extra_len;
34947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        memmove(&inbuf[0], &inbuf[consumed], extra_len);
35047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        inbuf.resize(extra_len);
35147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      } else {
35247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        inbuf.clear();
35347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
35447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // TODO: Handle SEC_I_CONTEXT_EXPIRED to do clean shutdown
35547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      if (status != SEC_E_OK) {
35647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        LOG(LS_INFO) << "DecryptMessage returned continuation code: "
35747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                      << ErrorName(status, SECURITY_ERRORS);
35847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
35947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      continue;
36047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
36147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
36247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (status == SEC_E_INCOMPLETE_MESSAGE) {
36347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      break;
36447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    } else {
36547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return status;
36647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
36747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
36847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
36947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return 0;
37047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
37147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
37247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid
37347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSChannelAdapter::Cleanup() {
37447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (impl_->ctx_init)
37547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    DeleteSecurityContext(&impl_->ctx);
37647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (impl_->cred_init)
37747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    FreeCredentialsHandle(&impl_->cred);
37847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  delete impl_;
37947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
38047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
38147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid
38247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSChannelAdapter::PostEvent() {
38347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Check if there's anything notable to signal
38447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (impl_->readable.empty() && !signal_close_)
38547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return;
38647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
38747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Only one post in the queue at a time
38847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (message_pending_)
38947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return;
39047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
39147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (Thread* thread = Thread::Current()) {
39247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    message_pending_ = true;
39347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    thread->Post(this);
39447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  } else {
39547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_ERROR) << "No thread context available for SChannelAdapter";
39647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ASSERT(false);
39747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
39847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
39947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
40047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid
40147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSChannelAdapter::Error(const char* context, int err, bool signal) {
40247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  LOG(LS_WARNING) << "SChannelAdapter::Error("
40347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                  << context << ", "
40447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                  << ErrorName(err, SECURITY_ERRORS) << ")";
40547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  state_ = SSL_ERROR;
40647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SetError(err);
40747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (signal)
40847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    AsyncSocketAdapter::OnCloseEvent(this, err);
40947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
41047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
41147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint
41247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSChannelAdapter::Read() {
41347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  char buffer[4096];
41447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SChannelBuffer& inbuf = impl_->inbuf;
41547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  while (true) {
41647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    int ret = AsyncSocketAdapter::Recv(buffer, sizeof(buffer));
41747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (ret > 0) {
41847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      inbuf.insert(inbuf.end(), buffer, buffer + ret);
41947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    } else if (GetError() == EWOULDBLOCK) {
42047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return 0;  // Blocking
42147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    } else {
42247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return GetError();
42347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
42447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
42547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
42647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
42747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint
42847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSChannelAdapter::Flush() {
42947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int result = 0;
43047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  size_t pos = 0;
43147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SChannelBuffer& outbuf = impl_->outbuf;
43247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  while (pos < outbuf.size()) {
43347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    int sent = AsyncSocketAdapter::Send(&outbuf[pos], outbuf.size() - pos);
43447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (sent > 0) {
43547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      pos += sent;
43647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    } else if (GetError() == EWOULDBLOCK) {
43747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      break;  // Blocking
43847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    } else {
43947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      result = GetError();
44047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      break;
44147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
44247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
44347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (int remainder = static_cast<int>(outbuf.size() - pos)) {
44447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    memmove(&outbuf[0], &outbuf[pos], remainder);
44547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    outbuf.resize(remainder);
44647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  } else {
44747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    outbuf.clear();
44847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
44947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return result;
45047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
45147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
45247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org//
45347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// AsyncSocket Implementation
45447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org//
45547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
45647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint
45747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSChannelAdapter::Send(const void* pv, size_t cb) {
45847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  switch (state_) {
45947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  case SSL_NONE:
46047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return AsyncSocketAdapter::Send(pv, cb);
46147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
46247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  case SSL_WAIT:
46347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  case SSL_CONNECTING:
46447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    SetError(EWOULDBLOCK);
46547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return SOCKET_ERROR;
46647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
46747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  case SSL_CONNECTED:
46847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    break;
46947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
47047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  case SSL_ERROR:
47147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  default:
47247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return SOCKET_ERROR;
47347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
47447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
47547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  size_t written = 0;
47647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SChannelBuffer& outbuf = impl_->outbuf;
47747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  while (written < cb) {
47847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    const size_t encrypt_len = std::min<size_t>(cb - written,
47947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                                impl_->sizes.cbMaximumMessage);
48047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
48147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CSecBufferBundle<4> out_buf;
48247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    out_buf[0].BufferType = SECBUFFER_STREAM_HEADER;
48347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    out_buf[0].cbBuffer = impl_->sizes.cbHeader;
48447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    out_buf[1].BufferType = SECBUFFER_DATA;
48547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    out_buf[1].cbBuffer = static_cast<unsigned long>(encrypt_len);
48647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    out_buf[2].BufferType = SECBUFFER_STREAM_TRAILER;
48747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    out_buf[2].cbBuffer = impl_->sizes.cbTrailer;
48847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
48947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    size_t packet_len = out_buf[0].cbBuffer
49047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                      + out_buf[1].cbBuffer
49147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                      + out_buf[2].cbBuffer;
49247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
49347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    SChannelBuffer message;
49447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    message.resize(packet_len);
49547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    out_buf[0].pvBuffer = &message[0];
49647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    out_buf[1].pvBuffer = &message[out_buf[0].cbBuffer];
49747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    out_buf[2].pvBuffer = &message[out_buf[0].cbBuffer + out_buf[1].cbBuffer];
49847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
49947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    memcpy(out_buf[1].pvBuffer,
50047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org           static_cast<const char*>(pv) + written,
50147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org           encrypt_len);
50247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
50347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    //DescribeBuffers(LS_VERBOSE, "Encrypt In ", out_buf.desc());
50447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    SECURITY_STATUS res = EncryptMessage(&impl_->ctx, 0, out_buf.desc(), 0);
50547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    //DescribeBuffers(LS_VERBOSE, "Encrypt Out ", out_buf.desc());
50647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
50747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (FAILED(res)) {
50847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      Error("EncryptMessage", res, false);
50947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return SOCKET_ERROR;
51047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
51147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
51247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // We assume that the header and data segments do not change length,
51347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // or else encrypting the concatenated packet in-place is wrong.
51447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ASSERT(out_buf[0].cbBuffer == impl_->sizes.cbHeader);
51547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ASSERT(out_buf[1].cbBuffer == static_cast<unsigned long>(encrypt_len));
51647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
51747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // However, the length of the trailer may change due to padding.
51847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ASSERT(out_buf[2].cbBuffer <= impl_->sizes.cbTrailer);
51947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
52047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    packet_len = out_buf[0].cbBuffer
52147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org               + out_buf[1].cbBuffer
52247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org               + out_buf[2].cbBuffer;
52347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
52447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    written += encrypt_len;
52547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    outbuf.insert(outbuf.end(), &message[0], &message[packet_len-1]+1);
52647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
52747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
52847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (int err = Flush()) {
52947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    state_ = SSL_ERROR;
53047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    SetError(err);
53147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return SOCKET_ERROR;
53247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
53347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
53447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return static_cast<int>(written);
53547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
53647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
53747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint
53847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSChannelAdapter::Recv(void* pv, size_t cb) {
53947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  switch (state_) {
54047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  case SSL_NONE:
54147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return AsyncSocketAdapter::Recv(pv, cb);
54247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
54347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  case SSL_WAIT:
54447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  case SSL_CONNECTING:
54547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    SetError(EWOULDBLOCK);
54647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return SOCKET_ERROR;
54747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
54847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  case SSL_CONNECTED:
54947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    break;
55047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
55147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  case SSL_ERROR:
55247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  default:
55347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return SOCKET_ERROR;
55447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
55547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
55647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SChannelBuffer& readable = impl_->readable;
55747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (readable.empty()) {
55847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    SetError(EWOULDBLOCK);
55947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return SOCKET_ERROR;
56047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
56147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  size_t read = _min(cb, readable.size());
56247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  memcpy(pv, &readable[0], read);
56347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (size_t remaining = readable.size() - read) {
56447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    memmove(&readable[0], &readable[read], remaining);
56547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    readable.resize(remaining);
56647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  } else {
56747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    readable.clear();
56847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
56947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
57047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  PostEvent();
57147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return static_cast<int>(read);
57247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
57347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
57447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint
57547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSChannelAdapter::Close() {
57647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!impl_->readable.empty()) {
57747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(WARNING) << "SChannelAdapter::Close with readable data";
57847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Note: this isn't strictly an error, but we're using it temporarily to
57947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // track bugs.
58047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    //ASSERT(false);
58147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
58247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (state_ == SSL_CONNECTED) {
58347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    DWORD token = SCHANNEL_SHUTDOWN;
58447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CSecBufferBundle<1> sb_in;
58547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    sb_in[0].BufferType = SECBUFFER_TOKEN;
58647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    sb_in[0].cbBuffer = sizeof(token);
58747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    sb_in[0].pvBuffer = &token;
58847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ApplyControlToken(&impl_->ctx, sb_in.desc());
58947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // TODO: In theory, to do a nice shutdown, we need to begin shutdown
59047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // negotiation with more calls to InitializeSecurityContext.  Since the
59147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // socket api doesn't support nice shutdown at this point, we don't bother.
59247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
59347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  Cleanup();
59447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  impl_ = new SSLImpl;
59547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  state_ = restartable_ ? SSL_WAIT : SSL_NONE;
59647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  signal_close_ = false;
59747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  message_pending_ = false;
59847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return AsyncSocketAdapter::Close();
59947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
60047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
60147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSocket::ConnState
60247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSChannelAdapter::GetState() const {
60347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (signal_close_)
60447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return CS_CONNECTED;
60547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ConnState state = socket_->GetState();
60647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if ((state == CS_CONNECTED)
60747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      && ((state_ == SSL_WAIT) || (state_ == SSL_CONNECTING)))
60847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    state = CS_CONNECTING;
60947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return state;
61047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
61147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
61247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid
61347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSChannelAdapter::OnConnectEvent(AsyncSocket* socket) {
61447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  LOG(LS_VERBOSE) << "SChannelAdapter::OnConnectEvent";
61547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (state_ != SSL_WAIT) {
61647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ASSERT(state_ == SSL_NONE);
61747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    AsyncSocketAdapter::OnConnectEvent(socket);
61847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return;
61947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
62047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
62147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  state_ = SSL_CONNECTING;
62247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (int err = BeginSSL()) {
62347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    Error("BeginSSL", err);
62447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
62547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
62647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
62747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid
62847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSChannelAdapter::OnReadEvent(AsyncSocket* socket) {
62947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (state_ == SSL_NONE) {
63047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    AsyncSocketAdapter::OnReadEvent(socket);
63147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return;
63247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
63347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
63447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (int err = Read()) {
63547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    Error("Read", err);
63647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return;
63747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
63847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
63947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (impl_->inbuf.empty())
64047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return;
64147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
64247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (state_ == SSL_CONNECTED) {
64347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (int err = DecryptData()) {
64447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      Error("DecryptData", err);
64547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    } else if (!impl_->readable.empty()) {
64647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      AsyncSocketAdapter::OnReadEvent(this);
64747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
64847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  } else if (state_ == SSL_CONNECTING) {
64947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (int err = ContinueSSL()) {
65047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      Error("ContinueSSL", err);
65147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
65247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
65347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
65447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
65547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid
65647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSChannelAdapter::OnWriteEvent(AsyncSocket* socket) {
65747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (state_ == SSL_NONE) {
65847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    AsyncSocketAdapter::OnWriteEvent(socket);
65947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return;
66047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
66147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
66247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (int err = Flush()) {
66347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    Error("Flush", err);
66447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return;
66547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
66647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
66747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // See if we have more data to write
66847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!impl_->outbuf.empty())
66947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return;
67047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
67147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Buffer is empty, submit notification
67247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (state_ == SSL_CONNECTED) {
67347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    AsyncSocketAdapter::OnWriteEvent(socket);
67447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
67547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
67647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
67747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid
67847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSChannelAdapter::OnCloseEvent(AsyncSocket* socket, int err) {
67947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if ((state_ == SSL_NONE) || impl_->readable.empty()) {
68047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    AsyncSocketAdapter::OnCloseEvent(socket, err);
68147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return;
68247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
68347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
68447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // If readable is non-empty, then we have a pending Message
68547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // that will allow us to signal close (eventually).
68647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  signal_close_ = true;
68747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
68847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
68947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid
69047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSChannelAdapter::OnMessage(Message* pmsg) {
69147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!message_pending_)
69247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return;  // This occurs when socket is closed
69347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
69447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  message_pending_ = false;
69547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!impl_->readable.empty()) {
69647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    AsyncSocketAdapter::OnReadEvent(this);
69747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  } else if (signal_close_) {
69847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    signal_close_ = false;
69947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    AsyncSocketAdapter::OnCloseEvent(this, 0); // TODO: cache this error?
70047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
70147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
70247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
70347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} // namespace rtc
704