简体   繁体   English

使用 X.509 证书的 Tomcat 9.xx 客户端身份验证

[英]Tomcat 9.x.x Client Authentication using X.509 Certificates

I'm using Tomcat 9.0.19 and trying to enable X.509 cert.-based client authentication (AKA I&A) for a particular Web application.我正在使用 Tomcat 9.0.19 并尝试为特定的 Web 应用程序启用基于 X.509 证书的客户端身份验证(AKA I&A)。

In summary, the Tomcat works for an application that has basic I&A enabled over one-way TLS.总之,Tomcat 适用于通过单向 TLS 启用基本 I&A 的应用程序。 When accessing the Web application that has certificate-based I&A, Tomcat does not seem to request a client certificate as part of the Server Hello message, prior to sending Server Hello Done and it later fails the authentication check:当访问具有基于证书的 I&A 的 Web 应用程序时,Tomcat 似乎不会在发送 Server Hello Done 之前请求客户端证书作为 Server Hello 消息的一部分,并且稍后无法通过身份验证检查:

02-Jan-2020 13:00:40.371 FINE [https-jsse-nio-443-exec-10] org.apache.catalina.authenticator.SSLAuthenticator.doAuthenticate Looking up certificates 02-Jan-2020 13:00:40.830 FINE [https-jsse-nio-443-exec-10] org.apache.catalina.authenticator.SSLAuthenticator.doAuthenticate No certificates included with this request 02-Jan-2020 13:00:40.371 FINE [https-jsse-nio-443-exec-10] org.apache.catalina.authenticator.SSLAuthenticator.doAuthenticate 查找证书 02-Jan-2020 13:00:40.830 FINE https-jsse-nio-443-exec-10] org.apache.catalina.authenticator.SSLAuthenticator.doAuthenticate 此请求中不包含证书

Traced the TLS flow in Wireshark and saw the TLS 1.2 handshake.在 Wireshark 中追踪 TLS 流程并看到了 TLS 1.2 握手。 Shortly after encrypted data is exchanged, the Tomcat sends an “Encrypted Alert” message and the socket is closed.交换加密数据后不久,Tomcat 会发送“加密警报”消息并关闭套接字。 Trying to contact the Tomcat from the browser, doing a GET.尝试从浏览器联系 Tomcat,执行 GET。 The browser does not prompt me to select a certificate, which also seems to point to Tomcat not requesting it from the browser.浏览器没有提示我选择证书,这似乎也指向 Tomcat 没有从浏览器请求它。

Any help will be greatly appreciated!任何帮助将不胜感激!

More Details:更多细节:

We have a set of certificates for the Tomcat and the client, issued by an Intermediate CA, which is signed (issued) by a Root CA.我们有一组 Tomcat 和客户端的证书,由中间 CA 颁发,由根 CA 签名(颁发)。 The trust stores have been setup on both sides (client and server) as well as key stores with the right certs/keys in them.双方(客户端和服务器)以及其中包含正确证书/密钥的密钥库都已设置信任库。 The Web application is setup to require certificate I&A (web.xml): Web 应用程序设置为需要证书 I&A (web.xml):

<security-constraint>
    <web-resource-collection>
        <web-resource-name>All by default</web-resource-name>
        <url-pattern>/*</url-pattern>
        <http-method>GET</http-method>
        <http-method>POST</http-method>
    </web-resource-collection>
    <auth-constraint>
        <role-name>OTService</role-name>
    </auth-constraint>

    <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>
</security-constraint>

<login-config>
    <auth-method>CLIENT-CERT</auth-method>
    <realm-name>certificate</realm-name>
</login-config>    

The OTService role is setup in the Tomcat-Users.xml, along with a single user account: OTService 角色与单个用户帐户一起在 Tomcat-Users.xml 中设置:

Now, the Connector in server.xml is configured as follows:现在,server.xml 中的连接器配置如下:

   <Connector port="443" protocol="org.apache.coyote.http11.Http11NioProtocol"
               maxThreads="100" SSLEnabled="true" scheme="https" secure="true">
        <SSLHostConfig>
                                <Certificate certificateKeystoreFile="/apache-tomcat-9.0.19/conf/km/keyStore.jks"
                                certificateKeystorePassword="PASSWORD"
                                certificateKeyAlias="tomcat"
                                type="RSA" />
                                truststoreFile="/apache-tomcat-9.0.19/conf/km/trust_store.jks"
                                truststorePass="PASSWORD"
                                truststoreType="JKS"
                                certificateVerification="required"
                                clientAuth="true"
                                protocols="TLSv1.2"
                </SSLHostConfig>
    </Connector>

Any ideas why Tomcat would not request a client certificate?为什么Tomcat不会请求客户端证书的任何想法?

When you have:当你有:

<Connector ...>
  <SSLHostConfig>
    <Certificate A=1 B=2 C=3 />
    D=4 E=5 F=6
  </SSLHostConfig>
</Connector>

then A,B,C are attributes of the Certificate object but D,E,F are NOT attributes of the SSLHostConfig object -- they are XML content which is different.那么 A、B、C 是 Certificate 对象的属性,但 D、​​E、F 不是 SSLHostConfig 对象的属性——它们是不同的 XML内容 Attributes need to be put IN THE TAG:需要在标签中放入属性:

<Connector ... >
  <SSLHostConfig certificateVerification="required" truststoreFile=... >
    <Certificate ...keystore... />
  </SSLHostConfig>
</Connector>

and that does cert-request on the initial handshake as desired (for me, tested on tomcat 9.0.14).并且根据需要在初始握手时执行证书请求(对我来说,在 tomcat 9.0.14 上测试过)。

The first issue that I discovered was that Tomcat ignored the Connector->SSLHostConfig settings for the trust store and used the JRE default trust store anyway.我发现的第一个问题是 Tomcat 忽略了信任库的 Connector->SSLHostConfig 设置,并且无论如何都使用了 JRE 默认信任库。 The way I discovered it was to have a browser save the negotiated TLS session key to a file (Google SSLKEYLOGFILE), then configured the Wireshark to use that file, captured the browser-Tomcat session and then was able to see every message in plaintext.我发现它的方法是让浏览器将协商的 TLS 会话密钥保存到文件 (Google SSLKEYLOGFILE),然后配置 Wireshark 以使用该文件,捕获浏览器-Tomcat 会话,然后能够以明文形式查看每条消息。

Next, I discovered that Tomcat was actually asking for a client cert., but the list of accepted Root CAs it was sending was from the default JRE cacerts file, not from the file specified by the truststoreFile attribute.接下来,我发现 Tomcat 实际上是在请求客户端证书。但是它发送的接受的根 CA 列表来自默认的 JRE cacerts 文件,而不是来自 truststoreFile 属性指定的文件。 Can have Tomcat use a different file across the board by adding a setenv.sh file to the Tomcat bin directory with Java properties to override default trust store location.通过将 setenv.sh 文件添加到具有 Java 属性的 Tomcat bin 目录以覆盖默认信任存储位置,可以让 Tomcat 全面使用不同的文件。

Now, I was in business, the browser was able to complete the TLS handshake, but then the authentication and authorization steps were failing.现在,我在做生意,浏览器能够完成 TLS 握手,但随后身份验证和授权步骤失败了。 I finally determinate that the proper way to provide the cert.我终于确定了提供证书的正确方法。 subject field in tomcat_users.xml file was not "CN=OU Client, OU=Control Systems, O=IoTOY, L=Scottsdale, S=AZ , C=US", but "CN=OU Client, OU=Control Systems, O=IoTOY, L=Scottsdale, ST=AZ , C=US". tomcat_users.xml 文件中的主题字段不是“CN=OU Client, OU=Control Systems, O=IoTOY, L=Scottsdale, S=AZ , C=US”,而是“CN=OU Client, OU=Control Systems, O =IoTOY,L=斯科茨代尔, ST=AZ ,C=US”。 Finally, I had 2-way TLS working.最后,我有 2-way TLS 工作。

One thing to keep in mind is if anything running on the Tomcat attempts to connect over TLS to another system that uses commercial CA certs, it will fail because the truststore you're using now does not have commercial Root CAs' certs.要记住的一件事是,如果在 Tomcat 上运行的任何东西尝试通过 TLS 连接到另一个使用商业 CA 证书的系统,它将失败,因为您现在使用的信任库没有商业根 CA 的证书。 One way to remediate it is to make a copy of the default JRE cacerts file and add your system-specific CA cert(s) to it and point to it from the setenv.sh file noted above.修复它的一种方法是制作默认 JRE cacerts 文件的副本,并将特定于系统的 CA 证书添加到其中,并从上面提到的 setenv.sh 文件中指向它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM