证书颁发机构根证书到期和续订

Rem*_*ank 124 openssl certificate-authority

2004 年,我在 Linux 上使用 OpenSSL 和 OpenVPN 提供的简单管理脚本建立了一个小型证书颁发机构。按照我当时找到的指南,我将根CA证书的有效期设置为10年。从那时起,我为OpenVPN隧道、网站和电子邮件服务器签署了许多证书,所有这些证书的有效期也都是10年(这可能是错误的,但当时我并不知道更好)。

我找到了很多关于设置 CA 的指南,但关于它的管理的信息很少,特别是关于根 CA 证书到期时必须做的事情,这将在 2014 年的某个时候发生。所以我有以下内容问题:

  • 根CA证书到期后有效期延长的证书会在根CA证书到期后立即失效,还是继续有效(因为它们是在CA证书有效期内签署的)?
  • 需要进行哪些操作来更新根 CA 证书并确保其在到期后平稳过渡?
    • 我能否以某种方式重新签署具有不同有效期的当前根 CA 证书,并将新签署的证书上传到客户端,以便客户端证书保持有效?
    • 或者我是否需要用新的根 CA 证书签名的新证书替换所有客户端证书?
  • 什么时候应该更新根 CA 证书?即将到期,还是到期前的合理时间?
  • 如果根CA证书的更新成为一项主要工作,我现在可以做些什么来确保在下一次更新时更平稳地过渡(当然,有效期不能设置为100年)?

由于我对某些客户端的唯一访问是通过使用当前 CA 证书签名的证书的 OpenVPN 隧道,因此情况稍微复杂一些,因此如果我必须替换所有客户端证书,我将需要复制将新文件发送到客户端,重新启动隧道,交叉我的手指并希望它随后出现。

Sha*_*den 174

在您的根 CA 上保留相同的私钥允许所有证书继续针对新根成功验证;您所需要的只是信任新的根。

证书签名关系基于来自私钥的签名;在生成新的公共证书时保留相同的私钥(并且隐含地,相同的公钥),具有新的有效期和根据需要更改的任何其他新属性,保持信任关系到位。CRL 也可以从旧证书延续到新证书,因为它们就像证书一样,由私钥签名。


那么,让我们来验证一下!

创建根 CA:

openssl req -new -x509 -keyout root.key -out origroot.pem -days 3650 -nodes
Run Code Online (Sandbox Code Playgroud)

从中生成子证书:

openssl genrsa -out cert.key 1024
openssl req -new -key cert.key -out cert.csr
Run Code Online (Sandbox Code Playgroud)

签署儿童证书:

openssl x509 -req -in cert.csr -CA origroot.pem -CAkey root.key -create_serial -out cert.pem
rm cert.csr
Run Code Online (Sandbox Code Playgroud)

都设置在那里,正常的证书关系。让我们验证信任:

# openssl verify -CAfile origroot.pem -verbose cert.pem
cert.pem: OK
Run Code Online (Sandbox Code Playgroud)

好的,那么,现在假设 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
Run Code Online (Sandbox Code Playgroud)

而且..有效吗?

# openssl verify -CAfile newroot.pem -verbose cert.pem
cert.pem: OK
Run Code Online (Sandbox Code Playgroud)

但为什么?它们是不同的文件,对吧?

# sha1sum newroot.pem
62577e00309e5eacf210d0538cd79c3cdc834020  newroot.pem
# sha1sum origroot.pem
c1d65a6cdfa6fc0e0a800be5edd3ab3b603e1899  origroot.pem
Run Code Online (Sandbox Code Playgroud)

是的,但是,这并不意味着新的公钥在加密上与证书上的签名不匹配。不同的序号,相同的模数:

# 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
Run Code Online (Sandbox Code Playgroud)

让我们进一步验证它是否在现实世界的证书验证中工作。

启动一个 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/
Run Code Online (Sandbox Code Playgroud)

我们将在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
Run Code Online (Sandbox Code Playgroud)

我们来看看 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)
Run Code Online (Sandbox Code Playgroud)

好的,使用 MS 的加密 API 的浏览器怎么样?首先要信任根,然后一切都好,有了​​新根的序列号:

新根

而且,我们也应该使用旧的根。切换 Apache 的配置:

SSLEngine on
SSLCertificateFile /etc/ssl/certs/cert.pem
SSLCertificateKeyFile /etc/ssl/private/cert.key
SSLCertificateChainFile /etc/ssl/certs/origroot.pem
Run Code Online (Sandbox Code Playgroud)

在 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)
Run Code Online (Sandbox Code Playgroud)

而且,使用 MS 加密 API 浏览器,Apache 会显示旧根,但新根仍在计算机的受信任根存储中。尽管 Apache 提供了不同的链(旧根),但它会自动找到它并根据受信任的(新)根验证证书。从受信任的根中剥离新根并添加原始根证书后,一切正常:

老根


就是这样了!更新时保留相同的私钥,换入新的受信任根,这几乎都可以正常工作。祝你好运!

  • 无论如何,如果您只是要重复使用相同的私钥,那么创建新的根证书有什么意义呢?如果您一遍又一遍地这样做,那么即使有证书的到期日期又有什么意义呢?我认为 root 过期被用来强制管理员制作一个更新的(很可能是更强的)私钥,它对试图破解密钥的不断进步的机器更安全。20 年前制作的 40 位密钥不够安全 (5认同)
  • 除了上述之外,我发现序列号需要相同才能使此方法起作用。 (3认同)
  • `-set_serial 01`-WTF???***您不能重复使用序列号***。您是否甚至查阅过 [RFC 4158,Internet X.509 公钥基础设施:认证路径构建](https://tools.ietf.org/html/rfc4158)?或者你只是在进行时编造它?当用户代理开始路径构建时,您不知道在用户代理中造成的问题。 (3认同)
  • @jvhashe 如果根证书的加密强度不再足够强,那么无论其到期日期如何,您都应该摆脱它。如果您正在生成自己的根,那么没有什么可以阻止您将其设置为在数百年后您将不再存在于地球上时到期。到期与根证书几乎无关 - 对于子证书,到期也与加密强度无关(询问准备在 10 月撤销所有 1024 位证书的 CA) - 请参阅 [此处](http: //security.stackexchange.com/q/11949/4479)了解更多信息。 (2认同)

小智 16

我注意到原始 CA 密钥的更新证书中可能缺少 CA 扩展。这对我来说更合适(它创建了一个./renewedselfsignedca.conf,其中定义了 v3 CA 扩展,并且假定ca.keyca.crt是原始 CA 密钥和证书):

openssl x509 -x509toreq -in ca.crt -signkey ca.key -out renewedselfsignedca.csr
echo -e "[ v3_ca ]\nbasicConstraints= CA:TRUE\nsubjectKeyIdentifier= hash\nauthorityKeyIdentifier= keyid:always,issuer:always\n" > renewedselfsignedca.conf
openssl x509 -req -days 1095 -in renewedselfsignedca.csr -signkey ca.key -out renewedselfsignedca.crt -extfile ./renewedselfsignedca.conf -extensions v3_ca
Run Code Online (Sandbox Code Playgroud)

  • 这是一个非常有用的补充。如果您在原始根 ca 上有任意设置,则实际有效的答案不会为我生成足够兼容的证书。 (2认同)