From 5ad85cf30b2355ca727904d1a0d25240283813b3 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Sun, 10 Apr 2016 00:59:38 +0200 Subject: Signed and verified the MD5 hash of a given user name. --- ChangeLog | 24 ++++++ src/analysis/binary.c | 120 ++++++++++++++++++++++++++++-- src/analysis/binary.h | 3 - src/analysis/db/client.c | 56 ++++++++++---- src/analysis/db/client.h | 4 +- src/analysis/db/keymgn.c | 121 +++++++++++++++++++++++++++++- src/analysis/db/keymgn.h | 13 ++++ src/analysis/db/misc/rlestr.h | 2 + src/analysis/db/server.c | 169 ++++++++++++++++++++++++++++++++++++++++-- src/analysis/db/server.h | 2 +- src/main.c | 19 ++++- 11 files changed, 494 insertions(+), 39 deletions(-) diff --git a/ChangeLog b/ChangeLog index a074ccd..5822754 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +16-04-10 Cyrille Bagard + + * src/analysis/binary.c: + * src/analysis/binary.h: + Update code. + + * src/analysis/db/client.c: + * src/analysis/db/client.h: + Provide a signed hash of the user name to the server. + + * src/analysis/db/keymgn.c: + * src/analysis/db/keymgn.h: + Load RSA keys. Sign and verify the MD5 hash of a given user name. + + * src/analysis/db/misc/rlestr.h: + Define get_rle_length(). + + * src/analysis/db/server.c: + * src/analysis/db/server.h: + Verify the signed hash of the user name provided by the client. + + * src/main.c: + Update code. + 16-04-09 Cyrille Bagard * configure.ac: diff --git a/src/analysis/binary.c b/src/analysis/binary.c index d934c76..c71bc84 100644 --- a/src/analysis/binary.c +++ b/src/analysis/binary.c @@ -41,6 +41,7 @@ #include "disass/disassembler.h" #include "../common/extstr.h" #include "../common/cpp.h" +#include "../common/xdg.h" #include "../core/collections.h" #include "../core/formats.h" #include "../core/params.h" @@ -127,6 +128,12 @@ static bool g_loaded_binary_load_storage(GLoadedBinary *, xmlXPathContextPtr, co /* Ecrit les formes d'enregistrement du binaire dans du XML. */ static bool g_loaded_binary_save_storage(const GLoadedBinary *, xmlDocPtr, xmlXPathContextPtr, const char *); +/* Etablit une connexion au serveur interne en tant que client. */ +static bool g_loaded_binary_connect_internal(GLoadedBinary *); + +/* Etablit une connexion à un serveur distant comme client. */ +static bool g_loaded_binary_connect_remote(GLoadedBinary *); + /* -------------------------- MANIPULATION DES COLLECTIONS -------------------------- */ @@ -980,7 +987,7 @@ void g_loaded_binary_set_storage(GLoadedBinary *binary, DBFeatures feature, DBSt * * * Paramètres : binary = élément binaire à manipuler. * * * -* Description : Etablit une connexion à un serveur en tant que client. * +* Description : Etablit une connexion au serveur interne en tant que client. * * * * Retour : Bilan de l'opération. * * * @@ -988,44 +995,141 @@ void g_loaded_binary_set_storage(GLoadedBinary *binary, DBFeatures feature, DBSt * * ******************************************************************************/ -bool g_loaded_binary_connect(GLoadedBinary *binary) +static bool g_loaded_binary_connect_internal(GLoadedBinary *binary) { bool result; /* Bilan à retourner */ - + const char *tmp; /* Stockage temporaire */ + char *author; /* Identification à diffuser */ + char *priv; /* Chemin de la clef privée */ GBinContent *content; /* Contenu bianire manipulé */ const gchar *checksum; /* Identifiant de binaire */ + + char *host; /* Nom du serveur à contacter */ int port; /* Numéro du port associé */ - char *author; /* Identification à diffuser */ + result = false; + + /* Utilisateur représenté */ + + if (!g_generic_config_get_value(get_main_configuration(), MPK_AUTHOR_NAME, &tmp)) + goto glbcl_exit; + + author = strdup(tmp); + + /* Chemin vers la clef privée */ + + priv = get_xdg_config_dir("chrysalide" G_DIR_SEPARATOR_S "id_rsa.priv"); /* Détermination de l'identifiant */ + content = g_binary_format_get_content(G_BIN_FORMAT(binary->format)); checksum = g_binary_content_get_cheksum(content); g_object_unref(G_OBJECT(content)); - binary->local = g_db_client_new(g_loaded_binary_get_name(binary, false), + /* Tentative de connexion */ + + binary->local = g_db_client_new(author, priv, + g_loaded_binary_get_name(binary, false), checksum, binary->collections); + + if (!g_generic_config_get_value(get_main_configuration(), MPK_LOCAL_HOST, &host)) /* ... */; if (!g_generic_config_get_value(get_main_configuration(), MPK_LOCAL_PORT, &port)) /* ... */; - if (!g_generic_config_get_value(get_main_configuration(), MPK_AUTHOR_NAME, &author)) + + result = g_db_client_start(binary->local, host, port); + + printf("DB status :: %d\n", result); + + + glbcl_exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : binary = élément binaire à manipuler. * +* * +* Description : Etablit une connexion à un serveur distant comme client. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_loaded_binary_connect_remote(GLoadedBinary *binary) +{ + bool result; /* Bilan à retourner */ + const char *tmp; /* Stockage temporaire */ + char *author; /* Identification à diffuser */ + char *priv; /* Chemin de la clef privée */ + GBinContent *content; /* Contenu bianire manipulé */ + const gchar *checksum; /* Identifiant de binaire */ + + + + char *host; /* Nom du serveur à contacter */ + int port; /* Numéro du port associé */ + + + + result = false; + + /* Utilisateur représenté */ + + if (!g_generic_config_get_value(get_main_configuration(), MPK_AUTHOR_NAME, &tmp)) + goto glbcl_exit; + + author = strdup(tmp); + + /* Chemin vers la clef privée */ + + priv = get_xdg_config_dir("chrysalide" G_DIR_SEPARATOR_S "id_rsa.priv"); + + /* Détermination de l'identifiant */ + + content = g_binary_format_get_content(G_BIN_FORMAT(binary->format)); + checksum = g_binary_content_get_cheksum(content); + g_object_unref(G_OBJECT(content)); + + /* Tentative de connexion */ + + binary->local = g_db_client_new(author, priv, + g_loaded_binary_get_name(binary, false), + checksum, + binary->collections); + + + + + if (!g_generic_config_get_value(get_main_configuration(), MPK_LOCAL_HOST, &host)) + /* ... */; + + if (!g_generic_config_get_value(get_main_configuration(), MPK_LOCAL_PORT, &port)) /* ... */; - result = g_db_client_start(binary->local, host, port, author); + result = g_db_client_start(binary->local, host, port); printf("DB status :: %d\n", result); + + glbcl_exit: + return result; } @@ -1519,7 +1623,7 @@ void ack_completed_disassembly(GDelayedDisassembly *disass, GLoadedBinary *binar g_object_unref(G_OBJECT(disass)); - g_loaded_binary_connect(binary); + /* ... = */g_loaded_binary_connect_internal(binary); /* Décompilation... */ diff --git a/src/analysis/binary.h b/src/analysis/binary.h index 9447d17..8d87bf0 100644 --- a/src/analysis/binary.h +++ b/src/analysis/binary.h @@ -127,9 +127,6 @@ DBStorage g_loaded_binary_get_storage(const GLoadedBinary *, DBFeatures); /* Définit la forme d'enregistrement d'une fonctionnalité. */ void g_loaded_binary_set_storage(GLoadedBinary *, DBFeatures, DBStorage); -/* Etablit une connexion à un serveur en tant que client. */ -bool g_loaded_binary_connect(GLoadedBinary *); - /* -------------------------- MANIPULATION DES COLLECTIONS -------------------------- */ diff --git a/src/analysis/db/client.c b/src/analysis/db/client.c index 2a5a185..bb900ed 100644 --- a/src/analysis/db/client.c +++ b/src/analysis/db/client.c @@ -35,6 +35,7 @@ #include +#include "keymgn.h" #include "protocol.h" #include "misc/rlestr.h" #include "../../common/io.h" @@ -47,6 +48,9 @@ struct _GDbClient { GObject parent; /* A laisser en premier */ + char *author; /* Utilisateur représenté */ + char *key_file; /* Accès sa la clef privée */ + const char *name; /* Désignation du binaire */ rle_string hash; /* Empreinte du binaire lié */ @@ -141,6 +145,9 @@ static void g_db_client_init(GDbClient *client) static void g_db_client_finalize(GDbClient *client) { + free(client->author); + free(client->key_file); + unset_rle_string(&client->hash); G_OBJECT_CLASS(g_db_client_parent_class)->finalize(G_OBJECT(client)); @@ -150,24 +157,29 @@ static void g_db_client_finalize(GDbClient *client) /****************************************************************************** * * -* Paramètres : name = désignation humaine du binaire associé. * +* Paramètres : author = utilisateur à représenter via le client. * +* kfile = clef menant à sa clef privée. * +* name = désignation humaine du binaire associé. * * hash = empreinte d'un binaire en cours d'analyse. * * collections = ensemble de collections existantes. * * * * Description : Prépare un client pour une connexion à une BD. * * * -* Retour : Structure mise en plae ou NULL en cas d'échec. * +* Retour : Structure mise en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ -GDbClient *g_db_client_new(const char *name, const char *hash, GList *collections) +GDbClient *g_db_client_new(char *author, char *kfile, const char *name, const char *hash, GList *collections) { GDbClient *result; /* Adresse à retourner */ result = g_object_new(G_TYPE_DB_CLIENT, NULL); + result->author = author; + result->key_file = kfile; + result->name = name; set_rle_string(&result->hash, hash); @@ -180,10 +192,9 @@ GDbClient *g_db_client_new(const char *name, const char *hash, GList *collection /****************************************************************************** * * -* Paramètres : client = client pour les accès distants à manipuler. * -* host = hôte à représenter pour le service. * -* port = port de connexion pour les clients. * -* username = utilisateur effectuant les évolutions. * +* Paramètres : client = client pour les accès distants à manipuler. * +* host = hôte à représenter pour le service. * +* port = port de connexion pour les clients. * * * * Description : Démarre la connexion à la base de données. * * * @@ -193,12 +204,16 @@ GDbClient *g_db_client_new(const char *name, const char *hash, GList *collection * * ******************************************************************************/ -bool g_db_client_start(GDbClient *client, const char *host, unsigned short port, const char *username) +bool g_db_client_start(GDbClient *client, const char *host, unsigned short port) { struct hostent *hp; /* Informations sur l'hôte */ struct sockaddr_in addr; /* Adresse de transmission */ int ret; /* Bilan d'un appel */ rle_string user; /* Nom d'utilisateur associé */ + GChecksum *checksum; /* Empreinte MD5 à signer */ + unsigned char md5_digest[16]; /* Empreinte MD5 calculée */ + RSA *key; /* Clef pour la signature */ + unsigned char sig[RSA_USED_SIZE]; /* Signature effectuée */ uint32_t data; /* Mot de données lues */ DBError error; /* Validation de la connexion */ @@ -228,16 +243,13 @@ bool g_db_client_start(GDbClient *client, const char *host, unsigned short port, goto gdcs_no_listening; } - /* Préparation du nom d'utilisateur à diffuser */ - - init_rle_string(&user, username); - /** * On réalise l'envoi initial ; le premier paquet doit contenir : * - la commande 'DBC_HELO'. * - le numéro de version du client. * - l'empreinte du binaire analysé. * - l'identifiant de l'utilisateur effectuant des modifications. + * - la signature de l'empreinte MD5 de l'identifiant. * * Tout ceci est à synchroniser avec la fonction g_db_server_listener(). */ @@ -251,7 +263,25 @@ bool g_db_client_start(GDbClient *client, const char *host, unsigned short port, if (!send_rle_string(&client->hash, client->fd, MSG_MORE)) goto gdcs_error; - if (!send_rle_string(&user, client->fd, 0)) + init_rle_string(&user, client->author); + + if (!send_rle_string(&user, client->fd, MSG_MORE)) + goto gdcs_error; + + checksum = g_checksum_new(G_CHECKSUM_MD5); + g_checksum_update(checksum, (guchar *)get_rle_string(&user), get_rle_length(&user)); + g_checksum_get_digest(checksum, (guint8 *)md5_digest, (gsize []) { sizeof(md5_digest) }); + g_checksum_free(checksum); + + key = load_rsa_key(client->key_file, true); + if (key == NULL) goto gdcs_error; + + if (!sign_md5_hash(key, md5_digest, sig)) + goto gdcs_error; + + RSA_free(key); + + if (!safe_send(client->fd, sig, RSA_USED_SIZE, 0)) goto gdcs_error; /** diff --git a/src/analysis/db/client.h b/src/analysis/db/client.h index 0304786..749b8aa 100644 --- a/src/analysis/db/client.h +++ b/src/analysis/db/client.h @@ -51,10 +51,10 @@ typedef struct _GDbClientClass GDbClientClass; GType g_db_client_get_type(void); /* Prépare un client pour une connexion à une BD. */ -GDbClient *g_db_client_new(const char *, const char *, GList *); +GDbClient *g_db_client_new(char *, char *, const char *, const char *, GList *); /* Démarre la connexion à la base de données. */ -bool g_db_client_start(GDbClient *, const char *, unsigned short, const char *); +bool g_db_client_start(GDbClient *, const char *, unsigned short); /* Arrête la connexion à la base de données. */ void g_db_client_stop(GDbClient *); diff --git a/src/analysis/db/keymgn.c b/src/analysis/db/keymgn.c index bcd8d28..bce2ce8 100644 --- a/src/analysis/db/keymgn.c +++ b/src/analysis/db/keymgn.c @@ -24,12 +24,14 @@ #include "keymgn.h" +#include #include #include #include #include +#include #include -#include +#include #include @@ -79,7 +81,7 @@ bool ensure_user_has_rsa_keys(void) result = generate_user_rsa_keys(priv, pub); if (!result) - fprintf(stderr, _("Unable to create new user RSA key pair.")); + fprintf(stderr, _("Unable to create new user RSA key pair.\n")); } @@ -110,7 +112,6 @@ static bool generate_user_rsa_keys(const char *priv, const char *pub) EVP_PKEY_CTX *ctx; /* Contexte de génération */ int ret; /* Bilan d'un appel */ EVP_PKEY *pair; /* Paire de clefs RSA générée */ - char *filename; /* Chemin d'accès */ FILE *stream; /* Flux ouvert en écriture */ result = false; @@ -125,7 +126,7 @@ static bool generate_user_rsa_keys(const char *priv, const char *pub) ret = EVP_PKEY_keygen_init(ctx); if (ret != 1) goto euhrk_exit; - ret = EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048); + ret = EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, RSA_USED_SIZE * 8); if (ret != 1) goto euhrk_exit; ret = EVP_PKEY_keygen(ctx, &pair); @@ -164,3 +165,115 @@ static bool generate_user_rsa_keys(const char *priv, const char *pub) return result; } + + +/****************************************************************************** +* * +* Paramètres : filename = chemin d'accès à la clef à charger. * +* private = nature de la clef visée. * +* * +* Description : Charge une clef RSA à partir d'un fichier PEM. * +* * +* Retour : Clef RSA ou NULL en cas de soucis. * +* * +* Remarques : - * +* * +******************************************************************************/ + +RSA *load_rsa_key(const char *filename, bool private) +{ + RSA *result; /* Clef à retourner */ + FILE *stream; /* Flux ouvert en lecture */ + int bits; /* Taille de la clef en bits */ + + result = NULL; + + stream = fopen(filename, "r"); + if (stream == NULL) goto lrk_exit; + + if (private) + result = PEM_read_RSAPrivateKey(stream, &result, NULL, NULL); + else + result = PEM_read_RSA_PUBKEY(stream, &result, NULL, NULL); + + fclose(stream); + + if (result == NULL) + fprintf(stderr, _("Unable to read the RSA key from '%s'.\n"), filename); + + else + { + bits = RSA_size(result); + + if (bits != RSA_USED_SIZE) + { + fprintf(stderr, _("Wrong RSA key size for %s: expected %d, got %d.\n"), filename, RSA_USED_SIZE, bits); + RSA_free(result); + result = NULL; + } + + } + + lrk_exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : key = clef RSA à utiliser. * +* hash = empreinte à signer. * +* sig = signature calculée. * +* * +* Description : Signe une empreinte MD5 à l'aide d'une clef RSA. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool sign_md5_hash(RSA *key, const unsigned char *hash, unsigned char *sig) +{ + int ret; /* Bilan de l'opération */ + unsigned int siglen; /* Taille de la signature */ + + siglen = RSA_USED_SIZE; + + ret = RSA_sign(NID_md5, hash, 16, sig, &siglen, key); + + assert(siglen == RSA_USED_SIZE); + + if (ret != 1) + fprintf(stderr, "Unable to sign hash (error=%lu).\n", ERR_get_error()); + + return (ret == 1); + +} + + +/****************************************************************************** +* * +* Paramètres : key = clef RSA à utiliser. * +* hash = empreinte à signer. * +* sig = signature calculée. * +* * +* Description : Vérifie la signature d'une empreinte MD5 avec une clef RSA. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool verify_md5_hash(RSA *key, const unsigned char *hash, unsigned char *sig) +{ + int ret; /* Bilan de l'opération */ + + ret = RSA_verify(NID_md5, hash, 16, sig, RSA_USED_SIZE, key); + + return (ret == 1); + +} diff --git a/src/analysis/db/keymgn.h b/src/analysis/db/keymgn.h index 4aa33db..be6bf5e 100644 --- a/src/analysis/db/keymgn.h +++ b/src/analysis/db/keymgn.h @@ -26,12 +26,25 @@ #include +#include +/* Taille des clefs RSA */ +#define RSA_USED_SIZE (2048 / 8) + /* S'assure que l'utilisateur dispose de clefs RSA. */ bool ensure_user_has_rsa_keys(void); +/* Charge une clef RSA à partir d'un fichier PEM. */ +RSA *load_rsa_key(const char *, bool); + +/* Signe une empreinte MD5 à l'aide d'une clef RSA. */ +bool sign_md5_hash(RSA *, const unsigned char *, unsigned char *); + +/* Vérifie la signature d'une empreinte MD5 avec une clef RSA. */ +bool verify_md5_hash(RSA *, const unsigned char *, unsigned char *); + #endif /* _ANALYSIS_DB_KEYMGN_H */ diff --git a/src/analysis/db/misc/rlestr.h b/src/analysis/db/misc/rlestr.h index 7faafd0..2c9387a 100644 --- a/src/analysis/db/misc/rlestr.h +++ b/src/analysis/db/misc/rlestr.h @@ -52,6 +52,8 @@ void init_rle_string(rle_string *, const char *); #define get_rle_string(rle) (rle)->data +#define get_rle_length(rle) (rle)->length + #define is_rle_string_empty(rle) ((rle)->data == NULL) /* Constitue une représentation de chaîne de caractères. */ diff --git a/src/analysis/db/server.c b/src/analysis/db/server.c index 3107231..360b266 100644 --- a/src/analysis/db/server.c +++ b/src/analysis/db/server.c @@ -35,6 +35,7 @@ #include "cdb.h" +#include "keymgn.h" #include "protocol.h" #include "misc/rlestr.h" #include "../../common/io.h" @@ -43,6 +44,14 @@ +/* Utilisateur enregistré */ +typedef struct _registered_user +{ + rle_string author; /* Désignation d'utilisateur */ + char *key_file; /* Chemin vers sa clef publique*/ + +} registered_user; + /* Informations relatives à un client */ typedef struct _cdb_client { @@ -60,6 +69,9 @@ struct _GDbServer { GObject parent; /* A laisser en premier */ + registered_user *users; /* Liste d'utilisateurs */ + size_t users_count; /* Nombre d'enregistrés */ + int fd; /* Canal de communication */ char *hostname; /* Désignation humaine */ char *desc; /* Désignation du serveur */ @@ -91,12 +103,18 @@ static void g_db_server_init(GDbServer *); /* Procède à la libération totale de la mémoire. */ static void g_db_server_finalize(GDbServer *); +/* Supprime toute trace d'utilisateur inscrit. */ +static void g_db_server_unregister_all_user(GDbServer *); + +/* Inscrit un nouvel utilisateur comme étant enregistré. */ +static bool g_db_server_register_user(GDbServer *, const char *, char *); + +/* Inscrit un nouvel utilisateur comme étant enregistré. */ +static bool g_db_server_is_registered_user(GDbServer *, const rle_string *, unsigned char *); + /* Assure l'accueil des nouveaux clients. */ static void *g_db_server_listener(GDbServer *); -/* Assure le traitement des requêtes de clients. */ -//static void *g_db_server_process(cdb_client **); - /* Indique le type défini pour une description de serveur à l'écoute. */ @@ -161,6 +179,8 @@ static void g_db_server_init(GDbServer *server) static void g_db_server_finalize(GDbServer *server) { + g_db_server_unregister_all_user(server); + free(server->hostname); G_OBJECT_CLASS(g_db_server_parent_class)->finalize(G_OBJECT(server)); @@ -170,27 +190,30 @@ static void g_db_server_finalize(GDbServer *server) /****************************************************************************** * * -* Paramètres : host = hôte à représenter pour le service. * +* Paramètres : author = utilisateur à représenter via le client. * +* kfile = clef menant à sa clef publique. * +* host = hôte à représenter pour le service. * * port = port de connexion pour les clients. * * * * Description : Prépare un serveur de BD pour les clients. * * * -* Retour : Structure mise en plae ou NULL en cas d'échec. * +* Retour : Structure mise en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ -GDbServer *g_db_server_new(const char *host, short port) +GDbServer *g_db_server_new(const char *author, char *kfile, const char *host, short port) { GDbServer *result; /* Adresse à retourner */ struct hostent *hp; /* Informations sur l'hôte */ size_t desclen; /* Taille de désignation */ - const char *ip; /* Adresse IPv4 ou IPv6 */ result = g_object_new(G_TYPE_DB_SERVER, NULL); + /* ... =*/g_db_server_register_user(result, author, kfile); + result->hostname = strdup(host); hp = gethostbyname(host); @@ -232,6 +255,121 @@ GDbServer *g_db_server_new(const char *host, short port) * * * Paramètres : server = serveur pour les accès distants à manipuler. * * * +* Description : Supprime toute trace d'utilisateur inscrit. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_db_server_unregister_all_user(GDbServer *server) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < server->users_count; i++) + { + exit_rle_string(&server->users[i].author); + free(server->users[i].key_file); + } + + if (server->users != NULL) + free(server->users); + + server->users = NULL; + server->users_count = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : server = serveur pour les accès distants à manipuler. * +* author = utilisateur à représenter via le client. * +* kfile = clef menant à sa clef publique. * +* * +* Description : Inscrit un nouvel utilisateur comme étant enregistré. * +* * +* Retour : Bilan de l'inscription. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_db_server_register_user(GDbServer *server, const char *author, char *kfile) +{ + if (strlen(author) == 0) + return false; + + server->users = (registered_user *)realloc(server->users, + ++server->users_count * sizeof(registered_user)); + + init_rle_string(&server->users[server->users_count - 1].author, author); + server->users[server->users_count - 1].key_file = kfile; + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : server = serveur pour les accès distants à manipuler. * +* author = utilisateur à représenter via le client. * +* sig = signature d'utilisateur à valider. * +* * +* Description : Inscrit un nouvel utilisateur comme étant enregistré. * +* * +* Retour : true si l'utilisateur est bien enregistré, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_db_server_is_registered_user(GDbServer *server, const rle_string *author, unsigned char *sig) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + GChecksum *checksum; /* Empreinte MD5 à signer */ + unsigned char md5_digest[16]; /* Empreinte MD5 calculée */ + RSA *key; /* Clef pour la signature */ + + result = false; + + /* Recherche de l'utilisateur */ + + for (i = 0; i < server->users_count; i++) + if (cmp_rle_string(&server->users[i].author, author) == 0) + break; + + if (i == server->users_count) + goto gdsiru_exit; + + /* Validation de la signature présentée */ + + checksum = g_checksum_new(G_CHECKSUM_MD5); + g_checksum_update(checksum, (guchar *)get_rle_string(author), get_rle_length(author)); + g_checksum_get_digest(checksum, (guint8 *)md5_digest, (gsize []) { sizeof(md5_digest) }); + g_checksum_free(checksum); + + key = load_rsa_key(server->users[i].key_file, false); + if (key == NULL) goto gdsiru_exit; + + result = verify_md5_hash(key, md5_digest, sig); + + RSA_free(key); + + gdsiru_exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : server = serveur pour les accès distants à manipuler. * +* * * Description : Assure l'accueil des nouveaux clients. * * * * Retour : NULL. * @@ -254,6 +392,7 @@ static void *g_db_server_listener(GDbServer *server) uint32_t version; /* Version du client lue */ rle_string hash; /* Empreinte du binaire visé */ rle_string user; /* Nom d'utilisateur du client */ + unsigned char sig[RSA_USED_SIZE]; /* Signature effectuée */ GList *iter; /* Boucle de parcours */ fds.fd = server->fd; @@ -293,6 +432,7 @@ static void *g_db_server_listener(GDbServer *server) * - le numéro de version du client. * - l'empreinte du binaire analysé. * - l'identifiant de l'utilisateur effectuant des modifications. + * - la signature de l'empreinte MD5 de l'identifiant. * * Tout ceci est à synchroniser avec la fonction g_db_client_start(). */ @@ -329,6 +469,14 @@ static void *g_db_server_listener(GDbServer *server) goto gdsl_error_sending; } + if (!safe_recv(fd, sig, RSA_USED_SIZE, 0)) + { + log_variadic_message(LMT_ERROR, _("Error while getting the signature from '%s:%hu'..."), + source, ntohs(peer.sin_port)); + error = DBE_BAD_EXCHANGE; + goto gdsl_error_sending; + } + if (be32toh(cmd) != DBC_HELO) { log_variadic_message(LMT_ERROR, _("The client from '%s:%hu' did not introduce itself!"), @@ -361,6 +509,13 @@ static void *g_db_server_listener(GDbServer *server) goto gdsl_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; + } + /** * On met en place le maximum ici, de manière à pouvoir indiquer une erreur * en cas d'échec, et être le plus précis possible dans la courte réponse. diff --git a/src/analysis/db/server.h b/src/analysis/db/server.h index 799ed06..a06e89f 100644 --- a/src/analysis/db/server.h +++ b/src/analysis/db/server.h @@ -48,7 +48,7 @@ typedef struct _GDbServerClass GDbServerClass; GType g_db_server_get_type(void); /* Prépare un serveur de BD pour les clients. */ -GDbServer *g_db_server_new(const char *, short); +GDbServer *g_db_server_new(const char *, char *, const char *, short); /* Démarre le serveur de base de données. */ bool g_db_server_start(GDbServer *); diff --git a/src/main.c b/src/main.c index bd98b32..09fcf42 100644 --- a/src/main.c +++ b/src/main.c @@ -97,6 +97,11 @@ int main(int argc, char **argv) GDbServer *server; /* Enregistrements locaux */ GGenConfig *config; /* Configuration globale */ bool status; /* Bilan d'opérations */ + + + char *author; /* Identification à diffuser */ + char *pub; /* Chemin de la clef publique */ + const char *filename; /* Chemin du dernier projet */ GStudyProject *project; /* Nouveau projet courant */ @@ -176,7 +181,19 @@ int main(int argc, char **argv) status = complete_loading_of_all_gui_components(config); if (!status) goto exit_complete_gui; - server = g_db_server_new("localhost", 1337); + + + /* Utilisateur représenté */ + + if (!g_generic_config_get_value(config, MPK_AUTHOR_NAME, &author)) + /*goto glbcl_exit*/; + + /* Chemin vers la clef privée */ + + pub = get_xdg_config_dir("chrysalide" G_DIR_SEPARATOR_S "id_rsa.pub"); + + + server = g_db_server_new(author, pub, "localhost", 1337); g_db_server_start(server); /* Charge le dernier projet */ -- cgit v0.11.2-87-g4458