如何让 Apache 信任使用未知 CA 的客户端证书,而无需验证该 CA

如何让 Apache 信任使用未知 CA 的客户端证书,而无需验证该 CA

我的情况如下。我需要与外部系统建立双向集成。外部系统的管理员要求我发送两个 CSR,一个用于生成客户端证书,另一个用于生成服务器证书。他们向我发送了相应的证书。我成功设置了“我->他们”通道(即:我可以调用他们的服务来提供我的客户端证书),但我无法正确设置反向通道(即:我无法让我的 Apache 毫无怨言地接受他们的客户端证书)。

除了我的服务器证书(我们称之为 my-server.pem)外,他们还向我发送了他们自己的客户端证书(我们称之为 their-client.pem)。此证书(their-client.pem)由“自签名”CA 颁发,该 CA 不属于我的 Linux 系统中已有的那些知名 CA。我没有此证书,而且我尚未能够从外部系统管理员那里获得它(他们不太情愿……请先搁置对此的任何评论……>-|)

这是我在 Apache 中设置 VirtualHost 的方法:

SSLEngine on
SSLCertificateFile /path/to/my-server.pem
SSLCertificateKeyFile /path/to/my-server-secret-key.key
SSLVerifyClient require
SSLCACertificateFile /path/to/their-client.pem
SSLVerifyDepth 0

由于我没有 CA 证书,而且我可以说“只信任该客户端证书,其他的都不要信任!”,所以我将客户端证书本身作为SSLCACertificateFile,如以下回答中所建议的那样: https://security.stackexchange.com/questions/36069/use-client-certificate-using-self-signed-ca-while-using-web-certificate-of-a-pub

但是,这似乎不起作用。他们看到的错误是:

javax.net.ssl.SSLException: Received fatal alert: unknown_ca

启用 SSL 日志并将其设置为调试后,我看到的是:

[ssl:debug] [pid 3396] ssl_engine_kernel.c(1381): [client <their-ip>:41474] AH02275: Certificate Verification, depth 1, CRL checking mode: none [subject: CN=Test CA,OU=Foo,O=Bar,C=it / issuer: CN=Test CA,OU=Foo,O=Bar,C=it / serial: 1BFE / notbefore: Dec  6 15:22:45 2010 GMT / notafter: Dec  6 15:21:52 2020 GMT]
[ssl:info] [pid 3396] [client <their-IP>:41474] AH02276: Certificate Verification: Error (19): self signed certificate in certificate chain [subject: CN=Test CA,OU=Foo,O=Bar,C=it / issuer: CN=Test CA,OU=Foo,O=Bar,C=it / serial: 1BFE / notbefore: Dec  6 15:22:45 2010 GMT / notafter: Dec  6 15:21:52 2020 GMT]
[ssl:info] [pid 3396] [client <their-IP>:41474] AH02008: SSL library error 1 in handshake (server my-server.com:443)
[ssl:info] [pid 3396] SSL Library Error: error:140890B2:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:no certificate returned
[ssl:info] [pid 3396] [client <their-IP>:41474] AH01998: Connection closed to child 54 with abortive shutdown (server my-server.com:443)

换句话说,它仍在尝试验证客户端证书的虚拟 CA。我也尝试过将其更改SSLVerifyDepth为 1,但没有成功(同样的错误)。如果我禁用客户端证书请求(通过更改值SSLVerifyClient),调用会很顺利,但我认为这不是正确的方法。

一个非常相似的问题是: 如何让 apache 请求客户端 SSL 证书而无需根据已知 CA 进行验证?

但是我不确定我是否理解了可接受的解决方案。首先,我必须验证的客户端证书不是自签名的(它是由未知的 CA 颁发的)。

其次,根据我对 Apache/mod_ssl 文档的理解,SSLVerifyCLient optional_no_ca实际上禁用了强客户端证书认证,因为它使其成为可选项。

第三,创建与丢失的根 CA 证书具有相同 DN 的假证书听起来像是强制客户端发送其客户端证书的一种解决方法,但就我而言,我认为我的问题不是客户端没有向我发送证书,而是 Apache 无法完全正确地验证它。

关于这个主题的任何建议都会非常有帮助。

答案1

您的错误消息清楚地显示了原因:“深度 1”。您已SSLVerifyDepth 0根据手册进行了设置,这意味着:

仅接受自签名客户端证书

要检查客户端证书是否符合预期,并且不进行链验证,请尝试以下命令:

SSLVerify none
SSLRequire (   %{SSL_CLIENT_S_DN_O} eq "Snake Oil, Ltd."  and %{REMOTE_ADDR} =~ m/^192\.76\.162\.[0-9]+$/  )

答案2

我真的很讨厌那些建议替代方案但实际上并没有回答问题的回复,但是……如果你不想(或者因为他们不提供而不能)接受他们的 CA 颁发的证书,那么你应该从你自己的 CA 向他们颁发证书。这不仅可以解决他们不提供签名者证书的问题,还可以防止你不得不信任陌生的 CA。

答案3

这是适用于 Apache 2.4 的。

# Unchanged:
SSLEngine on
SSLCertificateFile /path/to/my-server.pem
SSLCertificateKeyFile /path/to/my-server-secret-key.key
SSLCACertificateFile /path/to/their-client.pem
SSLVerifyDepth 0

# Changed:
SSLVerifyClient optional_no_ca
Require expr "%{SSL_CLIENT_I_DN_CN} -eq 'www.example.com'"

还回答了如何让 apache 请求客户端 SSL 证书而无需根据已知 CA 进行验证?

答案4

我不是 Apache 专家,但从证书的角度来看,如果他们不想向您提供其根 CA 的公钥,只需要求他们从知名 CA 而不是他们自己的 CA 获取客户端证书即可。例如,StartSSL 提供免费的 1 年证书。您正在构建一场噩梦,因为合作伙伴不了解它是如何工作的。另一种方法是安装您自己的 CA(Linux)https://jamielinux.com/docs/openssl-certificate-authority/(视窗)http://datacenteroverlords.com/2012/03/01/creating-your-own-ssl-certificate-authority/并要求他们向您提供 CSR 来替换(their-client.pem)

相关内容