diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2016-04-09 22:59:38 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2016-04-09 22:59:38 (GMT) |
commit | 5ad85cf30b2355ca727904d1a0d25240283813b3 (patch) | |
tree | 1e1fdce3b7be4bf878161b4e9001686dd0d89ba3 /src/analysis/db | |
parent | 865be356c53afc3bdeae21c640bf0c3d5433fc4b (diff) |
Signed and verified the MD5 hash of a given user name.
Diffstat (limited to 'src/analysis/db')
-rw-r--r-- | src/analysis/db/client.c | 56 | ||||
-rw-r--r-- | src/analysis/db/client.h | 4 | ||||
-rw-r--r-- | src/analysis/db/keymgn.c | 121 | ||||
-rw-r--r-- | src/analysis/db/keymgn.h | 13 | ||||
-rw-r--r-- | src/analysis/db/misc/rlestr.h | 2 | ||||
-rw-r--r-- | src/analysis/db/server.c | 169 | ||||
-rw-r--r-- | src/analysis/db/server.h | 2 |
7 files changed, 340 insertions, 27 deletions
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 <i18n.h> +#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 <assert.h> #include <glib.h> #include <malloc.h> #include <stdio.h> #include <unistd.h> +#include <openssl/err.h> #include <openssl/evp.h> -#include <openssl/rsa.h> +#include <openssl/pem.h> #include <i18n.h> @@ -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 <stdbool.h> +#include <openssl/rsa.h> +/* 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 *); |