summaryrefslogtreecommitdiff
path: root/src/analysis/db/server.c
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2018-12-01 11:16:12 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2018-12-01 11:16:12 (GMT)
commit29eae5126251eb0f10d02700bb87dac9893bb445 (patch)
tree34e8906f0d6f3948b80cf59b86f2d5179fa379ad /src/analysis/db/server.c
parent09f07c9a523dce7b8d7e013857f988f727f1a72b (diff)
Encrypted all communications using TLS.
Diffstat (limited to 'src/analysis/db/server.c')
-rw-r--r--src/analysis/db/server.c163
1 files changed, 135 insertions, 28 deletions
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;
}