This shows you the differences between two versions of the page.
pc:laboratoare:13 [2020/05/10 05:18] catalin.leordeanu |
pc:laboratoare:13 [2022/06/02 13:09] (current) dorinel.filip |
||
---|---|---|---|
Line 2: | Line 2: | ||
==== Utilizare programatica ==== | ==== Utilizare programatica ==== | ||
+ | |||
+ | Protocolul SSL (Secure Socket Layer - https://www.ssl.com/faqs/faq-what-is-ssl/) a aparut ca urmare | ||
+ | a necesitatii de a asigura conexiuni sigure in Internet, in stiva de protocoale fiind situat intre nivelul TCP | ||
+ | si nivelul aplicatie. Protocolul asigura autentificarea mutuala a celor doua entitati care comunica, confidentialitatea | ||
+ | comunicarii si protectia integritatii datelor. Una dintre cele mai des intalnite aplicatii ale SSL-ului este | ||
+ | HTTPS (HTTP securizat), care consta din protocolul HTTP utilizat peste SSL. | ||
SSL si conexiunile securizate pot fi folosite pentru orice tip de protocol pe Internet, HTTP, POP3 sau FTP. | SSL si conexiunile securizate pot fi folosite pentru orice tip de protocol pe Internet, HTTP, POP3 sau FTP. | ||
Line 40: | Line 46: | ||
OpenSSL foloseste o biblioteca numita BIO pentru a asigura comunicarea atit securizata cat si nesecurizata. | OpenSSL foloseste o biblioteca numita BIO pentru a asigura comunicarea atit securizata cat si nesecurizata. | ||
Pentru a crea o conexiune fie ea securizata sau nu, un pointer pentru un obiect de tip BIO trebuie creat | Pentru a crea o conexiune fie ea securizata sau nu, un pointer pentru un obiect de tip BIO trebuie creat | ||
- | similar cu crearea unui pointer la FILE (in C). Crearea unei noi conexiuni se face cu BIO new connect, | + | similar cu crearea unui pointer la FILE (in C). Crearea unei noi conexiuni se face cu //BIO_new_connect()//, |
- | specificind hostname si portul. Daca a aparut vreo eroare la crearea obiectului BIO, functia va intoarce | + | specificand hostname si portul. Daca a aparut vreo eroare la crearea obiectului BIO, functia va intoarce |
NULL. Totodata se va incerca sa se deschida conexiunea. Pentru a verifica daca acest lucru s-a realizat cu | NULL. Totodata se va incerca sa se deschida conexiunea. Pentru a verifica daca acest lucru s-a realizat cu | ||
- | succes se apeleaza BIO do connect care returneaza 0 (OK) sau -1 (eroare). | + | succes se apeleaza //BIO_do_connect()// care returneaza 0 (OK) sau -1 (eroare). |
<code> | <code> | ||
Line 59: | Line 65: | ||
</code> | </code> | ||
- | Citirea/scrierea de la/la un obiect BIO se face cu functiile BIO read() si respectiv BIO write(). | + | Citirea/scrierea de la/la un obiect BIO se face cu functiile //BIO_read()// si respectiv //BIO_write()//. |
<code> | <code> | ||
int BIO_read(BIO *b, void *buf, int len); | int BIO_read(BIO *b, void *buf, int len); | ||
+ | int BIO_write(BIO *b, const void *buf, int len); | ||
</code> | </code> | ||
- | Functia incearca sa citeasca len octeti din b si sa plaseze rezultatul in bufferul buf. Pentru o conexiune blocanta | + | Functia //BIO_read()// incearca sa citeasca len octeti din b si sa plaseze rezultatul in bufferul buf. Pentru o conexiune blocanta |
0 inseamna ca conexiunea a fost inchisa in timp ce -1 indica ca a aparut o eroare. Pentru o conexiune | 0 inseamna ca conexiunea a fost inchisa in timp ce -1 indica ca a aparut o eroare. Pentru o conexiune | ||
neblocanta o valoare 0 inseamna ca nu s-a citit nimic iar -1 ca a aparut o eroare. In acest caz se poate | neblocanta o valoare 0 inseamna ca nu s-a citit nimic iar -1 ca a aparut o eroare. In acest caz se poate | ||
- | reincerca operatia care a dat eroare, cu BIO should retry. | + | reincerca operatia care a dat eroare, cu //BIO_should_retry()//. |
<code> | <code> | ||
Line 85: | Line 92: | ||
} | } | ||
</code> | </code> | ||
+ | |||
+ | Functia //BIO_write()// incearca sa scrie len octeti din buf la b.In ambele variante o valoare returnata de -2 inseamna ca functia nu | ||
+ | e implementata pentru tipul specific BIO folosit. | ||
+ | |||
+ | <code> | ||
+ | if(BIO_write(bio, buf, len) <= 0) | ||
+ | { | ||
+ | if(! BIO_should_retry(bio)) | ||
+ | { | ||
+ | /* trateaza esec operatie write */ | ||
+ | } | ||
+ | /* trateaza retry reusit */ | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Conexiunea poate fi inchisa in doua moduri, cu //BIO_reset()// astfel incat poate fi reutilizata ulterior sau cu | ||
+ | //BIO_free_all()// caz in care se elibereaza memoria alocata si se inchide socketul asociat. | ||
+ | |||
+ | <code> | ||
+ | /* reutilizare conexiune*/ | ||
+ | BIO_reset(bio); | ||
+ | /* eliberare memorie */ | ||
+ | BIO_free_all(bio); | ||
+ | </code> | ||
+ | |||
+ | === Stabilirea unei conexiuni securizate === | ||
+ | |||
+ | Conexiunile securizate necesita un handshake dupa stabilirea conexiunii. In cursul handshake-ului, serverul | ||
+ | trimite clientului un certificat, pe care apoi clientul il verifica folosind un set de certificate (certificate store) | ||
+ | pe care le considera de incredere (trusted). Deasemenea verifica daca certificatul nu a expirat. Clientul | ||
+ | trimite un certificat catre server numai daca acesta din urma cere unul (autentificarea clientului). Folosind | ||
+ | transferul de certificate se face setup-ul conexiunii securizate. Clientul sau serverul pot solicita un nou | ||
+ | handshake la orice moment. RFC 2246 detaliaza aspectele referitoare la protocolul de handshake. | ||
+ | |||
+ | Pentru a stabili o conexiune securizata mai sunt necesari doi pointeri unul de tip //SSL_CTX// (context object) | ||
+ | si unul de tip SSL. | ||
+ | |||
+ | <code> | ||
+ | SSL_CTX * ctx = SSL_CTX_new(SSLv23_client_method()); | ||
+ | SSL * ssl; | ||
+ | </code> | ||
+ | |||
+ | Urmatorul pas este includerea certificate store mentionat anterior. OpenSSL furnizeaza un set de certificate | ||
+ | trusted. In arhiva cu codul sursa din distributia OpenSSL se afla un fisier ”TrustStore.pem.” care include | ||
+ | toate certificatele trusted. | ||
+ | |||
+ | Functia //SSL_CTX_load_verify_ locations()// e folosita pentru a incarca acest fisier. Aceasta functie are trei | ||
+ | parametri: pointerul la context calea catre fisierul *.pem si calea catre un director ce contine certificate. | ||
+ | Unul din ultimii doi parametri trebuie specificat (ori fisierul *.pem sau, alternativ, directorul ce contine | ||
+ | certificatele trusted). Returneaza 1 in caz de succes si 0 daca a aparut o problema. | ||
+ | |||
+ | <code> | ||
+ | if(! SSL_CTX_load_verify_locations(ctx, "TrustStore.pem", NULL)) | ||
+ | { | ||
+ | /* trateaza esec incarcare trust store */ | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Crearea unei noi conexiuni securizate se face cu: | ||
+ | |||
+ | <code> | ||
+ | bio = BIO_new_ssl_connect(ctx); | ||
+ | BIO_get_ssl(bio, & ssl); | ||
+ | SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); | ||
+ | // cu aceasta optiune daca serverul | ||
+ | // doreste sa initieze din nou un handshake la un moment oarecare de timp, | ||
+ | // OpenSSL se va ocupa in background de acest task | ||
+ | </code> | ||
+ | |||
+ | Dupa ce acest set-up a fost realizat se poate trece la deschiderea propriu-zisa a conexiunii | ||
+ | |||
+ | <code> | ||
+ | /* incearca sa se conecteze */ | ||
+ | BIO_set_conn_hostname(bio, "hostname:port"); | ||
+ | |||
+ | /* verifica conexiunea deschisa si efectueaza handshake */ | ||
+ | if(BIO_do_connect(bio) <= 0) | ||
+ | { | ||
+ | /* trateaza esec conexiune */ | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Pentru a verifica daca validarea certificatului s-a facut cu succes se apeleaza //SSL_get_verify_result()// cu unic | ||
+ | parametru structura SSL. Daca validarea s-a efectuat cu succes returneaza X509 V OK, altfel intoarce un | ||
+ | cod de eroare care poate fi documentat daca se foloseste optiunea verify in linia de comanda a utilitarului. | ||
+ | |||
+ | <code> | ||
+ | if(SSL_get_verify_result(ssl) != X509_V_OK) | ||
+ | { | ||
+ | /* trateaza esec verificare */ | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Stiva de erori poate fi scrisa intr-un fisier cu //ERR_print_errors_fp(FILE *);// | ||
+ | Erorile au urmatorul format: | ||
+ | |||
+ | <code> | ||
+ | [pid]:error:[error code]:[library name]:[function name]:[reason string]:[file name]:[ | ||
+ | line]:[optional text message] | ||
+ | </code> | ||
+ | |||
+ | ==== Cerinte laborator ==== | ||
+ | |||
+ | Completati [[https://ocw.cs.pub.ro/courses/_media/pc/laboratoare/lab13-skel.zip|scheletul de cod]] astfel incat sa se efectueze o conexiune prin HTTPS la verisign.com si sa se | ||
+ | salveze local, intr-un fisier pe disc, pagina home, printr-un apel de tip GET. | ||
+ | |||
+ | Portul HTTPS implicit este 443. | ||
+ | |||
+ | Pentru compilare se poate folosi: | ||
+ | |||
+ | <code> | ||
+ | gcc http_client.c -lssl -lcrypto | ||
+ | </code> | ||
+ | |||
+ | ==== Referinte ==== | ||
+ | |||
+ | - http://www.openssl.org/ | ||
+ | - http://www.linuxjournal.com/article/4822 | ||
+ | - http://www.rfc-editor.org/rfc/rfc2246.txt | ||
+ |