從樣板戲《紅燈記》到好萊塢諜戰大片《風語者Windtalkers》等,許許多多動人故事都圍繞一個密電碼展開。那個年代通信密碼學裏都採用如今稱爲對稱密碼的技術,在這種技術中,加密和解密都使用同一個密鑰。因此,密鑰的保存運輸對通信的安全性顯得尤爲重要。直到70年代非對稱密碼技術的出現,情況才真正得到改善。在非對稱密碼技術中密鑰是成對出現的,一個私鑰一個公鑰。通信方只要妥善保管好私鑰而開放公鑰,就能保證安全通信。
非對稱密碼技術的出現,讓人們發現了另一個用途:數字簽名。它和合同商業文書的紙上簽名一樣,用於鑑別數字文書真實性的方法。一套數字簽名通常定義兩種互補的對數字文書的密鑰運算,私鑰用於簽名,而公鑰用於驗證。
網絡是一個開放的世界,服務器可以被不法節點冒名頂替,傳輸的數據可以被整個通路上的任何一個節點監聽。要保證客戶機和服務器在網絡中通信的安全,客戶機首先要檢查數字簽名以驗明服務器正身,然後還要加密要傳輸的數據,該數據到達服務器後再進行解密。非對稱密碼技術完滿地滿足了這兩種技術訴求。
1. 簡說RSA
作爲非對稱密碼技術典範的RSA是MIT的Rivest、Shamir和Adleman在1977年提出,他們是少有的幾個能用數學換豪宅豪車的天才。三個人以RSA技術成立了數家公司,最有名的當數RSA Security和VeriSign,兩家公司最終分別被EMC和Symantec以21億和12.8億美元收購。1983年RSA算法申請了專利,直到2000年9月按專利法失效。由於RSA的廣泛應用,發明人被授予2002年度的圖靈獎。RSA算法需要少少的數學基礎,濃縮如下。
1.1 同餘
稱a、b對N同餘,記爲a ≡ b (mod N),當且僅當a、b除以N之後的餘數相等。
加法性質:若a1 ≡ b1 (mod N),a2 ≡ b2 (mod N),則(a1 + a2) ≡ (b1 + b2) (mod N)。
乘法性質:若a1 ≡ b1 (mod N),a2 ≡ b2 (mod N),則a1 * a2 ≡ b1 * b2 (mod N)。
模數性質:若a ≡ b (mod N1),a ≡ b (mod N2),則a ≡ b (mod lcm[N1, N2]),其中 lcm[N1, N2]爲N1, N2的最小公倍數。
1.2 歐拉函數
在小於等於N的正整數之中,與N構成互質關係(coprime)的整數的個數稱爲歐拉函數φ(N)。
質數的歐拉函數:顯然,如果N是質數,則 φ(N)=N-1 。因爲質數N與小於它的每一個數都構成互質關係。
質數乘積的歐拉函數:若p1和p2是質數,則 φ(p1*p2) = φ(p1)*φ(p2) = (p1-1)*(p2-1) 。
1.3 歐拉定理
如果兩個正整數a和N互質,則N的歐拉函數 φ(N) 可以讓下面的等式成立:
a φ(N) ≡ 1 (mod N)
1.4 費馬小定理
歐拉定理中,當N爲質數時,任何小於N的整數a,都和N互質。因此作爲其特例
若N爲質數,則:a N-1 ≡ 1 (mod N)
1.5 RSA原理
㈠ 首先隨機選取2個大質數p1和p2,p1≠p2,令N=p1*p2,由此可得φ(N)=(p1-1)*(p2-1);
㈡ 隨機取一個小於φ(N),且與φ(N)互質的整數e;
㈢ 計算e對φ(N)的模反元素d,它滿足 e * d ≡ 1 (mod φ(N))。記d爲 d ≡ e-1 (mod φ(N));
㈣ 把(N,d)妥善保管作爲私鑰,(N,e)公開作爲公鑰。對於任何信息m,我們有
m ≡ me * d (mod N)
證明如下:
因爲 e * d ≡ 1 (mod (p1-1)*(p2-1)),所以存在整數k使 ed = k * (p1-1) * (p2-1) + 1
因此 me * d ≡ m * mk*(p1-1)*(p2-1) (mod N)
因p1和p2爲質數,由費馬小定理,mk*(p1-1)*(p2-1) ≡ 1 (mod p1),mk*(p1-1)*(p2-1) ≡ 1 (mod p2)
所以 mk*(p1-1)*(p2-1) ≡ 1 (mod lcm[p1,p2]),即 mk*(p1-1)*(p2-1) ≡ 1 (mod N)
根據同餘乘法性質,me * d ≡ m (mod N)
證明畢。
1.6 基於RSA的加密解密方法
發送方加密:以接受方公鑰(N,e)對信息m計算 me (mod N)
接受方解密:以接受方私鑰(N,d)還原信息m,計算 (me (mod N))d = me * d (mod N) = m
1.7 基於RSA的數字簽名方法
發送方簽名:以發送方私鑰(N,d)對信息m的散列函數h(m),計算 h(m)d (mod N) = h
接受方驗證:用發送方公鑰(N,e)計算 (hd (mod N))e = he * d (mod N) = h,比較其是否與h(m)值一致
基於RSA的網絡通信過程在X.509規範的公鑰體系(PKI - public key infrastructure)下得到完成,數據的加密解密由安全套接字層(SSL - secure socket layer)或傳輸層安全(TLS - transport layer security)實現。當客戶機需要與某個服務器建立通信連接時,雙方發生SSL握手過程:
客戶機通過網絡發送請求安全會話的消息(通常請求是HTTPS協議的形式)。服務器通過發送其X.509證書(包含公鑰)進行響應。
客戶機驗證服務器證書的有效性,並檢驗該證書是否由可信任的證書認證機構(CA - certification authority)所簽發。
當證書有效,客戶機生成一次性的密鑰,並用服務器的公鑰對該密鑰進行加密。然後,客戶機把加密的會話密鑰發送給服務器。
服務器用其私鑰對其次進行解密,然後得到本次通訊的會話密鑰。
客戶機和服務器用其約定的會話密鑰開始數據通信,直到一次會話結束。
由於編寫密鑰代碼的複雜性,許多網站使用開源免費軟件。OpenSSL就是這樣的一套原碼公開的C語言函數庫,它最初由Eric和Tim在入職RSA公司前開發,其豐富的在線使用手冊可以通過下列命令得到:
$ openssl -help Standard commands asn1parse ca ciphers cms crl crl2pkcs7 dgst dh dhparam dsa dsaparam ec ecparam enc engine errstr gendh gendsa genpkey genrsa nseq ocsp passwd pkcs12 pkcs7 pkcs8 pkey pkeyparam pkeyutl prime rand req rsa rsautl s_client s_server s_time sess_id smime speed spkac ts verify version x509 Message Digest commands md2 md4 md5 rmd160 sha sha1 Cipher commands aes-128-cbc aes-128-ecb aes-192-cbc aes-192-ecb aes-256-cbc aes-256-ecb base64 bf bf-cbc bf-cfb bf-ecb bf-ofb camellia-128-cbc camellia-128-ecb camellia-192-cbc camellia-192-ecb camellia-256-cbc camellia-256-ecb cast cast-cbc cast5-cbc cast5-cfb cast5-ecb cast5-ofb des des-cbc des-cfb des-ecb des-ede des-ede-cbc des-ede-cfb des-ede-ofb des-ede3 des-ede3-cbc des-ede3-cfb des-ede3-ofb des-ofb des3 desx idea idea-cbc idea-cfb idea-ecb idea-ofb rc2 rc2-40-cbc rc2-64-cbc rc2-cbc rc2-cfb rc2-ecb rc2-ofb rc4 rc4-40 seed seed-cbc seed-cfb seed-ecb seed-ofb zlib
客戶機、服務器和證書認證機構是涉足安全通信的三方。圍繞證書這個技術關鍵,下面逐一細說三方通信過程中的協作。
2. 服務器的初始密鑰對和認證請求
基於Java技術的Web服務器通常以服務導向架構爲藍本,通過HTTPS協議將應用程序功能作爲服務發送給客戶機。通信傳輸協議的SSL握手過程中,服務器首先將其X.509證書發送給客戶機,然後由客戶機依據其存儲的根CA證書驗證該證書的真實性。Java內部維護一個密鑰庫(keystore),用以存儲私鑰及其對應的附有證書鏈的證書。Java爲密鑰庫設置了一個密碼,密鑰庫中的每一個私鑰及其證書又有一個密碼來控制存取,keytool是管理密鑰庫的工具軟件。
$ keytool -help Commands: -certreq Generates a certificate request -changealias Changes an entry's alias -delete Deletes an entry -exportcert Exports certificate -genkeypair Generates a key pair -genseckey Generates a secret key -gencert Generates certificate from a certificate request -importcert Imports a certificate or a certificate chain -importkeystore Imports one or all entries from another keystore -keypasswd Changes the key password of an entry -list Lists entries in a keystore -printcert Prints the content of a certificate -printcertreq Prints the content of a certificate request -printcrl Prints the content of a CRL file -storepasswd Changes the store password of a keystore
2.1 創建初始密鑰庫
若服務器FQDN是www.mysite.com,它在DNS中又有別名foo.mysite.com,創建JKS格式的初始密鑰庫可以用如下命令完成。
$ keytool -genkeypair -keystore mystore.jks -storepass mypass -alias www \ -keypass mypass -keyalg rsa -dname "CN=www.mysite.com" -ext "SAN=dns:foo.mysite.com" $ keytool -list -v -keystore mystore.jks -storepass mypass Keystore type: JKS Keystore provider: SUN Your keystore contains 1 entry Alias name: www Creation date: Sep 28, 20xx Entry type: PrivateKeyEntry Certificate chain length: 1 Certificate[1]: Owner: CN=www.mysite.com Issuer: CN=www.mysite.com Serial number: 4d52195c Valid from: Tue Sep 28 17:59:44 GMT 20xx until: Mon Dec 27 17:59:44 GMT 20xx Certificate fingerprints: MD5: 00:D2:BE:27:4B:......:7E:EF:82:DF SHA1: 91:90:23:55:D0:......:F6:BB:5B:21:15:59 SHA256: DE:8A:82:8D:56:......:F7:54:EE:9A:2E:7B:97 Signature algorithm name: SHA256withRSA Version: 3 Extensions: #1: ObjectId: 2.5.29.17 Criticality=false SubjectAlternativeName [ DNSName: foo.mysite.com ] #2: ObjectId: 2.5.29.14 Criticality=false SubjectKeyIdentifier [ KeyIdentifier [ 0000: 07 40 44 3B 8F 2A 5E 88 31 79 AC AB 89 EF 8B 3C .@D;.*^.1y.....< 0010: 28 31 99 9D (1.. ] ]
可以看到,生成的密鑰庫mystore.jks裏有一個私鑰記錄PrivateKeyEntry,記錄中含有一個證書鏈(certificate chain),當然目前證書鏈裏只包含一個證書Certificate[1],它的簽名方法是SHA256作爲散列函數的RSA加密。也許會驚訝地發現,在PrivateKeyEntry里居然沒有對其中私鑰的描述,這也許是因爲Java私鑰不公開的原則。我們可以藉助於OpenSSL來一探究竟,發現私鑰結構的奧祕。
2.1.1 私鑰
前面說過,keytool沒有從密鑰庫中提取私鑰的功能。因此要想得到私鑰,只能先把JKS格式的密鑰庫轉換成PKCS#12格式,然後利用OpenSSL工具。
$ keytool -importkeystore -srckeystore mystore.jks -srcstorepass mypass -srcalias www \ -srckeypass mypass -destkeystore mystore.p12 -deststorepass mypass \ -destkeypass mypass -deststoretype pkcs12 $ keytool -list -v -keystore mystore.p12 -storepass mypass -storetype pkcs12 -alias www \ -keypass mypass Alias name: www Creation date: Sep 28, 20xx Entry type: PrivateKeyEntry Certificate chain length: 1 Certificate[1]: Owner: CN=www.mysite.com Issuer: CN=www.mysite.com Serial number: 4d52195c Valid from: Tue Sep 28 17:59:44 GMT 20xx until: Mon Dec 27 17:59:44 GMT 20xx Certificate fingerprints: MD5: 00:D2:BE:27:4B:......:7E:EF:82:DF SHA1: 91:90:23:55:D0:......:F6:BB:5B:21:15:59 SHA256: DE:8A:82:8D:56:......:F7:54:EE:9A:2E:7B:97 Signature algorithm name: SHA256withRSA Version: 3 Extensions: #1: ObjectId: 2.5.29.17 Criticality=false SubjectAlternativeName [ DNSName: foo.mysite.com ] #2: ObjectId: 2.5.29.14 Criticality=false SubjectKeyIdentifier [ KeyIdentifier [ 0000: 07 40 44 3B 8F 2A 5E 88 31 79 AC AB 89 EF 8B 3C .@D;.*^.1y.....< 0010: 28 31 99 9D (1.. ] ]
從密鑰庫mystore.p12中我們可以用OpenSSL工具提取出私鑰,存入的ASCII文件xxx_private.key按DES標準依據密碼進行加密,以保證私鑰的保密性。
$ openssl pkcs12 -nocerts -in mystore.p12 -passin pass:mypass -passout pass:mypass \ | awk "/--BEGIN/,/--END/" > xxx_private.key $ cat xxx_private.key -----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,95C784432BD4A3B3 M8tg+Erla1YG6K88u6AQJtCe+0iuvri.... isFo28UueQGTSHGYK4AZrIBU38rdb75.... aKYMz5Yd1AAUqBBQlzSyaImlvdza3cX.... -----END RSA PRIVATE KEY-----
進一步,我們可以刪除xxx_private.key文件的密碼保護,從而得到一個PKCS#1格式的RSA私鑰rsa_private.key,此時私鑰以Base64編碼形式存儲。
$ openssl rsa -in xxx_private.key -passin pass:mypass > rsa_private.key $ cat rsa_private.key -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAidMSG5Rava2Tr0g.... F6pL4KMe9xcJF0r5m1cpSBRrxUcBdwg.... 4cGPgFIr6O7VD/qN29UZrJ5kwji82yT.... -----END RSA PRIVATE KEY-----
用OpenSSL工具,可以具體查閱rsa_private.key私鑰中的詳細內容,它包含若干正整數參數。
$ openssl rsa -text -noout -in rsa_private.key Private-Key: (2048 bit) modulus: 00:89:d3:12:1b:94:5a:.... 18:f4:b2:64:69:b7:1b:.... 8d:b7 publicExponent: 65537 (0x10001) privateExponent: 1e:cc:68:ee:7a:cf:70:.... 3c:95:24:b5:2e:f2:bf:.... e1 prime1: 00:ee:41:c4:5b:95:e2:.... d0:2a:24:3f:81:8a:f3:.... 66:a4:b7:b7:af:04 prime2: 00:94:16:9d:e1:04:f3:.... 73:5a:9f:a3:73:22:72:.... 11:a7:b0:48 exponent1: 00:85:43:d2:01:ec:3f:.... 43:4d:1f:03:4a:81:1f:.... ca:57:dd:ce:e7:1c exponent2: 37:c3:d8:8a:0e:da:27:.... a3:76:b0:0f:40:2e:83:.... 7b:72:17:a9:6c coefficient: 00:c1:4c:9f:3f:e6:86:.... f2:87:e7:b9:dc:59:06:.... ce:f7:71:0b:81:83
可以看到,PKCS#1規範的私鑰文件把模數(modulus)、公鑰指數(publicExponent)、私鑰指數(privateExponent)、兩個質數(prime1和prime2)、兩個附加指數(exponent1和exponent2)、和一個附加係數(coefficient)封裝到私鑰結構中。按照RSA理論,模數N和私鑰指數d足以構成RSA私鑰。然而,規範還增加存儲了私鑰指數e、兩個質數p1和p2、兩個附加指數e1和e2、和一個附加係數c,目的是爲了加速RSA的計算過程。其中p1、p2、e1、e2、和c滿足
e * d ≡ 1 (mod φ(N)) e * e1 ≡ 1 (mod (p1-1)) e * e2 ≡ 1 (mod (p2-1)) p2 * c ≡ 1 (mod p1)
上述參數組將以ASN.1的形式被封裝到同一個數據結構中,ASN.1的編碼格式BER、CER和DER遵循ITU的X.690標準。OpenSSL裏有產生ASN.1序列結構的工具。
$ openssl asn1parse -i -in rsa_private.key 0:d=0 hl=4 l=1188 cons: SEQUENCE 4:d=1 hl=2 l= 1 prim: INTEGER :00 7:d=1 hl=4 l= 257 prim: INTEGER :89D3121B945ABDAD93AF4825DF6.... 268:d=1 hl=2 l= 3 prim: INTEGER :010001 273:d=1 hl=4 l= 256 prim: INTEGER :1ECC68EE7ACF70357A9C1FBE3ED.... 533:d=1 hl=3 l= 129 prim: INTEGER :EE41C45B95E20E29F83DABDC36E.... 665:d=1 hl=3 l= 129 prim: INTEGER :94169DE104F341B4BCE9E5FEC1F.... 797:d=1 hl=3 l= 129 prim: INTEGER :8543D201EC3F09EF1DC3D90A0EC.... 929:d=1 hl=3 l= 128 prim: INTEGER :37C3D88A0EDA27A90EE6A97468C.... 1060:d=1 hl=3 l= 129 prim: INTEGER :C14C9F3FE6865043D8BE903F964....
結構中,第7位開始是模數,第268位公鑰指數,第273位私鑰指數,第533和665位兩個質數,第797和929位兩個附加指數,第1060位最後一個附加係數。再進一步,可以用OpenSSL工具在RSA私鑰的基礎上加上版本號、算法標識等附加信息形成PKCS#8格式私鑰文件,它是更一般格式的私鑰形式,目的是爲了包含RSA和其它一切格式的私鑰。
$ openssl pkcs8 -topk8 -nocrypt -in rsa_private.key > private.key $ cat private.key -----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAAS.... SCXfYxj0smRptxsNMcd+VkbQKxTkUb9.... CBUVjg4veHsHXPwQH9z5MUCzz4NRmno.... -----END PRIVATE KEY-----
同樣,私鑰private.key以ASN.1的形式組織。
$ openssl asn1parse -i -in private.key 0:d=0 hl=4 l=1214 cons: SEQUENCE 4:d=1 hl=2 l= 1 prim: INTEGER :00 7:d=1 hl=2 l= 13 cons: SEQUENCE 9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 20:d=2 hl=2 l= 0 prim: NULL 22:d=1 hl=4 l=1192 prim: OCTET STRING HEX DUMP]:308204A4020100....
可以看到,第7位開始是一個rsaEncryption,其密鑰數據始於第22位。因此從第22位開始解析,可以得到和前述rsa_private.key同樣的數據結構:
$ openssl asn1parse -i -in private.key -strparse 22 0:d=0 hl=4 l=1188 cons: SEQUENCE 4:d=1 hl=2 l= 1 prim: INTEGER :00 7:d=1 hl=4 l= 257 prim: INTEGER :89D3121B945ABDAD93AF4825DF6.... 268:d=1 hl=2 l= 3 prim: INTEGER :010001 273:d=1 hl=4 l= 256 prim: INTEGER :1ECC68EE7ACF70357A9C1FBE3ED.... 533:d=1 hl=3 l= 129 prim: INTEGER :EE41C45B95E20E29F83DABDC36E.... 665:d=1 hl=3 l= 129 prim: INTEGER :94169DE104F341B4BCE9E5FEC1F.... 797:d=1 hl=3 l= 129 prim: INTEGER :8543D201EC3F09EF1DC3D90A0EC.... 929:d=1 hl=3 l= 128 prim: INTEGER :37C3D88A0EDA27A90EE6A97468C.... 1060:d=1 hl=3 l= 129 prim: INTEGER :C14C9F3FE6865043D8BE903F964....
把private.key轉化成DER存儲格式後可以看到私鑰的二進制表達形式。
$ openssl rsa -in private.key -outform DER | hexdump -C 00000000 30 82 04 a4 02 01 00 02 82 01 01 00 89 d3 12 1b |0...............| 00000010 94 5a bd ad 93 af 48 25 df 63 18 f4 b2 64 69 b7 |.Z....H%.c...di.| ...... 00000110 01 02 82 01 00 1e cc 68 ee 7a cf 70 35 7a 9c 1f |.......h.z.p5z..| 00000120 be 3e d6 11 3c 95 24 b5 2e f2 bf 97 11 22 5d 3b |.>..<.$......"];| ...... 00000210 89 5b b8 8f e1 02 81 81 00 ee 41 c4 5b 95 e2 0e |.[........A.[...| 00000220 29 f8 3d ab dc 36 e4 d0 2a 24 3f 81 8a f3 bc 01 |).=..6..*$?.....| ...... 00000290 66 a4 b7 b7 af 04 28 fd 47 02 81 81 00 94 16 9d |f.....(.G.......| 000002a0 e1 04 f3 41 b4 bc e9 e5 fe c1 fb 73 5a 9f a3 73 |...A.......sZ..s| ...... 00000320 00 85 43 d2 01 ec 3f 09 ef 1d c3 d9 0a 0e c6 43 |..C...?........C| 00000330 4d 1f 03 4a 81 1f 3d 8c a4 d8 33 ff 83 6b 51 f8 |M..J..=...3..kQ.| ...... 000003a0 67 02 81 80 37 c3 d8 8a 0e da 27 a9 0e e6 a9 74 |g...7.....'....t| 000003b0 68 c9 ee a3 76 b0 0f 40 2e 83 85 82 5c 7a 60 af |h...v..@....\z`.| ...... 00000420 6c 1f 42 71 02 81 81 00 c1 4c 9f 3f e6 86 50 43 |l.Bq.....L.?..PC| 00000430 d8 be 90 3f 96 45 f2 87 e7 b9 dc 59 06 e2 34 0e |...?.E.....Y..4.| ......
用OpenSSL命令可以方便地把PKCS#8格式的private.key中的RSA私鑰提取出來。
$ openssl pkcs8 -nocrypt -in private.key -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAidMSG5Rava2Tr0g.... F6pL4KMe9xcJF0r5m1cpSBRrxUcBdwg.... 4cGPgFIr6O7VD/qN29UZrJ5kwji82yT.... -----END RSA PRIVATE KEY----- $ openssl rsa -text -in private.key | awk "/--BEGIN/,/--END/" -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAidMSG5Rava2Tr0g.... F6pL4KMe9xcJF0r5m1cpSBRrxUcBdwg.... 4cGPgFIr6O7VD/qN29UZrJ5kwji82yT.... -----END RSA PRIVATE KEY-----
2.1.2 證書
從JKS格式的密鑰庫mystore.jks中提取自簽名證書相對容易。
$ keytool -exportcert -rfc -alias www -keystore mystore.jks \ -storepass mypass > public.crt $ cat public.crt -----BEGIN CERTIFICATE----- MIIC7DCCAdSgAwIBAgIETVIZXDANBgk.... LmNvbTAeFw0xNTA5MjkwNDU5NDRaFw0.... 0X8RPF23N3u116E= -----END CERTIFICATE-----
也可以從PKCS#12格式的密鑰庫mystore.p12中提取。
$ openssl pkcs12 -in mystore.p12 -nokeys -passin pass:mypass \ | awk "/--BEGIN/,/--END/" > public.crt
分析證書public.crt的結構和具體內容,可以看到這是一個自簽名的證書,由Issuer(www.mysite.com)簽發給Subject(www.mysite.com)。證書包含一個rsaEncryption公鑰(即模數和公鑰指數)、一些擴展部分(extensions)、和sha256WithRSAEncryption算法(即sha256散列函數的RSA加密)得到的數字簽名。
$ openssl x509 -text -noout -in public.crt Certificate: Data: Version: 3 (0x2) Serial Number: 1297226076 (0x4d52195c) Signature Algorithm: sha256WithRSAEncryption Issuer: CN=www.mysite.com Validity Not Before: Sep 28 04:59:44 20xx GMT Not After : Dec 27 04:59:44 20xx GMT Subject: CN=www.mysite.com Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (2048 bit) Modulus (2048 bit): 00:89:d3:12:1b:94:5a:bd:ad:93:af:48:25:df:63: 18:f4:b2:64:69:b7:1b:0d:31:...... Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Alternative Name: DNS:foo.mysite.com X509v3 Subject Key Identifier: 07:40:44:3B:8F:2A:5E:88:31:79:AC:AB:89:EF:8B:3C:28:31:99:9D Signature Algorithm: sha256WithRSAEncryption 02:d3:e1:20:71:e8:6d:b1:ec:61:bd:88:a5:04:3e:65:6c:2e: fb:36:61:28:06:d6:77:e7:......
對證書文件也可以做ASN.1分析:
$ openssl x509 -in public.crt -outform DER|openssl asn1parse -i -inform DER 0:d=0 hl=4 l= 748 cons: SEQUENCE 4:d=1 hl=4 l= 468 cons: SEQUENCE 8:d=2 hl=2 l= 3 cons: cont [ 0 ] 10:d=3 hl=2 l= 1 prim: INTEGER :02 13:d=2 hl=2 l= 4 prim: INTEGER :4D52195C 19:d=2 hl=2 l= 13 cons: SEQUENCE 21:d=3 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption 32:d=3 hl=2 l= 0 prim: NULL 34:d=2 hl=2 l= 25 cons: SEQUENCE 36:d=3 hl=2 l= 23 cons: SET 38:d=4 hl=2 l= 21 cons: SEQUENCE 40:d=5 hl=2 l= 3 prim: OBJECT :commonName 45:d=5 hl=2 l= 14 prim: PRINTABLESTRING :www.mysite.com 61:d=2 hl=2 l= 30 cons: SEQUENCE 63:d=3 hl=2 l= 13 prim: UTCTIME :150929045944Z 78:d=3 hl=2 l= 13 prim: UTCTIME :151228045944Z 93:d=2 hl=2 l= 25 cons: SEQUENCE 95:d=3 hl=2 l= 23 cons: SET 97:d=4 hl=2 l= 21 cons: SEQUENCE 99:d=5 hl=2 l= 3 prim: OBJECT :commonName 104:d=5 hl=2 l= 14 prim: PRINTABLESTRING :www.mysite.com 120:d=2 hl=4 l= 290 cons: SEQUENCE 124:d=3 hl=2 l= 13 cons: SEQUENCE 126:d=4 hl=2 l= 9 prim: OBJECT :rsaEncryption 137:d=4 hl=2 l= 0 prim: NULL 139:d=3 hl=4 l= 271 prim: BIT STRING 414:d=2 hl=2 l= 60 cons: cont [ 3 ] 416:d=3 hl=2 l= 58 cons: SEQUENCE 418:d=4 hl=2 l= 25 cons: SEQUENCE 420:d=5 hl=2 l= 3 prim: OBJECT :X509v3 Subject Alternative Name 425:d=5 hl=2 l= 18 prim: OCTET STRING [HEX DUMP]:3010820E666F.... 445:d=4 hl=2 l= 29 cons: SEQUENCE 447:d=5 hl=2 l= 3 prim: OBJECT :X509v3 Subject Key Identifier 452:d=5 hl=2 l= 22 prim: OCTET STRING [HEX DUMP]:04140740443B.... 476:d=1 hl=2 l= 13 cons: SEQUENCE 478:d=2 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption 489:d=2 hl=2 l= 0 prim: NULL 491:d=1 hl=4 l= 257 prim: BIT STRING $ openssl x509 -in public.crt -outform DER | hexdump -C 00000000 30 82 02 ec 30 82 01 d4 a0 03 02 01 02 02 04 4d |0...0..........M| 00000010 52 19 5c 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b |R.\0...*.H......| 00000020 05 00 30 19 31 17 30 15 06 03 55 04 03 13 0e 77 |..0.1.0...U....w| 00000030 77 77 2e 6d 79 73 69 74 65 2e 63 6f 6d 30 1e 17 |ww.mysite.com0..| 00000040 0d 31 35 30 39 32 39 30 34 35 39 34 34 5a 17 0d |.150929045944Z..| 00000050 31 35 31 32 32 38 30 34 35 39 34 34 5a 30 19 31 |151228045944Z0.1| 00000060 17 30 15 06 03 55 04 03 13 0e 77 77 77 2e 6d 79 |.0...U....www.my| 00000070 73 69 74 65 2e 63 6f 6d 30 82 01 22 30 0d 06 09 |site.com0.."0...| 00000080 2a 86 48 86 f7 0d 01 01 01 05 00 03 82 01 0f 00 |*.H.............| 00000090 30 82 01 0a 02 82 01 01 00 89 d3 12 1b 94 5a bd |0.............Z.| 000000a0 ad 93 af 48 25 df 63 18 f4 b2 64 69 b7 1b 0d 31 |...H%.c...di...1| ...... 00000190 de c4 07 3a b4 ce ca 8d b7 02 03 01 00 01 a3 3c |...:...........<| 000001a0 30 3a 30 19 06 03 55 1d 11 04 12 30 10 82 0e 66 |0:0...U....0...f| 000001b0 6f 6f 2e 6d 79 73 69 74 65 2e 63 6f 6d 30 1d 06 |oo.mysite.com0..| 000001c0 03 55 1d 0e 04 16 04 14 07 40 44 3b 8f 2a 5e 88 |.U.......@D;.*^.| 000001d0 31 79 ac ab 89 ef 8b 3c 28 31 99 9d 30 0d 06 09 |1y.....<(1..0...| 000001e0 2a 86 48 86 f7 0d 01 01 0b 05 00 03 82 01 01 00 |*.H.............| 000001f0 02 d3 e1 20 71 e8 6d b1 ec 61 bd 88 a5 04 3e 65 |... q.m..a....>e| 00000200 6c 2e fb 36 61 28 06 d6 77 e7......
2.1.3 公鑰
OpenSSL提供從證書中提取出公鑰的技術手段。
$ openssl x509 -pubkey -noout -in public.crt > public.key $ cat public.key -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8.... 9LJkabcbDTHHflZG0CsU5FG/V/BZF6p.... twIDAQAB -----END PUBLIC KEY-----
前面已經表述,PKCS#1或PKCS#8格式的私鑰文件也包含構建公鑰的模數和公鑰指數,因此可以從rsa_private.key或private.key中提取信息直接生成RSA公鑰文件,以此可以與密鑰庫中提取出來的公鑰進行比較。
$ openssl rsa -pubout -in private.key
用OpenSSL可以查看公鑰的具體內容。顯而易見,它包含模數和公鑰指數,通常公鑰指數取爲216+1。
$ openssl rsa -text -noout -pubin -in public.key Modulus (2048 bit): 00:89:d3:12:1b:94:5a:bd:ad:93:af:48:25:df:63: 18:f4:b2:64:69:b7:1b:0d:31:...... Exponent: 65537 (0x10001)
同樣可以生成ASN.1格式:
$ openssl asn1parse -in public.key 0:d=0 hl=4 l= 290 cons: SEQUENCE 4:d=1 hl=2 l= 13 cons: SEQUENCE 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption 17:d=2 hl=2 l= 0 prim: NULL 19:d=1 hl=4 l= 271 prim: BIT STRING $ openssl asn1parse -in public.key -strparse 19 0:d=0 hl=4 l= 266 cons: SEQUENCE 4:d=1 hl=4 l= 257 prim: INTEGER :89D3121B945ABDAD.... 265:d=1 hl=2 l= 3 prim: INTEGER :010001
最後,鑑別私鑰、公鑰和證書文件是否配對,可以檢查它們各自的模數。密鑰對的私鑰及其對應的公鑰和證書,模數應該相同。
$ openssl rsa -modulus -noout -in private.key Modulus=89D3121B945ABDAD.... $ openssl rsa -modulus -noout -pubin -in public.key Modulus=89D3121B945ABDAD.... $ openssl x509 -modulus -noout -in public.crt Modulus=89D3121B945ABDAD....
2.2 證書籤名請求
初始建立的密鑰庫,包含一個私鑰和一個自簽名的證書。下一步需要生成PKCS#10格式的證書籤名請求(CSR - certificate signing request),然後把證書籤名請求提交認證機構CA,等待該機構依據X.509國際標準對服務器管理者進行驗證,合格者簽發證書。
$ keytool -certreq -keystore mystore.jks -storepass mypass -alias www -keypass mypass \ -ext "SAN=dns:foo.mysite.com" -file www.csr $ cat www.csr -----BEGIN NEW CERTIFICATE REQUEST----- MIICqTCCAZECAQAwGTEXMB...... A4IBDwAwggEKAoIBAQCJ0x...... NA== -----END NEW CERTIFICATE REQUEST-----
OpenSSL可以檢驗、顯示證書籤名請求的內容。請求和證書格式基本相同,它包含一個rsaEncryption公鑰(即模數和公鑰指數)、一些擴展部分(extensions)、和sha256WithRSAEncryption算法(即sha256散列函數的RSA加密)產生的數字簽名。
$ openssl req -verify -noout -in www.csr verify OK $ openssl req -text -noout -in www.csr Certificate Request: Data: Version: 0 (0x0) Subject: CN=www.mysite.com Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (2048 bit) Modulus (2048 bit): 00:89:d3:12:1b:94:5a:bd:ad:93:af:48:25:df:63: 18:f4:b2:64:69:b7:1b:0d:31:...... Exponent: 65537 (0x10001) Attributes: Requested Extensions: X509v3 Subject Alternative Name: DNS:foo.mysite.com X509v3 Subject Key Identifier: 07:40:44:3B:8F:2A:5E:88:31:79:AC:AB:89:EF:8B:3C:28:31:99:9D Signature Algorithm: sha256WithRSAEncryption 26:4a:73:9f:3f:f8:91:78:b8:1d:9b:51:ab:63:32:c2:1f:cd: 76:3e:de:42:03:e1:7b:11:......
對證書籤名請求做ASN.1分析:
$ openssl asn1parse -i -in www.csr 0:d=0 hl=4 l= 681 cons: SEQUENCE 4:d=1 hl=4 l= 401 cons: SEQUENCE 8:d=2 hl=2 l= 1 prim: INTEGER :00 11:d=2 hl=2 l= 25 cons: SEQUENCE 13:d=3 hl=2 l= 23 cons: SET 15:d=4 hl=2 l= 21 cons: SEQUENCE 17:d=5 hl=2 l= 3 prim: OBJECT :commonName 22:d=5 hl=2 l= 14 prim: PRINTABLESTRING :www.mysite.com 38:d=2 hl=4 l= 290 cons: SEQUENCE 42:d=3 hl=2 l= 13 cons: SEQUENCE 44:d=4 hl=2 l= 9 prim: OBJECT :rsaEncryption 55:d=4 hl=2 l= 0 prim: NULL 57:d=3 hl=4 l= 271 prim: BIT STRING 332:d=2 hl=2 l= 75 cons: cont [ 0 ] 334:d=3 hl=2 l= 73 cons: SEQUENCE 336:d=4 hl=2 l= 9 prim: OBJECT :Extension Request 347:d=4 hl=2 l= 60 cons: SET 349:d=5 hl=2 l= 58 cons: SEQUENCE 351:d=6 hl=2 l= 25 cons: SEQUENCE 353:d=7 hl=2 l= 3 prim: OBJECT :X509v3 Subject Alternative Name 358:d=7 hl=2 l= 18 prim: OCTET STRING [HEX DUMP]:3010820E666F6F2E6D79.... 378:d=6 hl=2 l= 29 cons: SEQUENCE 380:d=7 hl=2 l= 3 prim: OBJECT :X509v3 Subject Key Identifier 385:d=7 hl=2 l= 22 prim: OCTET STRING [HEX DUMP]:04140740443B8F2A5E88.... 409:d=1 hl=2 l= 13 cons: SEQUENCE 411:d=2 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption 422:d=2 hl=2 l= 0 prim: NULL 424:d=1 hl=4 l= 257 prim: BIT STRING $ openssl asn1parse -i -in www.csr -strparse 57 0:d=0 hl=4 l= 266 cons: SEQUENCE 4:d=1 hl=4 l= 257 prim: INTEGER :89D3121B945ABDAD93AF.... 265:d=1 hl=2 l= 3 prim: INTEGER :010001
其結果可以和二進制存儲文件進行比較。
$ openssl asn1parse -noout -in www.csr -out >(hexdump -C) 00000000 30 82 02 a9 30 82 01 91 02 01 00 30 19 31 17 30 |0...0......0.1.0| 00000010 15 06 03 55 04 03 13 0e 77 77 77 2e 6d 79 73 69 |...U....www.mysi| 00000020 74 65 2e 63 6f 6d 30 82 01 22 30 0d 06 09 2a 86 |te.com0.."0...*.| 00000030 48 86 f7 0d 01 01 01 05 00 03 82 01 0f 00 30 82 |H.............0.| 00000040 01 0a 02 82 01 01 00 89 d3 12 1b 94 5a bd ad 93 |............Z...| 00000050 af 48 25 df 63 18 f4 b2 64 69 b7 1b 0d 31 c7 7e |.H%.c...di...1.~| ...... 00000140 07 3a b4 ce ca 8d b7 02 03 01 00 01 a0 4b 30 49 |.:...........K0I| 00000150 06 09 2a 86 48 86 f7 0d 01 09 0e 31 3c 30 3a 30 |..*.H......1<0:0| 00000160 19 06 03 55 1d 11 04 12 30 10 82 0e 66 6f 6f 2e |...U....0...foo.| 00000170 6d 79 73 69 74 65 2e 63 6f 6d 30 1d 06 03 55 1d |mysite.com0...U.| 00000180 0e 04 16 04 14 07 40 44 3b 8f 2a 5e 88 31 79 ac |......@D;.*^.1y.| 00000190 ab 89 ef 8b 3c 28 31 99 9d 30 0d 06 09 2a 86 48 |....<(1..0...*.H| 000001a0 86 f7 0d 01 01 0b 05 00 03 82 01 01 00 26 4a 73 |.............&Js| 000001b0 9f 3f f8 91 78 b8 1d 9b 51 ab 63 32 c2 1f cd 76 |.?..x...Q.c2...v| ...... 000002a0 e8 f8 4f 60 23 fc 97 02 c5 d2 6a bf 34 |..O`#.....j.4|
從證書籤名請求www.csr可以提取出其間包含的公鑰及其模數,與上節產生的私鑰公鑰的模數進行比較。
$ openssl req -pubkey -noout -in www.csr -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8.... 9LJkabcbDTHHflZG0CsU5FG/V/BZF6p.... twIDAQAB -----END PUBLIC KEY----- $ openssl req -modulus -noout -in www.csr Modulus=89D3121B945ABDAD....
3. 證書認證機構CA
數字證書認證機構是簽發包含公鑰的證書的機構,其英文名稱是Certificate Authority,經常被縮寫爲CA。有些簡單的SSL證書僅僅需要用該網站域名的郵箱向CA發封郵件就能簽發了,數據傳輸雙方以此進行數據安全傳輸。然而,https加密的目的除了保證客戶機信息在傳輸過程中的安全外,還保障了服務器的身份。對一些正規組織特別是一些金融機構,SSL證書的簽發就會變得十分繁瑣,這樣的網站需要提供大量的文件以證明該網站是可靠的。如果能夠證明該網站是可靠的,CA纔會給簽發證書。目前全球最著名的證書認證機構有:
Symantec--原VeriSign,後被Symantec收購的美國公司。佔數字認證市場三分之一的份額
Comodo--英國起家,幫助建立了擴展驗證證書(簡稱EV證書)的新標準。佔市場三分之一份額
GlobalSign--日本公司,佔數字認證市場10%
GoDaddy--全球最大的域名註冊商,業務包括SSL證書。佔數字認證市場10%
中國互聯網絡信息中心--擁有根證書的中國認證機構
香港郵政電子核證--擁有根證書的香港認證機構
澳門郵政eSignTrust--擁有根證書的澳門認證機構
需要補充說明一下EV證書(Extended Validation),這種證書遵循全球統一的嚴格身份驗證標準頒發的SSL證書,是目前業界最高安全級別的SSL證書。它是由Comodo聯合VeriSign、GeoTrust、Thawte等證書認證機構,聯合主流瀏覽器開發商微軟、Mozilla、Opera等,創立的數字證書和瀏覽器論壇cabforum.org制定的標準。這種證書在瀏覽器中以綠色地址欄顯示,並且滾動展示該網站真實管理機構和CA信息。如WoSign沃通電子認證服務有限公司的網站https://www.wosign.com/ 。
3.1 根證書
就像可口可樂公司的商業重器可口可樂配方一樣,數字證書認證機構的唯一資產就是它所擁有的一個或幾個根證書,這些根證書被預置在主流操作系統中,被各個系統所信任。作爲演示,我們在這裏一個僞“根證書”及其對應的私鑰,根證書是以自簽名的形式簽發的。
$ mkdir root $ openssl req -newkey rsa:4096 -keyout root/xxx_private.key \ -out root/public.csr $ openssl pkcs8 -topk8 -nocrypt -in root/xxx_private.key > root/private.key $ openssl x509 -req -signkey root/private.key -in root/public.csr \ -out root/public.crt
3.2 中級認證
通常,認證機構按照層次結構來組織的,它有一批下屬中級認證部門,每個部門又擁有一個或幾個中級證書。我們先生成一箇中級證書極其CSR來作爲演示。
$ mkdir intermediate $ openssl req -newkey rsa:2048 -keyout intermediate/xxx_private.key \ -out intermediate/public.csr $ openssl pkcs8 -topk8 -nocrypt -in intermediate/xxx_private.key \ > intermediate/private.key
這些中級證書,均具有根證書的簽名。OpenSSL使用根證書完成中級證書的簽發。
$ touch root/database.txt $ echo 01 > root/serial.txt $ cat > root/openssl.cnf <<EOF [ ca ] default_ca = ca_root [ ca_root ] new_certs_dir = intermediate serial = root/serial.txt database = root/database.txt certificate = root/public.crt private_key = root/private.key default_days = 3652 default_crl_days = 30 default_md = md5 policy = policy_any [ policy_any ] countryName = supplied stateOrProvinceName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional EOF $ openssl ca -config root/openssl.cnf -in intermediate/public.csr \ -out intermediate/public.crt Using configuration from root/openssl.cnf Check that the request matches the signature Signature ok The Subject's Distinguished Name is as follows countryName :PRINTABLE:'GB' stateOrProvinceName :PRINTABLE:'Berkshire' localityName :PRINTABLE:'Newbury' organizationName :PRINTABLE:'CA' commonName :PRINTABLE:'CA Intermediate' Certificate is to be certified until Sep 30 03:41:14 20xx GMT (3652 days) Sign the certificate? [y/n]:y 1 out of 1 certificate requests certified, commit? [y/n]y Write out database with 1 new entries Data Base Updated
有了中級證書,認證機構的中級認證部門就具備了依據服務器的www.csr請求,發送具有認證機構簽名的服務器SSL證書的能力了。
$ touch intermediate/database.txt $ echo 01 > intermediate/serial.txt $ cat > intermediate/openssl.cnf <<EOF [ ca ] default_ca = ca_intermediate [ ca_intermediate ] new_certs_dir = . serial = intermediate/serial.txt database = intermediate/database.txt certificate = intermediate/public.crt private_key = intermediate/private.key default_days = 365 default_crl_days = 30 default_md = md5 copy_extensions = copy policy = policy_any [ policy_any ] countryName = optional stateOrProvinceName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional EOF $ openssl ca -config intermediate/openssl.cnf -in www.csr -out www.crt Using configuration from intermediate/openssl.cnf Check that the request matches the signature Signature ok The Subject's Distinguished Name is as follows commonName :PRINTABLE:'www.mysite.com' Certificate is to be certified until Sep 30 03:47:44 20xx GMT (365 days) Sign the certificate? [y/n]:y 1 out of 1 certificate requests certified, commit? [y/n]y Write out database with 1 new entries Data Base Updated
3.3 認證機構發送具有數字簽名的數據
證書認證機構應答服務器的是具有數字簽名的數據。其原理是,認證機構把要發送的數據用私鑰進行簽名,然後把數據連同簽名一併發送給服務器。
$ echo testing > 1.txt $ openssl dgst -md5 -sign root/private.key 1.txt > 2.xxx
服務器可以獲取的根證書,以此得到認證機構的公鑰。
$ openssl x509 -pubkey -noout -in root/public.crt > root/public.key
接受到認證機構的數據及其簽名信息後,依據認證機構的公鑰對其進行簽名驗證
$ openssl dgst -md5 -verify root/public.key -signature 2.xxx 1.txt Verified OK
我們觀察www.crt的結構和內容不難發現,生成的證書包含一個公鑰和一個簽名。服務器收到的包含認證機構md5WithRSAEncryption簽名的證書,就表明已經完成了管理者身份的驗證。
$ openssl x509 -text -noout -in www.crt Certificate: Data: Version: 1 (0x0) Serial Number: 1 (0x1) Signature Algorithm: md5WithRSAEncryption Issuer: C=GB, ST=Berkshire, O=CA, CN=CA Intermediate Validity Not Before: Oct 1 03:47:44 20xx GMT Not After : Sep 30 03:47:44 20xx GMT Subject: CN=www.mysite.com Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (2048 bit) Modulus (2048 bit): 00:89:d3:12:1b:94:5a:bd:ad:93:af:48:25:df:63: 18:f4:b2:64:69:b7:1b:...... Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Alternative Name: DNS:foo.mysite.com X509v3 Subject Key Identifier: 07:40:44:3B:8F:2A:5E:88:31:79:AC:AB:...... Signature Algorithm: md5WithRSAEncryption 3b:63:2c:cc:12:dd:04:f6:48:a9:f8:c2:b9:da:54:d1:a4:d9: 91:f8:b4:c0:25:6a:db:4c:...... $ openssl asn1parse -i -in www.crt 0:d=0 hl=4 l= 725 cons: SEQUENCE 4:d=1 hl=4 l= 445 cons: SEQUENCE 8:d=2 hl=2 l= 1 prim: INTEGER :01 11:d=2 hl=2 l= 13 cons: SEQUENCE 13:d=3 hl=2 l= 9 prim: OBJECT :md5WithRSAEncryption 24:d=3 hl=2 l= 0 prim: NULL 26:d=2 hl=2 l= 72 cons: SEQUENCE 28:d=3 hl=2 l= 11 cons: SET 30:d=4 hl=2 l= 9 cons: SEQUENCE 32:d=5 hl=2 l= 3 prim: OBJECT :countryName 37:d=5 hl=2 l= 2 prim: PRINTABLESTRING :GB 41:d=3 hl=2 l= 18 cons: SET 43:d=4 hl=2 l= 16 cons: SEQUENCE 45:d=5 hl=2 l= 3 prim: OBJECT :stateOrProvinceName 50:d=5 hl=2 l= 9 prim: PRINTABLESTRING :Berkshire 61:d=3 hl=2 l= 11 cons: SET 63:d=4 hl=2 l= 9 cons: SEQUENCE 65:d=5 hl=2 l= 3 prim: OBJECT :organizationName 70:d=5 hl=2 l= 2 prim: PRINTABLESTRING :CA 74:d=3 hl=2 l= 24 cons: SET 76:d=4 hl=2 l= 22 cons: SEQUENCE 78:d=5 hl=2 l= 3 prim: OBJECT :commonName 83:d=5 hl=2 l= 15 prim: PRINTABLESTRING :CA Intermediate 100:d=2 hl=2 l= 30 cons: SEQUENCE 102:d=3 hl=2 l= 13 prim: UTCTIME :151001034744Z 117:d=3 hl=2 l= 13 prim: UTCTIME :160930034744Z 132:d=2 hl=2 l= 25 cons: SEQUENCE 134:d=3 hl=2 l= 23 cons: SET 136:d=4 hl=2 l= 21 cons: SEQUENCE 138:d=5 hl=2 l= 3 prim: OBJECT :commonName 143:d=5 hl=2 l= 14 prim: PRINTABLESTRING :www.mysite.com 159:d=2 hl=4 l= 290 cons: SEQUENCE 163:d=3 hl=2 l= 13 cons: SEQUENCE 165:d=4 hl=2 l= 9 prim: OBJECT :rsaEncryption 176:d=4 hl=2 l= 0 prim: NULL 178:d=3 hl=4 l= 271 prim: BIT STRING 453:d=1 hl=2 l= 13 cons: SEQUENCE 455:d=2 hl=2 l= 9 prim: OBJECT :md5WithRSAEncryption 466:d=2 hl=2 l= 0 prim: NULL 468:d=1 hl=4 l= 257 prim: BIT STRING
從ASN.1格式裏可以看見,從第159位開始的Sequence既是公鑰。
$ openssl asn1parse -noout -in www.crt -strparse 159 -out pubkey.der $ cat pubkey.der | openssl base64 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAidMSG5Rava2Tr0gl32MY 9LJkabcbDTHHflZG0CsU5FG/V/BZF6pL4KMe9xcJF0r5m1cpSBRrxUcBdwgVFY4O L3h7B1z8EB/c+TFAs8+DUZp6GZ2+4cGPgFIr6O7VD/qN29UZrJ5kwji82yTOABf2 2L+c6dpi7ubu3c7fgnW48lmXwJRJtrtFrWzNhiRYugESfudnS98ykxGJDdIK5OBY 1HRv7Ss5xXiCYUrARchV/ORNaPEuUlDRjKCfa0ea9FC++1y4JbyoTJymueUM78vu 1I1E3gqG3syGOUqygC5kEvFocJ+26rlseJPxgnUGnR/Lbh98De9B0d7EBzq0zsqN twIDAQAB
把它和用命令提取出來的公鑰作個比較,可以看見它們是一致的。
$ openssl x509 -pubkey -noout -in www.crt -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAidMSG5Rava2Tr0gl32MY 9LJkabcbDTHHflZG0CsU5FG/V/BZF6pL4KMe9xcJF0r5m1cpSBRrxUcBdwgVFY4O L3h7B1z8EB/c+TFAs8+DUZp6GZ2+4cGPgFIr6O7VD/qN29UZrJ5kwji82yTOABf2 2L+c6dpi7ubu3c7fgnW48lmXwJRJtrtFrWzNhiRYugESfudnS98ykxGJDdIK5OBY 1HRv7Ss5xXiCYUrARchV/ORNaPEuUlDRjKCfa0ea9FC++1y4JbyoTJymueUM78vu 1I1E3gqG3syGOUqygC5kEvFocJ+26rlseJPxgnUGnR/Lbh98De9B0d7EBzq0zsqN twIDAQAB -----END PUBLIC KEY-----
事實上,RFC5280的4.1.1節說明了證書文件由三個Sequence域構成:第一個域tbsCertificate(即待簽名to be signed的縮寫),第二個域signatureAlgorithm,和第三個域signatureValue。我們下面把tbsCertificate(第4位開始)和signatureValue(第468位開始)提取出來。
$ openssl asn1parse -noout -in www.crt -strparse 4 -out tbs.der $ openssl asn1parse -noout -in www.crt -strparse 468 -out sig.der $ hexdump -C sig.der 00000000 3b 63 2c cc 12 dd 04 f6 48 a9 f8 c2 b9 da 54 d1 |;c,.....H.....T.| 00000010 a4 d9 91 f8 b4 c0 25 6a db 4c ......
簽名過程是對tbsCertificate域的散列函數值,再以CA中級證書的私鑰值計算RSA值。
$ openssl dgst -md5 -sign intermediate/private.key tbs.der | hexdump -C 00000000 3b 63 2c cc 12 dd 04 f6 48 a9 f8 c2 b9 da 54 d1 |;c,.....H.....T.| 00000010 a4 d9 91 f8 b4 c0 25 6a db 4c ......
3.4 PKCS#7證書鏈
通常,證書認證機構向服務器管理者頒發PKCS#7格式的證書鏈:
$ cat www.crt intermediate/public.crt | awk "/--BEGIN/,/--END/" \ > chain.crt $ openssl crl2pkcs7 -nocrl -certfile chain.crt -out chain.p7b $ cat chain.p7b -----BEGIN PKCS7----- MIIHGAYJKoZIhvcNAQcCoIIH.... 1TCCAb0CAQEwDQYJKoZIhvcN.... 1HuMu/q/5J+8BVGkNV.... -----END PKCS7-----
OpenSSL可以查閱PKCS#7格式的文件中包含的證書鏈。
$ openssl pkcs7 -print_certs -in chain.p7b subject=/CN=www.mysite.com issuer=/C=GB/ST=Berkshire/O=CA/CN=CA Intermediate -----BEGIN CERTIFICATE----- MIIC1TCCAb0CAQEwDQYJKoZIhvcNA.... BAgTCUJlcmtzaGlyZTELMAkGA1UEC.... sCSemwRaoHNK -----END CERTIFICATE----- subject=/C=GB/ST=Berkshire/O=CA/CN=CA Intermediate issuer=/C=GB/ST=Berkshire/L=Newbury/O=CA/CN=CA Root -----BEGIN CERTIFICATE----- MIIEDjCCAfYCAQEwDQYJKoZIhvcNA.... BAgTCUJlcmtzaGlyZTEQMA4GA1UEB.... 5J+8BVGkNVHmgmZjvakg.... -----END CERTIFICATE-----
4. 服務器安裝CA簽名證書
Java存儲國際認可的認證機構的根CA證書在其Truststore中$JAVA_HOME/jre/lib/security/cacerts,默認密碼通常爲changeit。本文爲了模擬,把自己生成的CA根證書加入其中。
# keytool -importcert -trustcacerts -file root/public.crt \ -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit \ -alias myCA Owner: CN=CA Root, O=CA, L=Newbury, ST=Berkshire, C=GB Issuer: CN=CA Root, O=CA, L=Newbury, ST=Berkshire, C=GB Serial number: c5671bc640ecbd38 Valid from: Thu Oct 01 16:37:50 NZDT 20xx until: Sat Oct 31 16:37:50 NZDT 20xx Certificate fingerprints: MD5: A2:E1:2F:87:D2:37:74:.... SHA1: FA:3A:3B:7E:CB:80:DC:22.... SHA256: 8A:95:7A:DF:8A:C4:77:9D:.... Signature algorithm name: SHA1withRSA Version: 1 Trust this certificate? [no]: yes Certificate was added to keystore $ keytool -list -keystore $JAVA_HOME/jre/lib/security/cacerts \ -storepass changeit -alias myCA myCA, Oct 1, 2015, trustedCertEntry, Certificate fingerprint (SHA1): FA:3A:3B:7E:CB:80:DC:22:....
4.1 證書鏈分離證書
服務器得到chain.p7b後,先把證書鏈分割成若干個單獨的證書文件:
$ openssl pkcs7 -print_certs -in chain.p7b | awk \ 'BEGIN{i=0} /--BEGIN/{i=-i+1} {if(i>0) print>"ca" i ".crt"} /--END/{i=-i}' $ cat ca1.crt -----BEGIN CERTIFICATE----- MIIC1TCCAb0CAQEwDQYJKoZIhvcNA.... BAgTCUJlcmtzaGlyZTELMAkGA1UEC.... sCSemwRaoHNK -----END CERTIFICATE----- $ cat ca2.crt -----BEGIN CERTIFICATE----- MIIEDjCCAfYCAQEwDQYJKoZIhvcNA.... BAgTCUJlcmtzaGlyZTEQMA4GA1UEB.... 5J+8BVGkNVHmgmZjvakgb.... -----END CERTIFICATE-----
得到的簽名證書,一般ca1.crt是和私鑰配對的證書,而ca2.crt是CA中級證書。
$ openssl x509 -subject -issuer -noout -in ca1.crt subject= /CN=www.mysite.com issuer= /C=GB/ST=Berkshire/O=CA/CN=CA Intermediate $ openssl x509 -subject -issuer -noout -in ca2.crt subject= /C=GB/ST=Berkshire/O=CA/CN=CA Intermediate issuer= /C=GB/ST=Berkshire/L=Newbury/O=CA/CN=CA Root
4.2 證書的驗證和安裝
簽名驗證的原理是用CA的中級證書中的公鑰來驗證tbsCertificate域和signatureValue域。
$ openssl dgst -md5 -verify intermediate/public.key -signature sig.der tbs.der Verified OK
事實上OpenSSL有更簡單的命令檢驗證書的簽名。首先依據CA提供的根證書來檢驗中級CA證書是否可信任。
$ openssl verify -CAfile root/public.crt ca2.crt ca2.crt: OK
檢驗服務器SSL證書ca1.crt需要提供用以簽名的中級CA證書和根CA證書。
$ openssl verify -CAfile <(cat ca2.crt root/public.crt) ca1.crt ca1.crt: OK
或先把根證書和中級證書組成證書鏈文件ca.crt,然後
$ cat ca2.crt root/public.crt > chain.crt $ openssl verify -CAfile chain.crt ca1.crt ca1.crt: OK
檢驗證書的模數,以確定ca1.crt和自己的CSR請求一致。
$ openssl x509 -modulus -noout -in ca1.crt Modulus=89D3121B945ABDAD....
確認正確即可以將它們安裝到密鑰庫中,首先安裝CA中級證書ca2.crt:
$ keytool -importcert -trustcacerts -file ca2.crt -keystore mystore.jks \ -storepass mypass -alias ca Certificate was added to keystore
然後再安裝ca1.crt,以取代密鑰庫中原來的自簽名證書。
$ keytool -importcert -trustcacerts -file ca1.crt -keystore mystore.jks \ -storepass mypass -alias www -keypass mypass Certificate reply was installed in keystore
如果需要,可以把修改後的密鑰庫重新轉化成PKCS#12格式:
$ rm mystore.p12 $ keytool -importkeystore -srckeystore mystore.jks -srcstorepass mypass -srcalias www \ -srckeypass mypass -destkeystore mystore.p12 -deststorepass mypass \ -destkeypass mypass -deststoretype pkcs12
最後,再驗證一下密鑰庫就可以看到一個具有三個證書構成的證書鏈。證書鏈最後一個是已經存儲在Truststore的CA根證書,以此表明整個證書鏈是可信任的。
$ keytool -list -v -keystore mystore.jks -storepass mypass -alias www -keypass mypass Alias name: www Creation date: Oct 1, 20xx Entry type: PrivateKeyEntry Certificate chain length: 3 Certificate[1]: Owner: CN=www.mysite.com Issuer: CN=CA Intermediate, O=CA, ST=Berkshire, C=GB Serial number: 1 Valid from: Thu Oct 01 16:47:44 NZDT 20xx until: Fri Sep 30 16:47:44 NZDT 20xx Certificate fingerprints: MD5: C3:CA:A8:10:8D:B9:BF:39:67:.... SHA1: 4B:91:C6:2D:30:D0:2D:E0:98:72:.... SHA256: 15:1F:EA:FE:92:34:A0:EE:C0:CC:.... Signature algorithm name: MD5withRSA Version: 1 Certificate[2]: Owner: CN=CA Intermediate, O=CA, ST=Berkshire, C=GB Issuer: CN=CA Root, O=CA, L=Newbury, ST=Berkshire, C=GB Serial number: 1 Valid from: Thu Oct 01 16:41:14 NZDT 20xx until: Tue Sep 30 16:41:14 NZDT 20xx Certificate fingerprints: MD5: 09:39:54:D5:02:14:99:A7:D8:.... SHA1: 21:77:D2:20:F4:4B:DA:0D:63:20:.... SHA256: 28:87:4B:4D:8A:A2:B4:0C:6A:A8:.... Signature algorithm name: MD5withRSA Version: 1 Certificate[3]: Owner: CN=CA Root, O=CA, L=Newbury, ST=Berkshire, C=GB Issuer: CN=CA Root, O=CA, L=Newbury, ST=Berkshire, C=GB Serial number: c5671bc640ecbd38 Valid from: Thu Oct 01 16:37:50 NZDT 20xx until: Sat Oct 31 16:37:50 NZDT 20xx Certificate fingerprints: MD5: A2:E1:2F:87:D2:37:74:CA:25:.... SHA1: FA:3A:3B:7E:CB:80:DC:22:5F:FA:.... SHA256: 8A:95:7A:DF:8A:C4:77:9D:3F:B7:.... Signature algorithm name: SHA1withRSA Version: 1 $ keytool -list -v -keystore mystore.p12 -storepass mypass -storetype pkcs12 -alias www \ -keypass mypass Alias name: www Creation date: Oct 1, 20xx Entry type: PrivateKeyEntry Certificate chain length: 3 Certificate[1]: Owner: CN=www.mysite.com Issuer: CN=CA Intermediate, O=CA, ST=Berkshire, C=GB Serial number: 1 Valid from: Thu Oct 01 16:47:44 NZDT 20xx until: Fri Sep 30 16:47:44 NZDT 20xx Certificate fingerprints: MD5: C3:CA:A8:10:8D:B9:BF:39:67:.... SHA1: 4B:91:C6:2D:30:D0:2D:E0:98:72:.... SHA256: 15:1F:EA:FE:92:34:A0:EE:C0:CC:.... Signature algorithm name: MD5withRSA Version: 1 Certificate[2]: Owner: CN=CA Intermediate, O=CA, ST=Berkshire, C=GB Issuer: CN=CA Root, O=CA, L=Newbury, ST=Berkshire, C=GB Serial number: 1 Valid from: Thu Oct 01 16:41:14 NZDT 20xx until: Tue Sep 30 16:41:14 NZDT 20xx Certificate fingerprints: MD5: 09:39:54:D5:02:14:99:A7:D8:.... SHA1: 21:77:D2:20:F4:4B:DA:0D:63:20:.... SHA256: 28:87:4B:4D:8A:A2:B4:0C:6A:A8:.... Signature algorithm name: MD5withRSA Version: 1 Certificate[3]: Owner: CN=CA Root, O=CA, L=Newbury, ST=Berkshire, C=GB Issuer: CN=CA Root, O=CA, L=Newbury, ST=Berkshire, C=GB Serial number: c5671bc640ecbd38 Valid from: Thu Oct 01 16:37:50 NZDT 20xx until: Sat Oct 31 16:37:50 NZDT 20xx Certificate fingerprints: MD5: A2:E1:2F:87:D2:37:74:CA:25:.... SHA1: FA:3A:3B:7E:CB:80:DC:22:5F:FA:.... SHA256: 8A:95:7A:DF:8A:C4:77:9D:3F:B7:08:.... Signature algorithm name: SHA1withRSA Version: 1
4.3 證書直接生成PKCS#12庫
也可以直接用私鑰和證書生成PKCS#12格式的密鑰庫。
$ openssl pkcs12 -export -out mystore.pfx -passout pass:mypass \ -inkey private.key -in ca1.crt -certfile chain.crt $ openssl pkcs12 -in mystore.pfx -nokeys -passin pass:mypass MAC verified OK Bag Attributes localKeyID: 4B 91 C6 2D 30 D0 2D E0 98 72 C3.... subject=/CN=www.mysite.com issuer=/C=GB/ST=Berkshire/O=CA/CN=CA Intermediate -----BEGIN CERTIFICATE----- MIIC1TCCAb0CAQEwDQYJKoZIhvcNA.... BAgTCUJlcmtzaGlyZTELMAkGA1UEC.... sCSemwRaoHNK -----END CERTIFICATE----- Bag Attributes: <No Attributes> subject=/C=GB/ST=Berkshire/O=CA/CN=CA Intermediate issuer=/C=GB/ST=Berkshire/L=Newbury/O=CA/CN=CA Root -----BEGIN CERTIFICATE----- MIIEDjCCAfYCAQEwDQYJKoZIhvcNA.... BAgTCUJlcmtzaGlyZTEQMA4GA1UEB.... 5J+8BVGkNVHmgmZjvak.... -----END CERTIFICATE----- Bag Attributes: <No Attributes> subject=/C=GB/ST=Berkshire/L=Newbury/O=CA/CN=CA Root issuer=/C=GB/ST=Berkshire/L=Newbury/O=CA/CN=CA Root -----BEGIN CERTIFICATE----- MIIFIDCCAwgCCQDFZxvGQOy9ODANB.... QjESMBAGA1UECBMJQmVya3NoaXJlM.... w6j6KrpgLdawc+kkfKyacSslVAY= -----END CERTIFICATE----- $ keytool -list -v -keystore mystore.pfx -storepass mypass -storetype pkcs12 Keystore type: PKCS12 Keystore provider: SunJSSE Your keystore contains 1 entry Alias name: 1 Creation date: Oct 1, 20xx Entry type: PrivateKeyEntry Certificate chain length: 3 Certificate[1]: Owner: CN=www.mysite.com Issuer: CN=CA Intermediate, O=CA, ST=Berkshire, C=GB Serial number: 1 Valid from: Thu Oct 01 16:47:44 NZDT 20xx until: Fri Sep 30 16:47:44 NZDT 20xx Certificate fingerprints: MD5: C3:CA:A8:10:8D:B9:BF:.... SHA1: 4B:91:C6:2D:30:D0:2D:E0:.... SHA256: 15:1F:EA:FE:92:34:A0:EE:.... Signature algorithm name: MD5withRSA Version: 1 Certificate[2]: Owner: CN=CA Intermediate, O=CA, ST=Berkshire, C=GB Issuer: CN=CA Root, O=CA, L=Newbury, ST=Berkshire, C=GB Serial number: 1 Valid from: Thu Oct 01 16:41:14 NZDT 20xx until: Tue Sep 30 16:41:14 NZDT 20xx Certificate fingerprints: MD5: 09:39:54:D5:02:14:99:.... SHA1: 21:77:D2:20:F4:4B:DA:0D:.... SHA256: 28:87:4B:4D:8A:A2:B4:0C:.... Signature algorithm name: MD5withRSA Version: 1 Certificate[3]: Owner: CN=CA Root, O=CA, L=Newbury, ST=Berkshire, C=GB Issuer: CN=CA Root, O=CA, L=Newbury, ST=Berkshire, C=GB Serial number: c5671bc640ecbd38 Valid from: Thu Oct 01 16:37:50 NZDT 20xx until: Sat Oct 31 16:37:50 NZDT 20xx Certificate fingerprints: MD5: A2:E1:2F:87:D2:37:74:.... SHA1: FA:3A:3B:7E:CB:80:DC:22:.... SHA256: 8A:95:7A:DF:8A:C4:77:9D:.... Signature algorithm name: SHA1withRSA Version: 1
4.4 應用程序的配置
【JBoss】把下列配置加入$CATALINA_HOME/conf/server.xml
<-- Define a SSL Coyote HTTP/1.1 Connector on port 8443 --> <Connector port="8443" minSpareThreads="5" maxSpareThreads="75" enableLookups="true" disableUploadTimeout="true" acceptCount="100" maxThreads="200" scheme="https" secure="true" SSLEnabled="true" keystoreFile="${user.home}/keystore.jks" keystorePass="mypass" clientAuth="false" sslProtocol="TLS"/>
【Tomcat】把下列配置加入$CATALINA_BASE/conf/server.xml
<-- Define a SSL Coyote HTTP/1.1 Connector on port 8443 --> <Connector protocol="org.apache.coyote.http11.Http11Protocol" port="8443" maxThreads="200" scheme="https" secure="true" SSLEnabled="true" keystoreFile="${user.home}/keystore.jks" keystorePass="mypass" clientAuth="false" sslProtocol="TLS"/>
5. 客戶機
客戶機如果是Windows,微軟提供一個證書實用程序來管理密鑰證書文件。
C:\> CertUtil -? Verbs: -dump -- Dump configuration information or files -asn -- Parse ASN.1 file -decodehex -- Decode hexadecimal-encoded file -decode -- Decode Base64-encoded file -encode -- Encode file to Base64 -deny -- Deny pending request -resubmit -- Resubmit pending request -setattributes -- Set attributes for pending request -setextension -- Set extension for pending request -revoke -- Revoke Certificate -isvalid -- Display current certificate disposition -getconfig -- Get default configuration string -ping -- Ping Active Directory Certificate Services Request interface -pingadmin -- Ping Active Directory Certificate Services Admin interface -CAInfo -- Display CA Information -ca.cert -- Retrieve the CA's certificate -ca.chain -- Retrieve the CA's certificate chain -GetCRL -- Get CRL -CRL -- Publish new CRLs [or delta CRLs only] -shutdown -- Shutdown Active Directory Certificate Services -installCert -- Install Certification Authority certificate -renewCert -- Renew Certification Authority certificate -schema -- Dump Certificate Schema -view -- Dump Certificate View -db -- Dump Raw Database -deleterow -- Delete server database row -backup -- Backup Active Directory Certificate Services -backupDB -- Backup Active Directory Certificate Services database -backupKey -- Backup Active Directory Certificate Services certificate and private key -restore -- Restore Active Directory Certificate Services -restoreDB -- Restore Active Directory Certificate Services database -restoreKey -- Restore Active Directory Certificate Services certificate and private key -importPFX -- Import certificate and private key -dynamicfilelist -- Display dynamic file List -databaselocations -- Display database locations -hashfile -- Generate and display cryptographic hash over a file -store -- Dump certificate store -addstore -- Add certificate to store -delstore -- Delete certificate from store -verifystore -- Verify certificate in store -repairstore -- Repair key association or update certificate properties or key security descriptor -viewstore -- Dump certificate store -viewdelstore -- Delete certificate from store -dsPublish -- Publish certificate or CRL to Active Directory -ADTemplate -- Display AD templates -Template -- Display Enrollment Policy templates -TemplateCAs -- Display CAs for template -CATemplates -- Display templates for CA -enrollmentServerURL -- Display, add or delete enrollment server URLs associated with a CA -ADCA -- Display AD CAs -CA -- Display Enrollment Policy CAs -Policy -- Display Enrollment Policy -PolicyCache -- Display or delete Enrollment Policy Cache entries -CredStore -- Display, add or delete Credential Store entries -InstallDefaultTemplates -- Install default certificate templates -URLCache -- Display or delete URL cache entries -pulse -- Pulse autoenrollment events -MachineInfo -- Display Active Directory machine object information -DCInfo -- Display domain controller information -EntInfo -- Display enterprise information -TCAInfo -- Display CA information -SCInfo -- Display smart card information -SCRoots -- Manage smart card root certificates -verifykeys -- Verify public/private key set -verify -- Verify certificate, CRL or chain -syncWithWU -- Sync with Windows Update -generateSSTFromWU -- Generate SST from Windows Update -sign -- Re-sign CRL or certificate -vroot -- Create/delete web virtual roots and file shares -vocsproot -- Create/delete web virtual roots for OCSP web proxy -addEnrollmentServer -- Add an Enrollment Server application -deleteEnrollmentServer -- Delete an Enrollment Server application -oid -- Display ObjectId or set display name -error -- Display error code message text -getreg -- Display registry value -setreg -- Set registry value -delreg -- Delete registry value -ImportKMS -- Import user keys and certificates into server database for key archival -ImportCert -- Import a certificate file into the database -GetKey -- Retrieve archived private key recovery blob -RecoverKey -- Recover archived private key -MergePFX -- Merge PFX files -ConvertEPF -- Convert PFX files to EPF file
通常服務器提供給客戶機的證書都附有證書鏈,它是由一系列CA證書發出的證書序列,最終以根CA證書結束。客戶機預 先存儲了一組可信任的根CA證書,服務器證書鏈的終結根CA證書若在其列,客戶機即可確認該服務器可信任。在Windows查閱PC中存儲的根CA證書, 可以在命令行中鍵入
C:\> certmgr.msc
客戶機從服務器管理者取得證書鏈ca1.crt和ca2.crt,又從證書認證機構取得根CA證書,便可以驗證該證書鏈的真實性。通常,可信任的證書認證機構的根CA證書均在系統安裝時就被預植在各類操作系統中。
$ openssl verify -CAfile root/public.crt ca2.crt ca2.crt: OK $ cat ca2.crt root/public.crt > chain.crt $ openssl verify -CAfile chain.crt ca1.crt ca1.crt: OK
5.1 客戶機測試SSL握手
客戶機查詢服務器的證書、測試能否用根CA證書與服務器成功完成SSL握手,可以執行如下OpenSSL的命令。通常,OpenSSL本身不包含可信任的根證書庫。因此檢查默認的OpenSSL配置目錄,在未安裝配置根證書庫/etc/pki/tls/cert.pem的客戶機測試可能出錯。
$ openssl version -d OPENSSLDIR: "/etc/pki/tls" $ openssl s_client -connect www.mysite.com:443 CONNECTED(00000003) depth=1 CN = www.mysite.com verify error:num=20:unable to get local issuer certificate verify return:0 ---
當用根CA證書進行同樣的測試,可以發現測試通過。
$ openssl s_client -CAfile root/public.crt -connect www.mysite.com:443 CONNECTED(00000003) depth=2 C = GB, O = CA, CN = CA Root verify return:1 depth=1 C = GB, O = CA, CN = CA Intermediate verify return:1 depth=0 CN = www.mysite.com verify return:1 ---
也可以首先構建根CA目錄,再對該目錄用c_rehash命令建立散列目錄,進而進行測試。
$ mkdir cacerts $ cp root/public.crt cacerts/ca-root.pem $ c_rehash cacerts Doing cacerts ca-root.pem => f9c1c685.0 $ openssl s_client -CApath cacerts -connect www.mysite.com:443 CONNECTED(00000003) depth=2 C = GB, O = CA, CN = CA Root verify return:1 depth=1 C = GB, O = CA, CN = CA Intermediate verify return:1 depth=0 CN = www.mysite.com verify return:1 ---
5.2 客戶機向服務器發送加密數據
客戶機把要發送的數據有私鑰進行簽名
$ echo testing > 1.txt $ openssl rsautl -encrypt -inkey ca1.crt -certin -in 1.txt -out 2.xxx
服務器對接受到數據進行解密
$ openssl rsautl -decrypt -inkey private.key -in 2.xxx -out 3.txt
6. 小結
CCITT的X.509採納了RSA公司的PKCS系列建議,規範建立了PKI下的密鑰(PKCS#1和PKCS#8)、簽名請求(PKCS#10)、證書(PKCS#7)、密鑰庫(PKCS#12)等各種數字對象。ITU制定了ASN.1標準以規範描述數字對象的抽象語法,其存儲的具體格式有BER、CER、DER等標準,其中DER(Distinguished Encoding Rules)被用在X.509數字簽名領域。把DER存儲格式進行Base64編碼,得到的PEM(Privacy-Enhanced Mail)格式也被納入X.509中而被廣泛應用於密鑰、簽名請求和證書的存儲與交換。
6.1 Java密鑰庫工具
keytool -genkeypair ... | 生成密鑰庫記錄(.jks) $ keytool -genkeypair -keyalg rsa -keystore 密鑰庫文件 -storepass 庫口令 \ -alias 密鑰名 -keypass 私鑰口令 -dname "CN=網站名" |
keytool -certreq ... | 生成簽名請求(.csr) $ keytool -certreq -keystore 密鑰庫文件 -storepass 庫口令 -alias 密鑰名 \ -keypass 私鑰口令 -file 簽名請求文件 |
keytool -importcert ... | 安裝證書(.jks) $ keytool -importcert -trustcacerts -keystore 密鑰庫 -storepass 庫口令 \ -alias 密鑰名 -keypass 私鑰口令 -file 證書文件 |
keytool -importkeystore ... | 密鑰庫格式轉換(.jks -> .pfx) $ keytool -importkeystore -srckeystore 密鑰庫文件1 -srcstorepass 庫口令1 \ -srcalias 密鑰名 -srckeypass 私鑰口令1 -destkeystore 密鑰庫文件2 \ -deststorepass 庫口令2 -destkeypass 私鑰口令2 -deststoretype pkcs12 |
keytool -list ... | 顯示密鑰庫記錄(.jks/.pfx) $ keytool -list -v -keystore 密鑰庫文件 -storepass 庫口令 -alias 密鑰名 \ -keypass 私鑰口令 |
6.2 OpenSSL工具
6.2.1 RSA私鑰PKCS#1
openssl genrsa ... openssl rsa ... | 生成RSA密鑰(.key) $ openssl genrsa -des -passout pass:口令 -out 加密RSA私鑰 2048 顯示RSA密鑰 $ openssl rsa -text -noout -passin pass:口令 -in 加密RSA私鑰 刪除口令 $ openssl rsa -passin pass:口令 -in 加密RSA私鑰 -out RSA私鑰 顯示RSA密鑰 $ openssl rsa -text -noout -in RSA私鑰
$ openssl rsa -pubout -passin pass:口令 -in 加密RSA私鑰 -out 公鑰 顯示公鑰 $ openssl rsa -pubin -text -noout -in 公鑰 PEM格式轉換成DER格式 # openssl rsa -in RSA私鑰.pem -outform der -out RSA私鑰.der |
openssl asn1parse ... | RSA私鑰的ASN.1分析 |
6.2.2 私鑰PKCS#8
openssl pkcs8 ... | 提取私鑰(.key) $ openssl pkcs8 -topk8 -nocrypt -in RSA私鑰 -out 私鑰 顯示私鑰 $ openssl rsa -text -noout -in 私鑰 |
openssl asn1parse ... | 私鑰的ASN.1分析 |
6.2.3 簽名請求PKCS#10
openssl req ... | 生成簽名請求(.csr) $ cat >openssl.cnf <<EOF $ openssl req -new -md5 -config openssl.cnf -passin pass:口令 \ -key 加密RSA私鑰 -out 簽名請求 $ openssl req -new -md5 -config openssl.cnf -key 私鑰 -out 簽名請求 顯示簽名請求 $ openssl req -text -noout -in 簽名請求 |
openssl ca ... | 簽名(.crt) |
6.2.4 證書鏈PKCS#7
openssl crl2pkcs7 ... | 生成X.509證書鏈(.p7b) |
openssl pkcs7 ... | 處理X.509證書鏈(.p7b) |
6.2.5 證書X.509
openssl x509 ... | 處理X.509證書文件(.crt) |
6.2.6 密鑰庫PKCS#12
openssl pkcs12 ... | 構建PKCS#12格式的密鑰庫(.pfx) |
參考資料:ASN.1、ASN.1/DER、X.509、Keytool、OpenSSL。
作者郵箱:zhang(dot)f(at)hotmail(dot)com