static DWORD netcon_secure_connect_setup(netconn_t *connection, BOOL compat_mode) { SecBuffer out_buf = {0, SECBUFFER_TOKEN, NULL}, in_bufs[2] = {{0, SECBUFFER_TOKEN}, {0, SECBUFFER_EMPTY}}; SecBufferDesc out_desc = {SECBUFFER_VERSION, 1, &out_buf}, in_desc = {SECBUFFER_VERSION, 2, in_bufs}; SecHandle *cred = &cred_handle; BYTE *read_buf; SIZE_T read_buf_size = 2048; ULONG attrs = 0; CtxtHandle ctx; SSIZE_T size; int bits; const CERT_CONTEXT *cert; SECURITY_STATUS status; DWORD res = ERROR_SUCCESS; const DWORD isc_req_flags = ISC_REQ_ALLOCATE_MEMORY|ISC_REQ_USE_SESSION_KEY|ISC_REQ_CONFIDENTIALITY |ISC_REQ_SEQUENCE_DETECT|ISC_REQ_REPLAY_DETECT|ISC_REQ_MANUAL_CRED_VALIDATION; if(!ensure_cred_handle()) return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; if(compat_mode) { if(!have_compat_cred_handle) return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; cred = &compat_cred_handle; } read_buf = heap_alloc(read_buf_size); if(!read_buf) return ERROR_OUTOFMEMORY; status = InitializeSecurityContextW(cred, NULL, connection->server->name, isc_req_flags, 0, 0, NULL, 0, &ctx, &out_desc, &attrs, NULL); assert(status != SEC_E_OK); while(status == SEC_I_CONTINUE_NEEDED || status == SEC_E_INCOMPLETE_MESSAGE) { if(out_buf.cbBuffer) { assert(status == SEC_I_CONTINUE_NEEDED); TRACE("sending %lu bytes\n", out_buf.cbBuffer); size = sock_send(connection->socket, out_buf.pvBuffer, out_buf.cbBuffer, 0); if(size != out_buf.cbBuffer) { ERR("send failed\n"); status = ERROR_INTERNET_SECURITY_CHANNEL_ERROR; break; } FreeContextBuffer(out_buf.pvBuffer); out_buf.pvBuffer = NULL; out_buf.cbBuffer = 0; } if(status == SEC_I_CONTINUE_NEEDED) { assert(in_bufs[1].cbBuffer < read_buf_size); memmove(read_buf, (BYTE*)in_bufs[0].pvBuffer+in_bufs[0].cbBuffer-in_bufs[1].cbBuffer, in_bufs[1].cbBuffer); in_bufs[0].cbBuffer = in_bufs[1].cbBuffer; in_bufs[1].BufferType = SECBUFFER_EMPTY; in_bufs[1].cbBuffer = 0; in_bufs[1].pvBuffer = NULL; } assert(in_bufs[0].BufferType == SECBUFFER_TOKEN); assert(in_bufs[1].BufferType == SECBUFFER_EMPTY); if(in_bufs[0].cbBuffer + 1024 > read_buf_size) { BYTE *new_read_buf; new_read_buf = heap_realloc(read_buf, read_buf_size + 1024); if(!new_read_buf) { status = E_OUTOFMEMORY; break; } in_bufs[0].pvBuffer = read_buf = new_read_buf; read_buf_size += 1024; } size = sock_recv(connection->socket, read_buf+in_bufs[0].cbBuffer, read_buf_size-in_bufs[0].cbBuffer, 0); if(size < 1) { WARN("recv error\n"); res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR; break; } TRACE("recv %tu bytes\n", size); in_bufs[0].cbBuffer += size; in_bufs[0].pvBuffer = read_buf; status = InitializeSecurityContextW(cred, &ctx, connection->server->name, isc_req_flags, 0, 0, &in_desc, 0, NULL, &out_desc, &attrs, NULL); TRACE("InitializeSecurityContext ret %08x\n", status); if(status == SEC_E_OK) { if(SecIsValidHandle(&connection->ssl_ctx)) DeleteSecurityContext(&connection->ssl_ctx); connection->ssl_ctx = ctx; if(in_bufs[1].BufferType == SECBUFFER_EXTRA) FIXME("SECBUFFER_EXTRA not supported\n"); status = QueryContextAttributesW(&ctx, SECPKG_ATTR_STREAM_SIZES, &connection->ssl_sizes); if(status != SEC_E_OK) { WARN("Could not get sizes\n"); break; } status = QueryContextAttributesW(&ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&cert); if(status == SEC_E_OK) { res = netconn_verify_cert(connection, cert, cert->hCertStore); CertFreeCertificateContext(cert); if(res != ERROR_SUCCESS) { WARN("cert verify failed: %u\n", res); break; } }else { WARN("Could not get cert\n"); break; } connection->ssl_buf = heap_alloc(connection->ssl_sizes.cbHeader + connection->ssl_sizes.cbMaximumMessage + connection->ssl_sizes.cbTrailer); if(!connection->ssl_buf) { res = GetLastError(); break; } } } heap_free(read_buf); if(status != SEC_E_OK || res != ERROR_SUCCESS) { WARN("Failed to establish SSL connection: %08x (%u)\n", status, res); heap_free(connection->ssl_buf); connection->ssl_buf = NULL; return res ? res : ERROR_INTERNET_SECURITY_CHANNEL_ERROR; } TRACE("established SSL connection\n"); connection->secure = TRUE; connection->security_flags |= SECURITY_FLAG_SECURE; bits = NETCON_GetCipherStrength(connection); if (bits >= 128) connection->security_flags |= SECURITY_FLAG_STRENGTH_STRONG; else if (bits >= 56) connection->security_flags |= SECURITY_FLAG_STRENGTH_MEDIUM; else connection->security_flags |= SECURITY_FLAG_STRENGTH_WEAK; if(connection->mask_errors) connection->server->security_flags = connection->security_flags; return ERROR_SUCCESS; }
int _mongoc_sspi_auth_sspi_client_step (mongoc_sspi_client_state_t *state, SEC_CHAR *challenge) { SecBufferDesc inbuf; SecBuffer inBufs[1]; SecBufferDesc outbuf; SecBuffer outBufs[1]; ULONG ignored; SECURITY_STATUS status = MONGOC_SSPI_AUTH_GSS_CONTINUE; DWORD len; if (state->response != NULL) { free (state->response); state->response = NULL; } inbuf.ulVersion = SECBUFFER_VERSION; inbuf.cBuffers = 1; inbuf.pBuffers = inBufs; inBufs[0].pvBuffer = NULL; inBufs[0].cbBuffer = 0; inBufs[0].BufferType = SECBUFFER_TOKEN; if (state->haveCtx) { inBufs[0].pvBuffer = _mongoc_sspi_base64_decode (challenge, &len); if (!inBufs[0].pvBuffer) { return MONGOC_SSPI_AUTH_GSS_ERROR; } inBufs[0].cbBuffer = len; } outbuf.ulVersion = SECBUFFER_VERSION; outbuf.cBuffers = 1; outbuf.pBuffers = outBufs; outBufs[0].pvBuffer = NULL; outBufs[0].cbBuffer = 0; outBufs[0].BufferType = SECBUFFER_TOKEN; status = InitializeSecurityContextW (/* CredHandle */ &state->cred, /* CtxtHandle (NULL on first call) */ state->haveCtx ? &state->ctx : NULL, /* Service Principal Name */ state->spn, /* Flags */ ISC_REQ_ALLOCATE_MEMORY | state->flags, /* Always 0 */ 0, /* Target data representation */ SECURITY_NETWORK_DREP, /* Challenge (NULL on first call) */ state->haveCtx ? &inbuf : NULL, /* Always 0 */ 0, /* CtxtHandle (Set on first call) */ &state->ctx, /* Output */ &outbuf, /* Context attributes */ &ignored, /* Expiry (We don't use this) */ NULL); if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { _mongoc_sspi_set_gsserror (status, "InitializeSecurityContext"); status = MONGOC_SSPI_AUTH_GSS_ERROR; goto done; } state->haveCtx = 1; if (outBufs[0].cbBuffer) { state->response = _mongoc_sspi_base64_encode (outBufs[0].pvBuffer, outBufs[0].cbBuffer); if (!state->response) { status = MONGOC_SSPI_AUTH_GSS_ERROR; goto done; } } if (status == SEC_E_OK) { /* Get authenticated username. */ SecPkgContext_NamesW names; status = QueryContextAttributesW (&state->ctx, SECPKG_ATTR_NAMES, &names); if (status != SEC_E_OK) { _mongoc_sspi_set_gsserror (status, "QueryContextAttributesW"); status = MONGOC_SSPI_AUTH_GSS_ERROR; goto done; } state->username = _mongoc_sspi_wide_to_utf8 (names.sUserName); if (state->username == NULL) { FreeContextBuffer (names.sUserName); status = MONGOC_SSPI_AUTH_GSS_ERROR; goto done; } FreeContextBuffer (names.sUserName); status = MONGOC_SSPI_AUTH_GSS_COMPLETE; } else { status = MONGOC_SSPI_AUTH_GSS_CONTINUE; } done: if (inBufs[0].pvBuffer) { free (inBufs[0].pvBuffer); } if (outBufs[0].pvBuffer) { FreeContextBuffer (outBufs[0].pvBuffer); } return status; }
BOOL netconn_secure_connect( netconn_t *conn, WCHAR *hostname ) { SecBuffer out_buf = {0, SECBUFFER_TOKEN, NULL}, in_bufs[2] = {{0, SECBUFFER_TOKEN}, {0, SECBUFFER_EMPTY}}; SecBufferDesc out_desc = {SECBUFFER_VERSION, 1, &out_buf}, in_desc = {SECBUFFER_VERSION, 2, in_bufs}; BYTE *read_buf; SIZE_T read_buf_size = 2048; ULONG attrs = 0; CtxtHandle ctx; SSIZE_T size; const CERT_CONTEXT *cert; SECURITY_STATUS status; DWORD res = ERROR_SUCCESS; const DWORD isc_req_flags = ISC_REQ_ALLOCATE_MEMORY|ISC_REQ_USE_SESSION_KEY|ISC_REQ_CONFIDENTIALITY |ISC_REQ_SEQUENCE_DETECT|ISC_REQ_REPLAY_DETECT|ISC_REQ_MANUAL_CRED_VALIDATION; if(!ensure_cred_handle()) return FALSE; read_buf = heap_alloc(read_buf_size); if(!read_buf) return FALSE; status = InitializeSecurityContextW(&cred_handle, NULL, hostname, isc_req_flags, 0, 0, NULL, 0, &ctx, &out_desc, &attrs, NULL); assert(status != SEC_E_OK); while(status == SEC_I_CONTINUE_NEEDED || status == SEC_E_INCOMPLETE_MESSAGE) { if(out_buf.cbBuffer) { assert(status == SEC_I_CONTINUE_NEEDED); TRACE("sending %u bytes\n", out_buf.cbBuffer); size = sock_send(conn->socket, out_buf.pvBuffer, out_buf.cbBuffer, 0); if(size != out_buf.cbBuffer) { ERR("send failed\n"); res = ERROR_WINHTTP_SECURE_CHANNEL_ERROR; break; } FreeContextBuffer(out_buf.pvBuffer); out_buf.pvBuffer = NULL; out_buf.cbBuffer = 0; } if(status == SEC_I_CONTINUE_NEEDED) { assert(in_bufs[1].cbBuffer < read_buf_size); memmove(read_buf, (BYTE*)in_bufs[0].pvBuffer+in_bufs[0].cbBuffer-in_bufs[1].cbBuffer, in_bufs[1].cbBuffer); in_bufs[0].cbBuffer = in_bufs[1].cbBuffer; in_bufs[1].BufferType = SECBUFFER_EMPTY; in_bufs[1].cbBuffer = 0; in_bufs[1].pvBuffer = NULL; } assert(in_bufs[0].BufferType == SECBUFFER_TOKEN); assert(in_bufs[1].BufferType == SECBUFFER_EMPTY); if(in_bufs[0].cbBuffer + 1024 > read_buf_size) { BYTE *new_read_buf; new_read_buf = heap_realloc(read_buf, read_buf_size + 1024); if(!new_read_buf) { status = E_OUTOFMEMORY; break; } in_bufs[0].pvBuffer = read_buf = new_read_buf; read_buf_size += 1024; } size = sock_recv(conn->socket, read_buf+in_bufs[0].cbBuffer, read_buf_size-in_bufs[0].cbBuffer, 0); if(size < 1) { WARN("recv error\n"); status = ERROR_WINHTTP_SECURE_CHANNEL_ERROR; break; } TRACE("recv %lu bytes\n", size); in_bufs[0].cbBuffer += size; in_bufs[0].pvBuffer = read_buf; status = InitializeSecurityContextW(&cred_handle, &ctx, hostname, isc_req_flags, 0, 0, &in_desc, 0, NULL, &out_desc, &attrs, NULL); TRACE("InitializeSecurityContext ret %08x\n", status); if(status == SEC_E_OK) { if(in_bufs[1].BufferType == SECBUFFER_EXTRA) FIXME("SECBUFFER_EXTRA not supported\n"); status = QueryContextAttributesW(&ctx, SECPKG_ATTR_STREAM_SIZES, &conn->ssl_sizes); if(status != SEC_E_OK) { WARN("Could not get sizes\n"); break; } status = QueryContextAttributesW(&ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&cert); if(status == SEC_E_OK) { res = netconn_verify_cert(cert, hostname, conn->security_flags); CertFreeCertificateContext(cert); if(res != ERROR_SUCCESS) { WARN("cert verify failed: %u\n", res); break; } } else { WARN("Could not get cert\n"); break; } conn->ssl_buf = heap_alloc(conn->ssl_sizes.cbHeader + conn->ssl_sizes.cbMaximumMessage + conn->ssl_sizes.cbTrailer); if(!conn->ssl_buf) { res = GetLastError(); break; } } } heap_free(read_buf); if(status != SEC_E_OK || res != ERROR_SUCCESS) { WARN("Failed to initialize security context failed: %08x\n", status); heap_free(conn->ssl_buf); conn->ssl_buf = NULL; DeleteSecurityContext(&ctx); set_last_error(res ? res : ERROR_WINHTTP_SECURE_CHANNEL_ERROR); return FALSE; } TRACE("established SSL connection\n"); conn->secure = TRUE; conn->ssl_ctx = ctx; return TRUE; }
int sspiClientMechStep(void *conn_context, sasl_client_params_t *cparams, const char *serverin, unsigned serverinlen, sasl_interact_t **prompt_need, const char **clientout, unsigned *clientoutlen, sasl_out_params_t *oparams) { SspiConnContext* pcctx = static_cast<SspiConnContext*>(conn_context); *clientout = NULL; *clientoutlen = 0; if (pcctx->authComplete) { return sspiSendClientAuthzId(pcctx, cparams, serverin, serverinlen, clientout, clientoutlen, oparams); } SecBufferDesc inbuf; SecBuffer inBufs[1]; SecBufferDesc outbuf; SecBuffer outBufs[1]; if (pcctx->haveCtxt) { // If we already have a context, we now have data to send. // Put this data in an inbuf. inbuf.ulVersion = SECBUFFER_VERSION; inbuf.cBuffers = 1; inbuf.pBuffers = inBufs; inBufs[0].pvBuffer = const_cast<char*>(serverin); inBufs[0].cbBuffer = serverinlen; inBufs[0].BufferType = SECBUFFER_TOKEN; } outbuf.ulVersion = SECBUFFER_VERSION; outbuf.cBuffers = 1; outbuf.pBuffers = outBufs; outBufs[0].pvBuffer = NULL; outBufs[0].cbBuffer = 0; outBufs[0].BufferType = SECBUFFER_TOKEN; ULONG contextAttr = 0; SECURITY_STATUS status = InitializeSecurityContextW(&pcctx->cred, pcctx->haveCtxt ? &pcctx->ctx : NULL, const_cast<wchar_t*>( pcctx->nameToken.c_str()), ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_MUTUAL_AUTH, 0, SECURITY_NETWORK_DREP, (pcctx->haveCtxt ? &inbuf : NULL), 0, &pcctx->ctx, &outbuf, &contextAttr, NULL); if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { HandleLastError(cparams->utils, status, "InitializeSecurityContext"); return SASL_FAIL; } ON_BLOCK_EXIT(FreeContextBuffer, outbuf.pBuffers[0].pvBuffer); pcctx->haveCtxt = true; if (status == SEC_E_OK) { // Send back nothing and wait for the server to reply with the security capabilities *clientout = NULL; *clientoutlen = 0; pcctx->authComplete = true; return SASL_CONTINUE; } char *newoutbuf = static_cast<char*>(cparams->utils->malloc(outBufs[0].cbBuffer)); *clientoutlen = outBufs[0].cbBuffer; memcpy(newoutbuf, outBufs[0].pvBuffer, *clientoutlen); *clientout = newoutbuf; return SASL_CONTINUE; }
bool NegotiateAuth::authorize(const AuthParams &challenge, AuthParams &authorization, const URI &uri) { SECURITY_STATUS status; std::wstring packageW = toUtf16(challenge.scheme); std::string param = challenge.base64; std::string outboundBuffer; SecBufferDesc outboundBufferDesc; SecBuffer outboundSecBuffer; TimeStamp lifetime; ULONG contextAttributes; outboundBuffer.resize(4096); outboundBufferDesc.ulVersion = 0; outboundBufferDesc.cBuffers = 1; outboundBufferDesc.pBuffers = &outboundSecBuffer; outboundSecBuffer.BufferType = SECBUFFER_TOKEN; outboundSecBuffer.pvBuffer = &outboundBuffer[0]; outboundSecBuffer.cbBuffer = (unsigned long)outboundBuffer.size(); if (param.empty()) { // No response from server; we're starting a new session if (SecIsValidHandle(&m_creds)) return false; SEC_WINNT_AUTH_IDENTITY_W id; id.User = (unsigned short *)m_username.c_str(); id.UserLength = (unsigned long)m_username.size(); id.Domain = (unsigned short *)m_domain.c_str(); id.DomainLength = (unsigned long)m_domain.size(); id.Password = (unsigned short *)m_password.c_str(); id.PasswordLength = (unsigned long)m_password.size(); id.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; status = AcquireCredentialsHandleW(NULL, (wchar_t *)packageW.c_str(), SECPKG_CRED_OUTBOUND, NULL, m_username.empty() ? NULL : &id, NULL, NULL, &m_creds, &lifetime); MORDOR_LOG_TRACE(g_log) << "AcquireCredentialsHandleW(" << challenge.scheme << ", " << toUtf8(m_username) << "): (" << status << ")"; if (!SUCCEEDED(status)) MORDOR_THROW_EXCEPTION_FROM_ERROR_API(status, "AcquireCredentialsHandleW"); status = InitializeSecurityContextW( &m_creds, NULL, (wchar_t *)toUtf16(uri.toString()).c_str(), ISC_REQ_CONFIDENTIALITY, 0, SECURITY_NATIVE_DREP, NULL, 0, &m_secCtx, &outboundBufferDesc, &contextAttributes, &lifetime); MORDOR_LOG_TRACE(g_log) << "InitializeSecurityContextW(" << uri << ", {0}): {" << outboundSecBuffer.cbBuffer << "} (" << status << ")"; } else { // Prepare the response from the server std::string inboundBuffer = base64decode(param); SecBufferDesc inboundBufferDesc; SecBuffer inboundSecBuffer; inboundBufferDesc.ulVersion = 0; inboundBufferDesc.cBuffers = 1; inboundBufferDesc.pBuffers = &inboundSecBuffer; inboundSecBuffer.BufferType = SECBUFFER_TOKEN; inboundSecBuffer.pvBuffer = &inboundBuffer[0]; inboundSecBuffer.cbBuffer = (unsigned long)inboundBuffer.size(); status = InitializeSecurityContextW( &m_creds, &m_secCtx, (wchar_t *)toUtf16(uri.toString()).c_str(), ISC_REQ_CONFIDENTIALITY, 0, SECURITY_NATIVE_DREP, &inboundBufferDesc, 0, &m_secCtx, &outboundBufferDesc, &contextAttributes, &lifetime); MORDOR_LOG_TRACE(g_log) << "InitializeSecurityContextW(" << uri << ", {" << inboundSecBuffer.cbBuffer << "}): {" << outboundSecBuffer.cbBuffer << "} (" << status << ")"; } if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) { status = CompleteAuthToken(&m_secCtx, &outboundBufferDesc); MORDOR_LOG_TRACE(g_log) << "CompleteAuthToken(): {" << outboundSecBuffer.cbBuffer << "} (" << status << ")"; } if (!SUCCEEDED(status)) MORDOR_THROW_EXCEPTION_FROM_ERROR(status); outboundBuffer.resize(outboundSecBuffer.cbBuffer); authorization.scheme = challenge.scheme; authorization.base64 = base64encode(outboundBuffer); authorization.parameters.clear(); return true; }