基於RSA的公鑰基礎體系下安全通信實戰

目錄

  1. 簡說RSA

  2. 服務器的初始密鑰對和認證請求

  3. 證書認證機構CA

  4. 服務器安裝CA簽名證書

  5. 客戶機

  6. 小結

從樣板戲《紅燈記》到好萊塢諜戰大片《風語者Windtalkers》等,許許多多動人故事都圍繞一個密電碼展開。那個年代通信密碼學裏都採用如今稱爲對稱密碼的技術,在這種技術中,加密和解密都使用同一個密鑰。因此,密鑰的保存運輸對通信的安全性顯得尤爲重要。直到70年代非對稱密碼技術的出現,情況才真正得到改善。在非對稱密碼技術中密鑰是成對出現的,一個私鑰一個公鑰。通信方只要妥善保管好私鑰而開放公鑰,就能保證安全通信。

非對稱密碼技術的出現,讓人們發現了另一個用途:數字簽名。它和合同商業文書的紙上簽名一樣,用於鑑別數字文書真實性的方法。一套數字簽名通常定義兩種互補的對數字文書的密鑰運算,私鑰用於簽名,而公鑰用於驗證。

網絡是一個開放的世界,服務器可以被不法節點冒名頂替,傳輸的數據可以被整個通路上的任何一個節點監聽。要保證客戶機和服務器在網絡中通信的安全,客戶機首先要檢查數字簽名以驗明服務器正身,然後還要加密要傳輸的數據,該數據到達服務器後再進行解密。非對稱密碼技術完滿地滿足了這兩種技術訴求。

↑TOP↑

1. 簡說RSA

作爲非對稱密碼技術典範的RSA是MIT的Rivest、Shamir和Adleman在1977年提出,他們是少有的幾個能用數學換豪宅豪車的天才。三個人以RSA技術成立了數家公司,最有名的當數RSA SecurityVeriSign,兩家公司最終分別被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)

證明如下:

  1. 因爲 e * d ≡ 1 (mod (p1-1)*(p2-1)),所以存在整數k使 ed = k * (p1-1) * (p2-1) + 1

  2. 因此 me * d  ≡ m * mk*(p1-1)*(p2-1)  (mod N)

  3. 因p1和p2爲質數,由費馬小定理,mk*(p1-1)*(p2-1) ≡ 1 (mod p1),mk*(p1-1)*(p2-1) ≡ 1 (mod p2)

  4. 所以 mk*(p1-1)*(p2-1) ≡ 1 (mod lcm[p1,p2]),即 mk*(p1-1)*(p2-1) ≡ 1 (mod N)

  5. 根據同餘乘法性質,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握手過程:

  1. 客戶機通過網絡發送請求安全會話的消息(通常請求是HTTPS協議的形式)。服務器通過發送其X.509證書(包含公鑰)進行響應。

  2. 客戶機驗證服務器證書的有效性,並檢驗該證書是否由可信任的證書認證機構(CA - certification authority)所簽發。

  3. 當證書有效,客戶機生成一次性的密鑰,並用服務器的公鑰對該密鑰進行加密。然後,客戶機把加密的會話密鑰發送給服務器。

  4. 服務器用其私鑰對其次進行解密,然後得到本次通訊的會話密鑰。

  5. 客戶機和服務器用其約定的會話密鑰開始數據通信,直到一次會話結束。


由於編寫密鑰代碼的複雜性,許多網站使用開源免費軟件。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


客戶機、服務器和證書認證機構是涉足安全通信的三方。圍繞證書這個技術關鍵,下面逐一細說三方通信過程中的協作。

↑TOP↑

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.keyDES標準依據密碼進行加密,以保證私鑰的保密性。

$ 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.keyASN.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....

↑TOP↑

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-----

↑TOP↑

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"/>

↑TOP↑

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


↑TOP↑

6. 小結

CCITT的X.509採納了RSA公司的PKCS系列建議,規範建立了PKI下的密鑰(PKCS#1PKCS#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
[ req ]
distinguished_name = req_dname
prompt = no
[ req_dname ]
C  = CN
ST = My Street
L  = My Locality
O  = My Organization
OU = My Unit
CN = My Common Name
emailAddress = [email protected]
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.1ASN.1/DERX.509KeytoolOpenSSL。  
作者郵箱:zhang(dot)f(at)hotmail(dot)com





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章