2013-10-10 7 views
5

Ich arbeite daran, meinem Serverprogramm die OpenSSL-Unterstützung hinzuzufügen, und im Allgemeinen funktioniert es ziemlich gut, aber ich bin auf ein Problem gestoßen.Warum gibt OpenSSL mir einen Fehler "eine Funktion aufgerufen, die Sie nicht aufrufen sollten"?

Zuerst einige Hintergrund: Der Server ist single-threaded und verwendet nicht blockierende E/A und eine select() - Schleife, um mehrere Clients gleichzeitig zu behandeln. Der Server ist mit libssl.0.9.8.dylib und lib crypto.0.9.8.dylib verbunden (d.h. die Bibliotheken, die in/usr/lib von MacOS/X 10.8.5 bereitgestellt werden). Der Client < -> Serverprotokoll ist ein proprietäres Vollduplex-Nachrichtenprotokoll; das heißt, die Clients und der Server können alle jederzeit Daten senden und empfangen, und der Client < -> Server-TCP-Verbindungen bleiben auf unbestimmte Zeit verbunden (d. h. bis der Client oder Server sich entschließt, die Verbindung zu trennen).

Das Problem ist: meine Clients können eine Verbindung zum Server herstellen, und das Senden und Empfangen von Daten funktioniert gut (jetzt habe ich die SSL_ERROR_WANT_WRITE und SSL_ERROR_WANT_READ Logik aussortiert) ... aber wenn der Server accept() 'ist ein neuer Client Verbindung während andere Clients in der Mitte des Sendens oder Empfangen von Daten sind, scheint die SSL-Ebene zu brechen. Insbesondere, unmittelbar nachdem der Server die Routine SetupSSL() ausführt (siehe unten), um den neu akzeptierten Socket einzurichten, gibt SSL_read() auf einem oder mehreren der Sockets der anderen (bereits existierenden) Clients -1 zurück ERR_print_errors_fp (stderr) gibt die folgende Ausgabe:

SSL_read() ERROR: 5673:error:140F3042:SSL routines:SSL_UNDEFINED_CONST_FUNCTION:called a function you should not call:/SourceCache/OpenSSL098/OpenSSL098-47.2/src/ssl/ssl_lib.c:2248: 

Nachdem dieser Fehler zuerst erscheint, wird der Server weitgehend nicht mehr funktioniert. Datenbewegung stoppt, und wenn ich versuche, einen anderen Client zu verbinden, bekomme ich oft diesen Fehler:

SSL_read() ERROR: 5673:error:140760FC:SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol:/SourceCache/OpenSSL098/OpenSSL098-47.2/src/ssl/s23_srvr.c:578: 

Dies geschieht etwa 25% der Zeit in meinem Testszenario. Wenn ich sicherstelle, dass meine bestehenden Client-Verbindungen im Leerlauf sind (keine Daten gesendet oder empfangen werden), wenn der neue Client eine Verbindung herstellt, passiert das nie. Weiß jemand, was hier schief gehen könnte? Habe ich einen OpenSSL-Fehler gefunden, oder gibt es ein Detail, das ich übersehen habe? Einige relevante Code aus meinem Programm ist unten eingefügt, falls es hilfreich ist.

// Socket setup routine, called when the server accepts a new TCP socket 
int SSLSession :: SetupSSL(int sockfd) 
{ 
    _ctx = SSL_CTX_new(SSLv23_method()); 
    if (_ctx) 
    { 
    SSL_CTX_set_mode(_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); 

    _ssl = SSL_new(_ctx); 
    if (_ssl) 
    { 
     _sbio = BIO_new_socket(sockfd, BIO_NOCLOSE); 
     if (_sbio) 
     { 
      SSL_set_bio(_ssl, _sbio, _sbio); 
      SSL_set_accept_state(_ssl); 

      BIO_set_nbio(_sbio, !blocking); 
      ERR_print_errors_fp(stderr); 

      return RESULT_SUCCESS; 
     } 
     else fprintf(stderr, "SSLSession: BIO_new_socket() failed!\n"); 
    } 
    else fprintf(stderr, "SSLSession: SSL_new() failed!\n"); 
    } 
    else fprintf(stderr, "SSLSession: SSL_CTX_new() failed!\n"); 

    return RESULT_FAILURE; 
} 

// Socket read routine -- returns number of bytes read from SSL-land 
int32 SSLSession :: Read(void *buffer, uint32 size) 
{ 
    if (_ssl == NULL) return -1; 

    int32 bytes = SSL_read(_ssl, buffer, size); 
    if (bytes > 0) 
    { 
    _sslState &= ~(SSL_STATE_READ_WANTS_READABLE_SOCKET | SSL_STATE_READ_WANTS_WRITEABLE_SOCKET); 
    } 
    else if (bytes == 0) return -1; // connection was terminated 
    else 
    { 
    int err = SSL_get_error(_ssl, bytes); 
    if (err == SSL_ERROR_WANT_WRITE) 
    { 
     // We have to wait until our socket is writeable, and then repeat our SSL_read() call. 
     _sslState &= ~SSL_STATE_READ_WANTS_READABLE_SOCKET; 
     _sslState |= SSL_STATE_READ_WANTS_WRITEABLE_SOCKET; 
     bytes = 0; 
    } 
    else if (err == SSL_ERROR_WANT_READ) 
    { 
     // We have to wait until our socket is readable, and then repeat our SSL_read() call. 
     _sslState |= SSL_STATE_READ_WANTS_READABLE_SOCKET; 
     _sslState &= ~SSL_STATE_READ_WANTS_WRITEABLE_SOCKET; 
     bytes = 0; 
    } 
    else 
    { 
     fprintf(stderr, "SSL_read() ERROR: "); 
     ERR_print_errors_fp(stderr); 
    } 
    } 
    return bytes; 
} 

// Socket write routine -- returns number of bytes written to SSL-land 
int32 SSLSession :: Write(const void *buffer, uint32 size) 
{ 
    if (_ssl == NULL) return -1; 

    int32 bytes = SSL_write(_ssl, buffer, size); 
    if (bytes > 0) 
    { 
    _sslState &= ~(SSL_STATE_WRITE_WANTS_READABLE_SOCKET | SSL_STATE_WRITE_WANTS_WRITEABLE_SOCKET); 
    } 
    else if (bytes == 0) return -1; // connection was terminated 
    else 
    { 
    int err = SSL_get_error(_ssl, bytes); 
    if (err == SSL_ERROR_WANT_READ) 
    { 
     // We have to wait until our socket is readable, and then repeat our SSL_write() call. 
     _sslState |= SSL_STATE_WRITE_WANTS_READABLE_SOCKET; 
     _sslState &= ~SSL_STATE_WRITE_WANTS_WRITEABLE_SOCKET; 
     bytes = 0; 
    } 
    else if (err == SSL_ERROR_WANT_WRITE) 
    { 
     // We have to wait until our socket is writeable, and then repeat our SSL_write() call. 
     _sslState &= ~SSL_STATE_WRITE_WANTS_READABLE_SOCKET; 
     _sslState |= SSL_STATE_WRITE_WANTS_WRITEABLE_SOCKET; 
     bytes = 0; 
    } 
    else 
    { 
     fprintf(stderr,"SSL_write() ERROR!"); 
     ERR_print_errors_fp(stderr); 
    } 
    } 
    return bytes; 
} 

Antwort

7

Jemand auf der Mailingliste openssl-users half mir, dies herauszufinden; Das Problem war, dass ich meine SSL-Sitzung mit SSLv23_method() eingerichtet habe, und bei Verwendung von SSLv23_method() dürfen Sie SSL_pending() erst aufrufen, nachdem der SSL-Handshake abgeschlossen ist, welches Protokoll ausgehandelt wurde (SSLv2, SSLv3, TLSv1, etc) Es wird tatsächlich verwendet werden.

Da meine Anwendung keine Kompatibilität mit älteren SSL-Versionen erfordert, ist die schnelle Lösung für mich, SSLv3_method() während der Installation anstelle von SSLv23_method() aufzurufen. Wenn Abwärtskompatibilität erforderlich wäre, müsste ich herausfinden, wann die Protokollaushandlung abgeschlossen wurde, und bis dahin den Aufruf von SSL_pending() vermeiden. Aber ich werde das Problem jetzt ignorieren, da ich diese Funktionalität nicht benötige.

Verwandte Themen