我已经生成了 ROOT CA,并且可以成功使用它进行基于客户端的身份验证:
openssl req -x509 -sha256 -newkey rsa:4096 -subj "$SUBJECT" -days 3650 -keyout root_ca.key -out root_ca.crt
openssl req -newkey rsa:4096 -nodes -sha256 -subj "$SUBJECT_CLIENT" -out client.csr -keyout client.key
openssl x509 -req -sha256 -in client.csr -CA root_ca.crt -CAkey root_ca.key -CAcreateserial -out client.crt -days 730
openssl pkcs12 -export -nodes -in client.crt -inkey client.key -out client.p12 -passout pass:
(在 $SUBJECT_CLIENT 中,OU 不同。在 Web 服务器(apache)中):
SSLVerifyClient on
SSLCACertificateFile conf/root_ca.crt
root_ca.crt
client.p12
在浏览器(firefox、chromium)中作为授权机构和个人证书导入
现在我已经创建了一个中间CA:
openssl req -sha256 -newkey rsa:4096 -subj "$SUBJECT_INTER" -keyout intermediateCA.key -out intermediateCA.csr
openssl x509 -req -sha256 -in intermediateCA.csr -CA root_ca.crt -CAkey root_ca.key -CAcreateserial -out intermediateCA.crt -days 1095
并在网络服务器中使用它(intermediateCA.crt
)而不是root_ca.crt
。
$SUBJECT
并且$SUBJECT_INTER
CN 有所不同。
不幸的是,当尝试使用 访问网站时,网络浏览器(和网络服务器)报告错误client.p12
。
PS:
稍后我想为某些用户使用由中间 CA 签名的客户端证书。使用 的client_intermediate.p12
用户应该只能访问带有 的网站,而intermediateCA.crt
使用 的其他用户client.p12
应该只能访问使用 的网站intermediateCA.crt
和使用 的网站root_ca.crt
。
openssl req -newkey rsa:4096 -nodes -sha256 -subj "$SUBJECT_INTER" -out client_intermediate.csr -keyout client_intermediate.key
openssl x509 -req -sha256 -in client_intermediate.csr -CA intermediateCA.crt -CAkey intermediateCA.key -CAcreateserial -out client_intermediate.crt -days 730
openssl pkcs12 -export -nodes -in client_intermediate.crt -inkey client_client_intermediate.key -out client_intermediate.p12 -passout pass:
答案1
这里有几个问题。
首先,虽然您已经生成了中间 CA,但您还没有用它签署客户端证书。因此,使用此中间 CA 证书验证客户端肯定会失败,因为它不在链中。如果您要client.p12
验证,则SSLCACertificateFile
必须指向客户端的颁发者 - 根 CA。如果您将其更改为指向中间 CA,那么 Apache 将查找该证书的颁发者(根 CA 在中间 CA 中列为颁发者)但找不到它 - 因此出现错误。
证书中包含非标准属性和扩展名可能会造成混淆。为清楚起见,以下选项适用于与以下证书类似的证书:
- 根 CA:主题 = 颁发者 = “根 CA”,basicConstraints = critical,CA:true
- 中级 CA:主题 = “中级 CA”,颁发者 = “根 CA”,基本约束 = 关键,CA:true
- 客户端 1:主题 = “客户端 1”,发行者 = “根 CA”,keyUsage = digitalSignature & keyAgreement
- 客户端 2:主题 = “客户端 2”,发行者 = “中级 CA”,keyUsage = digitalSignature & keyAgreement
显然,您可以更改名称以适合您的环境。
如果您想在链中插入一个中间 CA,并且只接受由该中间 CA 签名的客户端证书,那么您可以使用要求指令按属性(例如 OU)过滤客户端证书。然后,您可以根据希望客户端访问的网站,颁发具有特定 OU 值的客户端证书。
由于您在上面的示例中没有 OU,因此通过检查颁发者的通用名称,以下内容将确保客户端证书由中间 CA 而不是根 CA 签名:
<Directory /var/www/html>
Require expr %{SSL_CLIENT_I_DN_CN} == "Intermediate CA"
...
</Directory>
以上假设$SUBJECT_INTER
设置为中级 CA并且您的目录是/var/www/html/
。您需要确保这不会干扰或受到其他Require
指令的影响(例如Require all granted
某些配置中的 hidden),否则您将会花很长时间来追寻自己的尾巴。您可以使用的表达式变量如下这里。您可以在每个虚拟主机中使用此变体来检查颁发者是中间 CA 还是根 CA,或者任何其他证书属性。例如,如果您想允许由根 CA 或中间 CA 签名的客户端访问,则可以使用:
<Directory /var/www/html>
<RequireAny>
Require expr %{SSL_CLIENT_I_DN_CN} == "Intermediate CA"
Require expr %{SSL_CLIENT_I_DN_CN} == "Root CA"
</RequireAny>
...
</Directory>
请小心,因为这可能会干扰或受到Require
配置中其他地方的其他指令的影响。
另一种方法是生成多个根 CA 用于客户端身份验证 - 每个网站(或网站组)一个。然后,您应用SSLCACertificateFile
每个虚拟主机,指向相关的根 CA 证书。您还可以添加其他指令,例如SSLVerifyDepth
,每个虚拟主机也一样。
请注意,在对此采取任何严肃措施之前,您确实需要重新认识证书。就目前情况而言,这些证书并不是非常安全。例如,您生成的客户端证书是版本 1 证书,因此可以充当 CA 并可能背着您签署其他客户端证书。您应该将客户端证书创建为没有基本约束扩展的版本 3 证书。
当然,如果您只是在进行实验,那么您可以忽略最后一点。