So teilen Sie eine PEM-Datei

37

Hinweis: Dies ist keine wirkliche Frage, da ich die Antwort bereits gefunden habe. Da ich sie hier jedoch nicht leicht gefunden habe, werde ich sie veröffentlichen, damit andere davon profitieren können.

Frage: Wie liest man eine verkettete PEM-Datei, wie sie von der Anweisung SSLCACertificateFile für Apache / mod_ssl verwendet wird ?

Antwort (Original) ( Quelle ):

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

Dies kann eine leere Datei hinterlassen, wenn am Ende eine leere Zeile steht, z. B. mit openssl pkcs7 -outform PEM -in my-chain-file -print_certs. Um dies zu verhindern, überprüfen Sie die Länge der Zeile vor dem Drucken:

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

Antwort 29.03.2016 :

Nach @slugchewer Antwort , csplitkönnte eine klarere Option sein mit:

csplit -f cert- $file '/-----BEGIN CERTIFICATE-----/' '{*}'
Cerber
quelle
Dies mag eine dumme Frage sein, aber warum sollte ich meine PEM-Datei aufteilen müssen?
Ashwani Agarwal
6
@AshwaniAgarwal Sie möchten eine PEM-Datei aufteilen, wenn sie mehrere Zertifikate enthält, und Sie möchten die Zertifikate einzeln mit Tools untersuchen openssl, für deren Analyse beispielsweise ein Zertifikat erforderlich ist.
Law29
Darüber hinaus möchten einige Tools oder Server eine kombinierte Datei mit Zertifikat und Schlüssel, andere möchten, dass sie getrennt werden.
Captncraig
Ich musste '% ----- BEGIN CERTIFICATE -----%' zur csplit-Befehlszeile hinzufügen, um eine leere Datei zu verhindern. Scheint mit den Angaben der Manpage übereinzustimmen: csplit -f ./tmp/cert- $ file '% ----- BEGIN CERTIFICATE -----%' '/ ----- BEGIN CERTIFICATE ----- / '' {*} '
Craig Hicks
2
Verwenden Sie "csplit -z", um keine leeren Dateien zu hinterlassen.
Paul M

Antworten:

23

Das awk-Snippet dient zum Extrahieren der verschiedenen Teile, aber Sie müssen noch wissen, welcher Abschnitt der Schlüssel / das Zertifikat / die Kette ist. Ich musste einen bestimmten Abschnitt extrahieren und fand diesen in der OpenSSL-Mailingliste: 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
Johannes 'Fisch' Ziemke
quelle
nice command set :) Ich werde es für die zukünftige Verwendung aufbewahren, aber in meinem obigen Anwendungsfall arbeite ich mit einer Nur-Zertifikat-Datei, die 50+ CA-Zertifikate enthält ==> weder pkey noch chain
Cerber 20.03.15
2
Ich denke, dies ist der awk-Lösung überlegen. Lassen Sie das openssl das Parsing ausführen, und Sie erhalten die Konvertierung.
Rusty
Es tut mir leid, aber nur der Befehl pkey ist korrekt. Zweite und Dritte machen nicht das, was Sie bewerben - sie machen etwas anderes. In einigen Fällen ist das Ergebnis gut, in einigen Fällen kann es bei Verbrauchern zu mysteriösen Verhaltensweisen kommen. Ein bisschen bearbeitet.
Kubanczyk
Irgendeine Idee, wie man auf diese Weise das dritte Zertifikat erhält?
Flickerfly
15

Dies wurde zuvor auf StackOverflow beantwortet :

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

Edit 29/03/2016 : Siehe @slugchewer Antwort

Cerber
quelle
Funktioniert nur unter Linux, schlägt unter FreeBSD fehl.
Michael-O
3
Davon inspiriert habe ich ein awk-Skript erstellt, das Zertifikate und Schlüssel in separate Dateien aufteilt
JinnKo
15

Der splitBefehl ist auf den meisten Systemen verfügbar, und sein Aufruf ist wahrscheinlich leichter zu merken.

Wenn Sie eine Datei haben collection.pem, die Sie in individual-*Dateien aufteilen möchten , verwenden Sie:

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

Wenn Sie nicht haben split, können Sie versuchen csplit:

csplit -f individual- collection.pem '/-----BEGIN CERTIFICATE-----/' '{*}'
Tintenfischpickel
quelle
2
Leider zeigt keines meiner Systeme (busybox, fedora, centos) eine -pOption (oder die von mir gelesenen Hilfeseiten) beim Teilen an. Vielleicht verwenden Sie eine spezielle Binärdatei / ein spezielles Paket
Cerber
1
@Cerber Könnte csplitstattdessen versuchen ... (siehe oben bearbeiten)
Squidpickles
1
funktioniert gut mit csplit!
Cerber
Auf FreeBSD bekomme ich von csplit: csplit: *}: bad repetition count(aber split scheint zu funktionieren)
Gwyneth Llewelyn
4

Wenn Sie ein einzelnes Zertifikat aus einem PEM-Paket mit mehreren Zertifikaten erhalten möchten, versuchen Sie Folgendes:

$ openssl crl2pkcs7 -nocrl -certfile INPUT.PEM | \
    openssl pkcs7 -print_certs | \
    awk '/subject.*CN=host.domain.com/,/END CERTIFICATE/'
  • Die ersten beiden opensslBefehle verarbeiten eine PEM-Datei und spucken sie vor jedem Zertifikat mit vorangestellten "subject:"und "issuer:"Zeilen aus. Wenn Ihre PEM bereits so formatiert ist, brauchen Sie nur den letzten awkBefehl.
  • Der Befehl awk spuckt das einzelne PEM aus, das der Zeichenfolge CN (Common Name) entspricht.

source1 , source2

cmcginty
quelle
Ich sehe das nicht in deiner Quelle. Neben sind PEM Base64 codiert werden Sie nicht Text wie „Betreff“, „CN“, ... mit awk finden
Cerber
1
Ja, das funktioniert nicht bei jedem PEM-Typ. Wenn Sie ein P7B mit openssl nach PEM extrahieren, wird vor jedem Zertifikat eine Betreffzeile aufgeführt. Oder Sie können eine beliebige Zeichenfolge ändern, mit der Sie Ihre PEM-Datei segmentieren.
12.
Aktualisierte Antwort, wenn PEM kein "subject" enthält
cmcginty
3

Erwähnenswert ist auch, dass PEM-Dateien nur eine Sammlung von Schlüsseln / Zertifikaten in BEGIN/ ENDBlöcken sind. Es ist also ziemlich einfach, sie nur auszuschneiden / einzufügen, wenn es sich nur um eine einzelne Datei mit ein oder zwei interessanten Entitäten handelt.

mgalgs
quelle
2

Wenn Sie Vollkettenzertifikate (dh solche, die von letsencrypt / certbot usw. generiert wurden) verarbeiten, die eine Verkettung des Zertifikats und der Zertifizierungsstellenkette darstellen, können Sie die Bash-String-Manipulation verwenden.

Beispielsweise:

# 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-----

So extrahieren Sie das Zertifikat und die Zertifizierungsstellenkette in Variablen:

# 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')

Erläuterung:

Anstatt awk oder openssl (leistungsstarke Tools, die jedoch nicht immer verfügbar sind, z. B. in Docker Alpine-Bildern) zu verwenden, können Sie die Bash-String-Manipulation verwenden.

"${FULLCHAIN%%-----END CERTIFICATE-----*}-----END CERTIFICATE-----": Am Ende des Inhalts von FULLCHAIN ​​wird die längste Teilstring-Übereinstimmung zurückgegeben, und anschließend wird die Konkretisierung ausgeführt, sobald -----END CERTIFICATE-----sie entfernt wird. Das *stimmt mit allen Zeichen nach überein -----END CERTIFICATE-----.

$(echo -e "${FULLCHAIN#*-----END CERTIFICATE-----}" | sed '/./,$!d'): Geben Sie vom Anfang des Inhalts von FULLCHAIN ​​die kürzeste Teilzeichenfolgenübereinstimmung zurück und entfernen Sie dann die führenden neuen Zeilen. Ebenso *stimmt das mit allen Zeichen vorher überein -----END CERTIFICATE-----.

Für eine schnelle Referenz (während Sie mehr über String - Manipulation in bash finden hier ):

${VAR#substring}= der kürzeste Teilstring vom Anfang des Inhalts von VAR

${VAR%substring}= der kürzeste Teilstring vom Ende des Inhalts von VAR

${VAR##substring}= der längste Teilstring vom Anfang des Inhalts von VAR

${VAR%%substring}= die längste Teilzeichenfolge vom Ende des Inhalts von VAR

Fabio
quelle
Wenn Sie diese Variablen als Echo ausgeben, müssen Sie die Variable mit Anführungszeichen umgeben, damit die Zeilenumbrüche erhalten bleiben, wie Sie sie gewohnt sind. Ich erinnere mich, als mir das nicht so klar war. Fabio, süße Verwendung der Bash-String-Manipulation!
Flickerfly
0

Hmmm ... fast genauso wie ich die Lösung vorbereitet habe (wie von @Cerber vorgeschlagen), ohne zu bemerken, dass diese Situation anscheinend viele Menschen haben. Meine Lösung folgt fast der gleichen Logik, verwendet jedoch einige grundlegendere Befehle:

Meine alle Zertifikate sind in Datei: 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

Dies schreibt im Grunde genommen so lange in eine Datei, bis "END" angezeigt wird, und beginnt dann schrittweise mit dem Schreiben in eine andere Datei. Auf diese Weise erhalten Sie "N" Anzahl von Ausgabedateien ( certout0.pem, certout1.pem usw.), je nachdem, wie viele Zertifikate sich in Ihrer Eingabe-PEM-Datei ( certin.pem ) befinden.

Ashish K Srivastava
quelle