Commit 1e5153cf authored by Robert Shearman's avatar Robert Shearman Committed by Alexandre Julliard

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.
parent b43afeef
...@@ -7037,6 +7037,7 @@ done ...@@ -7037,6 +7037,7 @@ done
for ac_header in \ for ac_header in \
IOKit/IOKitLib.h \ IOKit/IOKitLib.h \
alsa/asoundlib.h \ alsa/asoundlib.h \
...@@ -7085,6 +7086,7 @@ for ac_header in \ ...@@ -7085,6 +7086,7 @@ for ac_header in \
netinet/in_systm.h \ netinet/in_systm.h \
netinet/tcp.h \ netinet/tcp.h \
netinet/tcp_fsm.h \ netinet/tcp_fsm.h \
openssl/err.h \
openssl/ssl.h \ openssl/ssl.h \
poll.h \ poll.h \
process.h \ process.h \
......
...@@ -219,6 +219,7 @@ AC_CHECK_HEADERS(\ ...@@ -219,6 +219,7 @@ AC_CHECK_HEADERS(\
netinet/in_systm.h \ netinet/in_systm.h \
netinet/tcp.h \ netinet/tcp.h \
netinet/tcp_fsm.h \ netinet/tcp_fsm.h \
openssl/err.h \
openssl/ssl.h \ openssl/ssl.h \
poll.h \ poll.h \
process.h \ process.h \
......
...@@ -57,7 +57,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(wininet); ...@@ -57,7 +57,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(wininet);
* SSL stuff should use crypt32.dll * 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 #ifndef SONAME_LIBSSL
#define SONAME_LIBSSL "libssl.so" #define SONAME_LIBSSL "libssl.so"
...@@ -80,16 +82,22 @@ MAKE_FUNCPTR(SSL_load_error_strings); ...@@ -80,16 +82,22 @@ MAKE_FUNCPTR(SSL_load_error_strings);
MAKE_FUNCPTR(SSLv23_method); MAKE_FUNCPTR(SSLv23_method);
MAKE_FUNCPTR(SSL_CTX_new); MAKE_FUNCPTR(SSL_CTX_new);
MAKE_FUNCPTR(SSL_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_connect);
MAKE_FUNCPTR(SSL_shutdown);
MAKE_FUNCPTR(SSL_write); MAKE_FUNCPTR(SSL_write);
MAKE_FUNCPTR(SSL_read); 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_get_timeout);
MAKE_FUNCPTR(SSL_CTX_set_timeout); MAKE_FUNCPTR(SSL_CTX_set_timeout);
MAKE_FUNCPTR(SSL_CTX_set_default_verify_paths);
/* OpenSSL's libcrypto functions that we use */ /* OpenSSL's libcrypto functions that we use */
MAKE_FUNCPTR(BIO_new_socket);
MAKE_FUNCPTR(BIO_new_fp); MAKE_FUNCPTR(BIO_new_fp);
MAKE_FUNCPTR(ERR_get_error);
MAKE_FUNCPTR(ERR_error_string);
#undef MAKE_FUNCPTR #undef MAKE_FUNCPTR
#endif #endif
...@@ -100,7 +108,7 @@ void NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) ...@@ -100,7 +108,7 @@ void NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL)
connection->socketFD = -1; connection->socketFD = -1;
if (useSSL) if (useSSL)
{ {
#ifdef HAVE_OPENSSL_SSL_H #if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
TRACE("using SSL connection\n"); TRACE("using SSL connection\n");
if (OpenSSL_ssl_handle) /* already initilzed everything */ if (OpenSSL_ssl_handle) /* already initilzed everything */
return; return;
...@@ -136,12 +144,17 @@ void NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) ...@@ -136,12 +144,17 @@ void NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL)
DYNSSL(SSLv23_method); DYNSSL(SSLv23_method);
DYNSSL(SSL_CTX_new); DYNSSL(SSL_CTX_new);
DYNSSL(SSL_new); DYNSSL(SSL_new);
DYNSSL(SSL_set_bio); DYNSSL(SSL_free);
DYNSSL(SSL_set_fd);
DYNSSL(SSL_connect); DYNSSL(SSL_connect);
DYNSSL(SSL_shutdown);
DYNSSL(SSL_write); DYNSSL(SSL_write);
DYNSSL(SSL_read); DYNSSL(SSL_read);
DYNSSL(SSL_get_verify_result);
DYNSSL(SSL_get_peer_certificate);
DYNSSL(SSL_CTX_get_timeout); DYNSSL(SSL_CTX_get_timeout);
DYNSSL(SSL_CTX_set_timeout); DYNSSL(SSL_CTX_set_timeout);
DYNSSL(SSL_CTX_set_default_verify_paths);
#undef DYNSSL #undef DYNSSL
#define DYNCRYPTO(x) \ #define DYNCRYPTO(x) \
...@@ -153,7 +166,8 @@ void NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL) ...@@ -153,7 +166,8 @@ void NETCON_init(WININET_NETCONNECTION *connection, BOOL useSSL)
return; \ return; \
} }
DYNCRYPTO(BIO_new_fp); DYNCRYPTO(BIO_new_fp);
DYNCRYPTO(BIO_new_socket); DYNCRYPTO(ERR_get_error);
DYNCRYPTO(ERR_error_string);
#undef DYNCRYPTO #undef DYNCRYPTO
pSSL_library_init(); pSSL_library_init();
...@@ -185,7 +199,7 @@ BOOL NETCON_connected(WININET_NETCONNECTION *connection) ...@@ -185,7 +199,7 @@ BOOL NETCON_connected(WININET_NETCONNECTION *connection)
BOOL NETCON_create(WININET_NETCONNECTION *connection, int domain, BOOL NETCON_create(WININET_NETCONNECTION *connection, int domain,
int type, int protocol) int type, int protocol)
{ {
#ifndef HAVE_OPENSSL_SSL_H #if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
if (connection->useSSL) if (connection->useSSL)
return FALSE; return FALSE;
#endif #endif
...@@ -206,56 +220,128 @@ BOOL NETCON_close(WININET_NETCONNECTION *connection) ...@@ -206,56 +220,128 @@ BOOL NETCON_close(WININET_NETCONNECTION *connection)
if (!NETCON_connected(connection)) return FALSE; if (!NETCON_connected(connection)) return FALSE;
result = closesocket(connection->socketFD); #if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
connection->socketFD = -1;
#ifdef HAVE_OPENSSL_SSL_H
if (connection->useSSL) if (connection->useSSL)
{ {
HeapFree(GetProcessHeap(),0,connection->peek_msg_mem); HeapFree(GetProcessHeap(),0,connection->peek_msg_mem);
connection->peek_msg = NULL; connection->peek_msg = NULL;
connection->peek_msg_mem = 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; connection->useSSL = FALSE;
} }
#endif #endif
result = closesocket(connection->socketFD);
connection->socketFD = -1;
if (result == -1) if (result == -1)
return FALSE; return FALSE;
return TRUE; return TRUE;
} }
static BOOL check_hostname(X509 *cert, char *hostname)
{
/* FIXME: implement */
return TRUE;
}
/****************************************************************************** /******************************************************************************
* NETCON_secure_connect * NETCON_secure_connect
* Initiates a secure connection over an existing plaintext connection. * Initiates a secure connection over an existing plaintext connection.
*/ */
BOOL NETCON_secure_connect(WININET_NETCONNECTION *connection, LPCWSTR hostname) BOOL NETCON_secure_connect(WININET_NETCONNECTION *connection, LPCWSTR hostname)
{ {
#ifdef HAVE_OPENSSL_SSL_H #if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
BIO *sbio; 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) if (connection->useSSL)
{
ERR("already connected\n");
return FALSE; return FALSE;
}
ctx = pSSL_CTX_new(meth); 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); 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;
}
sbio = pBIO_new_socket(connection->socketFD, BIO_NOCLOSE);
pSSL_set_bio(connection->ssl_s, sbio, sbio);
if (pSSL_connect(connection->ssl_s) <= 0) if (pSSL_connect(connection->ssl_s) <= 0)
{ {
ERR("ssl couldn't connect\n"); ERR("SSL_connect failed: %s\n",
return FALSE; 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;
} }
/* FIXME: verify the security of the connection and that the WideCharToMultiByte(CP_UNIXCP, 0, hostname, -1, hostname_unix, len, NULL, NULL);
* hostname of the certificate matches */
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; connection->useSSL = TRUE;
return 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 #endif
return FALSE;
} }
/****************************************************************************** /******************************************************************************
...@@ -298,7 +384,7 @@ BOOL NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len, ...@@ -298,7 +384,7 @@ BOOL NETCON_send(WININET_NETCONNECTION *connection, const void *msg, size_t len,
} }
else else
{ {
#ifdef HAVE_OPENSSL_SSL_H #if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
if (flags) if (flags)
FIXME("SSL_write doesn't support any flags (%08x)\n", flags); FIXME("SSL_write doesn't support any flags (%08x)\n", flags);
*sent = pSSL_write(connection->ssl_s, msg, len); *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 ...@@ -329,7 +415,7 @@ BOOL NETCON_recv(WININET_NETCONNECTION *connection, void *buf, size_t len, int f
} }
else else
{ {
#ifdef HAVE_OPENSSL_SSL_H #if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
if (flags & (~MSG_PEEK)) if (flags & (~MSG_PEEK))
FIXME("SSL_read does not support the following flag: %08x\n", flags); 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 ...@@ -446,7 +532,7 @@ BOOL NETCON_getNextLine(WININET_NETCONNECTION *connection, LPSTR lpszBuffer, LPD
} }
else else
{ {
#ifdef HAVE_OPENSSL_SSL_H #if defined HAVE_OPENSSL_SSL_H && defined HAVE_OPENSSL_ERR_H
long prev_timeout; long prev_timeout;
DWORD nRecv = 0; DWORD nRecv = 0;
BOOL success = TRUE; BOOL success = TRUE;
......
...@@ -431,6 +431,9 @@ ...@@ -431,6 +431,9 @@
/* Define if OpenGL is present on the system */ /* Define if OpenGL is present on the system */
#undef HAVE_OPENGL #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. */ /* Define to 1 if you have the <openssl/ssl.h> header file. */
#undef HAVE_OPENSSL_SSL_H #undef HAVE_OPENSSL_SSL_H
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment