憑證主要分三種:根憑證(Root Certificate),中繼憑證(Intermediate Certificate),終端憑證(End-Entity Certificate),"通常"是階級式的驗證,像資料結構的樹一樣,根憑證就是根節點,終端憑證是葉節點,其他都是中繼憑證(如果沒有意外的話)。
不過還有一種網狀的,就是根憑證是跟其他根憑證互相信任那叫做互簽憑證(Cross Certificate),不過這不是要講的。
所以就要來用OpenSSL簽一組憑證串鏈(Certificate Chain)。
chrome 58版本(應該是)中,增加一個憑證驗證:SAN(Subject Alternative Name),SAN是x509憑證可選的欄位,當一組憑證想要簽不同的common name就可以使用SAN,有點類似DNS的canonical name,雖然他是可選的欄位,但是這次chrome更新讓很多不少自簽憑證都不能用。
先講一下會用到的副檔名:
- *.pem:是用ASCII方式表達憑證以base64編碼的憑證,我就用這格式保存公鑰以及私鑰。
- *.crt:憑證公鑰(通常是pem格式),保存公鑰。
- *.key:私鑰(通常是pem格式),保存私鑰。
- *.der:二進位的憑證,只放公鑰,給user用的。
- *.srl:憑證序號。
- *.csr:憑證的簽名請求(不會保存)。
預計最後產生的憑證串鏈
+ 192.168.1.100 +----- grism.packetx.biz + 192.168.1.150 packetx.biz + + 192.168.1.120 +----- ssl.packetx.biz
這邊是用common name表示,common name主要就是用哪個hostname(或IP地址)連到該網站。
根憑證是packetx.biz,兩個中繼憑證,grism.packetx.biz底下有三個憑證,所以使用這三個網站憑證只要驗證grism.packetx.biz或packetx.biz就好了。
說"或"是因為他是一條鏈,往上驗證只要一個成功就是安全的憑證。
首先簽一個根憑證,根憑證上面已經沒有可以再驗證的對象(authority),所以是自己簽給自己。
根憑證(Root Certificate)
私鑰
首先產生一把長度為4096 bit的私鑰(既然是根憑證,可以大一點沒關係,像是8192 bit),私鑰就是root_ca.key
。~ openssl genrsa -out root_ca.key 4096 Generating RSA private key, 4096 bit long modulus ......... .................................................. e is 65537 (0x10001)
產生config檔
我個人不喜歡用OpenSSL的組態檔和他的互動模式(interactive mode),能夠當參數給就用參數給;但是很不幸因為SAN關係,必須要用組態檔了。~ cat <<EOF > v3.ext subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer basicConstraints = critical, CA:true, pathlen:0 keyUsage = critical, digitalSignature, cRLSign, keyCertSign subjectAltName = @alt_names [alt_names] DNS.1 = packetx.biz EOF
先產生要增加的額外欄位,這邊注意底下的DNS.x = XXX就是增加common name的地方,所以如果有其他要增加就以這格式,
DNS.2
、DNS.3
...。其他欄位比較重要的是
basic constraints
的CA:true
和key usage
的key cert sign
,表示這個憑證可以再往下簽(總不可能讓它無限簽吧)。終端憑證這邊會有點不同,兩個差異可以看這邊。
What is the difference between the x.509 V3 extensions Basic Constraints and Key Usage to create a CA certificate?
接著複製預設的組態檔,然後把這個檔案append到後面。
~ cp /System/Library/OpenSSL/openssl.cnf . ~ cat v3.ext >> ./openssl.cnf ~ rm -f v3.ext
OS X預設的
openssl.cnf
位置在/System/Library/OpenSSL/openssl.cnf
,其他系統就自己查吧。產生自簽憑證(公鑰)
~ openssl req -new -x509 \ -days 3650 -sha256 \ -config ./openssl.cnf \ -key root_ca.key -out root_ca.crt \ -subj "/C=TW/ST=New Taipei City/L=Zhonghe Dist./O=PacketX Technology Ltd./OU=R&D/CN=packetx.biz"
-days
:憑證期限,根憑證時間長一點沒關係,不然到時候整組重簽會非常麻煩。-config
:就是剛剛的組態檔。-key
:剛剛的私鑰。-out
:要產生的憑證(公鑰)。-subj
:憑證主題,C是是國家,ST是州或省,L是地點或城市,O是組織名稱,OU是部門,CN就是common name。產生給使用者的憑證
使用者憑證給der
格式,把憑證(公鑰)轉成der格式。~ openssl x509 -in root_ca.crt -outform DER -out root_ca.der
使用者只要把這個
.der
加入受信任的根憑證,這憑證之後簽的所有憑證都會合法。合併公私鑰
有些server site可以接受公私鑰放在同一個檔案,方法很簡單,直接用cat把兩個檔案合併(必須是pem
格式)。
~ cat root_ca.crt root_ca.key > root_ca.pem
這樣就完成產生自簽根憑證了。
~ openssl x509 -in root_ca.pem -text -noout Certificate: Data: Version: 3 (0x2) Serial Number: dd:10:1d:57:89:03:e7:9d Signature Algorithm: sha256WithRSAEncryption Issuer: C=TW, ST=New Taipei City, L=Zhonghe Dist., O=PacketX Technology Ltd., OU=R&D, CN=packetx.biz Validity Not Before: May 29 08:46:10 2017 GMT Not After : May 27 08:46:10 2027 GMT Subject: C=TW, ST=New Taipei City, L=Zhonghe Dist., O=PacketX Technology Ltd., OU=R&D, CN=packetx.biz Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (4096 bit) Modulus (4096 bit): 00:db:05:71:21:00:72:86:c9:46:91:ba:7c:02:f5: 2a:b5:01:d8:59:9f:7d:21:5b:4e:aa:09:08:97:ef: ...略 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Key Identifier: C3:25:C1:9F:58:75:6E:18:44:13:A0:2A:70:54:4D:76:5B:6A:6E:D3 X509v3 Authority Key Identifier: keyid:C3:25:C1:9F:58:75:6E:18:44:13:A0:2A:70:54:4D:76:5B:6A:6E:D3 X509v3 Basic Constraints: critical CA:TRUE, pathlen:0 X509v3 Key Usage: critical Digital Signature, Certificate Sign, CRL Sign X509v3 Subject Alternative Name: DNS:packetx.biz Signature Algorithm: sha256WithRSAEncryption 95:83:7b:00:b3:c6:c1:f0:e2:b9:26:63:5e:e6:5b:49:d2:8b: f6:1e:ff:76:a9:88:fc:e8:53:bd:96:ee:b9:6a:a7:07:02:b7: ...略
可以看到
X509v3 Subject Alternative Name
有一個DNS了,這個就是SAN。中繼憑證(Intermediate Certificate)
私鑰
產生私鑰步驟都是一樣的。~ openssl genrsa -out sub_root_ca.key 4096 Generating RSA private key, 4096 bit long modulus ...................................................................................................................................++ ........................................++ e is 65537 (0x10001)
簽名請求
接著希望這把公私鑰是長在剛剛那張根憑證底下,所以產生一個簽名請求來跟根憑證簽署。~ openssl req -new \ -key sub_root_ca.key -out sub_root_ca.csr \ -subj "/C=TW/ST=New Taipei City/L=Zhonghe Dist./O=PacketX Technology Ltd./OU=R&D/CN=grism.packetx.biz"
這邊要注意,common name是不能重複的。
產生config檔
一樣先產生組態檔,這次不一樣的是不需要整個openssl.cnf,只需要增加的部分。~ cat <<EOF > v3.ext subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer basicConstraints = critical, CA:true, pathlen:0 keyUsage = critical, digitalSignature, cRLSign, keyCertSign subjectAltName = @alt_names [alt_names] DNS.1 = grism.packetx.biz EOF
簽名
~ openssl x509 -req \ -days 3650 -sha256 \ -extfile v3.ext -CAcreateserial \ -CA root_ca.crt -CAkey root_ca.key \ -in sub_root_ca.csr -out sub_root_ca.crt ~ rm -f v3.ext ~ rm -f sub_root_ca.csr
-extfile
:剛剛產生的組態檔。-CAcreateserial
:憑證中的序號,序號不能重複;使用這個參數會先產生sub_root_ca.srl
之後會利用這個檔案遞增上去。-CA
:憑證(上面的)公鑰。-CAkey
:憑證(上面的)私鑰。-in
:剛剛的簽名請求。-out
:該中繼憑證的公鑰。產生給使用者的憑證
~ openssl x509 -in sub_root_ca.crt -outform DER -out sub_root_ca.der
合併公私鑰
~ cat sub_root_ca.crt sub_root_ca.key > sub_root_ca.pem
這樣就完成中繼憑證了。
~ openssl x509 -in sub_root_ca.pem -text -noout Certificate: Data: Version: 3 (0x2) Serial Number: c4:94:9c:a5:f9:75:34:52 Signature Algorithm: sha256WithRSAEncryption Issuer: C=TW, ST=New Taipei City, L=Zhonghe Dist., O=PacketX Technology Ltd., OU=R&D, CN=packetx.biz Validity Not Before: May 29 09:32:18 2017 GMT Not After : May 27 09:32:18 2027 GMT Subject: C=TW, ST=New Taipei City, L=Zhonghe Dist., O=PacketX Technology Ltd., OU=R&D, CN=grism.packetx.biz Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (4096 bit) Modulus (4096 bit): 00:bd:06:e9:b2:27:31:8e:23:c7:74:3d:55:d7:89: 06:94:0b:31:ca:21:5e:25:4e:4b:65:a6:64:3f:c6: ...略 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Key Identifier: B2:E8:3A:64:59:33:3E:01:09:41:A1:F8:AD:06:90:62:CD:EE:0E:00 X509v3 Authority Key Identifier: keyid:C3:25:C1:9F:58:75:6E:18:44:13:A0:2A:70:54:4D:76:5B:6A:6E:D3 X509v3 Basic Constraints: critical CA:TRUE, pathlen:0 X509v3 Key Usage: critical Digital Signature, Certificate Sign, CRL Sign X509v3 Subject Alternative Name: DNS:grism.packetx.biz Signature Algorithm: sha256WithRSAEncryption 27:f1:5b:b3:02:70:12:5d:a0:8f:af:7a:d6:e4:ef:ca:9a:b8: ef:25:66:51:68:59:35:9b:4c:77:97:c2:2d:e4:34:37:98:94: ...略
Issuer
是簽發人,Subject
是這個憑證的一些基本資訊,一樣X509v3 Subject Alternative Name
有DNS。終端憑證(End-Entity Certificate)
私鑰
~ openssl genrsa -out server.key 2048 Generating RSA private key, 2048 bit long modulus ...+++ ..........+++ e is 65537 (0x10001)
簽名請求
~ openssl req -new \ -key server.key -out server.csr \ -subj "/C=TW/ST=New Taipei City/L=Zhonghe Dist./O=PacketX Technology Ltd./OU=R&D/CN=192.168.1.100"
簽名
~ cat <<EOF > v3.ext basicConstraints = CA:FALSE nsCertType = client, email subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment extendedKeyUsage = clientAuth, emailProtection subjectAltName = @alt_names [alt_names] DNS.1 = 192.168.1.100 EOF ~ openssl x509 -req \ -days 365 -sha256 \ -extfile v3.ext -CAcreateserial \ -CA sub_root_ca.crt -CAkey sub_root_ca.key \ -in server.csr -out server.crt ~ rm -f v3.ext ~ rm -f server.csr
這邊要注意的是,
basic constraints
的CA:false
,表示不能再往下簽了。-CA
和-CAkey
是上面一層的中繼憑證公私鑰。-days
最後發的憑證不用太久,通常一年就差不多了。合併公私鑰
~ cat server.crt server.key > server.pem
這裡不需要產生給使用者的憑證是因為只要匯入他上面的中繼憑證或根憑證就好了。
~ openssl x509 -in server.pem -text -noout Certificate: Data: Version: 3 (0x2) Serial Number: a7:42:3f:9b:28:91:45:13 Signature Algorithm: sha256WithRSAEncryption Issuer: C=TW, ST=New Taipei City, L=Zhonghe Dist., O=PacketX Technology Ltd., OU=R&D, CN=grism.packetx.biz Validity Not Before: May 29 10:16:14 2017 GMT Not After : May 29 10:16:14 2018 GMT Subject: C=TW, ST=New Taipei City, L=Zhonghe Dist., O=PacketX Technology Ltd., OU=R&D, CN=192.168.1.100 Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (2048 bit) Modulus (2048 bit): 00:9d:0d:59:64:a4:1d:09:98:dc:c4:cc:9f:30:ad: 77:b2:a5:1f:e6:8b:dd:1b:bb:5d:40:23:97:65:b2: ...略 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Cert Type: SSL Client, S/MIME X509v3 Subject Key Identifier: EA:C8:69:FA:95:E4:65:12:97:FE:13:E4:F0:DD:33:0B:9E:90:ED:E4 X509v3 Authority Key Identifier: keyid:B2:E8:3A:64:59:33:3E:01:09:41:A1:F8:AD:06:90:62:CD:EE:0E:00 X509v3 Key Usage: critical Digital Signature, Non Repudiation, Key Encipherment X509v3 Extended Key Usage: TLS Web Client Authentication, E-mail Protection X509v3 Subject Alternative Name: DNS:192.168.1.100 Signature Algorithm: sha256WithRSAEncryption 25:a4:90:00:e9:b0:06:18:79:b2:ca:ff:4b:e3:66:fb:4e:81: cc:df:16:aa:8c:e5:0e:4c:b8:c4:ec:55:f7:86:f4:a0:46:1b: ...略
Issuer
變成中繼憑證了。最後如果要透過指令驗證的話,需要把根憑證和中繼憑證加進來才能夠驗證。
~ cat root_ca.crt sub_root_ca.crt > tmp ~ openssl verify -CAfile tmp server.crt server.crt: OK ~ rm -f tmp或
~ openssl verify -CAfile <(cat root_ca.crt sub_root_ca.crt) server.crt server.crt: OK