使用OpenSSL實現私鑰和證書的轉換
近期在項目中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
- Enter Import Password:
- 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
- Enter Import Password:
- MAC verified OK
可以看到,在這里我們多添加了1個-nocerts的參數就做到了不導出證書的操作。那么不導出私鑰的操作應該如下:
- sky@sky-pc:~$ openssl pkcs12 -in key.p12 -nokeys -out cert.pem -nodes
- Enter Import Password:
- MAC verified OK
接下來,我們該如何將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
- Enter Import Password:
- MAC verified OK
- sky@sky-pc:~$ openssl pkcs12 -in cer.p12 -nocerts -out key.pem -nodes
- Enter Import Password:
- MAC verified OK
- sky@sky-pc:~$ cat cert.pem key.pem > certs.pem
我們先只導出客戶端的證書,然后是私鑰,最后我們將2個文件的內容合并在1個文件中即可。