From 29eae5126251eb0f10d02700bb87dac9893bb445 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard 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 #include +#include #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 #include #include #include #include #include +#include +#include #include @@ -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 #include #include +#include +#include #include @@ -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 #include +#include #include @@ -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 #include #include +#include #include @@ -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