winhttp: Use schannel in netconn_secure_connect if OpenSSL is not available.
This commit is contained in:
parent
25de5d7a55
commit
de0d75312b
|
@ -1,7 +1,7 @@
|
|||
MODULE = winhttp.dll
|
||||
IMPORTLIB = winhttp
|
||||
IMPORTS = uuid user32 advapi32
|
||||
DELAYIMPORTS = oleaut32 ole32 crypt32
|
||||
DELAYIMPORTS = oleaut32 ole32 crypt32 secur32
|
||||
EXTRALIBS = @SOCKETLIBS@
|
||||
|
||||
C_SRCS = \
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright 2008 Hans Leidekker for CodeWeavers
|
||||
* Copyright 2013 Jacek Caban for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -22,6 +23,7 @@
|
|||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
|
@ -52,6 +54,7 @@
|
|||
#include "winbase.h"
|
||||
#include "winhttp.h"
|
||||
#include "wincrypt.h"
|
||||
#include "schannel.h"
|
||||
|
||||
#include "winhttp_private.h"
|
||||
|
||||
|
@ -261,6 +264,7 @@ static PCCERT_CONTEXT X509_to_cert_context(X509 *cert)
|
|||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static DWORD netconn_verify_cert( PCCERT_CONTEXT cert, HCERTSTORE store,
|
||||
WCHAR *server, DWORD security_flags )
|
||||
|
@ -355,6 +359,7 @@ static DWORD netconn_verify_cert( PCCERT_CONTEXT cert, HCERTSTORE store,
|
|||
return err;
|
||||
}
|
||||
|
||||
#ifdef SONAME_LIBSSL
|
||||
static int netconn_secure_verify( int preverify_ok, X509_STORE_CTX *ctx )
|
||||
{
|
||||
SSL *ssl;
|
||||
|
@ -408,6 +413,44 @@ static int netconn_secure_verify( int preverify_ok, X509_STORE_CTX *ctx )
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static SecHandle cred_handle;
|
||||
static BOOL cred_handle_initialized;
|
||||
|
||||
static CRITICAL_SECTION init_sechandle_cs;
|
||||
static CRITICAL_SECTION_DEBUG init_sechandle_cs_debug = {
|
||||
0, 0, &init_sechandle_cs,
|
||||
{ &init_sechandle_cs_debug.ProcessLocksList,
|
||||
&init_sechandle_cs_debug.ProcessLocksList },
|
||||
0, 0, { (DWORD_PTR)(__FILE__ ": init_sechandle_cs") }
|
||||
};
|
||||
static CRITICAL_SECTION init_sechandle_cs = { &init_sechandle_cs_debug, -1, 0, 0, 0, 0 };
|
||||
|
||||
static BOOL ensure_cred_handle(void)
|
||||
{
|
||||
BOOL ret = TRUE;
|
||||
|
||||
EnterCriticalSection(&init_sechandle_cs);
|
||||
|
||||
if(!cred_handle_initialized) {
|
||||
SECURITY_STATUS res;
|
||||
|
||||
res = AcquireCredentialsHandleW(NULL, (WCHAR*)UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL, NULL,
|
||||
NULL, NULL, &cred_handle, NULL);
|
||||
if(res == SEC_E_OK) {
|
||||
cred_handle_initialized = TRUE;
|
||||
}else {
|
||||
WARN("AcquireCredentialsHandleW failed: %u\n", res);
|
||||
ret = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&init_sechandle_cs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
BOOL netconn_init( netconn_t *conn, BOOL secure )
|
||||
|
@ -580,6 +623,10 @@ void netconn_unload( void )
|
|||
heap_free( ssl_locks );
|
||||
}
|
||||
DeleteCriticalSection(&init_ssl_cs);
|
||||
#else
|
||||
if(cred_handle_initialized)
|
||||
FreeCredentialsHandle(&cred_handle);
|
||||
DeleteCriticalSection(&init_sechandle_cs);
|
||||
#endif
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
DeleteCriticalSection(&cs_gethostbyname);
|
||||
|
@ -606,7 +653,6 @@ BOOL netconn_close( netconn_t *conn )
|
|||
{
|
||||
int res;
|
||||
|
||||
#ifdef SONAME_LIBSSL
|
||||
if (conn->secure)
|
||||
{
|
||||
heap_free( conn->peek_msg_mem );
|
||||
|
@ -614,13 +660,19 @@ BOOL netconn_close( netconn_t *conn )
|
|||
conn->peek_msg = NULL;
|
||||
conn->peek_len = 0;
|
||||
|
||||
#ifdef SONAME_LIBSSL
|
||||
pSSL_shutdown( conn->ssl_conn );
|
||||
pSSL_free( conn->ssl_conn );
|
||||
|
||||
conn->ssl_conn = NULL;
|
||||
#else
|
||||
heap_free(conn->extra_buf);
|
||||
conn->extra_buf = NULL;
|
||||
conn->extra_len = 0;
|
||||
DeleteSecurityContext(&conn->ssl_ctx);
|
||||
#endif
|
||||
conn->secure = FALSE;
|
||||
}
|
||||
#endif
|
||||
res = closesocket( conn->socket );
|
||||
conn->socket = -1;
|
||||
if (res == -1)
|
||||
|
@ -719,8 +771,132 @@ fail:
|
|||
pSSL_free( conn->ssl_conn );
|
||||
conn->ssl_conn = NULL;
|
||||
}
|
||||
#else
|
||||
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 = send(conn->socket, out_buf.pvBuffer, out_buf.cbBuffer, 0);
|
||||
if(size != out_buf.cbBuffer) {
|
||||
ERR("send failed\n");
|
||||
status = 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 = 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, cert->hCertStore, 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(status != SEC_E_OK || res != ERROR_SUCCESS) {
|
||||
WARN("Failed to initialize security context failed: %08x\n", status);
|
||||
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;
|
||||
#endif
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL netconn_send( netconn_t *conn, const void *msg, size_t len, int flags, int *sent )
|
||||
|
|
|
@ -42,7 +42,9 @@
|
|||
# define closesocket close
|
||||
# define ioctlsocket ioctl
|
||||
#endif
|
||||
|
||||
#include "ole2.h"
|
||||
#include "sspi.h"
|
||||
|
||||
static const WCHAR getW[] = {'G','E','T',0};
|
||||
static const WCHAR postW[] = {'P','O','S','T',0};
|
||||
|
@ -128,6 +130,10 @@ typedef struct
|
|||
int socket;
|
||||
BOOL secure; /* SSL active on connection? */
|
||||
void *ssl_conn;
|
||||
CtxtHandle ssl_ctx;
|
||||
SecPkgContext_StreamSizes ssl_sizes;
|
||||
char *extra_buf;
|
||||
size_t extra_len;
|
||||
char *peek_msg;
|
||||
char *peek_msg_mem;
|
||||
size_t peek_len;
|
||||
|
|
Loading…
Reference in New Issue