⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 schanneladapter.cc

📁 本人收集整理的一份c/c++跨平台网络库
💻 CC
📖 第 1 页 / 共 2 页
字号:
#include "win32.h"#define SECURITY_WIN32#include <security.h>#include <schannel.h>#include <iomanip>#include <vector>#include "common.h"#include "logging.h"#include "schanneladapter.h"#include "sec_buffer.h"#include "thread.h"namespace utils_base {/////////////////////////////////////////////////////////////////////////////// SChannelAdapter/////////////////////////////////////////////////////////////////////////////extern const ConstantLabel SECURITY_ERRORS[];const ConstantLabel SECURITY_ERRORS[] = {  KLABEL(SEC_I_COMPLETE_AND_CONTINUE),  KLABEL(SEC_I_COMPLETE_NEEDED),  KLABEL(SEC_I_CONTEXT_EXPIRED),  KLABEL(SEC_I_CONTINUE_NEEDED),  KLABEL(SEC_I_INCOMPLETE_CREDENTIALS),  KLABEL(SEC_I_RENEGOTIATE),  KLABEL(SEC_E_CERT_EXPIRED),  KLABEL(SEC_E_INCOMPLETE_MESSAGE),  KLABEL(SEC_E_INSUFFICIENT_MEMORY),  KLABEL(SEC_E_INTERNAL_ERROR),  KLABEL(SEC_E_INVALID_HANDLE),  KLABEL(SEC_E_INVALID_TOKEN),  KLABEL(SEC_E_LOGON_DENIED),  KLABEL(SEC_E_NO_AUTHENTICATING_AUTHORITY),  KLABEL(SEC_E_NO_CREDENTIALS),  KLABEL(SEC_E_NOT_OWNER),  KLABEL(SEC_E_OK),  KLABEL(SEC_E_SECPKG_NOT_FOUND),  KLABEL(SEC_E_TARGET_UNKNOWN),  KLABEL(SEC_E_UNKNOWN_CREDENTIALS),  KLABEL(SEC_E_UNSUPPORTED_FUNCTION),  KLABEL(SEC_E_UNTRUSTED_ROOT),  KLABEL(SEC_E_WRONG_PRINCIPAL),  LASTLABEL};const ConstantLabel SCHANNEL_BUFFER_TYPES[] = {  KLABEL(SECBUFFER_EMPTY),              //  0  KLABEL(SECBUFFER_DATA),               //  1  KLABEL(SECBUFFER_TOKEN),              //  2  KLABEL(SECBUFFER_PKG_PARAMS),         //  3  KLABEL(SECBUFFER_MISSING),            //  4  KLABEL(SECBUFFER_EXTRA),              //  5  KLABEL(SECBUFFER_STREAM_TRAILER),     //  6  KLABEL(SECBUFFER_STREAM_HEADER),      //  7  KLABEL(SECBUFFER_MECHLIST),           // 11  KLABEL(SECBUFFER_MECHLIST_SIGNATURE), // 12  KLABEL(SECBUFFER_TARGET),             // 13  KLABEL(SECBUFFER_CHANNEL_BINDINGS),   // 14  LASTLABEL};void DescribeBuffer(LoggingSeverity severity, const char* prefix,                    const SecBuffer& sb) {  LOG_V(severity)     << prefix    << "(" << sb.cbBuffer    << ", " << FindLabel(sb.BufferType & ~SECBUFFER_ATTRMASK,                          SCHANNEL_BUFFER_TYPES)    << ", " << sb.pvBuffer << ")";}void DescribeBuffers(LoggingSeverity severity, const char* prefix,                     const SecBufferDesc* sbd) {  if (!LOG_CHECK_LEVEL_V(severity))    return;  LOG_V(severity) << prefix << "(";  for (size_t i=0; i<sbd->cBuffers; ++i) {    DescribeBuffer(severity, "  ", sbd->pBuffers[i]);  }  LOG_V(severity) << ")";}const ULONG SSL_FLAGS_DEFAULT = ISC_REQ_ALLOCATE_MEMORY                              | ISC_REQ_CONFIDENTIALITY                              | ISC_REQ_EXTENDED_ERROR                              | ISC_REQ_INTEGRITY                              | ISC_REQ_REPLAY_DETECT                              | ISC_REQ_SEQUENCE_DETECT                              | ISC_REQ_STREAM;                              //| ISC_REQ_USE_SUPPLIED_CREDS;typedef std::vector<char> SChannelBuffer;struct SChannelAdapter::SSLImpl {  CredHandle cred;  CtxtHandle ctx;  bool cred_init, ctx_init;  SChannelBuffer inbuf, outbuf, readable;  SecPkgContext_StreamSizes sizes;  SSLImpl() : cred_init(false), ctx_init(false) { }};SChannelAdapter::SChannelAdapter(AsyncSocket* socket)  : SSLAdapter(socket), state_(SSL_NONE),    restartable_(false), signal_close_(false), message_pending_(false),    impl_(new SSLImpl) {}SChannelAdapter::~SChannelAdapter() {  Cleanup();}intSChannelAdapter::StartSSL(const char* hostname, bool restartable) {  if (state_ != SSL_NONE)    return ERROR_ALREADY_INITIALIZED;  ssl_host_name_ = hostname;  restartable_ = restartable;  if (socket_->GetState() != Socket::CS_CONNECTED) {    state_ = SSL_WAIT;    return 0;  }  state_ = SSL_CONNECTING;  if (int err = BeginSSL()) {    Error("BeginSSL", err, false);    return err;  }  return 0;}intSChannelAdapter::BeginSSL() {  LOG(LS_VERBOSE) << "BeginSSL: " << ssl_host_name_;  ASSERT(state_ == SSL_CONNECTING);  SECURITY_STATUS ret;  SCHANNEL_CRED sc_cred = { 0 };  sc_cred.dwVersion = SCHANNEL_CRED_VERSION;  //sc_cred.dwMinimumCipherStrength = 128; // Note: use system default  sc_cred.dwFlags = SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_AUTO_CRED_VALIDATION;  ret = AcquireCredentialsHandle(NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL,                                 &sc_cred, NULL, NULL, &impl_->cred, NULL);  if (ret != SEC_E_OK) {    LOG(LS_ERROR) << "AcquireCredentialsHandle error: "                  << ErrorName(ret, SECURITY_ERRORS);    return ret;  }  impl_->cred_init = true;  if (LOG_CHECK_LEVEL(LS_VERBOSE)) {    SecPkgCred_CipherStrengths cipher_strengths = { 0 };    ret = QueryCredentialsAttributes(&impl_->cred,                                     SECPKG_ATTR_CIPHER_STRENGTHS,                                     &cipher_strengths);    if (SUCCEEDED(ret)) {      LOG(LS_VERBOSE) << "SChannel cipher strength: "                  << cipher_strengths.dwMinimumCipherStrength << " - "                  << cipher_strengths.dwMaximumCipherStrength;    }    SecPkgCred_SupportedAlgs supported_algs = { 0 };    ret = QueryCredentialsAttributes(&impl_->cred,                                     SECPKG_ATTR_SUPPORTED_ALGS,                                     &supported_algs);    if (SUCCEEDED(ret)) {      LOG(LS_VERBOSE) << "SChannel supported algorithms:";      for (DWORD i=0; i<supported_algs.cSupportedAlgs; ++i) {        ALG_ID alg_id = supported_algs.palgSupportedAlgs[i];        PCCRYPT_OID_INFO oinfo = CryptFindOIDInfo(CRYPT_OID_INFO_ALGID_KEY,                                                  &alg_id, 0);        LPCWSTR alg_name = (NULL != oinfo) ? oinfo->pwszName : L"Unknown";        LOG(LS_VERBOSE) << "  " << utils_base::ToUtf8(alg_name)                        << " (" << alg_id << ")";      }    }  }  ULONG flags = SSL_FLAGS_DEFAULT, ret_flags = 0;  if (ignore_bad_cert())    flags |= ISC_REQ_MANUAL_CRED_VALIDATION;  CSecBufferBundle<2, CSecBufferBase::FreeSSPI> sb_out;  ret = InitializeSecurityContextA(&impl_->cred, NULL,                                   const_cast<char*>(ssl_host_name_.c_str()),                                   flags, 0, 0, NULL, 0,                                   &impl_->ctx, sb_out.desc(),                                   &ret_flags, NULL);  if (SUCCEEDED(ret))    impl_->ctx_init = true;  return ProcessContext(ret, NULL, sb_out.desc());}intSChannelAdapter::ContinueSSL() {  LOG(LS_VERBOSE) << "ContinueSSL";  ASSERT(state_ == SSL_CONNECTING);  SECURITY_STATUS ret;  CSecBufferBundle<2> sb_in;  sb_in[0].BufferType = SECBUFFER_TOKEN;  sb_in[0].cbBuffer = static_cast<unsigned long>(impl_->inbuf.size());  sb_in[0].pvBuffer = &impl_->inbuf[0];  //DescribeBuffers(LS_VERBOSE, "Input Buffer ", sb_in.desc());  ULONG flags = SSL_FLAGS_DEFAULT, ret_flags = 0;  if (ignore_bad_cert())    flags |= ISC_REQ_MANUAL_CRED_VALIDATION;  CSecBufferBundle<2, CSecBufferBase::FreeSSPI> sb_out;  ret = InitializeSecurityContextA(&impl_->cred, &impl_->ctx,                                   const_cast<char*>(ssl_host_name_.c_str()),                                   flags, 0, 0, sb_in.desc(), 0,                                   NULL, sb_out.desc(),                                   &ret_flags, NULL);  return ProcessContext(ret, sb_in.desc(), sb_out.desc());}intSChannelAdapter::ProcessContext(long int status, _SecBufferDesc* sbd_in,                                _SecBufferDesc* sbd_out) {  LoggingSeverity level = LS_ERROR;  if ((status == SEC_E_OK)      || (status != SEC_I_CONTINUE_NEEDED)      || (status != SEC_E_INCOMPLETE_MESSAGE)) {    level = LS_VERBOSE;  // Expected messages  }  LOG_V(level)     << "InitializeSecurityContext error: "    << ErrorName(status, SECURITY_ERRORS);  //if (sbd_in)  //  DescribeBuffers(LS_VERBOSE, "Input Buffer ", sbd_in);  //if (sbd_out)  //  DescribeBuffers(LS_VERBOSE, "Output Buffer ", sbd_out);  if (status == SEC_E_INCOMPLETE_MESSAGE) {    // Wait for more input from server.    return Flush();  }    if (FAILED(status)) {    // We can't continue.  Common errors:    // SEC_E_CERT_EXPIRED - Typically, this means the computer clock is wrong.    return status;  }  // Note: we check both input and output buffers for SECBUFFER_EXTRA.  // Experience shows it appearing in the input, but the documentation claims  // it should appear in the output.  size_t extra = 0;  if (sbd_in) {    for (size_t i=0; i<sbd_in->cBuffers; ++i) {      SecBuffer& buffer = sbd_in->pBuffers[i];      if (buffer.BufferType == SECBUFFER_EXTRA) {        extra += buffer.cbBuffer;      }    }  }  if (sbd_out) {    for (size_t i=0; i<sbd_out->cBuffers; ++i) {      SecBuffer& buffer = sbd_out->pBuffers[i];      if (buffer.BufferType == SECBUFFER_EXTRA) {        extra += buffer.cbBuffer;      } else if (buffer.BufferType == SECBUFFER_TOKEN) {        impl_->outbuf.insert(impl_->outbuf.end(),          reinterpret_cast<char*>(buffer.pvBuffer),          reinterpret_cast<char*>(buffer.pvBuffer) + buffer.cbBuffer);      }    }  }  if (extra) {    ASSERT(extra <= impl_->inbuf.size());    size_t consumed = impl_->inbuf.size() - extra;    memmove(&impl_->inbuf[0], &impl_->inbuf[consumed], extra);    impl_->inbuf.resize(extra);  } else {    impl_->inbuf.clear();  }  if (SEC_I_CONTINUE_NEEDED == status) {    // Send data to server and wait for response.    // Note: ContinueSSL will result in a Flush, anyway.    return impl_->inbuf.empty() ? Flush() : ContinueSSL();  }  if (SEC_E_OK == status) {    LOG(LS_VERBOSE) << "QueryContextAttributes";    status = QueryContextAttributes(&impl_->ctx, SECPKG_ATTR_STREAM_SIZES,                                    &impl_->sizes);    if (FAILED(status)) {      LOG(LS_ERROR) << "QueryContextAttributes error: "                    << ErrorName(status, SECURITY_ERRORS);      return status;    }    state_ = SSL_CONNECTED;    if (int err = DecryptData()) {      return err;    } else if (int err = Flush()) {      return err;    } else {      // If we decrypted any data, queue up a notification here      PostEvent();      // Signal our connectedness      AsyncSocketAdapter::OnConnectEvent(this);    }    return 0;  }  if (SEC_I_INCOMPLETE_CREDENTIALS == status) {    // We don't support client authentication in schannel.    return status;  }  // We don't expect any other codes  ASSERT(false);  return status;}intSChannelAdapter::DecryptData() {  SChannelBuffer& inbuf = impl_->inbuf;  SChannelBuffer& readable = impl_->readable;  while (!inbuf.empty()) {    CSecBufferBundle<4> in_buf;    in_buf[0].BufferType = SECBUFFER_DATA;    in_buf[0].cbBuffer = static_cast<unsigned long>(inbuf.size());    in_buf[0].pvBuffer = &inbuf[0];    //DescribeBuffers(LS_VERBOSE, "Decrypt In ", in_buf.desc());    SECURITY_STATUS status = DecryptMessage(&impl_->ctx, in_buf.desc(), 0, 0);    //DescribeBuffers(LS_VERBOSE, "Decrypt Out ", in_buf.desc());    // Note: We are explicitly treating SEC_E_OK, SEC_I_CONTEXT_EXPIRED, and    // any other successful results as continue.    if (SUCCEEDED(status)) {      size_t data_len = 0, extra_len = 0;      for (size_t i=0; i<in_buf.desc()->cBuffers; ++i) {        if (in_buf[i].BufferType == SECBUFFER_DATA) {          data_len += in_buf[i].cbBuffer;          readable.insert(readable.end(),            reinterpret_cast<char*>(in_buf[i].pvBuffer),            reinterpret_cast<char*>(in_buf[i].pvBuffer) + in_buf[i].cbBuffer);        } else if (in_buf[i].BufferType == SECBUFFER_EXTRA) {          extra_len += in_buf[i].cbBuffer;        }      }      // There is a bug on Win2K where SEC_I_CONTEXT_EXPIRED is misclassified.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -