web-dev-qa-db-fra.com

Créer un certificat auto-signé avec une date de fin dans le passé

Je voudrais créer des certificats auto-signés à la volée avec des dates de début et de fin arbitraires, y compris des dates de fin dans le passé . Je préférerais utiliser des outils standard, par exemple OpenSSL, mais tout ce qui fait le travail serait formidable.

La question Stack Overflow Comment générer un certificat openssl avec une expiration inférieure à un jour? pose une question similaire, mais je veux que mon certificat soit auto-signé.

Au cas où vous vous poseriez la question, les certificats sont nécessaires pour les tests automatisés.

24
rlandster

Vous avez deux façons de créer des certificats dans le passé. Soit truquer l'heure (1) (2), soit définir l'intervalle de temps lors de la signature du certificat (3).

1) Tout d'abord, pour truquer le temps: pour faire croire à un programme qu'il est à une date différente du système, jetez un œil à libfaketime et faketime

Pour l'installer dans Debian:

Sudo apt-get install faketime

Vous utiliseriez alors faketime avant la commande openssl.

Pour des exemples d'utilisation:

$faketime 'last friday 5 pm' /bin/date
Fri Apr 14 17:00:00 WEST 2017
$faketime '2008-12-24 08:15:42' /bin/date
Wed Dec 24 08:15:42 WET 2008

De man faketime:

La commande donnée sera amenée à croire que l'heure actuelle du système est celle spécifiée dans l'horodatage. L'horloge murale continuera de fonctionner à partir de cette date et heure, sauf indication contraire (voir les options avancées). En fait, faketime est un simple wrapper pour libfaketime, qui utilise le mécanisme LD_PRELOAD pour charger une petite bibliothèque qui intercepte les appels système à des fonctions telles que time (2) et fstat (2).

Ainsi par exemple, dans votre cas, vous pouvez très bien définir une date de 2008, et créer ensuite un certificat d'une validité de 2 ans jusqu'en 2010.

faketime '2008-12-24 08:15:42' openssl ... 

En guise de remarque, cet utilitaire peut être utilisé dans plusieurs versions Unix, y compris MacOS, comme un wrapper pour tout type de programmes (non exclusif à la ligne de commande).

À titre de clarification, seuls les binaires chargés avec cette méthode (et leurs enfants) ont leur heure modifiée, et la fausse heure n'affecte pas l'heure actuelle du reste du système.

2) Comme l'indique @Wyzard, vous disposez également du package datefudge qui est très similaire à l'utilisation de faketime.

En tant que différences, datefudge n'influence pas fstat (c'est-à-dire ne change pas la création de l'heure du fichier). Il possède également sa propre bibliothèque, datefudge.so, qu'il charge à l'aide de LD_PRELOAD.

Il a également un -sstatic time où l'heure référencée est toujours renvoyée malgré le nombre de secondes supplémentaires écoulées.

$ datefudge --static "2007-04-01 10:23" sh -c "sleep 3; date -R"
Sun, 01 Apr 2007 10:23:00 +0100

3) En plus de simuler le temps, et plus simplement, vous pouvez également définir le point de départ et le point de fin de validité du certificat lorsque signe le certificat dans OpenSSL.

L'idée fausse de la question à laquelle vous liez dans votre question est que la validité du certificat n'est pas définie au moment de la demande (à la demande de RSE), mais lors de sa signature.

Lors de l'utilisation de openssl ca pour créer le certificat auto-signé, ajoutez les options -startdate et -enddate.

Le format de date dans ces deux options, selon les sources openssl à openssl/crypto/x509/x509_vfy.c, est ASN1_TIME alias ASN1UTCTime: le format doit être YYMMDDHHMMSSZ ou YYYYMMDDHHMMSSZ.

Citant openssl/crypto/x509/x509_vfy.c:

int X509_cmp_time(const ASN1_TIME *ctm, time_t *cmp_time)
{
    static const size_t utctime_length = sizeof("YYMMDDHHMMSSZ") - 1;
    static const size_t generalizedtime_length = sizeof("YYYYMMDDHHMMSSZ") - 1;
    ASN1_TIME *asn1_cmp_time = NULL;
    int i, day, sec, ret = 0;

    /*
     * Note that ASN.1 allows much more slack in the time format than RFC5280.
     * In RFC5280, the representation is fixed:
     * UTCTime: YYMMDDHHMMSSZ
     * GeneralizedTime: YYYYMMDDHHMMSSZ
     *
     * We do NOT currently enforce the following RFC 5280 requirement:
     * "CAs conforming to this profile MUST always encode certificate
     *  validity dates through the year 2049 as UTCTime; certificate validity
     *  dates in 2050 or later MUST be encoded as GeneralizedTime."
     */

Et à partir du journal CHANGE (bug 2038?) - Ce journal des modifications est juste une note de bas de page supplémentaire, car il ne concerne que ceux qui utilisent directement l'API.

Changements entre 1.1.0e et 1.1.1 [xx XXX xxxx]

*) Ajoutez les types ASN.1 INT32, UINT32, INT64, UINT64 et les variantes préfixées par Z. Celles-ci sont destinées à remplacer LONG et ZLONG et à garantir la taille. L'utilisation de LONG et ZLONG est déconseillée et programmée pour dépréciation dans OpenSSL 1.2.0.

Ainsi, la création d'un certificat du 1er janvier 2008 au 1er janvier 2010, peut se faire comme:

openssl ca -config /path/to/myca.conf -in req.csr -out ourdomain.pem \
-startdate 200801010000Z -enddate 201001010000Z

ou

openssl ca -config /path/to/myca.conf -in req.csr -out ourdomain.pem \
-startdate 0801010000Z -enddate 1001010000Z

-startdate et -enddate apparaissent dans les sources openssl et le journal CHANGE; comme l'a noté @guntbert, alors qu'ils n'apparaissent pas dans le principal man openssl page, ils apparaissent également dans man ca:

-startdate date
       this allows the start date to be explicitly set. The format of the date is
       YYMMDDHHMMSSZ (the same as an ASN1 UTCTime structure).

   -enddate date
       this allows the expiry date to be explicitly set. The format of the date is
       YYMMDDHHMMSSZ (the same as an ASN1 UTCTime structure).

Citant openssl/CHANGE:

Changements entre 0.9.3a et 0.9.4 [09 août 1999]

*) Correction des arguments -startdate et -enddate (qui manquaient) au programme 'ca'.

P.S. Quant à la réponse choisie de la question que vous référencez depuis StackExchange: c'est généralement une mauvaise idée de changer l'heure système, en particulier dans les systèmes de production; et avec les méthodes de cette réponse, vous n'avez pas besoin des privilèges root lorsque vous les utilisez.

34
Rui F Ribeiro

Je suis presque surpris de constater que la chose évidente fonctionne: alors que openssl prend comme argument le nombre de jours pour lesquels le certificat doit être valide, il suffit de fournir un nombre négatif!

openssl req -x509 -newkey rsa:4096 \
    -keyout key.pem -out cert.pem -days -365

Notez que cela se traduit en fait par quelque chose de très étrange: un certificat dont l'horodatage d'expiration précède son horodatage de début de validité. Je ne vous recommande pas réellement de l'utiliser pour vos tests automatisés, car c'est bizarre. Vous voulez probablement un moyen de dater également l'horodatage de début de validité.

8
Celada

Ou vous pouvez utiliser quelque chose comme ce court python ... (des mises en garde s'appliquent)

Il crée une clé (test.key) et un certificat (test.crt) avec un temps de création de 10 ans dans le passé (-10 * 365 * 24 * 60 * 60 secondes est de -10 ans) et un délai d'expiration de 5 ans dans le passé (-5 * 365 * 24 * 60 * 60).

Veuillez noter qu'il s'agit d'un programme de démonstration minimal, il ne prend donc pas la peine de définir des extensions (par exemple, BasicConstraints) et utilise une série fixe.

#!/usr/bin/env python

from OpenSSL import crypto

key = crypto.PKey()
key.generate_key(crypto.TYPE_RSA, 2048)
cert = crypto.X509()
cert.get_subject().CN = "Test"
cert.set_serial_number(666)
cert.gmtime_adj_notBefore(-10*365*24*60*60)
cert.gmtime_adj_notAfter(-5*365*24*60*60)
cert.set_issuer(cert.get_subject())
cert.set_pubkey(key)
cert.sign(key, 'sha384')

open("test.crt", "wb").write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
open("test.key", "wb").write(crypto.dump_privatekey(crypto.FILETYPE_PEM, key))
3
Edheldil