Question

J'ai une application C / C ++ et je dois créer un certificat pem X509 contenant à la fois une clé publique et une clé privée. Le certificat peut être auto-signé ou non signé, peu importe.

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

Quelles fonctions OpenSSL le feront pour moi? Tout exemple de code est un bonus!

Était-ce utile?

La solution

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. Il s'agit plutôt d'une version de la clé publique signée par une autorité de certification (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 appeler plus de 20 fonctions différentes de l'API OpenSSL pour créer une clé et un certificat auto-signé. Un exemple est dans la source OpenSSL elle-même, dans démos / x509 / mkcert.c

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

Autres conseils

Je réalise que c'est une réponse très tardive (et longue). Mais compte tenu du degré de classement de cette question dans les résultats des moteurs de recherche, j’ai pensé qu’il serait peut-être intéressant d’écrire une réponse décente.

Une grande partie de ce que vous allez lire ci-dessous est empruntée à cette démo et la documentation 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 en mémoire une clé privée indépendante de l’algorithme. Cette structure est déclarée dans openssl / evp.h mais est incluse dans openssl / x509.h (dont nous aurons besoin plus tard), vous n'avez donc pas vraiment besoin d'inclure explicitement l'en-tête.

Pour allouer une structure EVP_PKEY , nous utilisons < code> EVP_PKEY_new :

EVP_PKEY * pkey;
pkey = EVP_PKEY_new();

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

Nous devons maintenant générer une clé. Pour notre exemple, nous allons générer une clé RSA. Ceci est fait avec la fonction RSA_generate_key qui est déclarée dans openssl / rsa.h . Cette fonction renvoie un pointeur sur 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 , il se produit un problème. Sinon, nous avons maintenant une clé RSA que nous pouvons attribuer à notre structure EVP_PKEY précédemment:

EVP_PKEY_assign_RSA(pkey, rsa);

La structure RSA sera automatiquement libérée lorsque la structure EVP_PKEY sera 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 , une fonction correspondante permet de libérer la structure - X509_free .

Nous devons maintenant définir quelques propriétés du certificat à l'aide de certaines fonctions X509 _ * :

ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);

Ceci définit le numéro de série de notre certificat sur '1'. Certains serveurs HTTP open-source refusent d'accepter un certificat avec un numéro de série de "0", qui est le numéro 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 de secondes spécifié à l'heure actuelle - dans ce cas, aucune.) La deuxième ligne définit la propriété notAfter du certificat sur 365 jours à compter de maintenant (60 secondes * 60 minutes * 24 heures * 365 jours).

Nous devons maintenant définir la clé publique de notre certificat à l'aide de la clé que nous avons générée précédemment:

X509_set_pubkey(x509, pkey);

S'agissant d'un certificat auto-signé, nous affectons le nom de l'émetteur au nom du sujet. La première étape de ce processus consiste à obtenir le nom du sujet:

X509_NAME * name;
name = X509_get_subject_name(x509);

Si vous avez déjà créé un certificat auto-signé sur la ligne de commande auparavant, vous vous souvenez probablement de vous avoir 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 qu'il s'agit de notre code de pays. Notez également que le paramètre n ° 4 doit être explicitement converti en un caractère non signé .)

Nous pouvons maintenant définir le nom de l'émetteur:

X509_set_issuer_name(x509, name);

Et enfin, nous sommes prêts à exécuter le processus de signature. Nous appelons X509_sign avec la clé générée précédemment. Le code pour cela est extrêmement 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émonstration mkcert.c 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 un disque. Heureusement, OpenSSL nous y a également couverts avec les fonctions PEM _ * 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 souhaitez pas chiffrer la clé privée, transmettez simplement NULL pour les troisième et quatrième paramètres ci-dessus. Quoi qu'il en soit, vous voudrez certainement vous assurer que le fichier n'est pas lisible par tout le monde. (Pour les utilisateurs Unix, cela signifie chmod 600 key.pem .)

Ouf! Maintenant, nous n’avons plus qu’une fonction: nous devons écrire le certificat sur disque. La fonction dont 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 nous avons fini! Espérons que les informations contenues dans cette réponse sont suffisantes pour vous donner une idée de la façon dont tout fonctionne, bien que nous ayons à peine effleuré OpenSSL.

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

Avez-vous une chance de le faire via un appel système depuis votre application? Plusieurs bonnes raisons pour cela:

  • Licences: l'appel de l'exécutable openssl le sépare sans doute de votre application et peut offrir certains avantages. Clause de non-responsabilité: consultez un avocat à ce sujet.

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

  • Testability: vous pouvez exercer OpenSSL à partir de la ligne de commande jusqu'à ce que vous sachiez exactement comment créer vos certs. Il y a beaucoup d'options; attendez-vous à y consacrer environ une journée jusqu'à ce que tous les détails soient corrects. Après cela, il est facile d'intégrer la commande à votre application.

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

Bonne chance!

Tutoriel très simple sur la création de certificats numériques http://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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top