近期在项目中ios需要用到apns的推送,而公司的ios女同事(纯哥)只给了我2个p12格式的文件。突然发现,证书的转换问题还是比较常见的,比如之前支付开发。而在程序中,实际需要使用的是pem格式的证书,因此这里涉及到证书之间的转换问题。
由于私钥和证书可以以不同格式的存储,这意味着我们需要对它们进行转换。而大多数常用的格式如下,首先是证书的格式:
二进制的der证书,包含x.509证书为原始格式,使用der asn.1编码。
ascii的pem证书,包含1个base64编码的der证书,以-----begin certificate-----开头而以-----end certificate-----结束。
pkcs#7证书,1个复杂格式的设计用于传输签名或加密数据,定义在rfc 2315中。通常以.p7b和.p7c作为后缀且可以包含整个证书链。这种格式被java的keytool工具支持。
pkcs#12(pfx)的证书和私钥,1个复杂的格式它可以存储和保护1个服务器的私钥并和1个完整的证书链一起。它通常以.p12和.pfx为后缀。这种格式常用于微软的产品,不过也可以用于客户端证书。
然后是对应的私钥的格式:
二进制的der私钥,包含1个私钥以原始形式,使用der asn.1编码。openssl以它传统的ssleay格式创建私钥,不过也可以使用另外1种称为pkcs#8,但不广泛使用的格式(定义在rfc 5208)。在openssl中可以使用pkcs8命令来进行pkcs#8格式的处理操作。
ascii格式的私钥,包含1个base64编码的der私钥,有些时候有一些额外的元信息,例如密码保护采用的算法。
说了这么多,可以发现对于私钥之间的转换就简单的很多,只能在der和pem格式之间进行转换。而相比证书之间的转换,就稍微复杂一些。
如果有兴趣还可以查看我的另一篇文章pki格式标准查看其概念。
在这里,我们需要将pkcs#12格式的文件中提取出私钥和证书。下面我们先从pem和der格式的转换开始:
pem和der转换
pem和der格式证书的转换可以通过openssl提供的x509工具来完成。下面我们转换1个der格式的证书为pem:
sky@sky-pc:~$ openssl x509 -inform der -in private_key.der -outform pem -out private_key.pem
在这里,我们通过-inform参数指定输入的格式为der,通过-in参数指定输入的文件名称,而后对应的-outform和-out用于指定输出的格式及文件名称。
同样的,我们也可以将pem格式的整数转换为der格式:
sky@sky-pc:~$ openssl x509 -inform pem -in private_key.pem -outform der -out private_key.der
下面我们来看下如何从pkcs#12格式中提取出私钥和证书。
pkcs#12转换
我们可以使用openssl提供的pkcs12命令来实现pkcs#12格式的操作,首先我们将证书和私钥导出为pem格式:
sky@sky-pc:~$ openssl pkcs12 -in key.p12 -out key.pem -nodes
enter import password:
mac verified ok
在这里,我们通过-in参数指定传入的文件名称,而-out文件指定输出的文件名称,而-nodes参数表示不对私钥进行加密。在这个过程中,我们需要输入签名时的密码。
如果我们不添加-nodes参数,将是如下的结果:
sky@sky-pc:~$ openssl pkcs12 -in key.p12 -out key.pem
mac verified ok
enter pem pass phrase:
verifying - enter pem pass phrase:
可以看到,验证签名成功后还需要我们重新输入新的加密口令。而在导出的文件中可以看到此时文件的内容为:
...
-----begin encrypted private key-----
miifdjbabgkqhkig9w0bbq0wmzabbgkqhkig9w0bbqwwdgqipduuocbjdxucagga
-----end encrypted private key-----
而添加-nodes后的结果为:
-----begin private key-----
miievwibadanbgkqhkig9w0baqefaascbkkwggslageaaoibaqc+qdkkakq0fcvh
-----end private key-----
之后,我们就可以使用编辑器打开输出的key.pem文件,手动的拆分它们为独立的私钥、证书和中间证书文件。
作为程序猿,一般人都是懒惰的,这个繁琐的操作能不能简便些呢,让机器自己去完成呢?
其实是可以做到的,在openssl中提供这样的操作,我们先来看看不导出证书的操作,这样我们就可以得到私钥了:
sky@sky-pc:~$ openssl pkcs12 -in key.p12 -nocerts -out private_key.pem -nodes
可以看到,在这里我们多添加了1个-nocerts的参数就做到了不导出证书的操作。那么不导出私钥的操作应该如下:
sky@sky-pc:~$ openssl pkcs12 -in key.p12 -nokeys -out cert.pem -nodes
接下来,我们该如何将pem格式的证书和私钥导出为pkcs#12格式呢,我们可以这样来操作:
sky@sky-pc:~$ openssl pkcs12 -name "my certificate" -export -out fd.p12 -inkey key.pem -in cert.pem -certfile fd-chain.crt
enter export password:
verifying - enter export password:
其中,-name选项指定了证书中的friendlyname,而-certfile指定信任链的文件名称。
最后,我们还可以通过-clcerts和-cacerts选项指定是否只导出客户端及ca证书。
pkcs#7转换
为了转换pem为pkcs#7,我们可以使用crl2pkcs7命令。
sky@sky-pc:~$ openssl crl2pkcs7 -nocrl -out key.p7b -certfile cert.pem -certfile fd-chain.crt
那么,生成的文件头部将以-----begin pkcs7-----开始。
最后,为了转换pkcs#7为pem,我们可以使用pkcs7命令:
sky@sky-pc:~$ openssl pkcs7 -in key.p7b -print_certs -out key1.pem
在这里,我们使用-print_certs参数将输入的证书输出。
pkcs#8与ssleay转换
如果我们想将pkcs#8格式的私钥转换为ssleay格式,我们可以这样来操作:
sky@sky-pc:~$ openssl rsa -in key.pem -out ssleay.pem
writing rsa key
而此时文件的内容将如下所示:
-----begin rsa private key-----
miiepqibaakcaqeavkayimpenh3lx4d8vh96xcyfkfcz7qvtnuvseavkstc0q5dw
-----end rsa private key-----
可以看到头部和尾部多追加了rsa的字样。
而如果要将传统的ssleay私钥转换为pkcs#格式,我们需要使用pkcs8命令:
sky@sky-pc:~$ openssl pkcs8 -topk8 -in ssleay.pem -out pkcs8_key.pem
enter encryption password:
verifying - enter encryption password:
默认情况下,会为该格式进行1个加密的处理,但是我们可以通过-nocrypt参数让其不进行加密处理:
sky@sky-pc:~$ openssl pkcs8 -topk8 -nocrypt -in ssleay.pem -out pkcs8_key.pem
可以我们便实现了将传统的ssleay格式转换为pkcs#8格式了。
apns中证书的生成
下面我们来生成apns推送时需要的证书。
sky@sky-pc:~$ openssl pkcs12 -in cer.p12 -clcerts -nokeys -out cert.pem -nodes
sky@sky-pc:~$ openssl pkcs12 -in cer.p12 -nocerts -out key.pem -nodes
sky@sky-pc:~$ cat cert.pem key.pem > certs.pem
我们先只导出客户端的证书,然后是私钥,最后我们将2个文件的内容合并在1个文件中即可。
作者:我勒个去
来源:51cto