From 29eae5126251eb0f10d02700bb87dac9893bb445 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sat, 1 Dec 2018 12:16:12 +0100
Subject: Encrypted all communications using TLS.

---
 src/analysis/db/cdb.c    |  16 ++---
 src/analysis/db/cdb.h    |   3 +-
 src/analysis/db/client.c | 138 +++++++++++++++++++++++++++++++--------
 src/analysis/db/keymgn.c |   5 +-
 src/analysis/db/keymgn.h |   3 +
 src/analysis/db/server.c | 163 +++++++++++++++++++++++++++++++++++++++--------
 src/common/packed.c      |  79 ++++++++++++++++++++++-
 src/common/packed.h      |   7 ++
 src/core/core.c          |   8 ++-
 9 files changed, 351 insertions(+), 71 deletions(-)

diff --git a/src/analysis/db/cdb.c b/src/analysis/db/cdb.c
index bfe6238..fd1f5cf 100644
--- a/src/analysis/db/cdb.c
+++ b/src/analysis/db/cdb.c
@@ -56,7 +56,7 @@
 /* Informations relatives à un client */
 typedef struct _cdb_client
 {
-    int fd;                                 /* Canal de communication      */
+    SSL *ssl_fd;                            /* Canal de communication      */
     rle_string user;                        /* Utilisateur à l'autre bout  */
 
     uint64_t last_time;                     /* Date de dernier envoi       */
@@ -779,7 +779,7 @@ static void on_collection_changed(GDbCollection *collec, DBAction action, GDbIte
     g_mutex_lock(&archive->clients_access);
 
     for (i = 0; i < archive->count && status; i++)
-        status = send_packed_buffer(&pbuf, archive->clients[i].fd);
+        status = ssl_send_packed_buffer(&pbuf, archive->clients[i].ssl_fd);
 
     g_mutex_unlock(&archive->clients_access);
 
@@ -849,7 +849,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
 
         for (i = 0; i < nfds; i++)
         {
-            fds[i].fd = archive->clients[i].fd;
+            fds[i].fd = SSL_get_fd(archive->clients[i].ssl_fd);
             fds[i].events = POLLIN | POLLPRI;
         }
 
@@ -883,7 +883,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
             {
                 init_packed_buffer(&in_pbuf);
 
-                status = recv_packed_buffer(&in_pbuf, fds[i].fd);
+                status = ssl_recv_packed_buffer(&in_pbuf, archive->clients[i].ssl_fd);
                 if (!status) goto gcap_bad_exchange;
 
                 status = extract_packed_buffer(&in_pbuf, &tmp32, sizeof(uint32_t), true);
@@ -906,7 +906,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
                         status = extend_packed_buffer(&out_pbuf, (uint32_t []) { error }, sizeof(uint32_t), true);
                         if (!status) goto gcap_bad_reply;
 
-                        status = send_packed_buffer(&out_pbuf, fds[i].fd);
+                        status = ssl_send_packed_buffer(&out_pbuf, archive->clients[i].ssl_fd);
                         if (!status) goto gcap_bad_reply;
 
                         exit_packed_buffer(&out_pbuf);
@@ -1008,7 +1008,7 @@ static void *g_cdb_archive_process(GCdbArchive *archive)
 *                                                                             *
 ******************************************************************************/
 
-DBError g_cdb_archive_add_client(GCdbArchive *archive, int fd, const rle_string *user)
+DBError g_cdb_archive_add_client(GCdbArchive *archive, SSL *fd, const rle_string *user)
 {
 
     GList *iter;                            /* Boucle de parcours          */
@@ -1028,7 +1028,7 @@ DBError g_cdb_archive_add_client(GCdbArchive *archive, int fd, const rle_string
 
     archive->clients = (cdb_client *)realloc(archive->clients, ++archive->count * sizeof(cdb_client));
 
-    archive->clients[archive->count - 1].fd = fd;
+    archive->clients[archive->count - 1].ssl_fd = fd;
     dup_into_rle_string(&archive->clients[archive->count - 1].user, get_rle_string(user));
 
     /* Démarrage ou redémarrage du processus d'écoute */
@@ -1072,7 +1072,7 @@ DBError g_cdb_archive_add_client(GCdbArchive *archive, int fd, const rle_string
     }
 
     if (status && get_packed_buffer_payload_length(&out_pbuf) > 0)
-        status = send_packed_buffer(&out_pbuf, fd);
+        status = ssl_send_packed_buffer(&out_pbuf, fd);
 
     exit_packed_buffer(&out_pbuf);
 
diff --git a/src/analysis/db/cdb.h b/src/analysis/db/cdb.h
index 15f425c..49a18a5 100644
--- a/src/analysis/db/cdb.h
+++ b/src/analysis/db/cdb.h
@@ -27,6 +27,7 @@
 
 #include <glib-object.h>
 #include <stdbool.h>
+#include <openssl/ssl.h>
 
 
 #include "protocol.h"
@@ -66,7 +67,7 @@ int g_cdb_archive_compare_hash(const GCdbArchive *, const rle_string *);
 
 
 /* Associe un nouvel utilisateur à l'archive. */
-DBError g_cdb_archive_add_client(GCdbArchive *, int, const rle_string *);
+DBError g_cdb_archive_add_client(GCdbArchive *, SSL *, const rle_string *);
 
 
 
diff --git a/src/analysis/db/client.c b/src/analysis/db/client.c
index 5999b70..2256a21 100644
--- a/src/analysis/db/client.c
+++ b/src/analysis/db/client.c
@@ -24,11 +24,14 @@
 #include "client.h"
 
 
+#include <assert.h>
 #include <netdb.h>
 #include <poll.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
 
 
 #include <i18n.h>
@@ -49,14 +52,19 @@ struct _GDbClient
     GObject parent;                         /* A laisser en premier        */
 
     char *author;                           /* Utilisateur représenté      */
-    char *key_file;                         /* Accès sa la clef privée     */
+    //char *key_file;                         /* Accès sa la clef privée     */
 
     const char *name;                       /* Désignation du binaire      */
 
     rle_string hash;                        /* Empreinte du binaire lié    */
     GList *collections;                     /* Collections d'un binaire    */
 
+    SSL_CTX *tls_ctx;                       /* Contexte du chiffrement     */
+    char *cert_file;                        /* Fichier du certificat       */
+    char *key_file;                         /* Fichier de la clef privée   */
+
     int fd;                                 /* Canal de communication      */
+    SSL *tls_fd;                            /* Même canal, mais sécurisé   */
 
     GMutex sending_lock;                    /* Concurrence des envois      */
     GThread *update;                        /* Procédure de traitement     */
@@ -129,7 +137,12 @@ static void g_db_client_class_init(GDbClientClass *klass)
 
 static void g_db_client_init(GDbClient *client)
 {
+    client->tls_ctx = NULL;
+    client->cert_file = NULL;
+    client->key_file = NULL;
+
     client->fd = -1;
+    client->tls_fd = NULL;
 
 }
 
@@ -153,6 +166,16 @@ static void g_db_client_finalize(GDbClient *client)
 
     unset_rle_string(&client->hash);
 
+    assert(client->tls_ctx == NULL);
+
+    if (client->cert_file != NULL)
+        free(client->cert_file);
+
+    if (client->key_file != NULL)
+        free(client->key_file);
+
+    assert(client->tls_fd == NULL);
+
     G_OBJECT_CLASS(g_db_client_parent_class)->finalize(G_OBJECT(client));
 
 }
@@ -342,6 +365,8 @@ bool g_db_client_start_remote(GDbClient *client, const char *host, unsigned shor
 
 static bool g_db_client_start_common(GDbClient *client, const char *desc)
 {
+    const SSL_METHOD *method;               /* Mode du canal sécurisé      */
+    int ret;                                /* Bilan d'un appel            */
     packed_buffer out_pbuf;                 /* Tampon d'émission           */
     bool status;                            /* Bilan d'une opération       */
     rle_string user;                        /* Nom d'utilisateur associé   */
@@ -354,6 +379,38 @@ static bool g_db_client_start_common(GDbClient *client, const char *desc)
     DBError error;                          /* Validation de la connexion  */
 
     /**
+     * Mise en place d'un environnement sécurisé.
+     */
+
+    method = TLS_client_method();
+
+    client->tls_ctx = SSL_CTX_new(method);
+
+    if (client->tls_ctx == NULL)
+    {
+        LOG_ERROR_OPENSSL;
+        goto quick_error;
+    }
+
+    client->tls_fd = SSL_new(client->tls_ctx);
+
+    if (client->tls_fd == NULL)
+    {
+        LOG_ERROR_OPENSSL;
+        goto tls_error;
+    }
+
+    SSL_set_fd(client->tls_fd, client->fd);
+
+    ret = SSL_connect(client->tls_fd);
+
+    if (ret != 1)
+    {
+        LOG_ERROR_OPENSSL;
+        goto tls_error;
+    }
+
+    /**
      * On réalise l'envoi initial ; le premier paquet doit contenir :
      *    - la commande 'DBC_HELO'.
      *    - le numéro de version du client.
@@ -367,18 +424,18 @@ static bool g_db_client_start_common(GDbClient *client, const char *desc)
     init_packed_buffer(&out_pbuf);
 
     status = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_HELO }, sizeof(uint32_t), true);
-    if (!status) goto gdcs_error;
+    if (!status) goto setup_error;
 
     status = extend_packed_buffer(&out_pbuf, (uint32_t []) { CDB_PROTOCOL_VERSION }, sizeof(uint32_t), true);
-    if (!status) goto gdcs_error;
+    if (!status) goto setup_error;
 
     status = pack_rle_string(&client->hash, &out_pbuf);
-    if (!status) goto gdcs_error;
+    if (!status) goto setup_error;
 
     dup_into_rle_string(&user, client->author); /* FIXME : src ? */
 
     status = pack_rle_string(&user, &out_pbuf);
-    if (!status) goto gdcs_error;
+    if (!status) goto setup_error;
 
     checksum = g_checksum_new(G_CHECKSUM_MD5);
     g_checksum_update(checksum, (guchar *)get_rle_string(&user), get_rle_length(&user));
@@ -386,18 +443,21 @@ static bool g_db_client_start_common(GDbClient *client, const char *desc)
     g_checksum_free(checksum);
 
     key = load_rsa_key(client->key_file, true);
-    if (key == NULL) goto gdcs_error;
+    if (key == NULL) goto setup_error;
 
     if (!sign_md5_hash(key, md5_digest, sig))
-        goto gdcs_error;
+    {
+        RSA_free(key);
+        goto setup_error;
+    }
 
     RSA_free(key);
 
     status = extend_packed_buffer(&out_pbuf, sig, RSA_USED_SIZE, false);
-    if (!status) goto gdcs_error;
+    if (!status) goto setup_error;
 
-    status = send_packed_buffer(&out_pbuf, client->fd);
-    if (!status) goto gdcs_error;
+    status = ssl_send_packed_buffer(&out_pbuf, client->tls_fd);
+    if (!status) goto setup_error;
 
     /**
      * Le serveur doit répondre pour un message type :
@@ -408,20 +468,20 @@ static bool g_db_client_start_common(GDbClient *client, const char *desc)
 
     init_packed_buffer(&in_pbuf);
 
-    status = recv_packed_buffer(&in_pbuf, client->fd);
-    if (!status) goto gdsc_error;
+    status = ssl_recv_packed_buffer(&in_pbuf, client->tls_fd);
+    if (!status) goto comm_error;
 
     status = extract_packed_buffer(&in_pbuf, &data, sizeof(uint32_t), true);
-    if (!status) goto gdsc_error;
+    if (!status) goto comm_error;
 
     if (data != DBC_WELCOME)
     {
         log_variadic_message(LMT_ERROR, _("The server '%s' did not welcome us!"), desc);
-        goto gdsc_error;
+        goto comm_error;
     }
 
     status = extract_packed_buffer(&in_pbuf, &data, sizeof(uint32_t), true);
-    if (!status) goto gdsc_error;
+    if (!status) goto comm_error;
 
     error = data;
 
@@ -434,25 +494,25 @@ static bool g_db_client_start_common(GDbClient *client, const char *desc)
         case DBE_WRONG_VERSION:
             log_variadic_message(LMT_ERROR, _("The server '%s' does not use our protocol version (0x%08x)..."),
                                  desc, CDB_PROTOCOL_VERSION);
-            goto gdsc_error;
+            goto comm_error;
             break;
 
         case DBE_XML_VERSION_ERROR:
             log_variadic_message(LMT_ERROR, _("The archive from the server '%s' does not use our protocol version (0x%08x)..."),
                                  desc, CDB_PROTOCOL_VERSION);
-            goto gdsc_error;
+            goto comm_error;
             break;
 
         case DBE_DB_LOADING_ERROR:
             log_variadic_message(LMT_ERROR, _("The server '%s' got into troubles while loading the database...."),
                                  desc);
-            goto gdsc_error;
+            goto comm_error;
             break;
 
         default:
             log_variadic_message(LMT_ERROR, _("The server '%s' has run into an error (%u)..."),
                                  desc, error);
-            goto gdsc_error;
+            goto comm_error;
             break;
 
     }
@@ -462,7 +522,7 @@ static bool g_db_client_start_common(GDbClient *client, const char *desc)
     {
         log_variadic_message(LMT_ERROR, _("Failed to start a listening thread for the server '%s'!"),
                              desc);
-        goto gdsc_error;
+        goto comm_error;
     }
 
     exit_packed_buffer(&out_pbuf);
@@ -470,16 +530,23 @@ static bool g_db_client_start_common(GDbClient *client, const char *desc)
 
     return true;
 
- gdsc_error:
+ comm_error:
 
     exit_packed_buffer(&in_pbuf);
 
- gdcs_error:
+ setup_error:
 
     exit_packed_buffer(&out_pbuf);
 
     unset_rle_string(&user);
 
+ tls_error:
+
+    SSL_CTX_free(client->tls_ctx);
+    client->tls_ctx = NULL;
+
+ quick_error:
+
     close(client->fd);
     client->fd = -1;
 
@@ -529,7 +596,7 @@ static void *g_db_client_update(GDbClient *client)
         {
             reset_packed_buffer(&in_pbuf);
 
-            status = recv_packed_buffer(&in_pbuf, fds.fd);
+            status = ssl_recv_packed_buffer(&in_pbuf, client->tls_fd);
             if (!status) goto gdcu_bad_exchange;
 
             status = extract_packed_buffer(&in_pbuf, &command, sizeof(uint32_t), true);
@@ -607,14 +674,28 @@ static void *g_db_client_update(GDbClient *client)
 
 void g_db_client_stop(GDbClient *client)
 {
+    int ret;                                /* Bilan d'un appel            */
+
+    /* Canal de communication */
+
     if (client->fd != -1)
+    {
+        assert(client->tls_ctx == NULL);
         return;
+    }
 
-    close(client->fd);
-    client->fd = -1;
+    ret = close(client->fd);
+    if (ret == -1) perror("close");
 
     g_thread_join(client->update);
 
+    client->fd = -1;
+
+    /* Environnement TLS */
+
+    SSL_CTX_free(client->tls_ctx);
+    client->tls_ctx = NULL;
+
 }
 
 
@@ -673,10 +754,13 @@ void g_db_client_put_fd(GDbClient *client)
 bool g_db_client_save(GDbClient *client)
 {
     bool result;                            /* Bilan partiel à remonter    */
+    int sent;                               /* Quantité de données traitées*/
 
     g_db_client_get_fd(client);
 
-    result = safe_send(client->fd, (uint32_t []) { htobe32(DBC_SAVE) }, sizeof(uint32_t), 0);
+    sent = SSL_write(client->tls_fd, (uint32_t []) { htobe32(DBC_SAVE) }, sizeof(uint32_t));
+
+    result = (sent == sizeof(uint32_t));
 
     g_db_client_put_fd(client);
 
@@ -715,7 +799,7 @@ bool g_db_client_set_last_active(GDbClient *client, timestamp_t timestamp)
     g_db_client_put_fd(client);
 
     if (result)
-        result = send_packed_buffer(&out_pbuf, client->fd);
+        result = ssl_send_packed_buffer(&out_pbuf, client->tls_fd);
 
     exit_packed_buffer(&out_pbuf);
 
diff --git a/src/analysis/db/keymgn.c b/src/analysis/db/keymgn.c
index 5c66e66..4334896 100644
--- a/src/analysis/db/keymgn.c
+++ b/src/analysis/db/keymgn.c
@@ -39,9 +39,6 @@
 /* Mémorise en mémoire la définition d'une identité courante. */
 static void store_identity(const x509_entries *, bool);
 
-/* Fournit le répertoire de travail pour les certifications. */
-static char *get_cert_working_directory(const char *, const char *);
-
 
 
 /******************************************************************************
@@ -219,7 +216,7 @@ static void store_identity(const x509_entries *entries, bool client)
 *                                                                             *
 ******************************************************************************/
 
-static char *get_cert_working_directory(const char *type, const char *name)
+char *get_cert_working_directory(const char *type, const char *name)
 {
     char *result;                           /* Chemin à retourner          */
     char *suffix;                           /* Fin de la destination       */
diff --git a/src/analysis/db/keymgn.h b/src/analysis/db/keymgn.h
index be6ce83..df4f1f5 100644
--- a/src/analysis/db/keymgn.h
+++ b/src/analysis/db/keymgn.h
@@ -35,6 +35,9 @@
 /* Charge en mémoire la définition de l'identité courante. */
 void load_identity(bool, x509_entries *);
 
+/* Fournit le répertoire de travail pour les certifications. */
+char *get_cert_working_directory(const char *, const char *);
+
 /* Définit les certificats utilisés pour les échanges internes. */
 bool register_standalone_certs(const x509_entries *);
 
diff --git a/src/analysis/db/server.c b/src/analysis/db/server.c
index eaf3775..a996360 100644
--- a/src/analysis/db/server.c
+++ b/src/analysis/db/server.c
@@ -31,6 +31,8 @@
 #include <string.h>
 #include <unistd.h>
 #include <arpa/inet.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
 
 
 #include <i18n.h>
@@ -41,6 +43,7 @@
 #include "protocol.h"
 #include "misc/rlestr.h"
 #include "../../common/io.h"
+#include "../../common/pathname.h"
 #include "../../common/xdg.h"
 #include "../../core/logs.h"
 #include "../../core/params.h"
@@ -76,6 +79,10 @@ struct _GDbServer
     registered_user *users;                 /* Liste d'utilisateurs        */
     size_t users_count;                     /* Nombre d'enregistrés        */
 
+    SSL_CTX *tls_ctx;                       /* Contexte du chiffrement     */
+    char *cert_file;                        /* Fichier du certificat       */
+    char *key_file;                         /* Fichier de la clef privée   */
+
     int fd;                                 /* Canal de communication      */
     int domain;                             /* Domaine du canal            */
     gen_sockaddr_t addr;                    /* Adresse d'écoute générique  */
@@ -172,6 +179,10 @@ static void g_db_server_class_init(GDbServerClass *klass)
 
 static void g_db_server_init(GDbServer *server)
 {
+    server->tls_ctx = NULL;
+    server->cert_file = NULL;
+    server->key_file = NULL;
+
     server->fd = -1;
 
     server->basedir = NULL;
@@ -197,6 +208,8 @@ static void g_db_server_dispose(GDbServer *server)
 {
     GList *iter;                            /* Boucle de parcours          */
 
+    g_db_server_stop(server);
+
     for (iter = g_list_first(server->archives);
          iter != NULL;
          iter = g_list_first(server->archives))
@@ -230,6 +243,14 @@ static void g_db_server_finalize(GDbServer *server)
 
     free(server->desc);
 
+    assert(server->tls_ctx == NULL);
+
+    if (server->cert_file != NULL)
+        free(server->cert_file);
+
+    if (server->key_file != NULL)
+        free(server->key_file);
+
     if (server->basedir != NULL)
         free(server->basedir);
 
@@ -255,6 +276,7 @@ GDbServer *g_db_server_new_internal(const char *author, char *kfile)
 {
     GDbServer *result;                      /* Adresse à retourner         */
     bool status;                            /* Bilan d'un chargement       */
+    char *working;                          /* Répertoire par le client    */
 
     result = g_object_new(G_TYPE_DB_SERVER, NULL);
 
@@ -263,6 +285,15 @@ GDbServer *g_db_server_new_internal(const char *author, char *kfile)
     status = g_db_server_register_user(result, author, kfile);
     if (!status) goto gdsni_error;
 
+    /* Paramètres de chiffrement */
+
+    working = get_cert_working_directory("servers", "standalone");
+
+    result->cert_file = build_absolute_filename(working, "server-cert.pem");
+    result->key_file = build_absolute_filename(working, "server-key.pem");
+
+    free(working);
+
     /* Détermination du point d'écoute */
 
     result->domain = AF_UNIX;
@@ -395,7 +426,7 @@ GDbServer *g_db_server_new_remote(const char *conf)
     result->sock_len = sizeof(struct sockaddr_in);
 
     desclen = INET6_ADDRSTRLEN + 1 + 5 + 1;
-    result->desc = (char *)calloc(desclen, sizeof(char));
+    result->desc = calloc(desclen, sizeof(char));
 
     ip = inet_ntop(AF_INET, &result->addr.inet_addr.sin_addr, result->desc, INET6_ADDRSTRLEN);
     if (ip == NULL)
@@ -480,8 +511,7 @@ static bool g_db_server_register_user(GDbServer *server, const char *author, cha
     if (strlen(author) == 0)
         return false;
 
-    server->users = (registered_user *)realloc(server->users,
-                                               ++server->users_count * sizeof(registered_user));
+    server->users = realloc(server->users, ++server->users_count * sizeof(registered_user));
 
     dup_into_rle_string(&server->users[server->users_count - 1].author, author);    /* FIXME : src ? */
     server->users[server->users_count - 1].key_file = kfile;
@@ -563,6 +593,7 @@ static void *g_db_server_listener(GDbServer *server)
     int ret;                                /* Bilan d'un appel            */
     gen_sockaddr_t peer;                    /* Adresse cliente             */
     int fd;                                 /* Canal établi vers un client */
+    SSL *tls_fd;                            /* Même canal, mais sécurisé   */
     rle_string hash;                        /* Empreinte du binaire visé   */
     rle_string user;                        /* Nom d'utilisateur du client */
     const char *ip;                         /* Statut de la conversion     */
@@ -598,6 +629,24 @@ static void *g_db_server_listener(GDbServer *server)
                 continue;
             }
 
+            tls_fd = SSL_new(server->tls_ctx);
+
+            if (tls_fd == NULL)
+            {
+                LOG_ERROR_OPENSSL;
+                goto end_of_client;
+            }
+
+            SSL_set_fd(tls_fd, fd);
+
+            ret = SSL_accept(tls_fd);
+
+            if (ret != 1)
+            {
+                LOG_ERROR_OPENSSL;
+                goto invalid_conn;
+            }
+
             /* Initialisation à vide pour les sorties en erreur */
 
             init_dynamic_rle_string(&hash, NULL);
@@ -610,13 +659,13 @@ static void *g_db_server_listener(GDbServer *server)
 
             else if (*((sa_family_t *)&peer) == AF_INET)
             {
-                peer_name = (char *)calloc(INET6_ADDRSTRLEN + 1 + 5 + 1, sizeof(char));
+                peer_name = calloc(INET6_ADDRSTRLEN + 1 + 5 + 1, sizeof(char));
 
                 ip = inet_ntop(AF_INET, &peer.inet_addr.sin_addr, peer_name, INET6_ADDRSTRLEN);
                 if (ip == NULL)
                 {
                     perror("inet_ntop");
-                    goto gdsl_error;
+                    goto id_error;
                 }
 
                 snprintf(peer_name + strlen(ip), 1 + 5, ":%hu", ntohs(peer.inet_addr.sin_port));
@@ -624,7 +673,7 @@ static void *g_db_server_listener(GDbServer *server)
             }
 
             else
-                goto gdsl_invalid;
+                goto invalid_conn;
 
             error = DBE_NONE;
             archive = NULL;
@@ -642,13 +691,13 @@ static void *g_db_server_listener(GDbServer *server)
 
             init_packed_buffer(&in_pbuf);
 
-            status = recv_packed_buffer(&in_pbuf, fd);
+            status = ssl_recv_packed_buffer(&in_pbuf, tls_fd);
             if (!status)
             {
                 log_variadic_message(LMT_ERROR, _("Error while getting the initial packet from '%s'..."),
                                      peer_name);
                 error = DBE_BAD_EXCHANGE;
-                goto gdsl_error_sending;
+                goto error_sending;
             }
 
             status = extract_packed_buffer(&in_pbuf, &cmd, sizeof(uint32_t), true);
@@ -657,7 +706,7 @@ static void *g_db_server_listener(GDbServer *server)
                 log_variadic_message(LMT_ERROR, _("Error while getting the initial command from '%s'..."),
                                      peer_name);
                 error = DBE_BAD_EXCHANGE;
-                goto gdsl_error_sending;
+                goto error_sending;
             }
 
             status = extract_packed_buffer(&in_pbuf, &version, sizeof(uint32_t), true);
@@ -666,7 +715,7 @@ static void *g_db_server_listener(GDbServer *server)
                 log_variadic_message(LMT_ERROR, _("Error while getting the protocol version from '%s'..."),
                                      peer_name);
                 error = DBE_BAD_EXCHANGE;
-                goto gdsl_error_sending;
+                goto error_sending;
             }
 
             status = unpack_rle_string(&hash, &in_pbuf);
@@ -675,7 +724,7 @@ static void *g_db_server_listener(GDbServer *server)
                 log_variadic_message(LMT_ERROR, _("Error while getting the binary hash from '%s'..."),
                                      peer_name);
                 error = DBE_BAD_EXCHANGE;
-                goto gdsl_error_sending;
+                goto error_sending;
             }
 
             status = unpack_rle_string(&user, &in_pbuf);
@@ -684,7 +733,7 @@ static void *g_db_server_listener(GDbServer *server)
                 log_variadic_message(LMT_ERROR, _("Error while getting the user name from '%s'..."),
                                      peer_name);
                 error = DBE_BAD_EXCHANGE;
-                goto gdsl_error_sending;
+                goto error_sending;
             }
 
             status = extract_packed_buffer(&in_pbuf, sig, RSA_USED_SIZE, false);
@@ -693,7 +742,7 @@ static void *g_db_server_listener(GDbServer *server)
                 log_variadic_message(LMT_ERROR, _("Error while getting the signature from '%s'..."),
                                      peer_name);
                 error = DBE_BAD_EXCHANGE;
-                goto gdsl_error_sending;
+                goto error_sending;
             }
 
             if (cmd != DBC_HELO)
@@ -701,7 +750,7 @@ static void *g_db_server_listener(GDbServer *server)
                 log_variadic_message(LMT_ERROR, _("The client from '%s' did not introduce itself!"),
                                      peer_name);
                 error = DBE_BAD_EXCHANGE;
-                goto gdsl_error_sending;
+                goto error_sending;
             }
 
             if (version != CDB_PROTOCOL_VERSION)
@@ -709,7 +758,7 @@ static void *g_db_server_listener(GDbServer *server)
                 log_variadic_message(LMT_ERROR, _("The client from '%s' does not use the same protocol: 0x%08x vs 0x%08x..."),
                                      peer_name, be32toh(version), CDB_PROTOCOL_VERSION);
                 error = DBE_WRONG_VERSION;
-                goto gdsl_error_sending;
+                goto error_sending;
             }
 
             if (is_rle_string_empty(&hash))
@@ -717,7 +766,7 @@ static void *g_db_server_listener(GDbServer *server)
                 log_variadic_message(LMT_ERROR, _("The submitted binary hash from '%s' is empty!"),
                                      peer_name);
                 error = DBE_BAD_EXCHANGE;
-                goto gdsl_error_sending;
+                goto error_sending;
             }
 
             if (is_rle_string_empty(&user))
@@ -725,14 +774,14 @@ static void *g_db_server_listener(GDbServer *server)
                 log_variadic_message(LMT_ERROR, _("No user is associated with the client from '%s'..."),
                                      peer_name);
                 error = DBE_BAD_EXCHANGE;
-                goto gdsl_error_sending;
+                goto error_sending;
             }
 
             if (!g_db_server_is_registered_user(server, &user, sig))
             {
                 log_variadic_message(LMT_ERROR, _("This user is not registered."));
                 error = DBE_BAD_EXCHANGE;
-                goto gdsl_error_sending;
+                goto error_sending;
             }
 
             /**
@@ -761,20 +810,20 @@ static void *g_db_server_listener(GDbServer *server)
              *      ou 'DBE_WRONG_VERSION' ... 'DBE_LOADING_ERROR').
              */
 
- gdsl_error_sending:
+ error_sending:
 
             exit_packed_buffer(&in_pbuf);
 
             init_packed_buffer(&out_pbuf);
 
             status = extend_packed_buffer(&out_pbuf, (uint32_t []) { DBC_WELCOME }, sizeof(uint32_t), true);
-            if (!status) goto gdsl_out_error;
+            if (!status) goto out_error;
 
             status = extend_packed_buffer(&out_pbuf, (uint32_t []) { error }, sizeof(uint32_t), true);
-            if (!status) goto gdsl_out_error;
+            if (!status) goto out_error;
 
-            status = send_packed_buffer(&out_pbuf, fd);
-            if (!status) goto gdsl_out_error;
+            status = ssl_send_packed_buffer(&out_pbuf, tls_fd);
+            if (!status) goto out_error;
 
             /**
              * L'ajout dans la liste des clients connectés provoque un envoi de mises à jour.
@@ -790,7 +839,7 @@ static void *g_db_server_listener(GDbServer *server)
                 if (iter == NULL)
                     server->archives = g_list_append(server->archives, archive);
 
-                error = g_cdb_archive_add_client(archive, fd, &user);
+                error = g_cdb_archive_add_client(archive, tls_fd, &user);
 
                 exit_packed_buffer(&out_pbuf);
 
@@ -805,7 +854,7 @@ static void *g_db_server_listener(GDbServer *server)
 
             assert(error != DBE_NONE);
 
- gdsl_out_error:
+ out_error:
 
             exit_packed_buffer(&out_pbuf);
 
@@ -813,14 +862,18 @@ static void *g_db_server_listener(GDbServer *server)
             if (iter == NULL && archive != NULL)
                 g_object_unref(G_OBJECT(archive));
 
- gdsl_error:
+ id_error:
 
             free(peer_name);
 
             exit_rle_string(&hash);
             exit_rle_string(&user);
 
- gdsl_invalid:
+ invalid_conn:
+
+            SSL_free(tls_fd);
+
+ end_of_client:
 
             close(fd);
 
@@ -847,10 +900,49 @@ static void *g_db_server_listener(GDbServer *server)
 
 bool g_db_server_start(GDbServer *server)
 {
+    const SSL_METHOD *method;               /* Mode du canal sécurisé      */
     int ret;                                /* Bilan d'un appel            */
     bool status;                            /* Bilan d'un nettoyage        */
     int backlog;                            /* Nombre de connexions maximal*/
 
+    /* Définition d'un environnement TLS */
+
+    method = TLS_server_method();
+
+    server->tls_ctx = SSL_CTX_new(method);
+
+    if (server->tls_ctx == NULL)
+    {
+        LOG_ERROR_OPENSSL;
+        goto quick_error;
+    }
+
+    ret = SSL_CTX_use_certificate_file(server->tls_ctx, server->cert_file, SSL_FILETYPE_PEM);
+
+    if (ret != 1)
+    {
+        LOG_ERROR_OPENSSL;
+        goto tls_error;
+    }
+
+    ret = SSL_CTX_use_PrivateKey_file(server->tls_ctx, server->key_file, SSL_FILETYPE_PEM);
+
+    if (ret != 1)
+    {
+        LOG_ERROR_OPENSSL;
+        goto tls_error;
+    }
+
+    ret = SSL_CTX_check_private_key(server->tls_ctx);
+
+    if (ret != 1)
+    {
+        LOG_ERROR_OPENSSL;
+        goto tls_error;
+    }
+
+    /* Mise en place d'un canal de communication */
+
     server->fd = socket(server->domain, SOCK_STREAM, 0);
     if (server->fd == -1)
     {
@@ -899,6 +991,13 @@ bool g_db_server_start(GDbServer *server)
     close(server->fd);
     server->fd = -1;
 
+ tls_error:
+
+    SSL_CTX_free(server->tls_ctx);
+    server->tls_ctx = NULL;
+
+ quick_error:
+
     return false;
 
 }
@@ -920,8 +1019,13 @@ void g_db_server_stop(GDbServer *server)
 {
     int ret;                                /* Bilan d'un appel            */
 
+    /* Canal de communication */
+
     if (server->fd == -1)
+    {
+        assert(server->tls_ctx == NULL);
         return;
+    }
 
     ret = shutdown(server->fd, SHUT_RDWR);
     if (ret == -1) perror("shutdown");
@@ -936,6 +1040,9 @@ void g_db_server_stop(GDbServer *server)
     if (server->clean_socket != NULL)
         server->clean_socket(server);
 
-    /* TODO : s'occuper des archives ouvertes */
+    /* Environnement TLS */
+
+    SSL_CTX_free(server->tls_ctx);
+    server->tls_ctx = NULL;
 
 }
diff --git a/src/common/packed.c b/src/common/packed.c
index d956a42..e06e4bb 100644
--- a/src/common/packed.c
+++ b/src/common/packed.c
@@ -343,7 +343,6 @@ bool write_packed_buffer(packed_buffer *pbuf, int fd)
 }
 
 
-
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : pbuf = paquet de données à constituer. [OUT]                 *
@@ -409,3 +408,81 @@ bool send_packed_buffer(packed_buffer *pbuf, int fd)
     return result;
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : pbuf = paquet de données à constituer. [OUT]                 *
+*                fd   = flux ouvert en lecture.                               *
+*                                                                             *
+*  Description : Réceptionne des données depuis un flux réseau chiffré.       *
+*                                                                             *
+*  Retour      : true si toutes les données ont été reçues, false sinon.      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool ssl_recv_packed_buffer(packed_buffer *pbuf, SSL *fd)
+{
+    bool result;                            /* Bilan à retourner           */
+    uint32_t used;                          /* Taille de charge utile      */
+    int got;                                /* Quantité de données traitées*/
+
+    got = SSL_read(fd, &used, sizeof(uint32_t));
+
+    result = (got == sizeof(uint32_t));
+
+    if (result)
+    {
+        assert(pbuf->pos == sizeof(uint32_t));
+
+        if ((pbuf->pos + used) > pbuf->allocated)
+        {
+            pbuf->allocated = pbuf->pos + used;
+            pbuf->data = realloc(pbuf->data, pbuf->allocated * sizeof(uint8_t));
+        }
+
+        pbuf->used = used;
+
+        got = SSL_read(fd, pbuf->data + pbuf->pos, used);
+
+        result = (got == used);
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : pbuf = paquet de données à émettre.                          *
+*                fd   = flux ouvert en écriture.                              *
+*                                                                             *
+*  Description : Envoie des données au travers un flux réseau chiffré.        *
+*                                                                             *
+*  Retour      : true si toutes les données ont été émises, false sinon.      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool ssl_send_packed_buffer(packed_buffer *pbuf, SSL *fd)
+{
+    bool result;                            /* Bilan à retourner           */
+    int quantity;                           /* Nombre de données à traiter */
+    int sent;                               /* Quantité de données traitées*/
+
+    *((uint32_t *)pbuf->data) = pbuf->used;
+
+    quantity = sizeof(uint32_t) + pbuf->used;
+
+    sent = SSL_write(fd, pbuf->data, quantity);
+
+    result = (quantity == sent);
+
+    return result;
+
+}
diff --git a/src/common/packed.h b/src/common/packed.h
index d25c947..5c724e0 100644
--- a/src/common/packed.h
+++ b/src/common/packed.h
@@ -27,6 +27,7 @@
 
 #include <stdbool.h>
 #include <stdint.h>
+#include <openssl/ssl.h>
 #include <sys/types.h>
 
 
@@ -76,6 +77,12 @@ bool recv_packed_buffer(packed_buffer *, int);
 /* Envoie des données au travers un flux réseau. */
 bool send_packed_buffer(packed_buffer *, int);
 
+/* Réceptionne des données depuis un flux réseau chiffré. */
+bool ssl_recv_packed_buffer(packed_buffer *, SSL *);
+
+/* Envoie des données au travers un flux réseau chiffré. */
+bool ssl_send_packed_buffer(packed_buffer *, SSL *);
+
 
 
 #endif  /* _COMMON_PACKED_H */
diff --git a/src/core/core.c b/src/core/core.c
index fe8ccbb..cdcfce5 100644
--- a/src/core/core.c
+++ b/src/core/core.c
@@ -27,6 +27,7 @@
 #include <stdlib.h>
 #include <time.h>
 #include <unistd.h>
+#include <openssl/err.h>
 #include <openssl/ssl.h>
 
 
@@ -82,11 +83,12 @@ bool load_all_basic_components(void)
                                      (GBoxedCopyFunc)dup_vmpa,
                                      (GBoxedFreeFunc)delete_vmpa);
 
-        result &= load_main_config_parameters();
-
+        ERR_load_crypto_strings();
         SSL_load_error_strings();
         SSL_library_init();
 
+        result &= load_main_config_parameters();
+
         result &= ensure_user_has_rsa_keys();
 
         result &= g_generic_config_read(get_main_configuration());
@@ -140,4 +142,6 @@ void unload_all_basic_components(void)
 
     unload_main_config_parameters();
 
+    ERR_free_strings();
+
 }
-- 
cgit v0.11.2-87-g4458