最近项目中需要用到iOS推送APNs,但是公司的iOS女同事(春哥)只给了我2个p12格式的文件。突然发现证书转换的问题比较普遍,比如之前付费开发。程序中实际需要pem格式的证书,所以这里涉及到证书之间的转换。由于私钥和证书可以以不同的格式存储,这意味着我们需要对它们进行转换。最常用的格式如下,首先是证书的格式:二进制DER证书,包括原始格式的X.509证书,使用DERASN.1编码。ASCIIPEM证书(包括base64编码的DER证书)以-----BEGINCERTIFICATE-----开头,以-----ENDCERTIFICATE-----结尾。PKCS#7证书是一种复杂的格式,旨在传输签名或加密的数据,在RFC2315中定义。通常以.p7b和.p7c为后缀,可以包含整个证书链。Java的keytool工具支持这种格式。PKCS#12(PFX)证书和私钥,一种复杂的格式,可以存储和保护服务器的私钥以及完整的证书链。它通常以.p12和.pfx为后缀。此格式常用于Microsoft产品,但也可用于客户端证书。然后是对应私钥的格式:BinaryDERprivatekey,其中包含1个原始形式的私钥,使用DERASN.1编码。OpenSSL以其传统的SSLeay格式创建私钥,但也可以使用另一种称为PKCS#8的格式,但未广泛使用(在RFC5208中定义)。在OpenSSL中,可以使用pkcs8命令来处理PKCS#8格式。ASCII格式的私钥包含一个base64编码的DER私钥,有时还带有一些额外的元信息,例如用于密码保护的算法。说了这么多,可以发现私钥之间的转换要简单很多,只能在DER和PEM格式之间转换。与证书之间的转换相比,它稍微复杂一些。有兴趣的也可以查看我的另一篇文章PKIformatstandard,查看其概念。在这里,我们需要从PKCS#12格式的文件中提取私钥和证书。先从PEM和DER格式的转换说起:PEM和DER转换PEM和DER格式证书的转换可以通过OpenSSL提供的x509工具来完成。接下来,我们将DER格式的证书转换为PEM:sky@sky-pc:~$opensslx509-informDER-inprivate_key.der-outformPEM-outprivate_key.pem这里,我们通过-inform参数指定输入格式为DER,并通过-in参数指定输入文件名,然后对应的-outform和-out用于指定输出格式和文件名。同样,我们也可以将PEM格式的整数转换成DER格式:sky@sky-pc:~$opensslx509-informPEM-inprivate_key.pem-outformDER-outprivate_key.der下面看看如何从PKCS#12格式中提取出私钥和证书。PKCS#12转换我们可以使用OpenSSL提供的pkcs12命令来实现对PKCS#12格式的操作。首先我们将证书和私钥导出为PEM格式:sky@sky-pc:~$opensslpkcs12-inkey.p12-outkey.pem-nodesEnterImportPassword:MACverifiedOK这里我们通过-in参数指定传入的文件名,-outfile指定输出文件名,-nodes参数表示私钥不加密。在这个过程中,我们需要在签名的时候输入密码。如果我们不加-nodes参数,结果会是这样:验证成功,需要重试输入新的加密密码。在导出的文件中,可以看到此时的文件内容为:...-----BEGINENCRYPTEDPRIVATEKEY-----MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIPdUUocbjDXUCAggA...-----ENDENCRYPTEDPRIVATEKEY-----添加后-nodes结果为:...-----BEGINPRIVATEKEY-----MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC+QDKKakQ0fcvH...-----ENDPRIVATEKEY-----之后我们可以使用编辑器打开输出密钥.pem文件,并手动将它们拆分为单独的私钥、证书和中间证书文件。作为程序员,大多数人都是懒惰的。这种繁琐的操作能不能简化一点,让机器自己来做呢?其实是可以做到的。在OpenSSL中提供这样的操作,我们看一下不导出证书的操作,这样我们就可以得到私钥了:sky@sky-pc:~$opensslpkcs12-inkey.p12-nocerts-outprivate_key.pem-nodesEnterImportPassword:MACverifiedOK可以看到这里我们多加了一个-nocerts参数来实现不导出证书的操作。那么不导出私钥的操作应该是这样的:sky@sky-pc:~$opensslpkcs12-inkey.p12-nokeys-outcert.pem-nodesEnterImportPassword:MACverifiedOK接下来我们如何将证书和私钥导出为PEM格式到PKCS#12格式,我们可以这样操作::其中-name选项指定证书中的friendlyName,-certfile指定信任链的文件名。最后,我们还可以通过-clcerts和-cacerts选项指定是否只导出客户端和CA证书。PKCS#7转换要将PEM转换为PKCS#7,我们可以使用crl2pkcs7命令。sky@sky-pc:~$opensslcrl2pkcs7-nocrl-outkey.p7b-certfilecert.pem-certfilefd-chain.crt然后,生成的文件头将以-----BEGINPKCS7-----开头。最后,要将PKCS#7转换为PEM,我们可以使用pkcs7命令:sky@sky-pc:~$opensslpkcs7-inkey.p7b-print_certs-outkey1.pem在这里,我们使用-print_certs参数输出输入证书。PKCS#8和SSLeay转换如果我们想将PKCS#8格式的私钥转换为SSLeay格式,我们可以这样做:sky@sky-pc:~$opensslrsa-inkey.pem-outssleay.pemwritingRSAkey并在此timethefile内容将如下:-----BEGINRSAPRIVATEKEY-----MIIEpQIBAAKCAQEAvkAyimpENH3Lx4d8VH96XCYfKfCZ7qVtNuVseAvkSTC0q5dw...-----ENDRSAPRIVATEKEY-----可以看到头尾都加了RSA字样.而如果我们要将传统的SSLeay私钥转换成PKCS#格式,需要使用pkcs8命令:,它会对这个格式进行一次加密过程,但是我们可以通过-nocrypt参数来防止它被加密:sky@sky-pc:~$opensslpkcs8-topk8-nocrypt-inssleay.pem-outpkcs8_key.pem可以实现我们将传统的SSLeay格式转换为PKCS#8格式。在APNs中生成证书让我们生成APNs推送所需的证书。sky@sky-pc:~$opensslpkcs12-incer.p12-clcerts-nokeys-outcert.pem-nodesEnterImportPassword:MACverifiedOKsky@sky-pc:~$opensslpkcs12-incer.p12-nocerts-outkey.pem-nodesEnterImportPassword:MACverifiedOKsky@sky-pc:~$catcert.pemkey.pem>certs.pem我们只是先导出客户端的证书,然后是私钥,最后我们将两个文件的内容合并为一个文件。
