Comment diviser un fichier PEM

38

Note: Ce n'est pas vraiment une question parce que j'ai déjà trouvé la réponse, mais comme je ne l'ai pas trouvée facilement ici, je la posterai afin que cela profite à d'autres.

Question: Comment lire un fichier PEM concaténé comme celui utilisé par la directive apache / mod_ssl SSLCACertificateFile ?

Réponse (originale) ( source ):

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

Cela peut laisser un fichier vide s'il y a une ligne vide à la fin, comme avec openssl pkcs7 -outform PEM -in my-chain-file -print_certs. Pour éviter cela, vérifiez la longueur de la ligne avant d’imprimer:

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

Réponse 29/03/2016 :

Après la réponse de @slugchewer , cela csplitpourrait être une option plus claire avec:

csplit -f cert- $file '/-----BEGIN CERTIFICATE-----/' '{*}'
Cerber
la source
C'est peut-être une question idiote, mais pourquoi aurais-je besoin de scinder mon fichier PEM?
Ashwani Agarwal
6
@AshwaniAgarwal Vous souhaitez fractionner un fichier PEM contenant plusieurs certificats et examiner individuellement les certificats à l'aide d'outils tels que ceux-ci, opensslqui prennent un certificat à analyser.
Law29
De plus, certains outils ou serveurs veulent un fichier combiné avec cert et clé, alors que d'autres veulent les séparer.
captncraig
J'ai dû ajouter '% ----- BEGIN CERTIFICATE -----%' à la ligne de commande csplit pour empêcher un fichier vide. Semble correspondre à ce que la page de manuel spécifie: csplit -f ./tmp/cert- $ file '% ----- BEGIN CERTIFICATE -----%' '/ ----- BEGIN CERTIFICATE ----- / '' {*} '
Craig Hicks
2
utilisez "csplit -z" pour ne pas laisser de fichiers vides.
Paul M

Réponses:

23

L'extrait de code awk fonctionne pour extraire les différentes parties, mais vous devez toujours savoir quelle section est la clé / cert / chaîne. J'avais besoin d'extraire une section spécifique et je l'ai trouvée dans la liste de diffusion 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
Le poisson de Johannes Ziemke
la source
nice command set :) Je le garderai pour une utilisation future, mais dans mon cas d'utilisation ci-dessus, je travaille avec un fichier contenant uniquement des certificats contenant plus de 50 certificats CA ==> pas de clé ni de chaîne
Cerber
2
Je pense que ceci est supérieur à la solution awk, laissez l'OpenSL faire l'analyse + vous obtenez la conversion.
Rusty
Je suis désolé mais seule la commande pkey est correcte. Les deuxième et troisième ne font pas ce que vous annoncez - ils font autre chose. Dans certains cas, le résultat est bon. Dans certains cas, il peut générer des comportements mystérieux chez les consommateurs. Édité un peu.
Kubanczyk
Avez-vous une idée de comment obtenir le 3ème certificat textuel de cette manière?
papillotement le
16

Cela a déjà été répondu sur StackOverflow :

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

29/03/2016 : Voir la réponse de @slugchewer

Cerber
la source
Fonctionne sous Linux uniquement, échoue sous FreeBSD.
Michael-O
3
Inspiré par cela, j'ai créé un script awk qui divise les certificats et les clés en fichiers séparés: gist.github.com/jinnko/d6867ce326e8b6e88975
JinnKo
15

La splitcommande est disponible sur la plupart des systèmes et son invocation est probablement plus facile à mémoriser.

Si vous collection.pemvoulez diviser un fichier en individual-*fichier, utilisez:

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

Si vous n'en avez pas split, vous pouvez essayer csplit:

csplit -f individual- collection.pem '/-----BEGIN CERTIFICATE-----/' '{*}'
squidpickles
la source
2
Désolé, aucun de mes systèmes (busybox, fedora, centos) n'affiche d' -poption (ni les pages de manuel que j'ai lues ) sur split. Peut-être utilisez-vous un paquet / paquet spécial
Cerber
1
@Cerber pourrait essayer à la csplitplace ... (voir modification ci-dessus)
squidpickles
1
fonctionne bien avec csplit!
Cerber
Sur FreeBSD, je reçois de csplit: csplit: *}: bad repetition count(mais la scission semble fonctionner)
Gwyneth Llewelyn
4

Si vous souhaitez extraire un seul certificat d'un ensemble PEM à plusieurs certificats, essayez:

$ openssl crl2pkcs7 -nocrl -certfile INPUT.PEM | \
    openssl pkcs7 -print_certs | \
    awk '/subject.*CN=host.domain.com/,/END CERTIFICATE/'
  • Les deux premières opensslcommandes traiteront un fichier PEM et le cracheront en ajoutant des lignes avant "subject:"et "issuer:"après chaque certificat. Si votre PEM est déjà formaté de cette façon, tout ce dont vous avez besoin est la awkcommande finale .
  • La commande awk crache le PEM individuel correspondant à la chaîne CN (nom commun).

source1 , source2

cmcginty
la source
Je ne vois pas cela dans votre source. De plus, les PEM sont encodés en Base64, vous ne trouverez pas de texte comme "sujet", "CN", ... avec awk
Cerber
1
Oui, cela ne fonctionne pas pour tous les types de PEM. Si vous extrayez un fichier P7B vers PEM à l'aide de openssl, une ligne d'objet apparaît avant chaque certificat. Ou vous pouvez modifier n'importe quelle chaîne avec laquelle vous segmentez votre fichier PEM.
cmcginty
Réponse mise à jour à traiter lorsque PEM ne contient pas "subject"
cmcginty
3

Il convient également de noter que les fichiers PEM sont simplement une collection de clés / certificats à l'intérieur de BEGIN/ ENDblocs, il est donc assez facile de simplement couper / coller s'il ne s'agit que d'un seul fichier avec une ou deux entités intéressantes ...

mgalgs
la source
2

Si vous gérez des certificats de chaîne complète (c'est-à-dire ceux générés par letsencrypt / certbot, etc.), qui sont une concaténation du certificat et de la chaîne d'autorité de certification, vous pouvez utiliser la manipulation de chaîne bash.

Par exemple:

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

Pour extraire le certificat et la chaîne d'autorités de certification en variables:

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

Explication:

Au lieu d'utiliser awk ou openssl (outils puissants mais pas toujours disponibles, par exemple dans les images Docker Alpine), vous pouvez utiliser la manipulation de chaîne bash.

"${FULLCHAIN%%-----END CERTIFICATE-----*}-----END CERTIFICATE-----": à partir de la fin du contenu de FULLCHAIN, retourne la correspondance de sous-chaîne la plus longue, puis concatte à -----END CERTIFICATE-----mesure qu'elle est supprimée. Le *correspond à tous les caractères après -----END CERTIFICATE-----.

$(echo -e "${FULLCHAIN#*-----END CERTIFICATE-----}" | sed '/./,$!d'): depuis le début du contenu de FULLCHAIN, renvoie la correspondance de sous-chaîne la plus courte, puis supprime les nouvelles lignes principales. De même, le *correspond à tous les caractères avant -----END CERTIFICATE-----.

Pour une référence rapide (pour en savoir plus sur la manipulation de chaîne dans bash, cliquez ici ):

${VAR#substring}= la sous-chaîne la plus courte depuis le début du contenu de VAR

${VAR%substring}= la sous-chaîne la plus courte de la fin du contenu de VAR

${VAR##substring}= la plus longue sous-chaîne depuis le début du contenu de VAR

${VAR%%substring}= la plus longue sous-chaîne à partir de la fin du contenu de VAR

Fabio
la source
Pour les moins avertis, lorsque vous renvoyez en écho ces variables, entourez-les de guillemets afin de préserver la ligne. Je me souviens quand ce n'était pas si évident pour moi. Fabio, bon usage de la manipulation des cordes bash!
Scintillement du
0

Hmmm ... presque de la même manière, j'ai préparé la solution (comme suggéré y @Cerber) sans me rendre compte que cette situation semble être répandue. Ma solution suit à peu près la même logique mais utilise quelques commandes plus basiques:

Mes tous les certs sont dans le fichier: 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

En gros, cela continue à écrire dans un fichier jusqu’à rencontrer "END", puis commence à écrire dans un autre fichier de manière incrémentée. De cette manière, vous aurez "N" nombre de fichiers de sortie ( certout0.pem, certout1.pem , etc.) en fonction du nombre de certificats présents dans votre fichier PEM d’entrée ( certin.pem ).

Ashish K Srivastava
la source