Trasforma un semplice socket in un socket SSL


115

Ho scritto semplici programmi C, che utilizzano socket ("client" e "server"). (Utilizzo UNIX / Linux)

Il lato server crea semplicemente un socket:

sockfd = socket(AF_INET, SOCK_STREAM, 0);

E poi lo lega a sockaddr:

bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));

E ascolta (e accetta e legge):

listen(sockfd,5);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
read(newsockfd,buffer,255);

Il client crea il socket e quindi vi scrive.

Ora, voglio convertire questa semplice connessione in una connessione SSL, nel modo più semplice, idilliaco, pulito e veloce.

Ho provato ad aggiungere OpenSSL al mio progetto, ma non riesco a trovare un modo semplice per implementare ciò che voglio.


Se stai cercando "una connessione sicura" piuttosto che SSL in particolare, potresti guardare qualcosa come proxychains.sourceforge.net che risiede al di fuori della tua applicazione e impostarlo per inviare traffico su una connessione SSH. Per quanto riguarda SSL in-application, OpenSSL è piuttosto semplice se si capisce come dovrebbe funzionare SSL / TLS. Se vuoi un'alternativa, prova yaSSL o gnuTLS.
Borealid

3
Definisci "modo semplice". OpenSSl è lo standard per i programmatori C. Se hai difficoltà con esso, dovresti chiedere a riguardo.
Marchese di Lorne

Controlla questo Un'introduzione alla programmazione OpenSSL (Parte I) . La parte II è troppo avanzata e difficile per me. Ma vale la pena dare un'occhiata alla parte 2.
Rick

Controlla anche Programmazione sicura con l'API OpenSSL . Ma ho appena sentito delle opinioni su quanto sia pessimo Openssl e altre alternative che vale la pena provare.
Rick

Un'altra opzione è usare uno strumento wrapper SSL esterno come stunnel, il stunnel4pacchetto è in distribuzioni basate su Debian ed è facile da usare. Esistono alcune limitazioni rispetto all'aggiunta del supporto SSL appropriato nel server, ma può essere utile per una soluzione rapida. Mi piace lo stunnel perché sembra adattarsi all'approccio degli strumenti software UNIX.
Sam Watkins

Risposte:


150

Ci sono diversi passaggi quando si utilizza OpenSSL. È necessario disporre di un certificato SSL che possa contenere il certificato con la chiave privata, assicurarsi di specificare la posizione esatta del certificato (questo esempio lo ha nella radice). Ci sono molti buoni tutorial là fuori.

Alcuni includono:

#include <openssl/applink.c>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

Avrai bisogno di inizializzare OpenSSL:

void InitializeSSL()
{
    SSL_load_error_strings();
    SSL_library_init();
    OpenSSL_add_all_algorithms();
}

void DestroySSL()
{
    ERR_free_strings();
    EVP_cleanup();
}

void ShutdownSSL()
{
    SSL_shutdown(cSSL);
    SSL_free(cSSL);
}

Ora per la maggior parte delle funzionalità. Potresti voler aggiungere un ciclo while sulle connessioni.

int sockfd, newsockfd;
SSL_CTX *sslctx;
SSL *cSSL;

InitializeSSL();
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd< 0)
{
    //Log and Error
    return;
}
struct sockaddr_in saiServerAddress;
bzero((char *) &saiServerAddress, sizeof(saiServerAddress));
saiServerAddress.sin_family = AF_INET;
saiServerAddress.sin_addr.s_addr = serv_addr;
saiServerAddress.sin_port = htons(aPortNumber);

bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));

listen(sockfd,5);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);

sslctx = SSL_CTX_new( SSLv23_server_method());
SSL_CTX_set_options(sslctx, SSL_OP_SINGLE_DH_USE);
int use_cert = SSL_CTX_use_certificate_file(sslctx, "/serverCertificate.pem" , SSL_FILETYPE_PEM);

int use_prv = SSL_CTX_use_PrivateKey_file(sslctx, "/serverCertificate.pem", SSL_FILETYPE_PEM);

cSSL = SSL_new(sslctx);
SSL_set_fd(cSSL, newsockfd );
//Here is the SSL Accept portion.  Now all reads and writes must use SSL
ssl_err = SSL_accept(cSSL);
if(ssl_err <= 0)
{
    //Error occurred, log and close down ssl
    ShutdownSSL();
}

Sarai quindi in grado di leggere o scrivere utilizzando:

SSL_read(cSSL, (char *)charBuffer, nBytesToRead);
SSL_write(cSSL, "Hi :3\n", 6);

Aggiorna Il SSL_CTX_newdovrebbe essere chiamato con il metodo TLS che meglio si adatta alle tue esigenze per supportare le versioni più recenti di sicurezza, invece di SSLv23_server_method(). Vedi: OpenSSL SSL_CTX_new descrizione

TLS_method (), TLS_server_method (), TLS_client_method (). Questi sono i metodi SSL / TLS flessibili per la versione generici . La versione effettiva del protocollo utilizzata verrà negoziata con la versione più alta supportata reciprocamente dal client e dal server. I protocolli supportati sono SSLv3, TLSv1, TLSv1.1, TLSv1.2 e TLSv1.3.


9
non così "semplice" come pensavo, ma finalmente (grazie a Dio!) vedo del codice. È multipiattaforma o solo per sistemi unix / unix?
juliomalegria

3
Ho usato codice simile su più piattaforme: arm, linux e windows.
CaptainBli

2
L'ultimo però ifè sbagliato. Dovrebbe essere if (ssl_err <= 0) {solo allora è un errore. SSL_accept()ritorna 1sul successo, 0sul "fallimento controllato" e -1sul "fallimento fatale". Vedere la pagina man.
Jite

2
Inoltre, i cifrari DH non funzioneranno se SSL_CTX_set_tmp_dh[_callback]()non vengono chiamati. Ho appena scoperto nel modo più duro che un cifrario NULL non funzionerà senza di esso, producendo l'avviso numero 40.
Roman Dmitrienko

5
@DevNull Indica SSLv23_server_method()che il server comprende SSLv2 e v3 ed è ora deprecato. Per supportare TLS 1.1 e 1.2, sostituire tale metodo con TLS_server_method(). fonte
ezPaint

17

OpenSSL è abbastanza difficile. È facile buttare via accidentalmente tutta la tua sicurezza se la negoziazione non è esattamente corretta. (Diamine, sono stato personalmente morso da un bug in cui curl non leggeva esattamente gli avvisi di OpenSSL e non riuscivo a parlare con alcuni siti.)

Se vuoi davvero veloce e semplice, metti stud davanti al tuo programma e chiamalo un giorno. Avere SSL in un processo diverso non ti rallenterà: http://vincent.bernat.im/en/blog/2011-ssl-benchmark.html


11
Questa è una risposta pratica, ma non risponde realmente alla domanda.
Svizzera

4
STUD è stato abbandonato nel 2016. Il file readme consiglia: github.com/varnish/hitch
Charles

7

Per altri come me:

C'era una volta un esempio nell'origine SSL nella directory demos/ssl/con codice di esempio in C ++. Ora è disponibile solo tramite la cronologia: https://github.com/openssl/openssl/tree/691064c47fd6a7d11189df00a0d1b94d8051cbe0/demos/ssl

Probabilmente dovrai trovare una versione funzionante, originariamente ho pubblicato questa risposta il 6 novembre 2015. E ho dovuto modificare la fonte - non molto.

Certificati: .pem in demos/certs/apps/: https://github.com/openssl/openssl/tree/master/demos/certs/apps


-1

Qui il mio esempio di thread del server socket ssl (connessione multipla) https://github.com/breakermind/CppLinux/blob/master/QtSslServerThreads/breakermindsslserver.cpp

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <unistd.h>
#include <iostream>

#include <breakermindsslserver.h>

using namespace std;

int main(int argc, char *argv[])
{
    BreakermindSslServer boom;
    boom.Start(123,"/home/user/c++/qt/BreakermindServer/certificate.crt", "/home/user/c++/qt/BreakermindServer/private.key");
    return 0;
}

Includi la soluzione direttamente nel tuo messaggio SO.
Maciej Jureczko
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.