/* Chrysalide - Outil d'analyse de fichiers binaires * keymgn.c - mise en place et gestion des clefs cryptographiques * * Copyright (C) 2016 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Chrysalide is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Foobar. If not, see . */ #include "keymgn.h" #include #include #include #include #include #include #include #include #include #include "../../common/xdg.h" /* Met en place de nouvelles clefs RSA. */ static bool generate_user_rsa_keys(const char *, const char *); /****************************************************************************** * * * Paramètres : - * * * * Description : S'assure que l'utilisateur dispose de clefs RSA. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool ensure_user_has_rsa_keys(void) { bool result; /* Bilan à retourner */ char *priv; /* Chemin de la clef privée */ char *pub; /* Chemin de la clef publique */ int priv_check; /* Bilan d'une vérification #1 */ int pub_check; /* Bilan d'une vérification #2 */ result = NULL; priv = get_xdg_config_dir("chrysalide" G_DIR_SEPARATOR_S "id_rsa.priv"); pub = get_xdg_config_dir("chrysalide" G_DIR_SEPARATOR_S "id_rsa.pub"); priv_check = access(priv, R_OK); pub_check = access(pub, R_OK); result = (priv_check == 0 && pub_check == 0); if (!result) { result = generate_user_rsa_keys(priv, pub); if (!result) fprintf(stderr, _("Unable to create new user RSA key pair.\n")); } free(priv); free(pub); return result; } /****************************************************************************** * * * Paramètres : priv = chemin d'accès pour la clef privée. * * pub = chemin d'accès pour la clef publique. * * * * Description : Met en place de nouvelles clefs RSA. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static bool generate_user_rsa_keys(const char *priv, const char *pub) { bool result; /* Bilan à retourner */ 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 */ FILE *stream; /* Flux ouvert en écriture */ result = false; /** * Cf. https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_keygen.html */ ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); if (ctx == NULL) goto euhrk_exit; ret = EVP_PKEY_keygen_init(ctx); if (ret != 1) goto euhrk_exit; ret = EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, RSA_USED_SIZE * 8); if (ret != 1) goto euhrk_exit; pair = NULL; ret = EVP_PKEY_keygen(ctx, &pair); if (ret != 1) goto euhrk_exit; /* Clef privée */ stream = fopen(priv, "wt"); if (stream == NULL) goto euhrk_bad_write; ret = PEM_write_PrivateKey(stream, pair, NULL, NULL, 0, NULL, NULL); if (ret != 1) goto euhrk_bad_write; fclose(stream); /* Clef publique */ stream = fopen(pub, "wt"); if (stream == NULL) goto euhrk_bad_write; ret = PEM_write_PUBKEY(stream, pair); if (ret != 1) goto euhrk_bad_write; result = true; euhrk_bad_write: fclose(stream); EVP_PKEY_free(pair); euhrk_exit: EVP_PKEY_CTX_free(ctx); 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); }