Beispiel #1
0
/******************************************************************************
 * 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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
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;
}
Beispiel #5
0
/******************************************************************************
 * 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;
}
Beispiel #6
0
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
}