OpenSSL Fehler bei irc.mozilla.org



  • Hi,

    ich habe in HexChat (IRC Client) das Problem, dass ich mich mit einem selbst erstellten Client-Zertifikat nicht zu irc.mozilla.org verbinden kann. Da HexChat glücklicherweise Open Source ist, konnte ich den Quellcode anschauen und das Problem auf ein Minimalbeispiel runterbrechen.

    Die verwendete Moznet.pem hab ich einfach nach dieser Anleitung erstellt.

    Ich nutze OpenSSL 1.0.2k, die statische Lib. Man findet kompilierte Versionen im Netz. Neben dem unten stehenden Code und der Moznet.pem gibt es keine weiteren Dateien von mir, ihr könnt also problemlos eine .cpp erstellen, OpenSSL einbinden und das Zeug kompilieren. Ich nutze Visual Studio Community 2015 und kompiliere für 32-Bit.

    Vorweg: Bitte kritisierst nicht den Code. Der ist schlecht und das spielt auch keine Rolle. Ich nutze den ausschließlich in der Form zum Experimentieren und für die Analyse des Problems genügt er:

    #include "stdafx.h"
    
    #include <windows.h>
    #include <iostream>
    #include <errno.h>
    
    #include <openssl/ssl.h>
    #include <openssl/err.h>
    
    using namespace std;
    
    SSL_CTX *_SSL_context_init();
    SSL *_SSL_socket(SSL_CTX *ctx, int sd);
    
    int print_errors(const char *error, size_t len, void *userData)
    {
    	cerr << error << endl;
    
    	return 1;
    }
    
    int main()
    {
    	WSADATA wsaData = {0};
    
    	int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
    
    	if (result != 0)
    	{
    		cerr << "WSAStartup failed: " << result << endl;
    		return 1;
    	}
    
    	SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    
    	if (sock == INVALID_SOCKET)
    	{
    		cerr << "Error creating socket: " << GetLastError() << endl;
    
    		return 1;
    	}
    
    	sockaddr_in addr;
    
    	addr.sin_family = AF_INET;
    	addr.sin_addr.s_addr = inet_addr("54.219.165.167");
    	addr.sin_port = htons(6697);
    
    	result = connect(sock, (sockaddr *)&addr, sizeof(addr));
    
    	if (result == SOCKET_ERROR)
    	{
    		cerr << "Error connecting: " << GetLastError() << endl;
    
    		return 1;
    	}
    
    	SSL_CTX *sslContext = _SSL_context_init();
    
    	if (SSL_CTX_use_certificate_file(sslContext, "certs\\Moznet.pem", SSL_FILETYPE_PEM) != 1)
    	{
    		cerr << "Error setting cert file" << endl;
    
    		return 1;
    	}
    
    	if (SSL_CTX_use_PrivateKey_file(sslContext, "certs\\Moznet.pem", SSL_FILETYPE_PEM) != 1)
    	{
    		cerr << "Error setting private key file" << endl;
    
    		return 1;
    	}
    
    	SSL *ssl = _SSL_socket(sslContext, sock);
    
    	if (ssl == NULL)
    	{
    		return 1;
    	}
    
    	int connectState = SSL_connect(ssl);
    
    	cout << "errno: " << errno << endl;
    	cout << "GetLastError(): " << GetLastError() << endl;
    	cout << "WSAGetLastError(): " << WSAGetLastError() << endl;
    	cout << "SSL_connect(): " << connectState << endl;
    	cout << "SSL_get_error(): " << SSL_get_error(ssl, connectState) << endl;
    	cout << "ERR_get_error(): " << ERR_get_error() << endl;
    
        return 0;
    }
    
    SSL_CTX *_SSL_context_init()
    {
    	SSL_CTX *ctx;
    
    	SSLeay_add_ssl_algorithms();
    	SSL_load_error_strings();
    	ERR_load_CRYPTO_strings();
    	ctx = SSL_CTX_new(SSLv23_client_method());
    
    	SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
    	SSL_CTX_set_timeout(ctx, 300);
    
    	SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION | SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_TICKET | SSL_OP_CIPHER_SERVER_PREFERENCE);
    
    	return(ctx);
    }
    
    SSL *_SSL_socket(SSL_CTX *ctx, int sd)
    {
    	SSL *ssl;
    
    	if (!(ssl = SSL_new(ctx)))
    	{
    		cerr << "Error creating SSL object" << endl;
    
    		return NULL;
    	}
    
    	SSL_set_fd(ssl, sd);
    
    	SSL_set_connect_state(ssl);
    
    	return ssl;
    }
    

    Ausgabe:

    errno: 0
    GetLastError(): 0
    WSAGetLastError(): 0
    SSL_connect(): 0
    SSL_get_error(): 5
    ERR_get_error(): 0
    

    Fehler 5 ist SSL_ERROR_SYSCALL. Für weitere Infos soll man laut Doku errno prüfen:

    https://www.openssl.org/docs/man1.0.2/ssl/SSL_get_error.html schrieb:

    SSL_ERROR_SYSCALL

    Some non-recoverable I/O error occurred. The OpenSSL error queue may contain more information on the error. For socket I/O on Unix systems, consult errno for details.

    Wie man im Code sieht, hab ich das gemacht. Spaßeshalber hab ich auch GetLastError() und WSAGetLastError() rein, die liefern aber beide ebenfalls 0.

    Ein paar Dinge hab ich noch rausgefunden. Die Änderungen beziehen sich immer auf den Code im Ursprungszustand (siehe oben). Die Ausgabe ist bei allen Änderungen:

    errno: 0
    GetLastError(): 0
    WSAGetLastError(): 0
    SSL_connect(): 1
    SSL_get_error(): 0
    ERR_get_error(): 0
    

    1. Ändert man Zeile 106 von

    SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION | SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_TICKET | SSL_OP_CIPHER_SERVER_PREFERENCE);
    

    in

    SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION | SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_TICKET);
    

    (Lediglich das Flag "SSL_OP_CIPHER_SERVER_PREFERENCE" wurde entfernt), geht es.

    2. Ändert man Zeile 101 von

    ctx = SSL_CTX_new(SSLv23_client_method());
    

    in

    ctx = SSL_CTX_new(SSLv3_client_method());
    

    (v23 vs v3), geht es.

    3. Ändert man Zeile 106 von

    SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION | SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_TICKET | SSL_OP_CIPHER_SERVER_PREFERENCE);
    

    in

    SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_COMPRESSION | SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_TICKET | SSL_OP_CIPHER_SERVER_PREFERENCE);
    

    (Lediglich Option "SSL_OP_NO_TLSv1_1" hinzugefügt), geht es.

    4. Kommentiert man Zeile 61 bis 73 aus:

    /*if (SSL_CTX_use_certificate_file(sslContext, "certs\\Moznet.pem", SSL_FILETYPE_PEM) != 1)
    	{
    		cerr << "Error setting cert file" << endl;
    
    		return 1;
    	}
    
    	if (SSL_CTX_use_PrivateKey_file(sslContext, "certs\\Moznet.pem", SSL_FILETYPE_PEM) != 1)
    	{
    		cerr << "Error setting private key file" << endl;
    
    		return 1;
    	}*/
    

    geht es!

    Aus den unterschiedlichen Kombinationen, die für mich keinen Zusammenhang zueinander haben, kann ich keinerlei Ursache erkennen. Auch das Debuggen hat mir leider nichts gebracht, weil es sich bei den vielen und verschachtelten Funktionsaufrufen, ohne den OpenSSL-Code zu kennen, sehr mühsam gestaltet.

    Also: Habt ihr einen Ansatz, wie man dem Problem auf die Schliche kommen kann? 😋



  • Nur mal allgemein, durch die cout-Aufrufe kann das Ergebnis von GetLastError() verfälscht werden. Also erst die ganzen Ergebnisse sammeln und dann ausgeben.



  • Guter Einwand, daran hab ich gar nicht gedacht. Danke!

    Hab die ursprünglichen Zeilen 84 bis 98 durch das ersetzt:

    int errorNumber = errno;
    int lastError = GetLastError();
    int wsaLastError = WSAGetLastError();
    
    cout << "errno: " << errorNumber << endl;
    cout << "GetLastError(): " << lastError << endl;
    cout << "WSAGetLastError(): " << wsaLastError << endl;
    cout << "SSL_connect(): " << connectState << endl;
    cout << "SSL_get_error(): " << SSL_get_error(ssl, connectState) << endl;
    cout << "ERR_get_error(): " << ERR_get_error() << endl;
    

    Leider kommt weiterhin 0 zurück. Wäre auch zu schön gewesen 😃


Anmelden zum Antworten