SSL_CTX : Une structure SSL_CTX doit être créée pour chaque application SSL (client ou serveur). Cette structure sauvegarde les valeurs par défaut qui seront héritées par les structures SSL. Elle détient aussi des informations sur les connexions et les sessions SSL. Création : SSL_CTX_new() Libération : SSL_CTX_free() SSL : Une structure SSL doit être créée pour chaque connexion dans une application SSL. Elle sera créée après avoir créer une structure SSL_CTX, puisque elle hérite ses informations à partir de celle-ci (mais ces informations peuvent être modifiées). Par exemple, un certificat chargé dans SSL_CTX est hérité par la structure SSL. Création : SSL_new() Libération : SSL_free() La structure SSL sauvegarde des pointeurs vers d'autres structures contenants des informations sur des connexions et sessions SSL (SSL_CTX, SSL_METHOD, BIO, SSL_SESSION ). SSL_METHOD : Cette structure contient un pointeur vers la méthode qui implémente une version du protocole SSL. Cette doit être créée avant SSL_CTX. SSL_CIPHER : Cette structure contient des informations sur les algorithme de cryptage utilisés par une connexion ou session SSL.
Programme SSL La structure générale d'un programme SSL : Fichiers d'entête #include <openssl/bio.h> #include <openssl/err.h> #include <openssl/rand.h > #include <openssl/ssl.h> #include <openssl/x509v3.h> Initialisation : SSL_library_init(); SSL_load_error_strings(); La première méthode charge les algorithmes de cryptage et hachage utilisés par les API SSL. La deuxième charge les messages d'erreurs associés aux erreurs des API SSL.
Création du contexte SSL : Avant la création du contexte il faut avant créer la méthode SSL à utiliser : SSL_METHOD *meth; SSL_CTX *ctx; meth = SSLv3_method(); ctx = SSL_CTX_new(meth); Pour la méthode, on peut utiliser une autre méthode selon l'application. Configuration du contexte SSL : Chargement du certificat de l'application : int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type) ctx : context SSL dans lequel on charge le certificat. file : le fichier contenant le certificat. type : le format utilisé : SSL_FILETYPE_PEM, SSL_FILETYPE_ASN1. Cette fonction permet de charger le certificat que l'application va utiliser. Par l'exemple d'ans le cas d'un serveur, c'est le certificat qu'il présente au client pour s'authentifier. int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) Cette fonction permet de charger la chaine de certification (plusieurs certificats) contenus dans file. Chargement de la clef privée : Plusieurs fonctions :
Ces fonctions chargent la clef privée associée au certificat. Chargement des certificats des CAs int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, const char *Capath) Cette fonction charge en mémoire les certificats des autorités de certification approuvées par l'application et qui seront utilisées pour vérifier les certificats qui seront reçus, envoyés par l'application distante. CAfile : pointe vers le fichier qui contient la liste des certificats des CAs et CRLs. IL peut être NULL. CApath : pointe vers le répertoire qui contient la liste des certificats des CAs et CRLs. Il peut être NULL. Les paramètres CApath et CAfile ne peuvent pas être NULL en même temps. SSL_CTX_set_default_verify_path() Cette fonction charge en mémoire les certificats qui se trouvent dans le répertoire par défaut. Création de la structure SSL : SSL *ssl = SSL_new(SSL_CTX *ctx);
Elle crée une structure SSL qui contiendra des information de la connexion, elle hérite une partie à partir de ctx. On peut modifier des informations héritées à partir de la structure SSL_CTX en utilisant un ensemble d'api sur la structure SSL. Par exemple, on peut charger un autre certificat que celui hérité à partir SSL_CTX en utilisant la fonction SSL_use_certificate() Configuration de la vérification du certificat reçu : void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, int (*cb) (int, X509_STORE_CTX* )) Cette fonction positionne les flag de vérification de la structure du contexte SSL. Elle contrôle la phase handshake d'une connexion SSL. ctx : le contexte. mode : le mode de vérification. Quatre modes : (SSL_VERIFY_NONE, SLL_VERIFY_PEER ). Par exemple, SLL_VERIFY_PEER utilisé dans une application indique une requête demandant un certificat sera envoyée à l'application distante. cb : pointeur vers une fonction du rappel. Cette fonction sera appelée après chaque étape de vérification de la chaine de certification. void SSL_CTX_set_verify_depth(SSL_CTX *ctx,int depth); Cette fonction positionne la longueur maximum de la chaine de certification à accepter. Par exemple si la valeur de depth = 4 et la longueur de la chaine de certification du certificat reçu de passe 4 alors la vérification échoue. On peut utiliser à la place la méthode void SSL_set_verify_depth(SSL *s, int depth) mais via la structure SSL. Mise en place d'une connexions TCP/IP : Cette phase est indépendante du protocole SSL. Elle est identique pour tout les programme utilisant la communication réseau. On peut utiliser les sockets. Le serveur utilise deux socket, une d'écoute et l'autre pour la communication. Mise en place d'une communication SSL : Après avoir créer une structure SSL et une socket, on doit mettre en place une communication SSL ( Faire le lien) via la socket : int SSL_set_fd(SSL *ssl, int fd);
fd : c'est un descripteur de fichier. Typiquement, il s'agit d'un descripteur d'une socket ou un autre moyen de connexion réseau. Utilisation de l'interface BIO : La librairie SSL propose un autre moyen de communication plus simple, c'est l'interface BIO (Basic Input/Output). Elle propose une interface commune d'accès à différantes sources de données, elle propose une multitude de fonctions créant et traitant des BIO. BIO *BIO_new( BIO_METHOD *type) Le type dépend de la source de données qui peut être : Socket Un segment mémoire Fichier L'interface BIO offre plusieurs possibilités : une interface commune pour toutes les sources de données, enchainement de plusieurs BIO, le filtrage Dans notre cas, avec une socket, on peut faire : bio=bio_new(bio_s_socket()); BIO_set_fd(bio, sock, BIO_NOCLOSE); SSL_set_bio(ssl, bio, bio); On peut créer une socket et un BIO en même temps : bio = BIO_new_socket(socket, BIO_NOCLOSE); SSL_set_bio(ssl, bio, bio); SSL Handshake : La phase Handshake se fait lors de l'appel des fonctions : int SSL_accept(SSL *ssl); int SSL_connect(SSL *ssl);
La première dans le serveur et la deuxième dans le client. Échange de données via SSL : Pour envoyer les données via SSL int SSL_write(SSL *ssl, const void *buf, int num); Pour recevoir des données via SSL : int SSL_read(SSL *ssl, void *buf, int num); Pour la communication de données on peut utiliser l'interface BIO : BIO_puts(), BIO_gets(), BIO_write() et BIO_read(). Fermeture de la connexion SSL et libération de ressources : int SSL_shutdown(SSL *ssl); void SSL_free(SSL *ssl); void SSL_CTX_free(SSL_CTX *ctx); Quelque fonction SSL Obtention du certificat reçu : X509 *SSL_get_peer_certificate(const SSL *ssl); Cette fonction retourne le certificat de l'entité distante. Elle doit être appelée après la phase Handshake. Obtention du résultat de vérification du certificat reçu : long SSL_get_verify_result(const SSL *ssl); Si la vérification à réussie, elle retourne la valeur X509_V_OK, sinon la vérification à echoué. Attention : S'il n'y a pas de certificat a vérifier ( L'entité distante n'a pas présenté un
certificat ), elle retourne comme même X509_V_OK. Récupération des informations à partir du certificat : La librairie SSL propose plusieurs fonctions pour récupérer toute sorte d'informations à partir du certificat via les structures SSL et SSL_CTX. Par exemple : char commonname [512]; X509_NAME * name = X509_get_subject_name(peerCert); X509_NAME_get_text_by_NID(name, NID_commonName, commonname, 512); /* Ou bien */ X509_NAME_oneline( X509_get_subject_name(peerCert), buf, size) X509_NAME_oneline( X509_get_issuer_name(peerCert), buf, size)