通过由 ROOT CA 签名的证书进行客户端身份验证

通过由 ROOT CA 签名的证书进行客户端身份验证

我已经生成了 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.crtclient.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_INTERCN 有所不同。

不幸的是,当尝试使用 访问网站时,网络浏览器(和网络服务器)报告错误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 证书。

当然,如果您只是在进行实验,那么您可以忽略最后一点。

相关内容