วิธีการแยกไฟล์ PEM


37

หมายเหตุ:นี่ไม่ใช่คำถามจริง ๆ เพราะฉันพบคำตอบแล้ว แต่เนื่องจากฉันไม่พบมันได้อย่างง่ายดายที่นี่ฉันจะโพสต์มันเพื่อให้เป็นประโยชน์ต่อผู้อื่น

คำถาม:วิธีการอ่านไฟล์ PEM ที่ต่อกันเป็นไฟล์ที่ใช้โดย apache / mod_ssl directive SSLCACertificateFile ?

คำตอบ (ต้นฉบับ) ( แหล่งที่มา ):

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

openssl pkcs7 -outform PEM -in my-chain-file -print_certsนี้สามารถออกจากไฟล์ที่ว่างเปล่าถ้ามีบรรทัดว่างที่สิ้นสุดเช่นกับ หากต้องการป้องกันให้ตรวจสอบความยาวของเส้นก่อนพิมพ์:

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

คำตอบ 29/03/2016 :

ต่อไปนี้ @slugchewer คำตอบ , csplitอาจเป็นตัวเลือกที่ชัดเจนด้วย:

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

นี่อาจเป็นคำถามที่โง่ แต่ทำไมฉันต้องแยกไฟล์ pem ของฉัน
Ashwani Agarwal

6
@AshwaniAgarwal คุณต้องการแยกไฟล์ PEM เมื่อมีใบรับรองหลายใบและคุณต้องการตรวจสอบใบรับรองแต่ละรายการด้วยเครื่องมือต่าง ๆ เช่นopensslที่ใช้ใบรับรองหนึ่งใบเพื่อวิเคราะห์
กฎหมาย

นอกจากนี้เครื่องมือหรือเซิร์ฟเวอร์บางตัวต้องการไฟล์รวมกับใบรับรองและคีย์ในขณะที่เครื่องมืออื่นต้องการแยกไฟล์
captncraig

ฉันต้องเพิ่ม '% ----- BEGIN CERTIFICATE -----%' ลงในบรรทัดคำสั่ง csplit เพื่อป้องกันไฟล์ว่าง ดูเหมือนว่าจะตรงกับสิ่งที่ man page ระบุ: csplit -f ./tmp/cert- $ file '% ----- BEGIN CERTIFICATE -----%' '/ ----- BEGIN CERTIFICATE ----- / '' {*} '
Craig Hicks

2
ใช้ "csplit -z" เพื่อไม่ปล่อยไฟล์ว่างเปล่า
พอล M

คำตอบ:


23

ตัวอย่างข้อมูล awk ใช้สำหรับการแยกส่วนต่าง ๆ แต่คุณยังจำเป็นต้องรู้ว่าส่วนใดเป็นกุญแจ / ใบรับรอง / ลูกโซ่ ฉันต้องการแยกส่วนที่เฉพาะเจาะจงและพบสิ่งนี้ในรายการส่งเมลของ 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

ชุดคำสั่งที่ดี :) ฉันจะเก็บไว้เพื่อการใช้งานในอนาคต แต่ในกรณีการใช้งานของฉันข้างต้นฉันทำงานกับไฟล์ใบรับรองอย่างเดียวที่มีใบรับรอง CA 50+ ==> ไม่มี pkey หรือ chain
Cerber

2
ฉันคิดว่านี่ยอดเยี่ยมกว่า awk solution ปล่อยให้ openssl ทำการแยกวิเคราะห์ + คุณจะได้รับการแปลง
Rusty

ฉันขอโทษ แต่คำสั่ง pkey เท่านั้นที่ถูกต้อง ที่สองและสามไม่ได้ทำสิ่งที่คุณโฆษณา - พวกเขาทำอย่างอื่น ในบางกรณีผลลัพธ์นั้นดีในบางกรณีมันสามารถสร้างพฤติกรรมลึกลับในผู้บริโภค แก้ไขนิดหน่อย
kubanczyk

ความคิดใดที่จะได้รับใบรับรองที่เป็นข้อความที่ 3 ในลักษณะนี้
flickerfly

15

นี้ได้รับการตอบก่อนหน้านี้ใน StackOverflow :

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

แก้ไข 29/03/2016 : ดูคำตอบ @slugchewer


ใช้งานได้กับ Linux เท่านั้นล้มเหลวบน FreeBSD
Michael-O

3
ได้รับแรงบันดาลใจจากสิ่งนี้ฉันได้สร้างสคริปต์ awk ที่แยก certs และกุญแจออกเป็นไฟล์แยกกัน: gist.github.com/jinnko/d6867ce326e8b6e88975
JinnKo

15

splitคำสั่งที่มีอยู่ในระบบมากที่สุดและการภาวนาของตนมีแนวโน้มที่ง่ายต่อการจดจำ

หากคุณมีไฟล์collection.pemที่คุณต้องการแยกเป็นindividual-*ไฟล์ให้ใช้:

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

หากคุณไม่มีsplitคุณสามารถลองcsplit:

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

2
ขออภัยระบบของฉัน (busybox, fedora, centos) ไม่แสดง-pตัวเลือก (หรือmanpages ที่ฉันอ่าน ) แยกออกมา บางทีคุณอาจใช้ไบนารี / แพ็คเกจพิเศษ
Cerber

1
@Cerber สามารถลองcsplitใช้แทน ... (ดูการแก้ไขด้านบน)
squidpickles

1
ทำงานได้ดีกับcsplit!
Cerber

ใน FreeBSD ฉันได้รับจาก csplit: csplit: *}: bad repetition count(แต่ดูเหมือนว่าจะทำงานได้ไม่ดี)
Gwyneth Llewelyn

4

หากคุณต้องการได้รับใบรับรองเดียวจากกลุ่ม PEM หลายใบรับรองลอง:

$ openssl crl2pkcs7 -nocrl -certfile INPUT.PEM | \
    openssl pkcs7 -print_certs | \
    awk '/subject.*CN=host.domain.com/,/END CERTIFICATE/'
  • opensslคำสั่งสองคำแรกจะประมวลผลไฟล์ PEM และแยกออกมาพร้อมกับ pre-pended "subject:"และ"issuer:"บรรทัดก่อนแต่ละใบรับรอง หาก PEM ของคุณได้รับการจัดรูปแบบด้วยวิธีนี้สิ่งที่คุณต้องมีก็คือawkคำสั่งสุดท้าย
  • คำสั่ง awk จะคาย PEM แต่ละรายการที่ตรงกับสตริง CN (ชื่อสามัญ)

source1 , source2


ฉันไม่เห็นสิ่งนี้ในแหล่งที่มาของคุณ นอกจากนี้ PEM จะถูกเข้ารหัส Base64 คุณจะไม่พบข้อความเช่น "หัวเรื่อง", "CN", ... ด้วย awk
Cerber

1
ใช่มันใช้ไม่ได้กับ PEM ทุกประเภท หากคุณแยก P7B เป็น PEM โดยใช้ openssl จะมีบรรทัดหัวเรื่องอยู่ก่อนใบรับรองแต่ละใบ หรือคุณสามารถแก้ไขสตริงใด ๆ ที่คุณแบ่งไฟล์ PEM ของคุณด้วย
cmcginty

คำตอบที่ได้รับการอัปเดตเพื่อจัดการเมื่อ PEM ไม่มี "เรื่อง"
cmcginty

3

นอกจากนี้ยังมีข้อสังเกตว่าไฟล์ PEMเป็นเพียงชุดของคีย์ / ใบรับรองภายในBEGIN/ ENDบล็อกดังนั้นจึงค่อนข้างง่ายที่จะตัด / วางหากเป็นไฟล์เดียวที่มีหนึ่งหรือสองรายการที่น่าสนใจ ...


2

หากคุณกำลังจัดการใบรับรองลูกโซ่แบบเต็ม (เช่นใบรับรองที่สร้างขึ้นโดย letsencrypt / certbot ฯลฯ ) ซึ่งเป็นการเชื่อมต่อใบรับรองและห่วงโซ่ผู้ออกใบรับรองคุณสามารถใช้การจัดการสตริงของ bash

ตัวอย่างเช่น:

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

ในการแยกใบรับรองและห่วงโซ่ผู้ออกใบรับรองให้เป็นตัวแปร:

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

คำอธิบาย:

แทนที่จะใช้ awk หรือ openssl (ซึ่งเป็นเครื่องมือที่ทรงพลัง แต่ไม่สามารถใช้ได้ตลอดเวลาเช่นในรูปภาพ Docker Alpine) คุณสามารถใช้การจัดการสตริงของ bash

"${FULLCHAIN%%-----END CERTIFICATE-----*}-----END CERTIFICATE-----": จากจุดสิ้นสุดของเนื้อหาของ FULLCHAIN ​​ให้ส่งคืนการจับคู่สตริงย่อยที่ยาวที่สุดจากนั้นต่อ-----END CERTIFICATE-----ด้วยการถอดออก ตรงกับตัวอักษรของทุกหลัง*-----END CERTIFICATE-----

$(echo -e "${FULLCHAIN#*-----END CERTIFICATE-----}" | sed '/./,$!d'): จากจุดเริ่มต้นของเนื้อหาของ FULLCHAIN ​​ส่งคืนการจับคู่สตริงย่อยที่สั้นที่สุดจากนั้นตัดส่วนนำหน้าของบรรทัดใหม่ ในทำนองเดียวกันตรงกับตัวละครทุกตัวก่อน*-----END CERTIFICATE-----

สำหรับการอ้างอิงอย่างรวดเร็ว (ในขณะที่คุณสามารถค้นหาเพิ่มเติมเกี่ยวกับการจัดการสตริงในการทุบตีที่นี่ ):

${VAR#substring}= สตริงย่อยสั้นที่สุดจากจุดเริ่มต้นของเนื้อหาของ VAR

${VAR%substring}= สตริงย่อยสั้นที่สุดจากจุดสิ้นสุดของเนื้อหาของ VAR

${VAR##substring}= สตริงย่อยที่ยาวที่สุดจากจุดเริ่มต้นของเนื้อหาของ VAR

${VAR%%substring}= สตริงย่อยที่ยาวที่สุดจากจุดสิ้นสุดของเนื้อหาของ VAR


สำหรับความเข้าใจในการทุบตีที่น้อยลงเมื่อคุณสะท้อนตัวแปรเหล่านี้ให้ล้อมรอบตัวแปรด้วยเครื่องหมายคำพูดเพื่อรักษาเส้นแบ่งตามวิธีที่คุณใช้ในการมองเห็นพวกเขา ฉันจำได้ว่าเมื่อไม่เห็นได้ชัดสำหรับฉัน Fabio การใช้การจัดการสตริงทุบตีหวาน!
flickerfly

0

อืม ... เกือบจะเหมือนกันที่ฉันได้เตรียมวิธีแก้ปัญหา (ตามที่แนะนำ y @Cerber) โดยไม่ทราบว่าสถานการณ์นี้ดูเหมือนว่าหลายคนจะมี โซลูชันของฉันใช้ตรรกะเกือบเหมือนกัน แต่ใช้คำสั่งพื้นฐานเพิ่มเติม:

ใบรับรองทั้งหมดของฉันอยู่ในไฟล์: 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

โดยทั่วไปจะเขียนในไฟล์จนกว่าจะพบ "END" จากนั้นเริ่มเขียนไปยังไฟล์อื่นด้วยวิธีที่เพิ่มขึ้น วิธีนี้คุณจะมีไฟล์ "N" จำนวนไฟล์เอาต์พุต ( certout0.pem, certout1.pemและอื่น ๆ .. ) ขึ้นอยู่กับจำนวนใบรับรองที่มีในไฟล์อินพุต pem ของคุณ ( certin.pem )

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.