Come dividere un file PEM


38

Nota: questa non è davvero una domanda perché ho già trovato la risposta, ma poiché non l'ho trovata facilmente qui la pubblicherò in modo che possa essere di beneficio agli altri.

Domanda: Come leggere un file PEM concatenato come quello utilizzato dalla direttiva apache / mod_ssl SSLCACertificateFile ?

Risposta (originale) ( fonte ):

cat $file|awk 'split_after==1{n++;split_after=0} /-----END CERTIFICATE-----/ {split_after=1} {print > "cert" n ".pem"}'

Questo può lasciare un file vuoto se c'è una riga vuota alla fine, come con openssl pkcs7 -outform PEM -in my-chain-file -print_certs. Per evitare ciò, controllare la lunghezza della linea prima di stampare:

cat $file|awk 'split_after==1{n++;split_after=0}
   /-----END CERTIFICATE-----/ {split_after=1}
   {if(length($0) > 0) print > "cert" n ".pem"}' 

Risposta 29/03/2016 :

Dopo la risposta di @slugchewer , csplitpotrebbe essere un'opzione più chiara con:

csplit -f cert- $file '/-----BEGIN CERTIFICATE-----/' '{*}'

Questa potrebbe essere una domanda stupida, ma perché dovrei dividere il mio file pem?
Ashwani Agarwal,

6
@AshwaniAgarwal Si desidera dividere un file PEM quando contiene diversi certificati e si desidera esaminare i certificati singolarmente con strumenti come quello opensslche richiedono un certificato da analizzare.
Legge 29

Inoltre, alcuni strumenti o server vogliono un file combinato con cert e chiave, mentre altri li vogliono separati.
captncraig,

Ho dovuto aggiungere '% ----- INIZIA CERTIFICATO -----%' alla riga di comando csplit per evitare un file vuoto. Sembra corrispondere a quanto specificato dalla pagina man: csplit -f ./tmp/cert- $ file '% ----- INIZIA CERTIFICATO -----%' '/ ----- INIZIA CERTIFICATO ----- / '' {*} '
Craig Hicks il

2
usa "csplit -z" per non lasciare file vuoti.
Paul M,

Risposte:


23

Lo snippet di awk funziona per estrarre le diverse parti, ma è comunque necessario sapere quale sezione è la chiave / certificato / catena. Avevo bisogno di estrarre una sezione specifica e l'ho trovato sulla mailing list di OpenSSL: http://openssl.6102.n7.nabble.com/Convert-pem-to-crt-and-key-files-tp47681p47697.html

# Extract key
openssl pkey -in foo.pem -out foo-key.pem

# Extract all the certs
openssl crl2pkcs7 -nocrl -certfile foo.pem |
  openssl pkcs7 -print_certs -out foo-certs.pem

# Extract the textually first cert as DER
openssl x509 -in foo.pem -outform DER -out first-cert.der

bel set di comandi :) Lo terrò per un uso futuro, ma nel mio caso d'uso sopra, sto lavorando con un file di solo cert contenente 50+ CA certs ==> no pkey né chain
Cerber

2
Penso che questo sia superiore alla soluzione awk, lascia che openssl esegua l'analisi + ottieni la conversione.
Rusty

Mi dispiace ma solo il comando pkey è corretto. Il secondo e il terzo non fanno ciò che pubblicizzi: fanno qualcos'altro. In alcuni casi il risultato è buono in alcuni casi può generare comportamenti misteriosi nei consumatori. Modificato un po '.
Kubanczyk,

Qualche idea su come ottenere il terzo certificato testuale in questo modo?
flickerfly


15

Il splitcomando è disponibile sulla maggior parte dei sistemi e la sua invocazione è probabilmente più facile da ricordare.

Se si dispone di un file collection.pemche si desidera dividere in individual-*file, utilizzare:

split -p "-----BEGIN CERTIFICATE-----" collection.pem individual-

Se non lo hai split, puoi provare csplit:

csplit -f individual- collection.pem '/-----BEGIN CERTIFICATE-----/' '{*}'

2
Siamo spiacenti, nessuno dei miei sistemi (busybox, fedora, centos) mostra -pun'opzione (né le manpage che ho letto ) su split. Forse stai usando un binario / pacchetto speciale
Cerber

1
@Cerber Potrebbe csplitinvece provare ... (vedi modifica sopra)
squidpickles

1
funziona bene con csplit!
Cerber,

Su FreeBSD ottengo da csplit: csplit: *}: bad repetition count(ma la divisione sembra funzionare)
Gwyneth Llewelyn

4

Se si desidera ottenere un singolo certificato da un pacchetto PEM multi-certificato, provare:

$ openssl crl2pkcs7 -nocrl -certfile INPUT.PEM | \
    openssl pkcs7 -print_certs | \
    awk '/subject.*CN=host.domain.com/,/END CERTIFICATE/'
  • I primi due opensslcomandi elaboreranno un file PEM e lo sputeranno indietro con linee in sospeso "subject:"e "issuer:"righe prima di ogni certificato. Se il tuo PEM è già formattato in questo modo, tutto ciò di cui hai bisogno è il awkcomando finale .
  • Il comando awk sputerà il singolo PEM corrispondente alla stringa CN (nome comune).

fonte1 , fonte2


Non lo vedo nella tua fonte. Accanto a PEM è codificato Base64 non troverai testo come "subject", "CN", ... con awk
Cerber,

1
Sì, questo non funziona per tutti i tipi di PEM. Se si estrae un P7B in PEM usando openssl, verrà visualizzato un oggetto prima di ogni certificato. Oppure puoi modificare qualsiasi stringa con cui segmenti il ​​tuo file PEM.
cmcginty,

Risposta aggiornata da gestire quando PEM non contiene "subject"
cmcginty

3

Vale anche la pena notare che i file PEM sono solo una raccolta di chiavi / certificati all'interno di BEGIN/ ENDblocchi, quindi è abbastanza facile tagliare / incollare se è solo un singolo file con una o due entità interessanti ...


2

Se si gestiscono certificati a catena completa (ovvero quelli generati da letsencrypt / certbot ecc.), Che sono una concatenazione del certificato e della catena dell'autorità di certificazione, è possibile utilizzare la manipolazione della stringa bash.

Per esempio:

# content of /path/to/fullchain.pem
-----BEGIN CERTIFICATE-----
some long base64 string containing
the certificate
-----END CERTIFICATE-----

-----BEGIN CERTIFICATE-----
another base64 string
containing the first certificate
in the authority chain
-----END CERTIFICATE-----

-----BEGIN CERTIFICATE-----
another base64 string
containing the second certificate
in the authority chain
(there might be more...)
-----END CERTIFICATE-----

Per estrarre il certificato e la catena dell'autorità di certificazione in variabili:

# load the certificate into a variable
FULLCHAIN=$(</path/to/fullchain.pem)
CERTIFICATE="${FULLCHAIN%%-----END CERTIFICATE-----*}-----END CERTIFICATE-----"
CHAIN=$(echo -e "${FULLCHAIN#*-----END CERTIFICATE-----}" | sed '/./,$!d')

Spiegazione:

Invece di usare awk o openssl (che sono strumenti potenti ma non sempre disponibili, ad esempio nelle immagini Docker Alpine), puoi usare la manipolazione della stringa bash.

"${FULLCHAIN%%-----END CERTIFICATE-----*}-----END CERTIFICATE-----": dalla fine del contenuto di FULLCHAIN, restituisce la corrispondenza di sottostringa più lunga, quindi concatola -----END CERTIFICATE-----mentre viene rimossa. Le *partite di tutti i caratteri dopo -----END CERTIFICATE-----.

$(echo -e "${FULLCHAIN#*-----END CERTIFICATE-----}" | sed '/./,$!d'): dall'inizio del contenuto di FULLCHAIN, restituisce la corrispondenza di sottostringa più corta, quindi elimina le nuove linee iniziali. Allo stesso modo, *corrisponde a tutti i personaggi precedenti -----END CERTIFICATE-----.

Per un rapido riferimento (mentre puoi trovare ulteriori informazioni sulla manipolazione delle stringhe in bash qui ):

${VAR#substring}= la sottostringa più corta dall'inizio del contenuto di VAR

${VAR%substring}= la sottostringa più corta dalla fine del contenuto di VAR

${VAR##substring}= la sottostringa più lunga dall'inizio del contenuto di VAR

${VAR%%substring}= la sottostringa più lunga dalla fine del contenuto di VAR


Per i meno esperti, quando fai eco queste variabili circondano la variabile con virgolette per preservare le interruzioni di linea nel modo in cui sei abituato a vederle. Ricordo quando non era così ovvio per me. Fabio, dolce uso della manipolazione delle corde bash!
flickerfly,

0

Hmmm ... quasi allo stesso modo ho preparato la soluzione (come suggerito y @Cerber) senza rendersi conto che questa situazione sembra avere molte persone. La mia soluzione segue quasi la stessa logica ma usa alcuni comandi di base:

Tutti i miei certificati sono in archivio: certin.pem

c=0
while read line
  do
    if echo $line | grep END; then
    echo $line >> certout$c.pem
    c=`expr $c + 1`
    else
     echo $line
     echo $line >> certout$c.pem
    fi
done < /tmp/certin.pem

Questo in sostanza continua a scrivere in un file fino a quando non si incontra "END" e quindi inizia a scrivere su un altro file in modo incrementale. In questo modo avrai "N" numero di file di output ( certout0.pem, certout1.pem e così via ..) a seconda di quanti certificati ci sono nel tuo file pem di input ( certin.pem ).

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.