2016-09-03 3 views
2

Ich versuche, SSL-Sockets zwischen meiner Qt-Anwendung (mit QSslSockets) und meinem C++ Server ausgeführt werden SSL-Sockets (unter Verwendung von OpenSSL) ..Connecting QSslSocket mit OpenSSL Server

Server-Code zu verbinden:

int create_socket(int port) 
{ 
    int s; 
    struct sockaddr_in addr; 

    addr.sin_family = AF_INET; 
    addr.sin_port = htons(port); 
    addr.sin_addr.s_addr = htonl(INADDR_ANY); 

    s = socket(AF_INET, SOCK_STREAM, 0); 
    if (s < 0) { 
     perror("Unable to create socket"); 
     exit(EXIT_FAILURE); 
    } 

    if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) { 
     perror("Unable to bind"); 
     exit(EXIT_FAILURE); 
    } 

    if (listen(s, 1) < 0) { 
     perror("Unable to listen"); 
     exit(EXIT_FAILURE); 
    } 
    return s; 
} 

void init_openssl() 
{ 
    SSL_load_error_strings(); 
    OpenSSL_add_ssl_algorithms(); 
} 

void cleanup_openssl() 
{ 
    EVP_cleanup(); 
} 

SSL_CTX *create_context() 
{ 
    const SSL_METHOD *method; 
    SSL_CTX *ctx; 
    method = SSLv23_server_method(); 
    ctx = SSL_CTX_new(method); 
    if (!ctx) { 
     perror("Unable to create SSL context"); 
     ERR_print_errors_fp(stderr); 
     exit(EXIT_FAILURE); 
    } 
    return ctx; 
} 

void configure_context(SSL_CTX *ctx) 
{  
    if(SSL_CTX_use_certificate_file(ctx, "/root/myCA/server_crt.pem", SSL_FILETYPE_PEM) > 0) 
    { 
     std::cout<<"Cert found"<<std::endl; 
    } 
    if (SSL_CTX_use_PrivateKey_file(ctx, "/root/myCA/server_key.pem", SSL_FILETYPE_PEM) > 0) { 
     std::cout<<"Key found"<<std::endl; 
    } 
    if(SSL_CTX_check_private_key(ctx) > 0) 
    { 
     std::cout<<"Key valid"<<std::endl; 
    } 
} 

int main(int argc, char **argv) 
{ 
    int sock; 
    SSL_CTX *ctx; 

    init_openssl(); 
    ctx = create_context(); 

    configure_context(ctx); 
    sock = create_socket(3000); 

    while(1) { 
     struct sockaddr_in addr; 
     uint len = sizeof(addr); 
     SSL *ssl; 
     const char reply[] = "test\n"; 

     int client = accept(sock, (struct sockaddr*)&addr, &len); 
     if (client > 0) { 
      std::cout<<"Client accepted..."<<std::endl; 
     } 
     else 
     { 
      perror("Unable to accept"); 
      exit(EXIT_FAILURE); 
     } 

     ssl = SSL_new(ctx); 
     SSL_set_fd(ssl, client); 

     if (SSL_accept(ssl) <= 0) { 
      ERR_print_errors_fp(stderr); 
     } 
     else { 
      SSL_write(ssl, reply, strlen(reply)); 
     } 

     SSL_free(ssl); 
     close(client); 
    } 
    close(sock); 
    SSL_CTX_free(ctx); 
    cleanup_openssl(); 

}

Qt-Client-Code:

SSLSOCKET::SSLSOCKET(QObject *parent):QObject(parent) 
{ 
    connect(&client,SIGNAL(encrypted()),this,SLOT(ConnectionEstablished())); 
    connect(&client,SIGNAL(sslErrors(const QList<QSslError>&)),this,SLOT(ErrorOccured(const QList<QSslError> &))); 
    QList<QSslCertificate> 
    trusted_ca=QSslCertificate::fromPath("/Users/test/Desktop/server_crt.pem"); 
    if(trusted_ca.empty()) 
    { 
     qDebug()<<"Error not trusted Ca."; 
    } 
    client.setCaCertificates(trusted_ca); 
    client.connectToHostEncrypted(*my ip address*,3000); 
} 

void SSLSOCKET::ErrorOccured(const QList<QSslError> &error) 
{ 
    qDebug()<<"ERROR HERE----:"; 
    qDebug()<<error; 
} 

void SSLSOCKET::ConnectionEstablished() 
{ 
    qDebug()<<"CONNECTION WORKED------:"; 
    if(!client.waitForEncrypted()) 
    { 
     qDebug()<<client.errorString(); 
    } 
    else 
    { 
     qDebug()<<"Encrypted Connection Established..."; 
    } 
    } 

kann ich die Verbindung b sehen Client.waitForEncrypted() zeigt 'Unbekannter Fehler' an.

Irgendwelche Ideen?

Antwort

2

Sie rufen waitForEncrypted() in Ihrem connected() Handler. Der Client hat den SSL-Handshake noch nicht initiiert, Sie können also noch nicht darauf warten. Per der connectToHostEncrypted() Dokumentation:

Startet eine verschlüsselte Verbindung zum Gerät hostname auf port, mode als OpenMode verwenden. Dies entspricht dem Aufruf der Verbindung connectToHost(), gefolgt von einem Anruf an startClientEncryption(). Über den Parameter kann festgelegt werden, welches Netzwerkprotokoll verwendet werden soll (z. B. IPv4 oder IPv6).

QSslSocket tritt zuerst die HostLookupState. Dann, nach Eingabe entweder der Ereignisschleife oder einer der waitFor...() Funktionen, tritt es in die ConnectingState, sendet connected(), und initiiert dann den SSL-Client-Handshake. Bei jedem Statuswechsel gibt QSslSocket das Signal stateChanged() aus.

Wenn Sie connected() wie das zu handhaben wollen, werden Sie connectToHost() statt connectToHostEncrypted(), verwenden und dann startClientEncryption() separat aufrufen:

SSLSOCKET::SSLSOCKET(QObject *parent):QObject(parent) 
{ 
    connect(&client, SIGNAL(connected()), this, SLOT(ConnectionEstablished())); 
    ... 
    client.connectToHost(*my ip address*, 3000); 
} 

void SSLSOCKET::ConnectionEstablished() 
{ 
    client.startClientEncryption(); 
    if (!client.waitForEncrypted()) 
     ... 
} 

EDIT: streich das. Ich dachte, du würdest das Signal connected() handhaben, aber ich sehe jetzt, dass du stattdessen das Signal encrypted() handelst. In diesem Fall:

Wenn das SSL-Handshake erfolgreich ist, sendet QSslSocketencrypted().

So brauchen Sie nicht waitForEncrypted() verwenden überhaupt:

void SSLSOCKET::ConnectionEstablished() 
{ 
    qDebug()<<"CONNECTION WORKED------:"; 
    qDebug()<<"Encrypted Connection Established..."; 
} 

Auch wenn du es getan hast nennen, sollte es einfach wahr zurück:

Wartet, bis der Sockel abgeschlossen der SSL-Handshake und hat encrypted() oder msecs Millisekunden ausgegeben, was auch immer zuerst eintritt.Wenn encrypted() ausgegeben wurde, gibt diese Funktion true zurück; Andernfalls (z. B. wenn der Socket getrennt ist oder der SSL-Handshake fehlschlägt), wird false zurückgegeben.

Also, es sei denn, die Steckdose getrennt wird, nachdem die Handshake abgeschlossen ist, oder encrypted() emittiert wird, bevor der verschlüsselte Zustand tatsächlich geändert wird oder ein anderer unvorhergesehener Fehler auftritt, ich sehe keinen Grund für waitForEncrypted() zu Falsch innerhalb des encrypted() Handlers zurückgeben.

+0

Danke - was ist der beste Weg, um den Status des SSL-Handshakes von Qt zu sehen? I.e. es sieht so aus, als würde etwas versagen und die Verbindung nicht aufrecht erhalten, daher muss man herausfinden, wo das ist .... –