/****************************************************************************** * NETCON_secure_connect * Initiates a secure connection over an existing plaintext connection. */ DWORD NETCON_secure_connect(netconn_t *connection) { DWORD res = ERROR_NOT_SUPPORTED; #ifdef SONAME_LIBSSL void *ssl_s; /* can't connect if we are already connected */ if (connection->ssl_s) { ERR("already connected\n"); return ERROR_INTERNET_CANNOT_CONNECT; } ssl_s = pSSL_new(ctx); if (!ssl_s) { ERR("SSL_new failed: %s\n", pERR_error_string(pERR_get_error(), 0)); return ERROR_OUTOFMEMORY; } if (!pSSL_set_fd(ssl_s, connection->socketFD)) { ERR("SSL_set_fd failed: %s\n", pERR_error_string(pERR_get_error(), 0)); res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR; goto fail; } if (!pSSL_set_ex_data(ssl_s, conn_idx, connection)) { ERR("SSL_set_ex_data failed: %s\n", pERR_error_string(pERR_get_error(), 0)); res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR; goto fail; } if (pSSL_connect(ssl_s) <= 0) { res = (DWORD_PTR)pSSL_get_ex_data(ssl_s, error_idx); if (!res) res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR; ERR("SSL_connect failed: %d\n", res); goto fail; } connection->ssl_s = ssl_s; return ERROR_SUCCESS; fail: if (ssl_s) { pSSL_shutdown(ssl_s); pSSL_free(ssl_s); } #endif return res; }
BOOL netconn_secure_connect( netconn_t *conn ) { #ifdef SONAME_LIBSSL X509 *cert; long res; ctx = pSSL_CTX_new( method ); 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 )); set_last_error( ERROR_OUTOFMEMORY ); return FALSE; } if (!(conn->ssl_conn = pSSL_new( ctx ))) { ERR("SSL_new failed: %s\n", pERR_error_string( pERR_get_error(), 0 )); set_last_error( ERROR_OUTOFMEMORY ); goto fail; } if (!pSSL_set_fd( conn->ssl_conn, conn->socket )) { ERR("SSL_set_fd failed: %s\n", pERR_error_string( pERR_get_error(), 0 )); set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR ); goto fail; } if (pSSL_connect( conn->ssl_conn ) <= 0) { ERR("SSL_connect failed: %s\n", pERR_error_string( pERR_get_error(), 0 )); set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR ); goto fail; } if (!(cert = pSSL_get_peer_certificate( conn->ssl_conn ))) { ERR("No certificate for server: %s\n", pERR_error_string( pERR_get_error(), 0 )); set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR ); goto fail; } if ((res = pSSL_get_verify_result( conn->ssl_conn )) != X509_V_OK) { /* FIXME: we should set an error and return, but we only print an error at the moment */ ERR("couldn't verify server certificate (%ld)\n", res); } TRACE("established SSL connection\n"); conn->secure = TRUE; return TRUE; fail: if (conn->ssl_conn) { pSSL_shutdown( conn->ssl_conn ); pSSL_free( conn->ssl_conn ); conn->ssl_conn = NULL; } #endif return FALSE; }
BOOL netconn_secure_connect( netconn_t *conn, WCHAR *hostname ) { #ifdef SONAME_LIBSSL if (!(conn->ssl_conn = pSSL_new( ctx ))) { ERR("SSL_new failed: %s\n", pERR_error_string( pERR_get_error(), 0 )); set_last_error( ERROR_OUTOFMEMORY ); goto fail; } if (!pSSL_set_ex_data( conn->ssl_conn, hostname_idx, hostname )) { ERR("SSL_set_ex_data failed: %s\n", pERR_error_string( pERR_get_error(), 0 )); set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR ); goto fail; } if (!pSSL_set_ex_data( conn->ssl_conn, conn_idx, conn )) { ERR("SSL_set_ex_data failed: %s\n", pERR_error_string( pERR_get_error(), 0 )); set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR ); return FALSE; } if (!pSSL_set_fd( conn->ssl_conn, conn->socket )) { ERR("SSL_set_fd failed: %s\n", pERR_error_string( pERR_get_error(), 0 )); set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR ); goto fail; } if (pSSL_connect( conn->ssl_conn ) <= 0) { DWORD err; err = (DWORD_PTR)pSSL_get_ex_data( conn->ssl_conn, error_idx ); if (!err) err = ERROR_WINHTTP_SECURE_CHANNEL_ERROR; ERR("couldn't verify server certificate (%d)\n", err); set_last_error( err ); goto fail; } TRACE("established SSL connection\n"); conn->secure = TRUE; return TRUE; fail: if (conn->ssl_conn) { pSSL_shutdown( conn->ssl_conn ); pSSL_free( conn->ssl_conn ); conn->ssl_conn = NULL; } #endif return FALSE; }
BOOL netconn_init( netconn_t *conn, BOOL secure ) { #if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO) int i; #endif conn->socket = -1; if (!secure) return TRUE; #if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO) EnterCriticalSection( &init_ssl_cs ); if (libssl_handle) { LeaveCriticalSection( &init_ssl_cs ); return TRUE; } if (!(libssl_handle = wine_dlopen( SONAME_LIBSSL, RTLD_NOW, NULL, 0 ))) { ERR("Trying to use SSL but couldn't load %s. Expect trouble.\n", SONAME_LIBSSL); set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR ); LeaveCriticalSection( &init_ssl_cs ); return FALSE; } if (!(libcrypto_handle = wine_dlopen( SONAME_LIBCRYPTO, RTLD_NOW, NULL, 0 ))) { ERR("Trying to use SSL but couldn't load %s. Expect trouble.\n", SONAME_LIBCRYPTO); set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR ); LeaveCriticalSection( &init_ssl_cs ); return FALSE; } #define LOAD_FUNCPTR(x) \ if (!(p##x = wine_dlsym( libssl_handle, #x, NULL, 0 ))) \ { \ ERR("Failed to load symbol %s\n", #x); \ set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR ); \ LeaveCriticalSection( &init_ssl_cs ); \ return FALSE; \ } LOAD_FUNCPTR( SSL_library_init ); LOAD_FUNCPTR( SSL_load_error_strings ); LOAD_FUNCPTR( SSLv23_method ); LOAD_FUNCPTR( SSL_CTX_free ); LOAD_FUNCPTR( SSL_CTX_new ); LOAD_FUNCPTR( SSL_new ); LOAD_FUNCPTR( SSL_free ); LOAD_FUNCPTR( SSL_set_fd ); LOAD_FUNCPTR( SSL_connect ); LOAD_FUNCPTR( SSL_shutdown ); LOAD_FUNCPTR( SSL_write ); LOAD_FUNCPTR( SSL_read ); LOAD_FUNCPTR( SSL_get_error ); LOAD_FUNCPTR( SSL_get_ex_new_index ); LOAD_FUNCPTR( SSL_get_ex_data ); LOAD_FUNCPTR( SSL_set_ex_data ); LOAD_FUNCPTR( SSL_get_ex_data_X509_STORE_CTX_idx ); LOAD_FUNCPTR( SSL_get_peer_certificate ); LOAD_FUNCPTR( SSL_CTX_set_default_verify_paths ); LOAD_FUNCPTR( SSL_CTX_set_verify ); LOAD_FUNCPTR( SSL_get_current_cipher ); LOAD_FUNCPTR( SSL_CIPHER_get_bits ); #undef LOAD_FUNCPTR #define LOAD_FUNCPTR(x) \ if (!(p##x = wine_dlsym( libcrypto_handle, #x, NULL, 0 ))) \ { \ ERR("Failed to load symbol %s\n", #x); \ set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR ); \ LeaveCriticalSection( &init_ssl_cs ); \ return FALSE; \ } LOAD_FUNCPTR( CRYPTO_num_locks ); LOAD_FUNCPTR( CRYPTO_set_id_callback ); LOAD_FUNCPTR( CRYPTO_set_locking_callback ); LOAD_FUNCPTR( ERR_free_strings ); LOAD_FUNCPTR( ERR_get_error ); LOAD_FUNCPTR( ERR_error_string ); LOAD_FUNCPTR( X509_STORE_CTX_get_ex_data ); LOAD_FUNCPTR( i2d_X509 ); LOAD_FUNCPTR( sk_value ); LOAD_FUNCPTR( sk_num ); #undef LOAD_FUNCPTR pSSL_library_init(); pSSL_load_error_strings(); method = pSSLv23_method(); ctx = pSSL_CTX_new( method ); 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 )); set_last_error( ERROR_OUTOFMEMORY ); LeaveCriticalSection( &init_ssl_cs ); return FALSE; } hostname_idx = pSSL_get_ex_new_index( 0, (void *)"hostname index", NULL, NULL, NULL ); if (hostname_idx == -1) { ERR("SSL_get_ex_new_index failed: %s\n", pERR_error_string( pERR_get_error(), 0 )); set_last_error( ERROR_OUTOFMEMORY ); LeaveCriticalSection( &init_ssl_cs ); return FALSE; } error_idx = pSSL_get_ex_new_index( 0, (void *)"error index", NULL, NULL, NULL ); if (error_idx == -1) { ERR("SSL_get_ex_new_index failed: %s\n", pERR_error_string( pERR_get_error(), 0 )); set_last_error( ERROR_OUTOFMEMORY ); LeaveCriticalSection( &init_ssl_cs ); return FALSE; } conn_idx = pSSL_get_ex_new_index( 0, (void *)"netconn index", NULL, NULL, NULL ); if (conn_idx == -1) { ERR("SSL_get_ex_new_index failed: %s\n", pERR_error_string( pERR_get_error(), 0 )); set_last_error( ERROR_OUTOFMEMORY ); LeaveCriticalSection( &init_ssl_cs ); return FALSE; } pSSL_CTX_set_verify( ctx, SSL_VERIFY_PEER, netconn_secure_verify ); pCRYPTO_set_id_callback(ssl_thread_id); num_ssl_locks = pCRYPTO_num_locks(); ssl_locks = HeapAlloc(GetProcessHeap(), 0, num_ssl_locks * sizeof(CRITICAL_SECTION)); if (!ssl_locks) { set_last_error( ERROR_OUTOFMEMORY ); LeaveCriticalSection( &init_ssl_cs ); return FALSE; } for (i = 0; i < num_ssl_locks; i++) InitializeCriticalSection( &ssl_locks[i] ); pCRYPTO_set_locking_callback(ssl_lock_callback); LeaveCriticalSection( &init_ssl_cs ); #else WARN("SSL support not compiled in.\n"); set_last_error( ERROR_WINHTTP_SECURE_CHANNEL_ERROR ); return FALSE; #endif return TRUE; }
/****************************************************************************** * NETCON_secure_connect * Initiates a secure connection over an existing plaintext connection. */ BOOL NETCON_secure_connect(WININET_NETCONNECTION *connection, LPCWSTR hostname) { #ifdef SONAME_LIBSSL long verify_res; X509 *cert; int len; char *hostname_unix; /* can't connect if we are already connected */ if (connection->useSSL) { ERR("already connected\n"); return FALSE; } 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)); INTERNET_SetLastError(ERROR_OUTOFMEMORY); 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)); INTERNET_SetLastError(ERROR_OUTOFMEMORY); 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)); INTERNET_SetLastError(ERROR_INTERNET_SECURITY_CHANNEL_ERROR); 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_OUTOFMEMORY); 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; fail: if (connection->ssl_s) { pSSL_shutdown(connection->ssl_s); pSSL_free(connection->ssl_s); connection->ssl_s = NULL; } #endif return FALSE; }
static DWORD init_openssl(void) { #if defined(SONAME_LIBSSL) && defined(SONAME_LIBCRYPTO) int i; if(OpenSSL_ssl_handle) return ERROR_SUCCESS; OpenSSL_ssl_handle = wine_dlopen(SONAME_LIBSSL, RTLD_NOW, NULL, 0); if(!OpenSSL_ssl_handle) { ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n", SONAME_LIBSSL); return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; } OpenSSL_crypto_handle = wine_dlopen(SONAME_LIBCRYPTO, RTLD_NOW, NULL, 0); if(!OpenSSL_crypto_handle) { ERR("trying to use a SSL connection, but couldn't load %s. Expect trouble.\n", SONAME_LIBCRYPTO); return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; } /* mmm nice ugly macroness */ #define DYNSSL(x) \ p##x = wine_dlsym(OpenSSL_ssl_handle, #x, NULL, 0); \ if (!p##x) { \ ERR("failed to load symbol %s\n", #x); \ return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; \ } DYNSSL(SSL_library_init); DYNSSL(SSL_load_error_strings); DYNSSL(SSLv23_method); DYNSSL(SSL_CTX_free); DYNSSL(SSL_CTX_new); DYNSSL(SSL_new); DYNSSL(SSL_free); DYNSSL(SSL_set_fd); DYNSSL(SSL_connect); DYNSSL(SSL_shutdown); DYNSSL(SSL_write); DYNSSL(SSL_read); DYNSSL(SSL_pending); DYNSSL(SSL_get_error); DYNSSL(SSL_get_ex_new_index); DYNSSL(SSL_get_ex_data); DYNSSL(SSL_set_ex_data); DYNSSL(SSL_get_ex_data_X509_STORE_CTX_idx); DYNSSL(SSL_get_peer_certificate); DYNSSL(SSL_CTX_get_timeout); DYNSSL(SSL_CTX_set_timeout); DYNSSL(SSL_CTX_set_default_verify_paths); DYNSSL(SSL_CTX_set_verify); DYNSSL(SSL_get_current_cipher); DYNSSL(SSL_CIPHER_get_bits); #undef DYNSSL #define DYNCRYPTO(x) \ p##x = wine_dlsym(OpenSSL_crypto_handle, #x, NULL, 0); \ if (!p##x) { \ ERR("failed to load symbol %s\n", #x); \ return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; \ } DYNCRYPTO(BIO_new_fp); DYNCRYPTO(CRYPTO_num_locks); DYNCRYPTO(CRYPTO_set_id_callback); DYNCRYPTO(CRYPTO_set_locking_callback); DYNCRYPTO(ERR_free_strings); DYNCRYPTO(ERR_get_error); DYNCRYPTO(ERR_error_string); DYNCRYPTO(X509_STORE_CTX_get_ex_data); DYNCRYPTO(X509_STORE_CTX_get_chain); DYNCRYPTO(i2d_X509); DYNCRYPTO(sk_num); DYNCRYPTO(sk_value); #undef DYNCRYPTO pSSL_library_init(); pSSL_load_error_strings(); pBIO_new_fp(stderr, BIO_NOCLOSE); /* FIXME: should use winedebug stuff */ meth = pSSLv23_method(); 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 ERROR_OUTOFMEMORY; } hostname_idx = pSSL_get_ex_new_index(0, (void *)"hostname index", NULL, NULL, NULL); if(hostname_idx == -1) { ERR("SSL_get_ex_new_index failed; %s\n", pERR_error_string(pERR_get_error(), 0)); return ERROR_OUTOFMEMORY; } error_idx = pSSL_get_ex_new_index(0, (void *)"error index", NULL, NULL, NULL); if(error_idx == -1) { ERR("SSL_get_ex_new_index failed; %s\n", pERR_error_string(pERR_get_error(), 0)); return ERROR_OUTOFMEMORY; } conn_idx = pSSL_get_ex_new_index(0, (void *)"netconn index", NULL, NULL, NULL); if(conn_idx == -1) { ERR("SSL_get_ex_new_index failed; %s\n", pERR_error_string(pERR_get_error(), 0)); return ERROR_OUTOFMEMORY; } pSSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, netconn_secure_verify); pCRYPTO_set_id_callback(ssl_thread_id); num_ssl_locks = pCRYPTO_num_locks(); ssl_locks = heap_alloc(num_ssl_locks * sizeof(CRITICAL_SECTION)); if(!ssl_locks) return ERROR_OUTOFMEMORY; for(i = 0; i < num_ssl_locks; i++) { InitializeCriticalSection(&ssl_locks[i]); ssl_locks[i].DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ssl_locks"); } pCRYPTO_set_locking_callback(ssl_lock_callback); return ERROR_SUCCESS; #else FIXME("can't use SSL, not compiled in.\n"); return ERROR_INTERNET_SECURITY_CHANNEL_ERROR; #endif }