在傳統的加密算法中,通信的雙方會採用一個共享祕鑰來對數據進行加密和解密。消息發送方先採用祕鑰對明文進行加密然後再進行傳送,待接收方收到消息後,再採用祕鑰對密文進行界面,以得到明文。由於加密和解密採用的祕鑰是相同的,這種加密算法也稱爲對稱加密。採用對稱加密的通信過程如下圖所示: 圖片來源 twilio

與傳統的對稱加密不同,非對稱加密算法採用了兩個密鑰:公開密鑰(publickey:簡稱公鑰)和私有密鑰(privatekey:簡稱私鑰)。公鑰與私鑰是成對使用的,如果用公鑰對數據進行加密,只有用對應的私鑰才能解密;同樣,使用私鑰對數據進行加密,只有用對應的公鑰才能解密。因爲加密和解密使用的是兩個不同的密鑰,所以這種算法叫作非對稱加密算法,也稱爲公開密鑰加密。採用非對稱加密的通信過程如下圖所示: 圖片來源 twilio

使用對稱加密算法需要雙方事先交換加/解密用的共享祕鑰,而交換的過程就存在密碼泄露的風險。非對稱加密的保密性比較好,因爲它消除了通信雙方交換祕鑰(加密用的私鑰)的需要。公鑰是不需要進行保密的,可以對外進行公佈,但加密後的信息只有私鑰的擁有者才能進行解密。

但是非對稱加密的效率比對稱加密低,因此在通信過程中一般會結合非對稱加密和對稱加密來實現數據加密傳輸。先通過非對稱加密協商一個用於對稱加密的共享祕鑰,後續在傳遞數據時採用該對稱加密祕鑰匙來對數據加密,以在保證安全性的同時兼顧加密傳輸的效率。SSL/TLS就採用了類似的加密傳輸機制。

下面我們用openssl命令來試驗創建一個祕鑰對,並使用該祕鑰對來進行加解密。 首先創建一個私鑰。

openssl genpkey -algorithm  RSA  -outform PEM -out private_key.pem

然後創建對應的公鑰。

openssl rsa -in private_key.pem -outform PEM -pubout -out public_key.pem
writing RSA key

使用公鑰加密文件,從命令輸出可以看到明文“Hello world”已經被加密爲密文。

#Create a test file...
echo 'Hello world' > plain_text

#Encrypt plain_text with public key...
openssl rsautl -encrypt -inkey public_key.pem -pubin -in plain_text -out encrypted_text

cat encrypted_text
?▒▒nC▒▒▒▒K▒߿$▒E▒{'▒k▒▒▒
▒▒▒▒>▒▒▒~▒▒▒▒p▒&Y▒▒▒▒'▒▒Z▒Z▒O$▒b▒ϒ▒Z▒mh▒*"▒^,▒▒6▒ê2▒▒▒?H▒&▒▒▒g▒5▒▒g▒a
▒yNs▒r▒75cyq▒P?p▒M[[email protected]▒▒b▒*o▒▒?(▒▒M▒▒x▒^▒▒ٱ  Q▒▒@▒jޤ▒K▒▒▒&=)▒▒▒▒y▒▒▒
 H▒▒▒B▒0Z▒0▒▒▒~t|<~▒b/Y▒O▒^⫯&a

使用私鑰進行解密,密文被還原爲明文“Hello world”。

#Decrypt encrypted_text with private  key...
openssl rsautl -decrypt -inkey private_key.pem -in encrypted_text -out decrypted_text

cat  decrypted_text
Hello world

哈希函數

哈希函數是一個具有以下輸入和輸出的數學函數 H(X)=Y:

  • H: 哈希函數,其輸入參數爲X,輸出爲Y。
  • X: 哈希方法的輸入,可以是任意長度的任意數據。
  • Y:哈希方法的輸出,是一段固定長度的二進制數據,長度可以是256,384,516…。

用於加密的哈希函數有下面的特徵:

  • 無法找到產生相同輸出的輸入。從數學理論上來說,我們是可以找到具備相同輸出的輸入的,因爲輸入可以是任何數據,而輸出則是固定長度的。但是對於一個好的哈希函數來說,我們就是使用地球上所有的計算機一起進行計算,也無法在可以接受的時間內找出該輸入。
  • 無法通過輸出反推出輸入。對於輸入值的範圍很大的情況來說,這是沒有問題的,如果輸入值是一個有限的集合,則很容易通過遍歷嘗試每一個輸入值來推斷出一個輸出對應的輸入。在這種情況下,我們可以爲輸入X加上一個隨機值R來隱藏輸入值,即 H(R|X)=Y。由於攻擊者不知道R的值,因此無法再通過遍歷嘗試每個輸入的方法推斷出Y對應的輸入。這種做法被稱爲“加鹽”,例如我們在存儲密碼時就會通過“加鹽”的方法來避免彩虹表攻擊。

從上面哈希函數的的特點可以看出,一段數據的哈希值就是該數據的一個固定長度的,獨一無二的“特徵”,我們可以把哈希值看作該數據的“數字指紋”。

數字簽名

我們在“非對稱加密”一節中演示了採用公鑰進行加密,私鑰進行解密的過程。實際上我們也可以採用私鑰進行加密,採用公鑰進行解密。祕鑰對的擁有者採用私鑰對一段數據進行加密,然後公佈密文,原文和公鑰,任何人都可以使用公鑰解密密文,然後覈對原文和密文是否一致。由於私鑰是不公開的,只有擁有者才能採用私鑰對數據加密,所以這種方式可以用於證明發布這條消息的用戶擁有消息中的公鑰對應的私鑰,這就是數字簽名的基本原理。在數字證書,區塊鏈,比特幣中就採用了這種方法來驗證用戶身份。採用數學公式來表示數字簽名的原理:

  • 消息發送者生成祕鑰對: (sk,pk):= generates(keysize)
  • 消息發送者生成數字簽名: signature := encrypt(sk, message)
  • 消息接收者驗證發送者身份: isValid := isEqual(decrypt(pk, message),message)

該方法直接對傳遞的原始數據進行加密,當數據很大時,對數據進行簽名和傳輸的效率很低。此時我們可以通過哈希函數提取數據的特徵值,然後只對數據的哈希值進行簽名。由於哈希函數的特點,通過哈希值同樣可以驗證簽名的私鑰身份,同時還避免了對整段數據進行加密和傳輸的開銷。採用哈希函數後的數字簽名原理如下:

  • 消息發送者生成祕鑰對: (sk,pk):= generates(keysize)
  • 消息發送者生成數字簽名: signature := encrypt(sk, hash(message))
  • 消息接受者驗證發送者身份: isValid := isEqual(decrypt(pk, message),hash(message))

下圖展示了數字簽名和驗證的流程: 圖片來源 revasolutions

除了驗證公鑰擁有者的身份之外,數字簽名還可以證明傳輸的數據沒有被人惡意篡改,因爲如果數據被篡改了,數據的哈希值就和解密後的簽名對不上。

數字證書

在前面我們講到可以通過數字簽名來證明一個人或者組織擁有一個公鑰對應的私鑰,因此我們可以把一個公鑰看作一個數字身份標識,如果一個人可以發出使用該標識(公鑰)簽名的數據,則說明該用戶是該公鑰及對應的私鑰的擁有者。

在現實生活中也有類似的身份證明,身份證明有匿名的,也有實名的。匿名的身份證明只是用於證明你擁有某一項身份或者權益,並不需要聲明你到底是誰,例如各種運動俱樂部的會員卡。實名的身份證明則需要你的姓名,住址,出生年月等信息,例如我們的身份證。

當我們只需要匿名的身份標識時,直接採用公鑰就可以了,採用公鑰對應的私鑰對任意一段數據進行數字簽名,併發布原生數據,公鑰和簽名數據,就可以證明公鑰擁有者的身份了。比特幣是一個匿名的交易系統,只需要證明你是比特幣的擁有者,並不需要公佈真實身份,因此在比特幣中就直接採用了公鑰作爲比特幣的錢包地址。

在大部分的情況下,我們還需要證明公鑰擁有者的真實身份,例如姓名,地址,電子郵件等,因此會將這些信息隨着公鑰一起發佈,這就是數字證書。在前面介紹的數字簽名中,傳輸的文本是任意一段數據,在數字證書中的數據則是證書擁有者的真實身份信息。我們可以把數字證書理解爲包含“公鑰+姓名+地址+電子郵件等個人/組織信息”的一段數據,通過數字簽名來證明證書擁有者的身份和確保證書中的信息在傳輸過程中不被惡意篡改。

RFC5280 定義了x.509公鑰證書的標準格式,如下圖所示: 圖片來源 researchgate

從圖中可以看到,除了證書擁有者的公鑰,證書擁有者的一些基本信息和數字簽名之外,還包含了證書籤發者的信息,我們後續會對此進行進一步說明。

我們可以採用openssl來創建一個數字證書及其對應的私鑰:

openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem
Generating a RSA private key
.................+++++
.......+++++
writing new private key to 'key.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:Sichuan
Locality Name (eg, city) []:Chengdu
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Make a Lot of Money Ltd        
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:zhaohuabing
Email Address []:[email protected]

在證書創建過程中,會要求輸入姓名、住址、電子郵件等身份信息。

查看剛纔生成的證書文件中的內容。

openssl x509 -in certificate.pem -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            22:92:57:9c:c4:2f:8a:fc:77:13:7a:67:71:78:2d:b3:f9:d1:6c:50
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = CN, ST = Sichuan, L = Chengdu, O = Make a Lot of Money Ltd, CN = zhaohuabing, emailAddress = [email protected]
        Validity
            Not Before: Mar 19 11:38:30 2020 GMT
            Not After : Mar 19 11:38:30 2021 GMT
        Subject: C = CN, ST = Sichuan, L = Chengdu, O = Make a Lot of Money Ltd, CN = zhaohuabing, emailAddress = [email protected]
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:a2:34:3d:bc:79:52:e0:aa:04:96:d3:89:12:d5:
                    ec:53:f2:60:b2:81:f6:77:99:0c:5f:ba:8d:b3:aa:
                    88:59:05:ae:4b:53:2a:03:f2:10:12:a3:71:eb:23:
                    9d:3c:63:d3:ec:b6:12:2a:f7:bc:8d:4b:a9:84:f5:
                    67:17:7a:6b:50:aa:dd:9b:5c:8c:b1:5e:a8:33:f4:
                    d0:69:ba:78:11:84:ee:44:80:46:2b:c3:a4:39:53:
                    f2:de:d6:1a:2b:3a:e2:87:0b:06:30:8f:1f:89:aa:
                    59:2a:f8:43:04:3a:b5:59:60:60:f0:2e:64:10:38:
                    84:4f:9a:07:67:f0:8a:d9:8e:04:20:9d:22:32:63:
                    79:2e:fb:e6:da:90:14:23:da:8f:3e:31:b4:96:91:
                    c6:3a:08:3b:a2:3c:c0:94:55:38:d3:73:1a:b1:e7:
                    ec:c8:44:3e:42:a0:8a:99:c5:8a:ac:e9:5a:4a:06:
                    f4:53:34:c7:88:fa:b9:81:40:19:bb:97:f2:26:74:
                    05:20:bd:2d:31:93:da:2c:ba:b3:87:96:0b:dc:de:
                    3f:86:05:b8:56:e8:ab:b1:75:8d:33:41:b3:cc:16:
                    dc:a7:fb:ae:05:55:a1:96:11:9d:1e:16:c6:55:d6:
                    4e:cf:ab:c3:b3:29:bd:43:84:2f:a0:29:ee:b1:3d:
                    02:45
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier:
                C9:45:FA:08:E2:95:6B:C4:CC:D5:15:DC:2C:19:05:C9:40:E6:DD:F2
            X509v3 Authority Key Identifier:
                keyid:C9:45:FA:08:E2:95:6B:C4:CC:D5:15:DC:2C:19:05:C9:40:E6:DD:F2

            X509v3 Basic Constraints: critical
                CA:TRUE
    Signature Algorithm: sha256WithRSAEncryption
         6b:bd:33:f7:4b:35:73:1f:bf:ad:24:f0:ce:9c:43:f0:51:96:
         19:08:bb:40:1b:a8:67:c6:e4:15:db:7a:09:78:74:56:06:7b:
         17:23:15:14:fc:d5:09:39:fd:dd:63:14:a3:6d:ca:e6:59:cf:
         83:1c:a9:f0:c4:8a:73:43:fc:12:9a:26:31:82:2a:99:74:0b:
         d2:57:ca:b9:85:fd:60:7e:c1:84:9a:51:9e:73:ac:84:43:f1:
         44:b9:ec:59:6b:42:2b:48:8c:b2:ff:32:0f:58:c6:61:7d:57:
         82:31:43:58:e8:76:2a:f4:eb:7f:96:50:b7:6b:69:15:39:fa:
         cc:63:b7:12:6d:ed:42:6b:62:cc:9c:f4:4d:e3:46:8e:a2:e8:
         ff:9c:2a:e9:c9:1f:b6:fa:a1:b6:4f:4b:92:8d:b2:1e:2e:64:
         67:1f:37:3c:6b:69:29:6f:1a:28:3a:f0:a9:35:ad:61:a8:5c:
         71:78:00:7f:48:48:ee:ef:dc:9a:17:ca:31:d0:da:ce:d4:f2:
         9e:de:7c:91:bb:aa:e7:ea:9d:4f:96:88:00:a9:25:09:0c:e0:
         fb:aa:4b:12:a2:d7:da:e9:3a:e6:1d:89:bf:05:96:76:aa:29:
         c4:c2:e2:0e:7d:39:23:b6:e9:56:17:89:d5:88:44:2e:ae:37:
         a6:50:b9:b4
-----BEGIN CERTIFICATE-----
MIIEATCCAumgAwIBAgIUIpJXnMQvivx3E3pncXgts/nRbFAwDQYJKoZIhvcNAQEL
BQAwgY8xCzAJBgNVBAYTAkNOMRAwDgYDVQQIDAdTaWNodWFuMRAwDgYDVQQHDAdD
aGVuZ2R1MSAwHgYDVQQKDBdNYWtlIGEgTG90IG9mIE1vbmV5IEx0ZDEUMBIGA1UE
AwwLemhhb2h1YWJpbmcxJDAiBgkqhkiG9w0BCQEWFXpoYW9odWFiaW5nQGdtYWls
LmNvbTAeFw0yMDAzMTkxMTM4MzBaFw0yMTAzMTkxMTM4MzBaMIGPMQswCQYDVQQG
EwJDTjEQMA4GA1UECAwHU2ljaHVhbjEQMA4GA1UEBwwHQ2hlbmdkdTEgMB4GA1UE
CgwXTWFrZSBhIExvdCBvZiBNb25leSBMdGQxFDASBgNVBAMMC3poYW9odWFiaW5n
MSQwIgYJKoZIhvcNAQkBFhV6aGFvaHVhYmluZ0BnbWFpbC5jb20wggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCiND28eVLgqgSW04kS1exT8mCygfZ3mQxf
uo2zqohZBa5LUyoD8hASo3HrI508Y9PsthIq97yNS6mE9WcXemtQqt2bXIyxXqgz
9NBpungRhO5EgEYrw6Q5U/Le1horOuKHCwYwjx+Jqlkq+EMEOrVZYGDwLmQQOIRP
mgdn8IrZjgQgnSIyY3ku++bakBQj2o8+MbSWkcY6CDuiPMCUVTjTcxqx5+zIRD5C
oIqZxYqs6VpKBvRTNMeI+rmBQBm7l/ImdAUgvS0xk9osurOHlgvc3j+GBbhW6Kux
dY0zQbPMFtyn+64FVaGWEZ0eFsZV1k7Pq8OzKb1DhC+gKe6xPQJFAgMBAAGjUzBR
MB0GA1UdDgQWBBTJRfoI4pVrxMzVFdwsGQXJQObd8jAfBgNVHSMEGDAWgBTJRfoI
4pVrxMzVFdwsGQXJQObd8jAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA
A4IBAQBrvTP3SzVzH7+tJPDOnEPwUZYZCLtAG6hnxuQV23oJeHRWBnsXIxUU/NUJ
Of3dYxSjbcrmWc+DHKnwxIpzQ/wSmiYxgiqZdAvSV8q5hf1gfsGEmlGec6yEQ/FE
uexZa0IrSIyy/zIPWMZhfVeCMUNY6HYq9Ot/llC3a2kVOfrMY7cSbe1Ca2LMnPRN
40aOouj/nCrpyR+2+qG2T0uSjbIeLmRnHzc8a2kpbxooOvCpNa1hqFxxeAB/SEju
79yaF8ox0NrO1PKe3nyRu6rn6p1PlogAqSUJDOD7qksSotfa6TrmHYm/BZZ2qinE
wuIOfTkjtulWF4nViEQurjemULm0
-----END CERTIFICATE-----

命令行輸出的前半部分是解碼後的正式內容,"—–BEGIN CERTIFICATE—–“之後的部分則是採用PEM(Privacy Enhanced Mail)格式進行Base64編碼的原始證書文件內容。其中值得重點關注的有以下字段:

  • Issuer: 證書頒發機構。
  • Subject: 證書擁有者。
  • Subject Public Key Info: 證書擁有者的公鑰。
  • Signature Algorithm: 簽名算法及數字簽名。

自簽名證書

生成數字證書時會使用證書頒發機構(Issuer)的私鑰對證書內容(證書擁有者的公鑰和身份信息)進行數字簽名。從上面實驗的輸出可以看到,Issuer和Subject中的信息是相同的。都是“C = CN, ST = Sichuan, L = Chengdu, O = Make a Lot of Money Ltd, CN = zhaohuabing”,這說明對該證書進行簽名使用的私鑰是證書中公鑰對應的私鑰。這種採用證書中的公鑰對應的私鑰進行簽名的證書被稱爲自簽名證書,意思是簽名者和證書擁有者爲同一人。

下圖展示了一個自簽名證書的內部結構:

我們可以用openssl verify命令來驗證證書,-CAfile參數指明驗證證書數字簽名使用的公鑰。由於這是一個自簽名證書,因此需要採用自身證書中的公鑰來驗證該證書。如下所示:

openssl verify -CAfile certificate.pem certificate.pem
certificate.pem: OK

自簽名證書可以證明該證書是由證書中公鑰(以及對應的私鑰)擁有者發佈的,並且可以保證證書中包含的信息例如姓名、組織機構、地址等未被第三方篡改過,但是並不能解決證書擁有者和證書使用者之間的信任問題。我們可以把自簽名證書理解爲一個人給自己印了一張名片,名片中寫上了自己的姓名,地址,電子郵件等信息,然後把這張名片分發給別人。如果別人從其他渠道中得知你是可以信任的,則會欣然接受該張名片,並且認可名片中的信息;但如果別人之前並不認識你,那麼就會對名片中的信息持懷疑態度:我怎麼知道你名片中的姓名等內容是真實的呢?因此自簽名證書的使用場合是有限的,只限於一些組織機構的內部系統中(我們可以認爲在一個系統內部中,自簽名證書所聲明的身份是可信的),並不能在互聯網上使用。

證書機構

前面我們講到自簽發證書存在內容的可信度問題,因此在數字證書體系中引入了證書機構來解決該問題。我們可以把證書機構看作真實世界中的權威機構,例如政府部門。我們使用的身份證具有可信度,這是因爲有政府部門擔保其中信息的正確性。在數字證書體系中也有類似的權威機構,我們稱爲證書機構。

引入證書機構後,我們使用證書機構而不是證書擁有者的私鑰來對數字證書進行簽名,如下圖所示: 我們認爲證書機構是可信的,那麼使用證書機構的私鑰對證書進行簽名相當於證書機構用自己的信譽來保證了證書中用戶身份信息和公鑰的真實性。只要使用該證書的用戶用證書機構的公鑰驗證了該證書中的簽名,就可以信任該證書中的公鑰和用戶身份。然後就可以使用該公鑰來和證書擁有者進行安全通信了,例如訪問證書擁有者的網站。

看到這裏你可能會發現一個問題:在驗證證書時我們需要用到證書機構的公鑰,那我們如何拿到證書機構的公鑰和身份信息,並保證證書機構自身身份的真實性呢?權威證書機構會爲自己頒發一個自簽名證書,這稱爲證書機構的根證書,然後操作系統和瀏覽器會將這些根證書內置到發佈的版本中,當驗證用戶證書時,操作系統和瀏覽器會認爲內置的這些證書機構的證書是可信的,這樣就解決了證書機構的信任問題。有時,我們可能想使用一些未被操作系統和瀏覽器缺省內置的證書機構,則可以把這些證書機構的根證書手動導入到操作系統或者瀏覽器中。

假設Alice要發送一個電子商務合同給Bob,爲了向Bob表明合同是Alice發送的,Alice使用自己的證書對該合同進行數字簽名後再發送,證書的簽發、使用和驗證過程是這樣的:

  1. Alice在本地生成Private Key和CSR(Certificate Signing Request)。CSR中包含了Alice的公鑰和姓名,機構、地址等身份信息。
  2. Alice使用該CSR向證書機構發起數字證書申請。
  3. 證書機構驗證Alice的身份後,使用CSR中的信息生成數字證書,並使用自己的CA根證書對應的私鑰對該證書籤名。
  4. Alice使用自己的Private Key對合同進行簽名,然後將簽名後的合同和自己的證書一起併發送給Bob。
  5. Bob使用操作系統中自帶的證書機構根證書中的公鑰來驗證Alice證書中的簽名,以確認Alice的身份和公鑰。
  6. Alice的證書驗證成功後,Bob使用Alice證書中的公鑰來驗證合同中數字簽名。
  7. 合同數字簽名通過驗證,可以證明該合同爲Alice本人發送,並且中間未被第三方篡改過。

下面我們通過openssl命令行來試驗這一流程。

模擬一個證書機構,爲該證書機構創建私鑰和自簽名的根證書。

openssl req -newkey rsa:2048 -nodes -keyout rootCA.key -x509 -days 365 -out rootCA.crt
Generating a RSA private key
.................................................................................................+++++
............+++++
writing new private key to 'rootCA.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:CN
string is too long, it needs to be no more than 2 bytes long
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:Sichuan
Locality Name (eg, city) []:Chengdu
Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Root CA
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:My Root CA
Email Address []:[email protected]

創建Alice的私鑰和CSR(證書籤名請求),該CSR中包含了Alice的私鑰對應的公鑰,以及Alice的姓名,機構等身份信息。

openssl req -new -nodes -keyout Alice.key -out Alice.csr
Generating a RSA private key
.....................+++++
................................................+++++
writing new private key to 'Alice.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:Sichuan
Locality Name (eg, city) []:Chengdu
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Alice Trade Ltd
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:Alice
Email Address []:[email protected]

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

使用證書機構的私鑰、根證書和Alice的CSR爲Alice創建數字證書。

openssl x509 -req -in Alice.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out Alice.crt
Signature ok
subject=C = CN, ST = Sichuan, L = Chengdu, O = Alice Trade Ltd, CN = Alice, emailAddress = [email protected]
Getting CA Private Key

Alice使用私鑰對商業合同簽名,然後把簽名後的合同和Alice的數字證書一起發給Bob。

echo "A very important business contract to Bob" > alice-contract
openssl dgst -sha256 -sign Alice.key -out alice-contract-sign.sha256 alice-contract

Bob收到該合同後,需要先驗證Alice的數字證書是否合法。

openssl verify Alice.crt
C = CN, ST = Sichuan, L = Chengdu, O = Alice Trade Ltd, CN = Alice, emailAddress = [email protected]
error 20 at 0 depth lookup: unable to get local issuer certificate
error Alice.crt: verification failed

在這裏看到驗證失敗了,原因是簽發Alice證書的的根證書是由我們生成的一個自簽名證書,不是內置在操作系統內的權威機構的根證書。

我們可以在驗證Alice證書的命令行中指定證書機構的根證書,可以看到在指定根證書後,驗證成功了。

openssl verify -CAfile rootCA.crt  Alice.crt
Alice.crt: OK

在正常情況下,該根證書應該是內置在操作系統中的,我們通過命令把該證書導入到系統中,以模擬內置證書的情況。備註:每種操作系統的證書導入方法有所區別,本例中是Arch Linux中的導入方法。

sudo cp rootCA.crt /etc/ca-certificates/trust-source/anchors/
sudo trust extract-compat

然後再對Alice的證書進行驗證,即使不指定根證書,也可以驗證成功。這是因爲驗證時會缺省使用操作系統中內置的根證書。

openssl verify Alice.crt
Alice.crt: OK

在驗證了Alice的證書後,使用Alice的證書中的公鑰對合同的電子簽名進行驗證,以證明該合同的確是由Alice發出的。

#從Alice的證書中導出Alice的公鑰
openssl x509 -pubkey -noout -in Alice.crt  > Alice-pub.key
#使用公鑰對合同簽名進行驗證
openssl dgst -sha256 -verify Alice-pub.key -signature alice-contract-sign.sha256 alice-contract
Verified OK

證書鏈

交叉驗證

本文試驗所採用的所有命令已經編寫成可以執行的腳本,可以從該 github 地址下載後自行執行試驗。

相關文章