Cách chia tệp PEM


37

Lưu ý: Đây thực sự không phải là một câu hỏi vì tôi đã tìm thấy câu trả lời nhưng vì tôi không tìm thấy nó dễ dàng ở đây nên tôi sẽ đăng nó để nó có thể mang lại lợi ích cho người khác.

Câu hỏi: Làm thế nào để đọc tệp PEM được nối với nhau như tệp được sử dụng bởi lệnh apache / mod_ssl SSLCACertertFile ?

Trả lời (bản gốc) ( nguồn ):

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

Điều này có thể để lại một tập tin trống nếu có một dòng trống ở cuối, chẳng hạn như với openssl pkcs7 -outform PEM -in my-chain-file -print_certs. Để ngăn chặn điều đó, hãy kiểm tra độ dài của dòng trước khi in:

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

Trả lời 29/03/2016 :

Theo câu trả lời @slugchewer , csplitcó thể là một tùy chọn rõ ràng hơn với:

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

Đây có thể là một câu hỏi ngớ ngẩn, nhưng tại sao tôi cần phải chia tập tin pem của mình?
Ashwani Agarwal

6
@AshwaniAgarwal Bạn muốn tách một tệp PEM khi nó chứa một số chứng chỉ và bạn muốn kiểm tra các chứng chỉ riêng lẻ bằng các công cụ như openssllấy một chứng chỉ để phân tích.
Luật29

Ngoài ra, một số công cụ hoặc máy chủ muốn có tệp kết hợp với cert và key, trong khi những công cụ khác muốn tách riêng chúng.
captncraig

Tôi đã phải thêm '% ----- BEGIN CHỨNG NHẬN -----%' vào dòng lệnh csplit để ngăn chặn một tệp trống. Có vẻ khớp với những gì trang man chỉ định: csplit -f ./tmp/cert- $ file '% ----- BEGIN CHỨNG NHẬN -----%' '/ ----- BEGIN CHỨNG NHẬN ----- / '' {*} '
Craig Hicks

2
sử dụng "csplit -z" để không để các tệp trống.
Paul M

Câu trả lời:


23

Đoạn mã awk hoạt động để trích xuất các phần khác nhau, nhưng bạn vẫn cần biết phần nào là khóa / cert / chain. Tôi cần trích xuất một phần cụ thể và tìm thấy phần này trong danh sách gửi thư 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

bộ lệnh đẹp :) Tôi sẽ giữ nó để sử dụng trong tương lai, nhưng trong trường hợp sử dụng của tôi ở trên, tôi đang làm việc với một tệp chỉ có chứng chỉ chứa 50+ CA certs ==> không có pkey hay chuỗi
Cerber

2
Tôi nghĩ rằng điều này là vượt trội so với giải pháp awk, hãy để openssl thực hiện phân tích cú pháp + bạn nhận được chuyển đổi.
Rusty

Tôi xin lỗi nhưng chỉ có lệnh pkey là chính xác. Thứ hai và thứ ba không làm những gì bạn quảng cáo - họ làm một cái gì đó khác. Trong một số trường hợp, kết quả là tốt trong một số trường hợp, nó có thể tạo ra những hành vi bí ẩn ở người tiêu dùng. Chỉnh sửa một chút.
kubanchot

Bất kỳ ý tưởng làm thế nào để có được chứng chỉ thứ 3 bằng văn bản theo cách này?
flickerfly

15

Điều này đã được trả lời trước đây trên StackOverflow :

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

Chỉnh sửa 29/03/2016 : Xem câu trả lời @slugchewer


Chỉ hoạt động trên Linux, không thành công trên FreeBSD.
Michael-O

3
Lấy cảm hứng từ này tôi đã tạo ra một kịch bản awk mà chia ra Certs và các phím vào các tập tin riêng biệt: gist.github.com/jinnko/d6867ce326e8b6e88975
JinnKo

15

Các splitlệnh có sẵn trên hầu hết các hệ thống, và gọi nó là khả năng dễ nhớ hơn.

Nếu bạn có một tệp collection.pemmà bạn muốn chia thành individual-*các tệp, hãy sử dụng:

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

Nếu bạn không có split, bạn có thể thử csplit:

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

2
Xin lỗi, không có hệ thống nào của tôi (busybox, fedora, centos) hiển thị -ptùy chọn (cũng không phải các trang tôi đọc ) khi chia. Có thể bạn đang sử dụng gói / nhị phân đặc biệt
Cerber

1
@Cerber Có thể thử csplitthay thế ... (xem chỉnh sửa ở trên)
squidpickles

1
hoạt động tốt với csplit!
Cerber

Trên FreeBSD tôi nhận được từ csplit: csplit: *}: bad repetition count(nhưng dường như sự phân chia hoạt động)
Gwyneth Llewelyn

4

Nếu bạn muốn nhận một chứng chỉ duy nhất trong gói PEM đa chứng chỉ, hãy thử:

$ openssl crl2pkcs7 -nocrl -certfile INPUT.PEM | \
    openssl pkcs7 -print_certs | \
    awk '/subject.*CN=host.domain.com/,/END CERTIFICATE/'
  • Hai openssllệnh đầu tiên sẽ xử lý tệp PEM và nhổ nó trở lại với các dòng được đặt trước "subject:""issuer:"các dòng trước mỗi chứng chỉ. Nếu PEM của bạn đã được định dạng theo cách này, tất cả những gì bạn cần là awklệnh cuối cùng .
  • Lệnh awk sẽ nhổ PEM riêng lẻ khớp với chuỗi CN (tên chung).

nguồn1 , nguồn2


Tôi không thấy điều này trong nguồn của bạn. Bên cạnh đó, PEM được mã hóa Base64 mà bạn sẽ không tìm thấy văn bản như "chủ đề", "CN", ... với awk
Cerber

1
Có, điều này không hoạt động đối với mọi loại PEM. Nếu bạn trích xuất P7B sang PEM bằng openssl, nó sẽ có một dòng chủ đề được liệt kê trước mỗi chứng chỉ. Hoặc bạn có thể sửa đổi thành bất kỳ chuỗi nào bạn phân đoạn tệp PEM của mình.
cmcginty

Câu trả lời được cập nhật để xử lý khi PEM không chứa "chủ đề"
cmcginty

3

Cũng đáng lưu ý rằng các tệp PEM chỉ là một tập hợp các khóa / chứng chỉ bên trong BEGIN/ ENDkhối, do đó, thật dễ dàng để cắt / dán nếu đó chỉ là một tệp duy nhất có một hoặc hai thực thể thú vị ...


2

Nếu bạn đang xử lý chứng chỉ chuỗi đầy đủ (tức là chứng chỉ được tạo bởi letencrypt / certbot, v.v.), đó là sự kết hợp giữa chứng chỉ và chuỗi ủy quyền chứng chỉ, bạn có thể sử dụng thao tác chuỗi bash.

Ví dụ:

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

Để trích xuất chứng chỉ và chuỗi quyền hạn chứng chỉ thành các biến:

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

Giải trình:

Thay vì sử dụng awk hoặc openssl (là những công cụ mạnh mẽ nhưng không phải lúc nào cũng có sẵn, tức là trong hình ảnh Docker Alpine), bạn có thể sử dụng thao tác chuỗi bash.

"${FULLCHAIN%%-----END CERTIFICATE-----*}-----END CERTIFICATE-----": từ cuối nội dung của FULLCHAIN, trả lại kết quả chuỗi con dài nhất, sau đó nối lại -----END CERTIFICATE-----khi nó bị xóa. Các *trận đấu tất cả các nhân vật sau -----END CERTIFICATE-----.

$(echo -e "${FULLCHAIN#*-----END CERTIFICATE-----}" | sed '/./,$!d'): từ đầu nội dung của FULLCHAIN, trả về kết quả chuỗi con ngắn nhất, sau đó loại bỏ các dòng mới. Tương tự như vậy, *phù hợp với tất cả các nhân vật trước đó -----END CERTIFICATE-----.

Để tham khảo nhanh (trong khi bạn có thể tìm hiểu thêm về thao tác chuỗi trong bash tại đây ):

${VAR#substring}= chuỗi con ngắn nhất từ ​​đầu nội dung của VAR

${VAR%substring}= chuỗi con ngắn nhất từ ​​cuối nội dung của VAR

${VAR##substring}= chuỗi con dài nhất từ ​​đầu nội dung của VAR

${VAR%%substring}= chuỗi con dài nhất từ ​​cuối nội dung của VAR


Đối với những người ít hiểu biết về bash, khi bạn lặp lại các biến này, hãy bao quanh biến đó bằng dấu ngoặc kép để bảo toàn dòng phá vỡ cách bạn đã quen nhìn thấy chúng. Tôi nhớ khi đó không rõ ràng với tôi. Fabio, sử dụng ngọt ngào của thao tác chuỗi bash!
flickerfly

0

Hmmm ... gần giống như cách tôi đã chuẩn bị giải pháp (như đề xuất y @Cerber) mà không nhận ra rằng tình huống này có vẻ như nhiều người mắc phải. Giải pháp của tôi tuân theo logic gần như giống nhau nhưng sử dụng một số lệnh cơ bản hơn:

Tất cả các certs của tôi là trong tập tin: 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

Điều này về cơ bản tiếp tục ghi vào một tệp cho đến khi gặp "KẾT THÚC" và sau đó bắt đầu ghi vào một tệp khác theo cách tăng dần. Bằng cách này, bạn sẽ có số lượng tệp "N" ( certout0.pem, certout1.pem, v.v. ) tùy thuộc vào số lượng chứng chỉ có trong tệp pem đầu vào của bạn ( certin.pem ).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.