summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/analysis/db/Makefile.am1
-rw-r--r--src/analysis/db/certs.c678
-rw-r--r--src/analysis/db/certs.h59
3 files changed, 738 insertions, 0 deletions
diff --git a/src/analysis/db/Makefile.am b/src/analysis/db/Makefile.am
index 7e9f177..9dee122 100755
--- a/src/analysis/db/Makefile.am
+++ b/src/analysis/db/Makefile.am
@@ -4,6 +4,7 @@ noinst_LTLIBRARIES = libanalysisdb.la libanalysiskeys.la
libanalysisdb_la_SOURCES = \
cdb.h cdb.c \
+ certs.h certs.c \
client.h client.c \
collection-int.h \
collection.h collection.c \
diff --git a/src/analysis/db/certs.c b/src/analysis/db/certs.c
new file mode 100644
index 0000000..ac2ff39
--- /dev/null
+++ b/src/analysis/db/certs.c
@@ -0,0 +1,678 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * certs.h - prototypes pour la gestion des certificats des échanges
+ *
+ * Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "certs.h"
+
+
+#include <malloc.h>
+#include <stdio.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+
+#include <i18n.h>
+
+
+#include "../../gui/panels/log.h"
+
+
+
+/* Ajoute une extension à un certificat. */
+static bool add_extension_to_cert(X509 *, X509 *, /*const */char *, /*const */char *);
+
+/* Ajoute une extension à une requête de signature. */
+static bool add_extension_to_req(STACK_OF(X509_EXTENSION) *, int, /*const */char *);
+
+
+
+/******************************************************************************
+* *
+* Paramètres : entries = éléments d'identité à supprimer de la mémoire. *
+* *
+* Description : Libère la mémoire occupée par une définition d'identité. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void free_x509_entries(x509_entries *entries)
+{
+ if (entries->country != NULL)
+ free(entries->country);
+
+ if (entries->state != NULL)
+ free(entries->state);
+
+ if (entries->locality != NULL)
+ free(entries->locality);
+
+ if (entries->organisation != NULL)
+ free(entries->organisation);
+
+ if (entries->organisational_unit != NULL)
+ free(entries->organisational_unit);
+
+ if (entries->common_name != NULL)
+ free(entries->common_name);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : issuer = certificat de l'autorité émettrice. *
+* subj = certificat à la reception. *
+* name = nom de l'extension. *
+* value = valeur portée par l'extension. *
+* *
+* Description : Ajoute une extension à un certificat. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool add_extension_to_cert(X509 *issuer, X509 *subj, /*const */char *name, /*const */char *value)
+{
+ bool result; /* Bilan à retourner */
+ X509V3_CTX ctx; /* Contexte à conserver */
+ X509_EXTENSION *ext; /* Définition d'une extension */
+ int ret; /* Bilan d'un ajout */
+
+ result = false;
+
+ X509V3_set_ctx_nodb(&ctx);
+ X509V3_set_ctx(&ctx, issuer, subj, NULL, NULL, 0);
+
+ ext = X509V3_EXT_conf(NULL, &ctx, name, value);
+
+ if (ext != NULL)
+ {
+ ret = X509_add_ext(subj, ext, -1);
+
+ result = (ret != 0);
+
+ X509_EXTENSION_free(ext);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dir = répertoire d'enregistrement de la création. *
+* label = étiquette à coller au certificat produit. *
+* valid = durée de validité en secondes. *
+* entries = éléments de l'identité à constituer. *
+* *
+* Description : Crée un certificat de signature racine. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool make_ca(const char *dir, const char *label, unsigned long valid, const x509_entries *entries)
+{
+ RSA *rsa; /* Clef RSA pour le certificat */
+ EVP_PKEY *pk; /* Enveloppe pour clef publique*/
+ int ret; /* Bilan d'un appel */
+ X509 *x509; /* Certificat X509 à définir */
+ X509_NAME *name; /* Désignation du certificat */
+ char *filename; /* Chemin d'accès à un fichier */
+ FILE *stream; /* Flux ouvert en écriture */
+
+ rsa = RSA_generate_key(4096, 17, NULL, NULL);
+ if (rsa == NULL)
+ {
+ log_variadic_message(LMT_ERROR, _("Unable to generate RSA key (error=%lu)"), ERR_get_error());
+ goto rsa_failed;
+ }
+
+ pk = EVP_PKEY_new();
+ if (pk == NULL) goto pk_failed;
+
+ ret = EVP_PKEY_assign_RSA(pk, rsa);
+ if (ret != 1) goto asign_failed;
+
+ x509 = X509_new();
+ if (x509 == NULL) goto x509_failed;
+
+ ret = X509_set_pubkey(x509, pk);
+ if (ret != 1) goto ca_failed;
+
+ ret = X509_set_version(x509, 2);
+ if (ret != 1) goto ca_failed;
+
+ ret = ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
+ if (ret != 1) goto ca_failed;
+
+ X509_gmtime_adj(X509_get_notBefore(x509), 0);
+ X509_gmtime_adj(X509_get_notAfter(x509), valid);
+
+ /* Etablissement d'une identité */
+
+ name = X509_get_subject_name(x509);
+
+#define SET_NAME_ENTRY(key, value) \
+ do \
+ { \
+ if (entries->value != NULL) \
+ { \
+ ret = X509_NAME_add_entry_by_txt(name, key, MBSTRING_UTF8, \
+ (unsigned char *)entries->value, -1, -1, 0); \
+ if (ret != 1) goto ca_failed; \
+ } \
+ } \
+ while (0)
+
+ SET_NAME_ENTRY("C", country);
+
+ SET_NAME_ENTRY("ST", state);
+
+ SET_NAME_ENTRY("L", locality);
+
+ SET_NAME_ENTRY("O", organisation);
+
+ SET_NAME_ENTRY("OU", organisational_unit);
+
+ SET_NAME_ENTRY("CN", common_name);
+
+#undef SET_NAME_ENTRY
+
+ ret = X509_set_issuer_name(x509, name);
+ if (ret != 1) goto ca_failed;
+
+ /* Extensions */
+
+ if (!add_extension_to_cert(x509, x509, "basicConstraints", "CA:TRUE"))
+ goto ca_failed;
+
+ if (!add_extension_to_cert(x509, x509, "keyUsage", "critical,keyCertSign,cRLSign"))
+ goto ca_failed;
+
+ if (!add_extension_to_cert(x509, x509, "subjectKeyIdentifier", "hash"))
+ goto ca_failed;
+
+ if (!add_extension_to_cert(x509, x509, "nsComment", "\"OpenSSL Generated Certificate\""))
+ goto ca_failed;
+
+ /* Signature */
+
+ ret = X509_sign(x509, pk, EVP_sha256());
+ if (ret == 0) goto ca_failed;
+
+ /* Ecriture dans des fichiers */
+
+ asprintf(&filename, "%s%c%s-key.pem", dir, G_DIR_SEPARATOR, label);
+
+ stream = fopen(filename, "wb");
+ if (stream == NULL) goto ca_failed;
+
+ ret = PEM_write_PrivateKey(stream, pk, NULL, NULL, 0, NULL, NULL);
+
+ if (ret != 1)
+ log_variadic_message(LMT_ERROR, _("Unable to write the CA key into '%s'"), filename);
+
+ fclose(stream);
+
+ free(filename);
+
+ if (ret != 1)
+ goto ca_failed;
+
+ asprintf(&filename, "%s%c%s-cert.pem", dir, G_DIR_SEPARATOR, label);
+
+ stream = fopen(filename, "wb");
+ if (stream == NULL) goto ca_failed;
+
+ ret = PEM_write_X509(stream, x509);
+
+ if (ret != 1)
+ log_variadic_message(LMT_ERROR, _("Unable to write the CA certificate into '%s'"), filename);
+
+ fclose(stream);
+
+ free(filename);
+
+ if (ret != 1)
+ goto ca_failed;
+
+ /* Libérations finales */
+
+ X509_free(x509);
+ EVP_PKEY_free(pk);
+
+ return true;
+
+ ca_failed:
+
+ X509_free(x509);
+
+ x509_failed:
+
+ EVP_PKEY_free(pk);
+
+ return false;
+
+ asign_failed:
+
+ EVP_PKEY_free(pk);
+
+ pk_failed:
+
+ RSA_free(rsa);
+
+ rsa_failed:
+
+ return false;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : sk = pile d'extension à agrandir. *
+* nid = identifiant de l'extension à apporter. *
+* value = valeur portée par l'extension. *
+* *
+* Description : Ajoute une extension à une requête de signature. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool add_extension_to_req(STACK_OF(X509_EXTENSION) *sk, int nid, /*const */char *value)
+{
+ bool result; /* Bilan à retourner */
+ X509_EXTENSION *ext; /* Définition d'une extension */
+ int ret; /* Bilan d'un ajout */
+
+ result = false;
+
+ ext = X509V3_EXT_conf_nid(NULL, NULL, nid, value);
+
+ if (ext != NULL)
+ {
+ ret = sk_X509_EXTENSION_push(sk, ext);
+ result = (ret == 1);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dir = répertoire d'enregistrement de la création. *
+* label = étiquette à coller au certificat produit. *
+* entries = éléments de l'identité à constituer. *
+* *
+* Description : Crée un certificat pour application. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool make_request(const char *dir, const char *label, const x509_entries *entries)
+{
+ RSA *rsa; /* Clef RSA pour le certificat */
+ EVP_PKEY *pk; /* Enveloppe pour clef publique*/
+ int ret; /* Bilan d'un appel */
+ X509_REQ *x509; /* Certificat X509 à définir */
+ X509_NAME *name; /* Désignation du certificat */
+ STACK_OF(X509_EXTENSION) *exts; /* Extensions du certificat */
+ char *filename; /* Chemin d'accès à un fichier */
+ FILE *stream; /* Flux ouvert en écriture */
+
+ rsa = RSA_generate_key(2048, 17, NULL, NULL);
+ if (rsa == NULL)
+ {
+ log_variadic_message(LMT_ERROR, _("Unable to generate RSA key (error=%lu)"), ERR_get_error());
+ goto rsa_failed;
+ }
+
+ pk = EVP_PKEY_new();
+ if (pk == NULL) goto pk_failed;
+
+ ret = EVP_PKEY_assign_RSA(pk, rsa);
+ if (ret != 1) goto asign_failed;
+
+ x509 = X509_REQ_new();
+ if (x509 == NULL) goto x509_failed;
+
+ ret = X509_REQ_set_pubkey(x509, pk);
+ if (ret != 1) goto asign_failed;
+
+ /* Etablissement d'une identité */
+
+ name = X509_REQ_get_subject_name(x509);
+
+#define SET_NAME_ENTRY(key, value) \
+ do \
+ { \
+ if (entries->value != NULL) \
+ { \
+ ret = X509_NAME_add_entry_by_txt(name, key, MBSTRING_UTF8, \
+ (unsigned char *)entries->value, -1, -1, 0); \
+ if (ret != 1) goto req_failed; \
+ } \
+ } \
+ while (0)
+
+ SET_NAME_ENTRY("C", country);
+
+ SET_NAME_ENTRY("ST", state);
+
+ SET_NAME_ENTRY("L", locality);
+
+ SET_NAME_ENTRY("O", organisation);
+
+ SET_NAME_ENTRY("OU", organisational_unit);
+
+ SET_NAME_ENTRY("CN", common_name);
+
+#undef SET_NAME_ENTRY
+
+ /* Extensions */
+
+ exts = sk_X509_EXTENSION_new_null();
+ if (exts == NULL) goto req_failed;
+
+ if (!add_extension_to_req(exts, NID_key_usage, "critical,digitalSignature,keyEncipherment"))
+ goto exts_failed;
+
+ ret = X509_REQ_add_extensions(x509, exts);
+ if (ret != 1) goto exts_failed;
+
+ sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
+
+ /* Signature */
+
+ ret = X509_REQ_sign(x509, pk, EVP_sha1());
+ if (ret == 0) goto req_failed_2;
+
+ ret = X509_REQ_verify(x509, pk);
+ if (ret != 1) goto req_failed_2;
+
+ /* Ecriture dans des fichiers */
+
+ asprintf(&filename, "%s%c%s-key.pem", dir, G_DIR_SEPARATOR, label);
+
+ stream = fopen(filename, "wb");
+ if (stream == NULL) goto req_failed_2;
+
+ ret = PEM_write_PrivateKey(stream, pk, NULL, NULL, 0, NULL, NULL);
+
+ if (ret != 1)
+ log_variadic_message(LMT_ERROR, _("Unable to write the CA key into '%s'"), filename);
+
+ fclose(stream);
+
+ free(filename);
+
+ if (ret != 1)
+ goto req_failed_2;
+
+ asprintf(&filename, "%s%c%s-csr.pem", dir, G_DIR_SEPARATOR, label);
+
+ stream = fopen(filename, "wb");
+ if (stream == NULL) goto req_failed_2;
+
+ ret = PEM_write_X509_REQ(stream, x509);
+
+ if (ret != 1)
+ log_variadic_message(LMT_ERROR, _("Unable to write the CA certificate into '%s'"), filename);
+
+ fclose(stream);
+
+ free(filename);
+
+ if (ret != 1)
+ goto req_failed_2;
+
+ return true;
+
+ req_failed_2:
+
+ exts_failed:
+
+ sk_X509_EXTENSION_free(exts);
+
+ req_failed:
+
+ X509_REQ_free(x509);
+
+ x509_failed:
+
+ EVP_PKEY_free(pk);
+
+ return false;
+
+ asign_failed:
+
+ EVP_PKEY_free(pk);
+
+ pk_failed:
+
+ RSA_free(rsa);
+
+ rsa_failed:
+
+ return false;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : csr = fichier contenant le certificat à signer. *
+* cacert = fichier contenant le certificat de l'autorité. *
+* cakey = fichier contenant la clef privée du CA. *
+* cert = fichier contenant le certificat signé. *
+* valid = durée de validité en secondes. *
+* *
+* Description : Signe un certificat pour application. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool sign_cert(const char *csr, const char *cacert, const char *cakey, const char *cert, unsigned long valid)
+{
+ FILE *stream; /* Flux ouvert en écriture */
+ X509_REQ *req; /* Certificat X509 à signer */
+ EVP_PKEY *pk; /* Enveloppe pour clef publique*/
+ X509 *ca_cert; /* Certificat de l'autorité */
+ EVP_PKEY *ca_pk; /* Enveloppe pour clef privée */
+ X509 *x509; /* Certificat X509 à définir */
+ int ret; /* Bilan d'un appel */
+ X509_NAME *name; /* Désignation du certificat */
+
+ /* Chargement de la requête */
+
+ stream = fopen(csr, "rb");
+ if (stream == NULL) goto csr_read_failed;
+
+ req = PEM_read_X509_REQ(stream, NULL, NULL, NULL);
+
+ fclose(stream);
+
+ if (req == NULL)
+ {
+ log_variadic_message(LMT_ERROR, _("Unable to read the certificate signing request from '%s'"), cert);
+ goto csr_read_failed;
+ }
+
+ pk = X509_REQ_get_pubkey(req);
+ if (pk == NULL) goto csr_no_pk;
+
+ ret = X509_REQ_verify(req, pk);
+ if (ret != 1) goto csr_bad_pk;
+
+ /* Chargement des éléments de l'autorité */
+
+ stream = fopen(cacert, "rb");
+ if (stream == NULL) goto cacert_read_failed;
+
+ ca_cert = PEM_read_X509(stream, NULL, NULL, NULL);
+
+ fclose(stream);
+
+ if (ca_cert == NULL)
+ {
+ log_variadic_message(LMT_ERROR, _("Unable to read the certificate from '%s'"), cert);
+ goto cacert_read_failed;
+ }
+
+ stream = fopen(cakey, "rb");
+ if (stream == NULL) goto cakey_read_failed;
+
+ ca_pk = PEM_read_PrivateKey(stream, NULL, NULL, NULL);
+
+ fclose(stream);
+
+ if (ca_pk == NULL)
+ {
+ log_variadic_message(LMT_ERROR, _("Unable to read the CA private key from %s"), cakey);
+ goto cakey_read_failed;
+ }
+
+ /* Création d'un nouveau certificat */
+
+ x509 = X509_new();
+ if (x509 == NULL) goto x509_failed;
+
+ ret = X509_set_version(x509, 2);
+ if (ret != 1) goto signing_failed;
+
+ ret = ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
+ if (ret != 1) goto signing_failed;
+
+ X509_gmtime_adj(X509_get_notBefore(x509), 0);
+ X509_gmtime_adj(X509_get_notAfter(x509), valid);
+
+ /* Transfert des informations existantes */
+
+ ret = X509_set_pubkey(x509, pk);
+ if (ret != 1) goto signing_failed;
+
+ name = X509_REQ_get_subject_name(req);
+
+ ret = X509_set_subject_name(x509, name);
+ if (ret != 1) goto signing_failed;
+
+ name = X509_get_subject_name(ca_cert);
+
+ ret = X509_set_issuer_name(x509, name);
+ if (ret != 1) goto signing_failed;
+
+ /* Extensions */
+
+ if (!add_extension_to_cert(ca_cert, x509, "basicConstraints", "CA:FALSE"))
+ goto signing_failed;
+
+ if (!add_extension_to_cert(ca_cert, x509, "keyUsage", "nonRepudiation,digitalSignature,keyEncipherment"))
+ goto signing_failed;
+
+ if (!add_extension_to_cert(ca_cert, x509, "subjectKeyIdentifier", "hash"))
+ goto signing_failed;
+
+ if (!add_extension_to_cert(ca_cert, x509, "authorityKeyIdentifier", "keyid,issuer:always"))
+ goto signing_failed;
+
+ if (!add_extension_to_cert(ca_cert, x509, "nsComment", "\"OpenSSL Generated Certificate\""))
+ goto signing_failed;
+
+ /* Signature */
+
+ ret = X509_sign(x509, ca_pk, EVP_sha256());
+ if (ret == 0) goto signing_failed;
+
+ /* Ecriture dans un fichier */
+
+ stream = fopen(cert, "wb");
+ if (stream == NULL) goto signing_failed;
+
+ ret = PEM_write_X509(stream, x509);
+
+ if (ret != 1)
+ log_variadic_message(LMT_ERROR, _("Unable to write the signed certificate into '%s'"), cert);
+
+ fclose(stream);
+
+ /* Libérations finales */
+
+ X509_free(x509);
+ EVP_PKEY_free(ca_pk);
+ X509_free(ca_cert);
+ EVP_PKEY_free(pk);
+ X509_REQ_free(req);
+
+ return true;
+
+ signing_failed:
+
+ X509_free(x509);
+
+ x509_failed:
+
+ EVP_PKEY_free(ca_pk);
+
+ cakey_read_failed:
+
+ X509_free(ca_cert);
+
+ cacert_read_failed:
+
+ csr_bad_pk:
+
+ EVP_PKEY_free(pk);
+
+ csr_no_pk:
+
+ X509_REQ_free(req);
+
+ csr_read_failed:
+
+ return false;
+
+}
diff --git a/src/analysis/db/certs.h b/src/analysis/db/certs.h
new file mode 100644
index 0000000..0f7c51d
--- /dev/null
+++ b/src/analysis/db/certs.h
@@ -0,0 +1,59 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * certs.h - prototypes pour la gestion des certificats des échanges
+ *
+ * Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_DB_CERTS_H
+#define _ANALYSIS_DB_CERTS_H
+
+
+#include <stdbool.h>
+
+
+
+/* Informations pour les certificats X509 */
+typedef struct _x509_entries
+{
+ char *country; /* Pays */
+ char *state; /* Etat */
+ char *locality; /* Localité */
+ char *organisation; /* Organisation */
+ char *organisational_unit; /* Département */
+ char *common_name; /* Désignation commune */
+
+} x509_entries;
+
+
+/* Libère la mémoire occupée par une définition d'identité. */
+void free_x509_entries(x509_entries *);
+
+/* Crée un certificat de signature racine. */
+bool make_ca(const char *, const char *, unsigned long, const x509_entries *);
+
+/* Crée un certificat pour application. */
+bool make_request(const char *, const char *, const x509_entries *);
+
+/* Signe un certificat pour application. */
+bool sign_cert(const char *, const char *, const char *, const char *, unsigned long);
+
+
+
+#endif /* _ANALYSIS_DB_CERTS_H */