Créer par programme un certificat X509 en utilisant OpenSSL

J'ai une application C / C++ et j'ai besoin de créer un certificat PEM x509 contenant à la fois une clé publique et privée. Le certificat auto-signé ou non signé, n'a pas d'importance.

Je veux le faire dans une application, pas à partir de la ligne de commande.

Quelles fonctions OpenSSL vont faire cela pour moi? Tout exemple de code est un bonus!

60
demandé sur jww 2008-11-02 05:16:49

4 réponses

Vous devrez d'abord vous familiariser avec la terminologie et les mécanismes.

Un certificat X. 509 , par définition, n'inclut pas de clé privée. Au lieu de cela, il s'agit d'une version signée par L'autorité de certification de la clé publique (avec tous les attributs que l'autorité de certification met dans la signature). Le format PEM ne prend en charge que le stockage séparé de la clé et du certificat - bien que vous puissiez ensuite concaténer les deux.

Dans tous les cas, vous devrez invoquer plus de 20 fonctions différentes du API OpenSSL pour créer une clé et un certificat auto-signé. Un exemple est dans la source OpenSSL elle-même, dans demos / x509 / mkcert.c

Pour une réponse plus détaillée, veuillez consulter l'explication de Nathan Osman ci-dessous.

40
répondu Martin v. Löwis 2017-05-23 12:34:44

Je me rends compte que c'est une réponse très tardive (et longue). Mais compte tenu de la façon dont cette question semble se classer dans les résultats des moteurs de recherche, j'ai pensé qu'il pourrait être utile d'écrire une réponse décente pour.

Beaucoup de ce que vous allez lire ci-dessous est emprunté à cette démo et les documents OpenSSL. Le code ci-dessous s'applique à la fois à C et c++.


Avant de pouvoir créer un certificat, nous devons créer une clé privée. OpenSSL fournit la structure EVP_PKEY pour stocker un algorithme-clé privée indépendante en mémoire. Cette structure est déclarée dans openssl/evp.h mais est incluse par openssl/x509.h (dont nous aurons besoin plus tard) donc vous n'avez pas vraiment besoin d'inclure explicitement l'en-tête.

, afin d'allouer un EVP_PKEY de la structure, nous utilisons EVP_PKEY_new:

EVP_PKEY * pkey;
pkey = EVP_PKEY_new();

Il y a aussi une fonction correspondante pour libérer la structure - EVP_PKEY_free - qui accepte un seul argument: la structure EVP_PKEY initialisée ci-dessus.

Maintenant, nous devons générer une clé. Pour notre exemple, nous allons générer une clé RSA. Ceci est fait avec le RSA_generate_key fonction qui est déclarée dans openssl/rsa.h. Cette fonction renvoie un pointeur vers une structure RSA.

Une simple invocation de la fonction pourrait ressembler à ceci:

RSA * rsa;
rsa = RSA_generate_key(
    2048,   /* number of bits for the key - 2048 is a sensible value */
    RSA_F4, /* exponent - RSA_F4 is defined as 0x10001L */
    NULL,   /* callback - can be NULL if we aren't displaying progress */
    NULL    /* callback argument - not needed in this case */
);

Si la valeur de retour de RSA_generate_key est NULL, puis quelque chose s'est mal passé. Si ce n'est pas le cas, nous avons maintenant une clé RSA, et nous pouvons l'assigner à notre structure EVP_PKEY de plus tôt:

EVP_PKEY_assign_RSA(pkey, rsa);

La structure RSA sera automatiquement libérée lorsque la structure EVP_PKEY est libérée.


Maintenant pour le certificat lui-même.

OpenSSL utilise la structure X509 pour représenter un certificat x509 en mémoire. La définition de cette structure est dans openssl/x509.h. La première fonction dont nous aurons besoin est X509_new. Son utilisation est relativement simple:

X509 * x509;
x509 = X509_new();

Comme ce fut le cas avec EVP_PKEY, Il existe une fonction correspondante pour libérer la structure - X509_free.

Maintenant, nous devons définir quelques propriétés de le certificat utilisant certaines fonctions X509_*:

ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);

Cela définit le numéro de série de notre certificat à '1'. Certains serveurs HTTP open-source refusent d'accepter un certificat avec un numéro de série '0', qui est la valeur par défaut. L'étape suivante consiste à spécifier la durée pendant laquelle le certificat est réellement valide. Nous le faisons avec les deux appels de fonction suivants:

X509_gmtime_adj(X509_get_notBefore(x509), 0);
X509_gmtime_adj(X509_get_notAfter(x509), 31536000L);

La première ligne définit la propriété notBefore du certificat sur l'heure actuelle. (La fonction X509_gmtime_adj ajoute le nombre spécifié de secondes à l'heure actuelle - dans ce cas, aucun.) La deuxième ligne définit la propriété notAfter du certificat sur 365 jours à partir de maintenant (60 secondes * 60 minutes * 24 heures * 365 jours).

Maintenant, nous devons définir la clé publique pour notre certificat en utilisant la clé que nous avons générée précédemment:

X509_set_pubkey(x509, pkey);

Comme il s'agit d'un certificat auto-signé, nous définissons le nom de l'émetteur sur le nom du sujet. La première étape de ce processus est d'obtenir le sujet nom:

X509_NAME * name;
name = X509_get_subject_name(x509);

Si vous avez déjà créé un certificat auto-signé sur la ligne de commande, vous vous souvenez probablement qu'on vous a demandé un code de pays. Voici où nous le fournissons avec l'organisation ('O') et le nom commun ('CN'):

X509_NAME_add_entry_by_txt(name, "C",  MBSTRING_ASC,
                           (unsigned char *)"CA", -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "O",  MBSTRING_ASC,
                           (unsigned char *)"MyCompany Inc.", -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
                           (unsigned char *)"localhost", -1, -1, 0);

(j'utilise la valeur 'CA' ici parce que je suis canadien et c'est notre code de pays. Notez également que le paramètre # 4 doit être explicitement converti en unsigned char *.)

Maintenant, nous pouvons réellement définir le nom de l'émetteur:

X509_set_issuer_name(x509, name);

Et enfin, nous sommes prêts à effectuer le processus de signature. Nous appelons X509_sign avec la clé que nous avons générée plus tôt. Le code pour cela est douloureusement simple:

X509_sign(x509, pkey, EVP_sha1());

Notez que nous utilisons l'algorithme de hachage SHA-1 pour signer la clé. Cela diffère de la démo mkcert.c que j'ai mentionnée au début de cette réponse, qui utilise MD5.


, Nous avons maintenant un certificat auto-signé! Mais nous n'avons pas encore terminé - nous devons écrire ces fichiers sur le disque. Heureusement OpenSSL nous a couvert là aussi avec les fonctions PEM_* qui sont déclarées dans openssl/pem.h. Le premier dont nous aurons besoin est PEM_write_PrivateKey pour enregistrer notre clé privée.

FILE * f;
f = fopen("key.pem", "wb");
PEM_write_PrivateKey(
    f,                  /* write the key to the file we've opened */
    pkey,               /* our key from earlier */
    EVP_des_ede3_cbc(), /* default cipher for encrypting the key on disk */
    "replace_me",       /* passphrase required for decrypting the key on disk */
    10,                 /* length of the passphrase string */
    NULL,               /* callback for requesting a password */
    NULL                /* data to pass to the callback */
);

Si vous ne voulez pas chiffrer la clé privée, passez simplement NULL pour les troisième et quatrième paramètres ci-dessus. De toute façon, vous voudrez certainement vous assurer que le fichier n'est pas lisible dans le monde. (Pour les utilisateurs Unix, cela signifie chmod 600 key.pem.)

Ouf! Maintenant, nous sommes à une fonction - nous devons écrire le certificat sur le disque. Fonction nous avons besoin pour cela est PEM_write_X509:

FILE * f;
f = fopen("cert.pem", "wb");
PEM_write_X509(
    f,   /* write the certificate to the file we've opened */
    x509 /* our certificate */
);

Et c'est fini! Espérons que les informations contenues dans cette réponse sont suffisantes pour vous donner une idée approximative de la façon dont tout fonctionne, bien que nous ayons à peine rayé la surface D'OpenSSL.

Pour ceux qui sont intéressés à voir à quoi ressemble tout le code ci-dessus dans une application réelle, j'ai jeté ensemble un essentiel (écrit en C++) que vous pouvez voir ici.

149
répondu Nathan Osman 2013-02-26 23:11:42

Une chance de le faire via un appel system depuis votre application? Plusieurs bonnes raisons de le faire:

  • Licence: L'appel de l'exécutable openssl le sépare sans doute de votre application et peut fournir certains avantages. avertissement: consultez un avocat à ce sujet.

  • Documentation: OpenSSL est livré avec phénoménal documentation en ligne de commande qui simplifie grandement un outil potentiellement compliqué.

  • La Testabilité: vous pouvez exercer OpenSSL à partir de la ligne de commande jusqu'à ce que vous compreniez exactement comment créer vos certificats. Il y a un lot d'options; attendez-vous à passer environ une journée à ce sujet jusqu'à ce que vous obteniez tous les détails. Après cela, il est trivial d'intégrer la commande dans votre application.

Si vous choisissez d'utiliser L'API, consultez la liste des développeurs openssl-dev sur www.openssl.org.

Bonne chance!

0
répondu Adam Liss 2008-11-02 03:01:57

Tutoriel très simple pour créer des certificats numériqueshttp://publib.boulder.ibm.com/infocenter/rsthelp/v8r0m0/index.jsp?topic=/com.ibm.rational.test.lt.doc/topics/tcreatecertopenssl.html

À propos de l'exécution de ces commandes à partir de votre code, je ne suis pas sûr.

0
répondu Jaime Hablutzel 2011-07-12 21:10:48