Openssl

證書頒發機構根證書到期和續訂

  • December 7, 2021

2004 年,我在 Linux 上使用 OpenSSL 和 OpenVPN 提供的簡單管理腳本建立了一個小型證書頒發機構。按照我當時找到的指南,我將根 CA 證書的有效期設置為 10 年。從那時起,我為 OpenVPN 隧道、網站和電子郵件伺服器簽署了許多證書,所有這些證書也都有 10 年的有效期(這可能是錯誤的,但我當時並不知道更好)。

我找到了很多關於設置 CA 的指南,但關於其管理的資訊很少,特別是關於根 CA 證書到期時必須做的事情,這將在 2014 年的某個時間發生。所以我有以下問題:

  • 在根 CA 證書到期後延長有效期的證書會在根 CA 證書到期後立即失效,還是繼續有效(因為它們是在 CA 證書的有效期內簽署的)?

  • 需要哪些操作來更新根 CA 證書並確保在其到期期間順利過渡?

    • 我可以以某種方式重新簽署具有不同有效期的目前根 CA 證書,並將新簽署的證書上傳到客戶端,以便客戶端證書保持有效嗎?
    • 還是我需要用新的根 CA 證書籤名的新證書替換所有客戶端證書?
  • 什麼時候應該更新根 CA 證書?接近到期日,還是到期前的合理時間?

  • 如果根 CA 證書的更新成為一項主要工作,我現在可以做些什麼來確保在下一次更新時更順利地過渡(當然,沒有將有效期設置為 100 年)?

由於我對某些客戶端的唯一訪問是通過使用由目前 CA 證書籤名的證書的 OpenVPN 隧道,因此情況稍微複雜一些,因此如果我必須替換所有客戶端證書,我將需要複製將新文件發送到客戶端,重新啟動隧道,交叉手指,希望之後會出現。

在根 CA 上保持相同的私鑰允許所有證書繼續針對新根成功驗證;您所要做的就是信任新的根。

證書籤名關係基於來自私鑰的簽名;在生成新的公共證書時保持相同的私鑰(以及隱含的相同的公鑰),並根據需要更改新的有效期和任何其他新屬性,從而保持信任關係。CRL 也可以從舊證書延續到新證書,因為它們就像證書一樣,由私鑰簽名。


那麼,讓我們來驗證一下吧!

創建根 CA:

openssl req -new -x509 -keyout root.key -out origroot.pem -days 3650 -nodes

從中生成一個子證書:

openssl genrsa -out cert.key 1024
openssl req -new -key cert.key -out cert.csr

簽署兒童證書:

openssl x509 -req -in cert.csr -CA origroot.pem -CAkey root.key -create_serial -out cert.pem
rm cert.csr

一切就緒,正常的證書關係。讓我們驗證信任:

# openssl verify -CAfile origroot.pem -verbose cert.pem
cert.pem: OK

好吧,現在讓我們說 10 年過去了。讓我們從同一個根私鑰生成一個新的公共證書。

openssl req -new -key root.key -out newcsr.csr
openssl x509 -req -days 3650 -in newcsr.csr -signkey root.key -out newroot.pem
rm newcsr.csr

而且..有用嗎?

# openssl verify -CAfile newroot.pem -verbose cert.pem
cert.pem: OK

但為什麼?它們是不同的文件,對吧?

# sha1sum newroot.pem
62577e00309e5eacf210d0538cd79c3cdc834020  newroot.pem
# sha1sum origroot.pem
c1d65a6cdfa6fc0e0a800be5edd3ab3b603e1899  origroot.pem

是的,但這並不意味著新的公鑰與證書上的簽名不匹配。不同的序列號,相同的模數:

# openssl x509 -noout -text -in origroot.pem
       Serial Number:
           c0:67:16:c0:8a:6b:59:1d
...
           RSA Public Key: (1024 bit)
               Modulus (1024 bit):
                   00:bd:56:b5:26:06:c1:f6:4c:f4:7c:14:2c:0d:dd:
                   3c:eb:8f:0a:c0:9d:d8:b4:8c:b5:d9:c7:87:4e:25:
                   8f:7c:92:4d:8f:b3:cc:e9:56:8d:db:f7:fd:d3:57:
                   1f:17:13:25:e7:3f:79:68:9f:b5:20:c9:ef:2f:3d:
                   4b:8d:23:fe:52:98:15:53:3a:91:e1:14:05:a7:7a:
                   9b:20:a9:b2:98:6e:67:36:04:dd:a6:cb:6c:3e:23:
                   6b:73:5b:f1:dd:9e:70:2b:f7:6e:bd:dc:d1:39:98:
                   1f:84:2a:ca:6c:ad:99:8a:fa:05:41:68:f8:e4:10:
                   d7:a3:66:0a:45:bd:0e:cd:9d
# openssl x509 -noout -text -in newroot.pem
       Serial Number:
           9a:a4:7b:e9:2b:0e:2c:32
...
           RSA Public Key: (1024 bit)
               Modulus (1024 bit):
                   00:bd:56:b5:26:06:c1:f6:4c:f4:7c:14:2c:0d:dd:
                   3c:eb:8f:0a:c0:9d:d8:b4:8c:b5:d9:c7:87:4e:25:
                   8f:7c:92:4d:8f:b3:cc:e9:56:8d:db:f7:fd:d3:57:
                   1f:17:13:25:e7:3f:79:68:9f:b5:20:c9:ef:2f:3d:
                   4b:8d:23:fe:52:98:15:53:3a:91:e1:14:05:a7:7a:
                   9b:20:a9:b2:98:6e:67:36:04:dd:a6:cb:6c:3e:23:
                   6b:73:5b:f1:dd:9e:70:2b:f7:6e:bd:dc:d1:39:98:
                   1f:84:2a:ca:6c:ad:99:8a:fa:05:41:68:f8:e4:10:
                   d7:a3:66:0a:45:bd:0e:cd:9d

讓我們進一步驗證它在現實世界的證書驗證中是否有效。

啟動一個 Apache 實例,讓我們試一試(debian 文件結構,根據需要進行調整):

# cp cert.pem /etc/ssl/certs/
# cp origroot.pem /etc/ssl/certs/
# cp newroot.pem /etc/ssl/certs/
# cp cert.key /etc/ssl/private/

我們將在VirtualHost監聽 443 時設置這些指令 - 請記住,根證書在生成和簽名newroot.pem時甚至都不存在。cert.pem

SSLEngine on
SSLCertificateFile /etc/ssl/certs/cert.pem
SSLCertificateKeyFile /etc/ssl/private/cert.key
SSLCertificateChainFile /etc/ssl/certs/newroot.pem

讓我們看看 openssl 是如何看待它的:

# openssl s_client -showcerts -CAfile newroot.pem -connect localhost:443

Certificate chain
0 s:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=server.lan
  i:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=root
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
1 s:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=root
  i:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=root
-----BEGIN CERTIFICATE-----
MIICHzCCAYgCCQCapHvpKw4sMjANBgkqhkiG9w0BAQUFADBUMQswCQYDVQQGEwJB
...
-----END CERTIFICATE-----
(this should match the actual contents of newroot.pem)
...
Verify return code: 0 (ok)

好的,那麼使用 MS 的加密 API 的瀏覽器怎麼樣?首先要信任根,然後就可以了,有了新根的序列號:

新根

而且,我們也應該使用舊的根。切換 Apache 的配置:

SSLEngine on
SSLCertificateFile /etc/ssl/certs/cert.pem
SSLCertificateKeyFile /etc/ssl/private/cert.key
SSLCertificateChainFile /etc/ssl/certs/origroot.pem

在 Apache 上完全重啟,重新載入不會正確切換證書。

# openssl s_client -showcerts -CAfile origroot.pem -connect localhost:443

Certificate chain
0 s:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=server.lan
  i:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=root
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
1 s:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=root
  i:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=root
-----BEGIN CERTIFICATE-----
MIIC3jCCAkegAwIBAgIJAMBnFsCKa1kdMA0GCSqGSIb3DQEBBQUAMFQxCzAJBgNV
...
-----END CERTIFICATE-----
(this should match the actual contents of origroot.pem)
...
Verify return code: 0 (ok)

並且,使用 MS 加密 API 瀏覽器,Apache 會顯示舊根,但新根仍然在電腦的受信任根儲存中。儘管 Apache 提供了不同的鏈(舊根),但它會自動找到它並針對受信任的(新)根驗證證書。從受信任的根中剝離新根並添加原始根證書後,一切都很好:

老根


就是這樣了!更新時保持相同的私鑰,換入新的受信任的根,它幾乎都可以正常工作。祝你好運!

引用自:https://serverfault.com/questions/306345