Cara membagi file PEM

38

Catatan: Ini sebenarnya bukan pertanyaan karena saya sudah menemukan jawabannya tetapi karena saya tidak menemukannya dengan mudah di sini saya akan mempostingnya sehingga dapat bermanfaat bagi orang lain.

Pertanyaan: Bagaimana cara membaca file PEM gabungan sebagai yang digunakan oleh apache / mod_ssl directive SSLCACertificateFile ?

Jawab (asli) ( sumber ):

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

Ini dapat meninggalkan file kosong jika ada baris kosong di bagian akhir, seperti dengan openssl pkcs7 -outform PEM -in my-chain-file -print_certs. Untuk mencegahnya, periksa panjang garis sebelum mencetak:

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

Jawab 29/03/2016 :

Mengikuti jawaban @slugchewer , csplitmungkin opsi yang lebih jelas dengan:

csplit -f cert- $file '/-----BEGIN CERTIFICATE-----/' '{*}'
Cerber
sumber
Ini mungkin pertanyaan bodoh, tapi mengapa saya harus membagi file pem saya?
Ashwani Agarwal
6
@AshwaniAgarwal Anda ingin membagi file PEM ketika berisi beberapa sertifikat dan Anda ingin memeriksa sertifikat secara individual dengan alat-alat seperti opensslyang mengambil satu sertifikat untuk dianalisis.
Law29
Selain itu, beberapa alat atau server menginginkan file gabungan dengan sertifikat dan kunci, sementara yang lain ingin mereka terpisah.
captncraig
Saya harus menambahkan '% ----- BEGIN CERTIFICATE -----%' ke baris perintah csplit untuk mencegah file kosong. Tampaknya cocok dengan yang ditentukan halaman manual: csplit -f ./tmp/cert- $ file '% ----- BEGIN CERTIFICATE -----%' '/ ----- BEGIN CERTIFICATE ----- / '' {*} '
Craig Hicks
2
gunakan "csplit -z" untuk tidak meninggalkan file kosong.
Paul M

Jawaban:

23

Cuplikan awk berfungsi untuk mengekstraksi bagian yang berbeda, tetapi Anda masih perlu tahu bagian mana yang merupakan kunci / sertifikat / rantai. Saya perlu mengekstrak bagian tertentu, dan menemukan ini di milis 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
Yohanes 'ikan' Ziemke
sumber
set perintah yang bagus :) Saya akan menyimpannya untuk digunakan di masa depan, tetapi dalam kasus penggunaan saya di atas, saya sedang bekerja dengan file hanya-sertifikat yang berisi 50+ CA certs ==> tanpa pkey atau rantai
Cerber
2
Saya pikir ini lebih baik daripada solusi awk, biarkan openssl melakukan parsing + Anda mendapatkan konversi.
Rusty
Maaf, tetapi hanya perintah pkey yang benar. Kedua dan ketiga tidak melakukan apa yang Anda iklankan - mereka melakukan sesuatu yang lain. Dalam beberapa kasus hasilnya bagus dalam beberapa kasus dapat menghasilkan perilaku misterius pada konsumen. Diedit sedikit.
kubanczyk
Adakah yang tahu bagaimana mendapatkan sertifikat ke-3 secara tekstual dengan cara ini?
flickerfly
16

Ini sebelumnya dijawab di StackOverflow :

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

Sunting 29/03/2016 : Lihat jawaban @slugchewer

Cerber
sumber
Hanya bekerja di Linux, gagal di FreeBSD.
Michael-O
3
Terinspirasi oleh ini, saya telah membuat skrip awk yang membagi sertifikat dan kunci menjadi file terpisah: gist.github.com/jinnko/d6867ce326e8b6e88975
JinnKo
15

The splitperintah tersedia pada kebanyakan sistem, dan doa yang cenderung lebih mudah untuk diingat.

Jika Anda memiliki file collection.pemyang ingin Anda bagi menjadi individual-*file, gunakan:

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

Jika belum split, Anda dapat mencoba csplit:

csplit -f individual- collection.pem '/-----BEGIN CERTIFICATE-----/' '{*}'
squidpickles
sumber
2
Maaf, tidak ada sistem saya (busybox, fedora, centos) yang menampilkan -popsi (atau halaman manual yang saya baca ) secara terpisah. Mungkin Anda menggunakan biner / paket khusus
Cerber
1
@Cerber Bisa mencoba csplitsebagai gantinya ... (lihat edit di atas)
squidpickles
1
bekerja dengan baik dengan csplit!
Cerber
Pada FreeBSD saya dapatkan dari csplit: csplit: *}: bad repetition count(tapi perpecahan tampaknya berhasil)
Gwyneth Llewelyn
4

Jika Anda ingin mendapatkan satu sertifikat dari bundel PEM multi-sertifikat, coba:

$ openssl crl2pkcs7 -nocrl -certfile INPUT.PEM | \
    openssl pkcs7 -print_certs | \
    awk '/subject.*CN=host.domain.com/,/END CERTIFICATE/'
  • Dua opensslperintah pertama akan memproses file PEM dan memuntahkannya dengan pra-pended "subject:"dan "issuer:"baris sebelum setiap sertifikat. Jika PEM Anda sudah diformat dengan cara ini, yang Anda butuhkan hanyalah awkperintah terakhir .
  • Perintah awk akan memuntahkan masing-masing PEM yang cocok dengan string CN (nama umum).

source1 , source2

cmcginty
sumber
Saya tidak melihat ini di sumber Anda. Selain itu, PEM adalah Base64 yang disandikan Anda tidak akan menemukan teks seperti "subjek", "CN", ... dengan awk
Cerber
1
Ya, ini tidak berfungsi untuk setiap jenis PEM. Jika Anda mengekstrak P7B ke PEM menggunakan openssl, itu akan memiliki baris subjek terdaftar sebelum setiap sertifikat. Atau Anda dapat memodifikasi string apa pun yang Anda segmentasikan file PEM Anda.
cmcginty
Jawaban yang diperbarui untuk menangani ketika PEM tidak mengandung "subjek"
cmcginty
3

Juga patut dicatat bahwa file PEM hanya kumpulan kunci / sertifikat di dalam BEGIN/ ENDblok, jadi cukup mudah untuk hanya memotong / menempelkan jika itu hanya satu file dengan satu atau dua entitas yang menarik ...

mgalg
sumber
2

Jika Anda menangani sertifikat rantai penuh (yaitu yang dihasilkan oleh letsencrypt / certbot dll), yang merupakan gabungan dari sertifikat dan rantai otoritas sertifikat, Anda dapat menggunakan manipulasi string bash.

Sebagai contoh:

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

Untuk mengekstrak sertifikat dan rantai otoritas sertifikat ke dalam variabel:

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

Penjelasan:

Alih-alih menggunakan awk atau openssl (yang merupakan alat yang kuat tetapi tidak selalu tersedia, yaitu dalam gambar Docker Alpine), Anda dapat menggunakan manipulasi string bash.

"${FULLCHAIN%%-----END CERTIFICATE-----*}-----END CERTIFICATE-----": dari akhir konten FULLCHAIN, kembalikan pertandingan substring terpanjang, lalu selesaikan -----END CERTIFICATE-----saat dilucuti. The *pertandingan semua karakter setelah -----END CERTIFICATE-----.

$(echo -e "${FULLCHAIN#*-----END CERTIFICATE-----}" | sed '/./,$!d'): dari awal konten FULLCHAIN, kembalikan pertandingan substring terpendek, lalu hapus baris baru. Demikian juga, *cocok dengan semua karakter sebelumnya -----END CERTIFICATE-----.

Untuk referensi cepat (sementara Anda dapat menemukan lebih banyak tentang manipulasi string di bash di sini ):

${VAR#substring}= substring terpendek dari awal konten VAR

${VAR%substring}= substring terpendek dari akhir konten VAR

${VAR##substring}= substring terpanjang dari awal konten VAR

${VAR%%substring}= substring terpanjang dari akhir konten VAR

Fabio
sumber
Untuk yang kurang paham bash, ketika Anda menggemakan variabel-variabel ini mengelilingi variabel dengan tanda kutip untuk mempertahankan garis memecah cara Anda terbiasa melihatnya. Saya ingat ketika itu tidak begitu jelas bagi saya. Fabio, penggunaan manipulasi string bash!
flickerfly
0

Hmmm ... cara yang hampir sama saya menyiapkan solusinya (seperti yang disarankan y @Cerber) tanpa menyadari bahwa situasi ini tampaknya sudah dimiliki banyak orang. Solusi saya mengikuti logika yang hampir sama tetapi menggunakan beberapa perintah yang lebih mendasar:

Semua sertifikat saya ada di file: 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

Ini pada dasarnya terus menulis dalam file sampai menemukan "SELESAI" dan kemudian mulai menulis ke file lain dengan cara bertahap. Dengan cara ini Anda akan memiliki "N" jumlah file output ( certout0.pem, certout1.pem dan sebagainya ..) file tergantung pada berapa banyak sertifikat yang ada di file input pem Anda ( certin.pem ).

Ashish K Srivastava
sumber