Crea un certificato autofirmato con data di fine nel passato


24

Vorrei creare al volo certificati autofirmati con date di inizio e fine arbitrarie, comprese le date di fine del passato . Preferirei utilizzare strumenti standard, ad esempio OpenSSL, ma qualsiasi cosa che porti a termine il lavoro sarebbe grandiosa.

La domanda Stack Overflow Come generare un certificato openssl con scadenza inferiore a un giorno? pone una domanda simile, ma voglio che il mio certificato sia autofirmato.

Nel caso ti stavi chiedendo, i certificati sono necessari per i test automatizzati.

Risposte:


32

Hai due modi per creare certificati in passato. Fingere il tempo (1) (2) o definire l'intervallo di tempo quando si firma il certificato (3).

1) Innanzitutto, fingere il tempo: per far pensare a un programma che è in una data diversa dal sistema, dai un'occhiata libfaketimeefaketime

Per installarlo in Debian:

sudo apt-get install faketime

Dovresti quindi utilizzare faketimeprima del opensslcomando.

Per esempi di utilizzo:

$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

Da man faketime:

Il comando dato verrà indotto a credere che l'ora corrente del sistema sia quella specificata nel timestamp. L'orologio da parete continuerà a funzionare da questa data e ora se non diversamente specificato (vedere le opzioni avanzate). In realtà, faketime è un semplice wrapper per libfaketime, che utilizza il meccanismo LD_PRELOAD per caricare una piccola libreria che intercetta le chiamate di sistema a funzioni come time (2) e fstat (2).

Ad esempio, nel tuo caso, puoi definire molto bene una data del 2008 e creare quindi un certificato con validità da 2 anni fino al 2010.

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

Come nota a margine, questa utility può essere utilizzata in diverse versioni Unix, incluso MacOS, come wrapper per qualsiasi tipo di programma (non esclusivo della riga di comando).

A titolo di chiarimento, solo i file binari caricati con questo metodo (e i loro figli) hanno il loro tempo cambiato e l'ora falsa non influisce sull'ora corrente del resto del sistema.

2) Come afferma @Wyzard, hai anche un datefudgepacchetto molto simile a faketime.

Come differenze, datefudgenon influenza fstat(cioè non cambia la creazione del tempo del file). Ha anche la sua libreria, datefudge.so, che carica usando LD_PRELOAD.

Ha anche un punto in -s static timecui viene sempre restituito il tempo di riferimento nonostante quanti secondi in più siano trascorsi.

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

3) Oltre a fingere il tempo, e ancora più semplicemente, puoi anche definire il punto iniziale e il punto finale di validità del certificato quando firmi il certificato in OpenSSL.

L'idea sbagliata della domanda a cui ci si collega nella domanda è che la validità del certificato non è definita al momento della richiesta (su richiesta CSR), ma al momento della firma.

Quando si utilizza openssl caper creare il certificato autofirmato, aggiungere le opzioni -startdatee -enddate.

Il formato della data in queste due opzioni, secondo le fonti di openssl a openssl/crypto/x509/x509_vfy.c, è ASN1_TIME aka ASN1UTCTime: il formato deve essere YYMMDDHHMMSSZ o YYYYMMDDHHMMSSZ.

Citando 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."
     */

E dal registro CHANGE (2038 bug?) - Questo registro delle modifiche è solo una nota a piè di pagina aggiuntiva, in quanto riguarda solo coloro che utilizzano direttamente l'API.

Cambia tra 1.1.0e e 1.1.1 [xx XXX xxxx]

*) Aggiungi i tipi ASN.1 INT32, UINT32, INT64, UINT64 e le varianti con il prefisso Z. Questi hanno lo scopo di sostituire LONG e ZLONG e di essere sicuri delle dimensioni. L'uso di LONG e ZLONG è sconsigliato e pianificato per il deprezzamento in OpenSSL 1.2.0.

Pertanto, la creazione di un certificato dal 1 gennaio 2008 al 1 gennaio 2010 può essere effettuata come:

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

o

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

-startdatee -enddateappare nel opensslregistro delle fonti e CHANGE; come notato da @guntbert, sebbene non compaiano nella man opensslpagina principale , compaiono anche in 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).

Citando openssl/CHANGE:

Variazioni tra 0.9.3a e 0.9.4 [09 ago 1999]

*) Correggi gli argomenti -startdate e -enddate (che mancavano) sul programma 'ca'.

PS Per quanto riguarda la risposta scelta alla domanda a cui fai riferimento da StackExchange: è generalmente una cattiva idea cambiare il tempo di sistema, specialmente nei sistemi di produzione; e con i metodi in questa risposta non hai bisogno dei privilegi di root quando li usi.


1
+1. Sapevo che qualcuno sarebbe arrivato con qualcosa di meglio di quello che ho scritto :)
Celada,

2
C'è anche un programma simile chiamato datefudge.
Wyzard

@Wyzard Grazie, in effetti l'ho trovato in Debian; abbastanza interessante, il manuale afferma che mentre cambia anche le chiamate di sistema a funzioni come il tempo (2), non influenza fstat (2).
Rui F Ribeiro,

1
Entrambi faketimee datefudgefunzionano magnificamente sul mio sistema Debian jessie.
rlandster,

1
OTOH: +5 per scoprire dove impostare quelle date!
Guntbert,

8

Sono quasi sorpreso di scoprire che la cosa ovvia funziona: considerando opensslcome argomento il numero di giorni per i quali il certificato dovrebbe essere valido, basta fornire un numero negativo!

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

Si noti che ciò si traduce in realtà in qualcosa di molto strano: un certificato la cui data e ora di scadenza precede la data di inizio della validità. In realtà non ti consiglio di usarlo per i tuoi test automatizzati, dal momento che è strano. Probabilmente vuoi un modo per retrodatare anche il timestamp di inizio validità.


Beh, ad essere sinceri, non avevo idea che potessi usare giorni negativi.
Rui F Ribeiro,

Non puoi specificare la data di inizio?
FreeSoftwareServers

@FreeSoftwareServers Nel CSR non puoi; vedi l'ultima parte della mia risposta.
Rui F Ribeiro,

Ancora più interessante, il codice non trova tale certificato? tra l'altro, ho ampliato la mia risposta
Rui F Ribeiro

3

Oppure potresti usare qualcosa di simile a questo breve programma Python ... (si applicano avvertenze)

Crea una chiave (test.key) e un certificato (test.crt) con tempo di inizio 10 anni nel passato (-10 * 365 * 24 * 60 * 60 secondi è -10 anni) e tempo di scadenza 5 anni nel passato (-5 * 365 * 24 * 60 * 60).

Si noti che si tratta di un programma dimostrativo minimo, quindi non si preoccupa di impostare estensioni (ad esempio vincoli di base) e utilizza un numero seriale fisso.

#!/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))

il codice sembra mancare campi standard X.509 essenziali.
Rui F Ribeiro,

2
Questo è molto utile Mi dà un controllo programmatico più semplice sulla creazione del certificato.
rlandster
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.