如何分割PEM文件


37

注意:这并不是一个真正的问题,因为我已经找到了答案,但是由于我在这里不太容易找到答案,因此我将其发布出来,以使其他人受益。

问题:如何将串联的PEM文件读取为apache / mod_ssl指令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分析一个证书的工具来分别检查证书时,要拆分该文件。
Law

此外,某些工具或服务器需要带有证书和密钥的组合文件,而另一些工具或服务器则希望它们分开。
captncraig

我必须在csplit命令行中添加'%----- BEGIN CERTIFICATE -----%'以防止文件为空。似乎与手册页中指定的内容匹配:csplit -f ./tmp/cert- $ file'%----- BEGIN CERTIFICATE -----%''/ ----- BEGIN CERTIFICATE ----- /''{*}'
Craig Hicks

2
使用“ csplit -z”不留空文件。
Paul M

Answers:


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

好的命令集:)我将其保留以备将来使用,但是在上面的用例中,我正在使用一个仅包含50个CA证书的仅证书文件==> no
pkey

2
我认为这优于awk解决方案,让openssl进行解析+获得转换。
生锈的

抱歉,只有pkey命令正确。第二和第三不做您做广告的事-他们做其他事。在某些情况下,结果是好的,在某些情况下,它可以在消费者中产生神秘的行为。编辑了一下。
kubanczyk

任何想法如何以这种方式获取文本第三证书?
flickerfly


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没有在拆分时显示任何选项(也没有显示我的联机帮助页)。也许您使用的是特殊的二进制文件/软件包
-Cerber

1
@Cerber可以尝试csplit...(请参见上面的编辑)
squidpickles

1
csplit
Cerber '16

在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文件,并在每个证书之前用预先添加的前缀"subject:"和行将其吐出"issuer:"。如果您的PEM已经以这种方式格式化,那么您只需要最后一条awk命令即可。
  • awk命令将吐出与CN(通用名称)字符串匹配的单个PEM。

1源2


我在您的消息来源中看不到此消息。此外,PEM是Base64编码的,您不会找到带有awk的“主题”,“ CN”,...之类的文本
Cerber '16

1
是的,这不适用于每种类型的PEM。如果使用openssl将P7B提取到PEM,它将在每个证书之前列出一个主题行。或者,您可以修改为用于分割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')

说明:

可以使用bash字符串操作来代替使用awk或openssl(它们是功能强大的工具,但并不总是可用,即在Docker Alpine映像中)。

"${FULLCHAIN%%-----END CERTIFICATE-----*}-----END CERTIFICATE-----":从FULLCHAIN内容的末尾开始,返回最长的子字符串匹配项,然后-----END CERTIFICATE-----将其剥离,然后再进行concat处理。本*场比赛中的所有字符之后-----END CERTIFICATE-----

$(echo -e "${FULLCHAIN#*-----END CERTIFICATE-----}" | sed '/./,$!d'):从FULLCHAIN的内容的开头开始,返回最短的子字符串匹配项,然后去除前导新行。同样,*匹配所有之前的字符-----END CERTIFICATE-----

对于一个快速参考(虽然你可以找到更多关于bash的字符串操作在这里):

${VAR#substring}=从VAR内容开始的最短子串

${VAR%substring}= VAR内容末尾最短的子字符串

${VAR##substring}=从VAR内容开始的最长子字符串

${VAR%%substring}= VAR内容末尾最长的子字符串


对于不太精打细算的人,当您回显这些变量时,请在变量周围加上引号,以保留换行符,这是您惯常使用的方式。我记得那对我来说不是那么明显。Fabio,使用bash字符串操纵的效果不错!
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”,然后开始以递增方式写入另一个文件。这样根据输入的pem文件(certin.pem)中有多少个证书您将获得“ N”个输出文件(certout0.pem,certout1.pem等)文件。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.