Leggi / scrivi direttamente i dati di Handshake con Memory BIO

Devo creare una connessione OpenSSL dove posso direttamente leggere / scrivere i dati dell’handshake. Il motivo è che i dati della stretta di mano verranno trasportati in una connessione UDP (DTLS non è un’opzione, perché i dati non sono direttamente nel datagramma, ma all’interno di altri pacchetti di protocollo, EAP se siete curiosi). Finora, ho creato una connessione OpenSSL ma non sono nemmeno riuscito a leggere l’handshake del client da inviare al server.

Nella mia ricerca ho trovato che ho bisogno di un Memory BIO per leggere / scrivere sulla connessione, ma non riesco a capire come estrarre i dati dell’handshake. Ecco come inizializzo la connessione client :

SSL_library_init(); SSL_load_error_strings(); OpenSSL_add_all_algorithms(); ctx = SSL_CTX_new(SSLv3_client_method()); SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); ssl = SSL_new(ctx); rbio = BIO_new(BIO_s_mem()); wbio = BIO_new(BIO_s_mem()); SSL_set_bio(ssl, rbio, wbio); SSL_set_connect_state(ssl); 

Ho provato doint SSL_connect , per avviare l’handshake:

 int ret = SSL_connect(ssl); 

Ma restituisce -1 , e facendo SSL_get_error(ssl, res) ottengo un codice di errore 2 , poi ERR_error_string con quel codice e ottengo:

 error:00000002:lib(0):func(0):system lib 

Inoltre, se utilizzo SSL_do_handshake invece di SSL_connect ottengo esattamente lo stesso errore.

Sono stato in grado di impostare una connessione OpenSSL su TCP, ma non l’ho mai fatto con Memory BIO, quindi qualsiasi aiuto con questo sarebbe molto apprezzato. Grazie!

Finalmente l’ho fatto funzionare, ero nel modo giusto:

La funzione SSL_set_connect_state(ssl) è necessaria per indicare alla connessione di essere preparata per l’init di handshake. Quindi, chiamiamo SSL_do_handshake(ssl) per avviare l’handshake. Questa funzione restituirà -1 perché l’handshake non è stato terminato, ma possiamo effettivamente leggere dalla connessione ssl del client il writer BIO e inviare i dati utilizzando il protocollo che vogliamo (nel mio caso, pacchetti EAP RADIUS su UDP).

Cliente

 ctx = SSL_CTX_new(SSLv3_client_method()); SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); ssl = SSL_new(ctx); rbio = BIO_new(BIO_s_mem()); wbio = BIO_new(BIO_s_mem()); SSL_set_bio(ssl, rbio, wbio); SSL_set_connect_state(ssl); SSL_do_handshake(ssl); // This will return -1 (error) as the handshake is not finished, we can ignore it. char buf[4096]; BIO_read(wbio, buf, 4096); // Read from BIO, put data in buffer // Then use data in buffer to send to the server 

Il server, d’altra parte, dovrebbe essere configurato utilizzando le credenziali e la chiave privata. Inoltre, invece di SSL_set_connect_state() dovremmo usare SSL_set_accept_state() poiché il server aspetterà l’handshake del client ciao. Quindi, scriviamo semplicemente i dati di handshake del client ciao al lettore BIO del server:

server

 ctx = SSL_CTX_new(SSLv3_server_method()); // This is the server! SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); ssl = SSL_new(ctx); rbio = BIO_new(BIO_s_mem()); wbio = BIO_new(BIO_s_mem()); SSL_set_bio(ssl, rbio, wbio); SSL_set_accept_state(ssl); // The server uses SSL_set_accept_state // Here we get the data from the client suppose it's in the variable buf // and write it to the connection reader BIO. BIO_write(rbio, buf, strlen(buf)); if (!SSL_is_init_finished(ssl)) { SSL_do_handshake(ssl); } 

Possiamo usare la funzione SSL_is_init_finished(ssl) per controllare se l’handshake è stato fatto, e mentre non è fatto, chiamiamo SSL_do_handshake(ssl) , e poi rileggiamo da BIO_writer per inviare i dati al client.

Questo processo tra client e server dovrebbe essere fatto fino al termine della connessione (cioè SSL_is_init_finished(ssl) restituisce true ).

Quindi, al termine SSL_read , è ansible inviare dati protetti tra client / server, utilizzando le funzioni SSL_read e SSL_write . Spero che questa breve spiegazione sia utile per qualcuno!

Prova a farlo

 // Connect the TCP socket (this is client side) int sock = tcp_connect(host, port); // Create BIO around the connected TCP socket BIO *sbio = BIO_new_socket(sock, BIO_NOCLOSE); SSL_set_bio(ssl,sbio,sbio); int ret = SSL_connect(ssl); 

Pensa a BIO come avvolgere lo zoccolo. Per il lato client, devi assegnargli un socket connesso all’host e alla porta desiderati usando la chiamata connect (…). Per il lato server, basta usare il socket che viene restituito dalla chiamata accept (…).