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.