From 912378bc36eb35465d89555bc25734e35b1f0843 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Wed, 21 Jul 2021 00:49:52 +0200
Subject: Extract identities from signed certificates.

---
 src/analysis/db/certs.c | 198 ++++++++++++++++++++++++++++++++++++++++++------
 src/analysis/db/certs.h |   6 ++
 2 files changed, 181 insertions(+), 23 deletions(-)

diff --git a/src/analysis/db/certs.c b/src/analysis/db/certs.c
index 148abf2..22ff397 100644
--- a/src/analysis/db/certs.c
+++ b/src/analysis/db/certs.c
@@ -39,6 +39,7 @@
 #include <i18n.h>
 
 
+#include "../../common/extstr.h"
 #include "../../core/logs.h"
 
 
@@ -52,6 +53,9 @@ static bool add_extension_to_req(STACK_OF(X509_EXTENSION) *, int, /*const */char
 /* Crée une paire de clefs RSA. */
 static RSA *generate_rsa_key(unsigned int, unsigned long);
 
+/* Recharge l'identité inscrite dans un élément X509. */
+static bool load_identity_from_x509(/*const */X509_NAME *, x509_entries *);
+
 
 
 /******************************************************************************
@@ -97,6 +101,70 @@ bool are_x509_entries_empty(const x509_entries *entries)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : entries = éléments d'identité à convertir.                   *
+*                                                                             *
+*  Description : Traduit en chaîne de caractères une définition d'identité.   *
+*                                                                             *
+*  Retour      : Chaîne de caractères ou NULL.                                *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+char *translate_x509_entries(const x509_entries *entries)
+{
+    char *result;                           /* Description à retourner     */
+
+    result = NULL;
+
+    if (entries->country != NULL)
+    {
+        result = stradd(result, "C=");
+        result = stradd(result, entries->country);
+    }
+
+    if (entries->state != NULL)
+    {
+        if (result != NULL) result = stradd(result, "/");
+        result = stradd(result, "ST=");
+        result = stradd(result, entries->state);
+    }
+
+    if (entries->locality != NULL)
+    {
+        if (result != NULL) result = stradd(result, "/");
+        result = stradd(result, "L=");
+        result = stradd(result, entries->locality);
+    }
+
+    if (entries->organisation != NULL)
+    {
+        if (result != NULL) result = stradd(result, "/");
+        result = stradd(result, "O=");
+        result = stradd(result, entries->organisation);
+    }
+
+    if (entries->organisational_unit != NULL)
+    {
+        if (result != NULL) result = stradd(result, "/");
+        result = stradd(result, "OU=");
+        result = stradd(result, entries->organisational_unit);
+    }
+
+    if (entries->common_name != NULL)
+    {
+        if (result != NULL) result = stradd(result, "/");
+        result = stradd(result, "CN=");
+        result = stradd(result, entries->common_name);
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  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é.     *
@@ -624,6 +692,64 @@ bool build_keys_and_request(const char *dir, const char *label, const x509_entri
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : subject = sujet d'un élément X509.                           *
+*                entries = éléments de l'identité constituée. [OUT]           *
+*                                                                             *
+*  Description : Recharge l'identité inscrite dans un élément X509.           *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool load_identity_from_x509(/*const */X509_NAME *subject, x509_entries *entries)
+{
+    bool result;                            /* Bilan à retourner           */
+    int length;                             /* Taille du champ visé        */
+
+    result = false;
+
+#define GET_NAME_ENTRY(key, value)                                                          \
+    do                                                                                      \
+    {                                                                                       \
+        length = X509_NAME_get_text_by_NID(subject, key, NULL, -1);                         \
+        if (length != -1)                                                                   \
+        {                                                                                   \
+            entries->value = malloc((length + 1) * sizeof(char));                           \
+            length = X509_NAME_get_text_by_NID(subject, key, entries->value, length + 1);   \
+            assert(length != -1);                                                           \
+            if (length == -1)                                                               \
+                goto copy_failed;                                                           \
+        }                                                                                   \
+    }                                                                                       \
+    while (0)
+
+    GET_NAME_ENTRY(NID_countryName, country);
+
+    GET_NAME_ENTRY(NID_stateOrProvinceName, state);
+
+    GET_NAME_ENTRY(NID_localityName, locality);
+
+    GET_NAME_ENTRY(NID_organizationName, organisation);
+
+    GET_NAME_ENTRY(NID_organizationalUnitName, organisational_unit);
+
+    GET_NAME_ENTRY(NID_commonName, common_name);
+
+#undef GET_NAME_ENTRY
+
+    result = true;
+
+ copy_failed:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : csr     = fichier contenant le certificat à signer.          *
 *                entries = éléments de l'identité constituée. [OUT]           *
 *                                                                             *
@@ -641,7 +767,6 @@ bool load_identity_from_request(const char *csr, x509_entries *entries)
     FILE *stream;                           /* Flux ouvert en lecture      */
     X509_REQ *req;                          /* Certificat X509 à signer    */
     X509_NAME *subject;                     /* Sujet du certificat         */
-    int length;                             /* Taille du champ visé        */
 
     result = false;
 
@@ -666,38 +791,65 @@ bool load_identity_from_request(const char *csr, x509_entries *entries)
 
     subject = X509_REQ_get_subject_name(req);
 
-#define GET_NAME_ENTRY(key, value)                                                          \
-    do                                                                                      \
-    {                                                                                       \
-        length = X509_NAME_get_text_by_NID(subject, key, NULL, -1);                         \
-        if (length != -1)                                                                   \
-        {                                                                                   \
-            entries->value = malloc((length + 1) * sizeof(char));                           \
-            length = X509_NAME_get_text_by_NID(subject, key, entries->value, length + 1);   \
-            assert(length != -1);                                                           \
-        }                                                                                   \
-    }                                                                                       \
-    while (0)
+    result = load_identity_from_x509(subject, entries);
 
-    GET_NAME_ENTRY(NID_countryName, country);
+    X509_REQ_free(req);
 
-    GET_NAME_ENTRY(NID_stateOrProvinceName, state);
+ csr_read_failed:
 
-    GET_NAME_ENTRY(NID_localityName, locality);
+    return result;
 
-    GET_NAME_ENTRY(NID_organizationName, organisation);
+}
 
-    GET_NAME_ENTRY(NID_organizationalUnitName, organisational_unit);
 
-    GET_NAME_ENTRY(NID_commonName, common_name);
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : crt     = fichier contenant un certificat signé.             *
+*                entries = éléments de l'identité constituée. [OUT]           *
+*                                                                             *
+*  Description : Recharge l'identité inscrite dans un certificat signé.       *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
-#undef GET_NAME_ENTRY
+bool load_identity_from_cert(const char *crt, x509_entries *entries)
+{
+    bool result;                            /* Bilan à retourner           */
+    FILE *stream;                           /* Flux ouvert en lecture      */
+    X509 *x;                                /* Certificat X509 signé       */
+    X509_NAME *subject;                     /* Sujet du certificat         */
 
-    X509_REQ_free(req);
+    result = false;
 
-    result = true;
+    memset(entries, 0, sizeof(*entries));
 
- csr_read_failed:
+    /* Chargement de la requête */
+
+    stream = fopen(crt, "rb");
+    if (stream == NULL) goto crt_read_failed;
+
+    x = PEM_read_X509(stream, NULL, NULL, NULL);
+
+    fclose(stream);
+
+    if (x == NULL)
+    {
+        log_variadic_message(LMT_ERROR, _("Unable to read the signed certificate from '%s'"), crt);
+        goto crt_read_failed;
+    }
+
+    /* Recherche des éléments */
+
+    subject = X509_get_subject_name(x);
+
+    result = load_identity_from_x509(subject, entries);
+
+    X509_free(x);
+
+ crt_read_failed:
 
     return result;
 
diff --git a/src/analysis/db/certs.h b/src/analysis/db/certs.h
index 51a2e34..359b3d3 100644
--- a/src/analysis/db/certs.h
+++ b/src/analysis/db/certs.h
@@ -45,6 +45,9 @@ typedef struct _x509_entries
 /* Indique si une définition existe dans l'identité. */
 bool are_x509_entries_empty(const x509_entries *);
 
+/* Traduit en chaîne de caractères une définition d'identité. */
+char *translate_x509_entries(const x509_entries *);
+
 /* Libère la mémoire occupée par une définition d'identité. */
 void free_x509_entries(x509_entries *);
 
@@ -57,6 +60,9 @@ bool build_keys_and_request(const char *, const char *, const x509_entries *);
 /* Recharge l'identité inscrite dans une requête de signature. */
 bool load_identity_from_request(const char *, x509_entries *);
 
+/* Recharge l'identité inscrite dans un certificat signé. */
+bool load_identity_from_cert(const char *, x509_entries *);
+
 /* Signe un certificat pour application. */
 bool sign_cert(const char *, const char *, const char *, const char *, unsigned long);
 
-- 
cgit v0.11.2-87-g4458