Cleanup SSL connections properly, do a few security checks in

NETCON_secure_connect and display errors from SSL on failure. Don't
use SSL_set_bio as SSL_set_fd is cleaner for us.
This commit is contained in:
Robert Shearman 2005-12-01 11:18:43 +01:00 committed by Alexandre Julliard
parent b43afeef89
commit 1e5153cf3c
4 changed files with 125 additions and 33 deletions

2
configure vendored
View File

@ -7035,6 +7035,7 @@ done
for ac_header in \
@ -7085,6 +7086,7 @@ for ac_header in \
netinet/in_systm.h \
netinet/tcp.h \
netinet/tcp_fsm.h \
openssl/err.h \
openssl/ssl.h \
poll.h \
process.h \

View File

@ -219,6 +219,7 @@ AC_CHECK_HEADERS(\
netinet/in_systm.h \
netinet/tcp.h \
netinet/tcp_fsm.h \
openssl/err.h \
openssl/ssl.h \
poll.h \
process.h \

View File

@ -57,7 +57,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(wininet);
* SSL stuff should use crypt32.dll
*/
#ifdef HAVE_OPENSSL_SSL_H
#if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
#include <openssl/err.h>
#ifndef SONAME_LIBSSL
#define SONAME_LIBSSL "libssl.so"
@ -80,16 +82,22 @@ MAKE_FUNCPTR(SSL_load_error_strings);
MAKE_FUNCPTR(SSLv23_method);
MAKE_FUNCPTR(SSL_CTX_new);
MAKE_FUNCPTR(SSL_new);
MAKE_FUNCPTR(SSL_set_bio);
MAKE_FUNCPTR(SSL_free);
MAKE_FUNCPTR(SSL_set_fd);
MAKE_FUNCPTR(SSL_connect);
MAKE_FUNCPTR(SSL_shutdown);
MAKE_FUNCPTR(SSL_write);
MAKE_FUNCPTR(SSL_read);
MAKE_FUNCPTR(SSL_get_verify_result);
MAKE_FUNCPTR(SSL_get_peer_certificate);
MAKE_FUNCPTR(SSL_CTX_get_timeout);
MAKE_FUNCPTR(SSL_CTX_set_timeout);
MAKE_FUNCPTR(SSL_CTX_set_default_verify_paths);
/* OpenSSL's libcrypto functions that we use */
MAKE_FUNCPTR(BIO_new_socket);
MAKE_FUNCPTR(BIO_new_fp);
MAKE_FUNCPTR(ERR_get_error);
MAKE_FUNCPTR(ERR_error_string);
#undef MAKE_FUNCPTR
#endif
@ -100,7 +108,7 @@ void NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL)
connection->socketFD = -1;
if (useSSL)
{
#ifdef HAVE_OPENSSL_SSL_H
#if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
TRACE("using SSL connection\n");
if (OpenSSL_ssl_handle) /* already initilzed everything */
return;
@ -136,12 +144,17 @@ void NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL)
DYNSSL(SSLv23_method);
DYNSSL(SSL_CTX_new);
DYNSSL(SSL_new);
DYNSSL(SSL_set_bio);
DYNSSL(SSL_free);
DYNSSL(SSL_set_fd);
DYNSSL(SSL_connect);
DYNSSL(SSL_shutdown);
DYNSSL(SSL_write);
DYNSSL(SSL_read);
DYNSSL(SSL_get_verify_result);
DYNSSL(SSL_get_peer_certificate);
DYNSSL(SSL_CTX_get_timeout);
DYNSSL(SSL_CTX_set_timeout);
DYNSSL(SSL_CTX_set_default_verify_paths);
#undef DYNSSL
#define DYNCRYPTO(x) \
@ -153,7 +166,8 @@ void NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL)
return; \
}
DYNCRYPTO(BIO_new_fp);
DYNCRYPTO(BIO_new_socket);
DYNCRYPTO(ERR_get_error);
DYNCRYPTO(ERR_error_string);
#undef DYNCRYPTO
pSSL_library_init();
@ -185,7 +199,7 @@ BOOL NETCON_connected(WININET_NETCONNECTION *connection)
BOOL NETCON_create(WININET_NETCONNECTION *connection, int domain,
int type, int protocol)
{
#ifndef HAVE_OPENSSL_SSL_H
#if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
if (connection->useSSL)
return FALSE;
#endif
@ -206,56 +220,128 @@ BOOL NETCON_close(WININET_NETCONNECTION *connection)
if (!NETCON_connected(connection)) return FALSE;
result = closesocket(connection->socketFD);
connection->socketFD = -1;
#ifdef HAVE_OPENSSL_SSL_H
#if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
if (connection->useSSL)
{
HeapFree(GetProcessHeap(),0,connection->peek_msg_mem);
connection->peek_msg = NULL;
connection->peek_msg_mem = NULL;
/* FIXME should we call SSL_shutdown here?? Probably on whatever is the
* opposite of NETCON_secure_connect.... */
pSSL_shutdown(connection->ssl_s);
pSSL_free(connection->ssl_s);
connection->ssl_s = NULL;
connection->useSSL = FALSE;
}
#endif
result = closesocket(connection->socketFD);
connection->socketFD = -1;
if (result == -1)
return FALSE;
return TRUE;
}
static BOOL check_hostname(X509 *cert, char *hostname)
{
/* FIXME: implement */
return TRUE;
}
/******************************************************************************
* NETCON_secure_connect
* Initiates a secure connection over an existing plaintext connection.
*/
BOOL NETCON_secure_connect(WININET_NETCONNECTION *connection, LPCWSTR hostname)
{
#ifdef HAVE_OPENSSL_SSL_H
BIO *sbio;
#if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
long verify_res;
X509 *cert;
int len;
char *hostname_unix;
/* nothing to do if we are already connected */
/* can't connect if we are already connected */
if (connection->useSSL)
return FALSE;
ctx = pSSL_CTX_new(meth);
connection->ssl_s = pSSL_new(ctx);
sbio = pBIO_new_socket(connection->socketFD, BIO_NOCLOSE);
pSSL_set_bio(connection->ssl_s, sbio, sbio);
if (pSSL_connect(connection->ssl_s) <= 0)
{
ERR("ssl couldn't connect\n");
ERR("already connected\n");
return FALSE;
}
/* FIXME: verify the security of the connection and that the
* hostname of the certificate matches */
ctx = pSSL_CTX_new(meth);
if (!pSSL_CTX_set_default_verify_paths(ctx))
{
ERR("SSL_CTX_set_default_verify_paths failed: %s\n",
pERR_error_string(pERR_get_error(), 0));
return FALSE;
}
connection->ssl_s = pSSL_new(ctx);
if (!connection->ssl_s)
{
ERR("SSL_new failed: %s\n",
pERR_error_string(pERR_get_error(), 0));
goto fail;
}
if (!pSSL_set_fd(connection->ssl_s, connection->socketFD))
{
ERR("SSL_set_fd failed: %s\n",
pERR_error_string(pERR_get_error(), 0));
goto fail;
}
if (pSSL_connect(connection->ssl_s) <= 0)
{
ERR("SSL_connect failed: %s\n",
pERR_error_string(pERR_get_error(), 0));
INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR);
goto fail;
}
cert = pSSL_get_peer_certificate(connection->ssl_s);
if (!cert)
{
ERR("no certificate for server %s\n", debugstr_w(hostname));
/* FIXME: is this the best error? */
INTERNET_SetLastError(ERROR_INTERNET_INVALID_CA);
goto fail;
}
verify_res = pSSL_get_verify_result(connection->ssl_s);
if (verify_res != X509_V_OK)
{
ERR("couldn't verify the security of the connection, %ld\n", verify_res);
/* FIXME: we should set an error and return, but we only warn at
* the moment */
}
len = WideCharToMultiByte(CP_UNIXCP, 0, hostname, -1, NULL, 0, NULL, NULL);
hostname_unix = HeapAlloc(GetProcessHeap(), 0, len);
if (!hostname_unix)
{
INTERNET_SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto fail;
}
WideCharToMultiByte(CP_UNIXCP, 0, hostname, -1, hostname_unix, len, NULL, NULL);
if (!check_hostname(cert, hostname_unix))
{
HeapFree(GetProcessHeap(), 0, hostname_unix);
INTERNET_SetLastError(ERROR_INTERNET_SEC_CERT_CN_INVALID);
goto fail;
}
HeapFree(GetProcessHeap(), 0, hostname_unix);
connection->useSSL = TRUE;
return TRUE;
#else
return FALSE;
fail:
if (connection->ssl_s)
{
pSSL_shutdown(connection->ssl_s);
pSSL_free(connection->ssl_s);
connection->ssl_s = NULL;
}
#endif
return FALSE;
}
/******************************************************************************
@ -298,7 +384,7 @@ BOOL NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len,
}
else
{
#ifdef HAVE_OPENSSL_SSL_H
#if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
if (flags)
FIXME("SSL_write doesn't support any flags (%08x)\n", flags);
*sent = pSSL_write(connection->ssl_s, msg, len);
@ -329,7 +415,7 @@ BOOL NETCON_recv(WININET_NETCONNECTION *connection, void *buf, size_t len, int f
}
else
{
#ifdef HAVE_OPENSSL_SSL_H
#if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
if (flags & (~MSG_PEEK))
FIXME("SSL_read does not support the following flag: %08x\n", flags);
@ -446,7 +532,7 @@ BOOL NETCON_getNextLine(WININET_NETCONNECTION *connection, LPSTR lpszBuffer, LPD
}
else
{
#ifdef HAVE_OPENSSL_SSL_H
#if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
long prev_timeout;
DWORD nRecv = 0;
BOOL success = TRUE;

View File

@ -431,6 +431,9 @@
/* Define if OpenGL is present on the system */
#undef HAVE_OPENGL
/* Define to 1 if you have the <openssl/err.h> header file. */
#undef HAVE_OPENSSL_ERR_H
/* Define to 1 if you have the <openssl/ssl.h> header file. */
#undef HAVE_OPENSSL_SSL_H