我正在尝试将运行在Tomcat 7中的Java Web服务设置为使用双向(双向)身份验证。无论我做什么,似乎都无法在安全端口上连接服务。
这是我创建证书和密钥库等的工作:
//create the key and certificate for the tomcat server. keytool -genkey -v -alias tomcat -keyalg RSA -validity 3650 -keystore tomcat.keystore //create the key and certificate for the client machine. keytool -genkey -v -alias clientkey -keyalg RSA -storetype PKCS12 -keystore client.p12 //export the client key keytool -export -alias clientkey -keystore client.p12 -storetype PKCS12 -rfc -file client.cer //import the client key into the server keystore keytool -import -v -file client.cer -keystore tomcat.keystore
这是server.xml文件中的连接器:
<Connector port="8443" maxThreads="150" scheme="https" secure="true" sslProtocol="TLS" clientAuth="true" keystoreFile="tomcat.keystore" keystorePass="tomcat" truststoreFile="tomcat.keystore" truststorePass="tomcat"/>
tomcat-users.xml文件如下所示:
<tomcat-users> <role rolename="tomcat"/> <role rolename="admin"/> <!-- note that the actual values for CN, OU, O, L, ST are different, but they match the values created in the client certificate --> <user username="CN=name, OU=unit, O=org, L=locality, ST=state, C=US" password="null" roles="admin" /> </tomcat-users>
在启动时设置以下内容:
-Djavax.net.ssl.keyStoreType=jks -Djavax.net.ssl.keyStore=tomcat.keystore -Djavax.net.ssl.keyStorePassword=tomcat -Djavax.net.ssl.trustStore=tomcat.keystore -Djavax.net.ssl.trustStorePassword=tomcat -Djavax.net.debug=SSL
最后,我将client.p12文件复制到我的客户端计算机上,并将其导入到Firefox的客户端证书中。
第一个问题:当我从Firefox 命中服务端点(例如-https://my.server.com:8443/test)时,收到响应“安全连接失败”。SSL收到的记录超过了最大允许长度。(错误代码:ssl_error_rx_record_too_long)
第二个问题:我真的不想在端口8443上运行此连接器。我想在端口7800(这是我们公司的HTTPS标准)上运行它。当我将连接器上的端口更改为7800并尝试命中端点(例如- https://my.server.com:7800/ test)时,它将永远无法解析该页面。
因此,在某个地方,我显然缺少一个关键的部分。谁能看到我的错误?
更新:@Dave G反馈后
运行命令:
openssl s_client -connect localhost:8443 -showcerts
产生以下输出:
CONNECTED(00000003) 140642290976584:error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol:s23_clnt.c:766: --- no peer certificate available --- No client certificate CA names sent --- SSL handshake has read 7 bytes and written 263 bytes --- New, (NONE), Cipher is (NONE) Secure Renegotiation IS NOT supported Compression: NONE Expansion: NONE ---
我还向启动添加了-Djavax.net.debug = SSL。这会在catalina.out文件的开头生成以下内容:
trustStore is: tomcat.keystore trustStore type is : jks trustStore provider is : init truststore adding as trusted cert: Subject: CN=localhost, OU=unit, O=org, L=Springfield, ST=MO, C=US Issuer: CN=localhost, OU=unit, O=org, L=Springfield, ST=MO, C=US Algorithm: RSA; Serial number: 0x5485b5a5 Valid from Mon Dec 08 14:28:53 UTC 2014 until Thu Dec 05 14:28:53 UTC 2024 adding as trusted cert: Subject: CN=William Jackson, OU=unit, O=org, L=Springfield, ST=MO, C=US Issuer: CN=William Jackson, OU=unit, O=org, L=Springfield, ST=MO, C=US Algorithm: RSA; Serial number: 0x5485b6af Valid from Mon Dec 08 14:33:19 UTC 2014 until Sun Mar 08 14:33:19 UTC 2015 trigger seeding of SecureRandom done seeding SecureRandom
然后是很多:
Ignoring unavailable cipher suite: <suite name> Ignoring unsupported cipher suite: <suite name>
好的-经过更多研究之后,我终于完成了这项工作。非常感谢@Dave G和本教程:在Tomcat上配置双向SSL身份验证,其中的大多数说明均由此解释。
通常,获得相互认证功能的步骤如下:
以上步骤在服务器上是必需的。完成后,要设置客户端,请执行以下操作:
对于证书配置,我在服务器计算机上执行了以下操作:
# For the following commands, set the values in parenthesis to be whatever makes sense for your environment. The parenthesis are not necessary for the command. # This is an all-in-one command that generates a certificate for the server and places it in a keystore file, while setting both the certifcate password and the keystore password. # The net result is a file called "tomcat.keystore". keytool -genkeypair -alias (serveralias) -keyalg RSA -dname "CN=(server-fqdn),OU=(organizationalunit),O=(organization),L=(locality),ST=(state),C=(country)" -keystore tomcat.keystore -keypass (password) -storepass (password) # This is the all-in-one command that generates the certificate for the client and places it in a keystore file, while setting both the certificate password and the keystore password. # The net result is a file called "client.keystore" keytool -genkeypair -alias (clientalias) -keyalg RSA -dname "CN=(client),OU=(organizationalunit),O=(organization),L=(locality),ST=(state),C=(country)" -keypass (password) -keystore client.keystore -storepass (password) # This command exports the client certificate. # The net result is a file called "client.cer" in your home directory. keytool -exportcert -rfc -alias (clientalias) -file client.cer -keypass (password) -keystore client.keystore -storepass (password) # This command imports the client certificate into the "tomcat.keystore" file. keytool -importcert -alias (clientalias) -file client.cer -keystore tomcat.keystore -storepass (password) -noprompt
现在应该适当设置证书。下一步是在tomcat server.xml中配置连接器。添加如下所示的连接器元素:
<Connector port="8443" maxThreads="150" scheme="https" secure="true" SSLEnabled="true" truststoreFile="/full/path/to/tomcat.keystore" truststorePass="(password)" keystoreFile="/full/path/to/tomcat.keystore" keystorePass="(password)" clientAuth="true" keyAlias="serverkey" sslProtocol="TLS"/>
请注意,在上述XML中:
此外,在server.xml中,确保 没有 定义AprLifecycleListner。该侦听器的XML如下所示:
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
该元素应删除/注释掉。AprLifecycleListener的配置方式与上述方法不同,因此无法与这些说明一起使用。
重新启动tomcat。服务器配置应完成。
我使用Firefox测试了我的工作,因为添加客户端证书很容易。打开Firefox并尝试在连接器中定义的端口上连接到tomcat服务的端点。
Ex: https://mytomcatdomain.com:8443/test
执行此操作时,您应该从Firefox得到有关不可信连接的标准警报,因为我们为Tomcat服务器创建了自签名证书。为证书添加一个例外,以便我们的客户端(Firefox)信任我们的服务器(Tomcat)。
添加例外后,您应该会收到“安全连接失败”消息。错误代码为“ ssl_error_bad_cert_alert”。这确认我们的Tomcat服务器正在从客户端请求身份验证。由于我们尚未将Firefox配置为发送受信任的客户端证书,因此请求失败。
要配置Firefox,我们需要做更多的魔术:
// Create a file called DumpPrivateKey.java. The contents should look like so: public class DumpPrivateKey { public static void main(String[] args) throws Exception { final String keystoreName = args[0]; final String keystorePassword = args[1]; final String alias = args[2]; java.security.KeyStore ks = java.security.KeyStore.getInstance("jks"); ks.load(new java.io.FileInputStream(keystoreName), keystorePassword.toCharArray()); System.out.println("-----BEGIN PRIVATE KEY-----"); System.out.println(new sun.misc.BASE64Encoder().encode(ks.getKey(alias, keystorePassword.toCharArray()).getEncoded())); System.out.println("-----END PRIVATE KEY-----"); } }
使用以下命令编译Java文件:
javac DumpPrivateKey.java
现在,我们将使用这个小工具从上面创建的client.keystore文件中提取密钥。将client.keystore和client.cer文件复制到与DumpPrivateKey类相同的目录中。执行以下命令:
# This extracts the client key from the client keystore java DumpPrivateKey client.keystore (password) clientkey > clientkey.pkcs8 # This creates a client.p12 file that can be used by Firefox openssl pkcs12 -export -in client.cer -inkey clientkey.pkcs8 -password pass:(password) -out client.p12
请注意,在上面的代码中,(密码)应该是您用来创建client.keystore的密码。
打开Firefox首选项。单击“证书”选项卡。单击“查看证书”按钮。点击“您的证书”标签。
单击“导入”按钮,然后浏览到先前创建的“ client.p12”文件。应该提示您输入客户端证书的密码。
假设已成功导入“ client.p12”,则现在可以刷新Firefox页面,并且应该从Tomcat服务器端点获得成功的响应。