与Tomcat 7的相互认证

时间:2014-12-08 16:38:49

标签: java tomcat ssl mutual-authentication

我正在尝试设置在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>

4 个答案:

答案 0 :(得分:28)

好的 - 经过深入挖掘后,我终于有了这个工作。非常感谢@Dave G和本教程:Configuring two-way SSL authentication on Tomcat,其中大部分说明都是转述的。

通常,获得相互身份验证功能的步骤如下:

  1. 为tomcat服务器创建证书。客户必须信任此证书。
  2. 为tomcat服务器创建密钥库,并将服务器证书导入其中。
  3. 为客户端创建证书。服务器必须信任此证书。
  4. 客户端证书导入服务器密钥库
  5. 使用正确的Connector XML更新tomcat server.xml文件。
  6. 服务器上需要执行上述步骤。完成后,要设置客户端,请执行以下操作:

    1. 将客户端证书从服务器复制到客户端。
    2. 与服务器通信时使用客户端证书(此过程因客户端应用程序的性质而异)。
    3. 对于证书配置,我在服务器计算机上执行了以下操作:

      # 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中:

      1. &#34; port&#34;属性可以是你想要的任何东西。
      2. &#34; keystoreFile&#34;和&#34; truststoreFile&#34;属性应该是完整路径。默认情况下,Tomcat不会与server.xml位于同一目录中。
      3. &#34; keystorePass&#34;和&#34; truststorePass&#34;属性应该与您在创建tomcat.keystore文件时使用的(密码)值相匹配。
      4. &#34; clientAuth&#34;属性必须设置为&#34; true&#34;。这就是触发相互身份验证的原因。
      5. 此外,在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)。

        一旦您添加了例外,就会出现&#34;安全连接失败&#34;信息。错误代码是&#34; ssl_error_bad_cert_alert&#34;。这确认我们的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
        

        请注意,在上面的代码中,(password)应该是您用来创建client.keystore的密码。

        打开Firefox偏好设置。点击&#34;证书&#34;标签。点击&#34;查看证书&#34;按钮。点击&#34;您的证书&#34;标签

        点击&#34;导入&#34;按钮并浏览到&#34; client.p12&#34;先前创建的文件。系统将提示您输入客户端证书的密码。

        假设&#34; client.p12&#34;已成功导入,您现在可以刷新Firefox页面,您应该从Tomcat服务器端点获得成功的响应。

答案 1 :(得分:4)

@wbj,从JKS到PKCS#12的PrivateKeyEntry导出可以更容易:

keytool -importkeystore -srckeystore client.keystore -destkeystore client.p12 -deststoretype PKCS12 -srcalias client -deststorepass <password> -destkeypass <password>

干杯。

答案 2 :(得分:3)

我花了一些时间才能使用Openssl证书正确地工作,起草我的笔记,以便它可以帮助其他人访问此页面。

第1步:创建自己的根CA

~/openssl$ mkdir -m 0700 /home/ubuntu/openssl/CA /home/ubuntu/openssl/CA/certs /home/ubuntu/openssl/CA/crl /home/ubuntu/openssl/CA/newcerts /home/ubuntu/openssl/CA/private
~/openssl$ touch /home/ubuntu/openssl/CA/indext.txt
~/openssl$ echo 1000 >> /home/ubuntu/openssl/CA/serial
~/openssl$ mv karun-tomcat-root-ca.key CA/private/

~/openssl$ sudo vi /etc/openssl.cnf
    # Make changes here
    dir = /home/ubuntu/openssl/CA
    #optionally change policy definitions as well
~/openssl$ openssl genrsa -des3 -out karun-tomcat-root-ca.key 2048

  #In below command make sure to use CN=<hostname of your machine>
~/openssl$ openssl req -new -x509 -days 36520 -key karun-tomcat-root-ca.key -out karun-tomcat-root-ca.crt -config openssl.cnf

~$ sudo cp ~/openssl/CA/certs/karun-tomcat-root-ca.crt /usr/share/ca-certificates/

  # make sure in the UI you enable/select the certificate created above
~$ sudo dpkg-reconfigure ca-certificates
  # Now reboot ubuntu machine just to make sure certificates are loaded successfully and tomcat picks it

第2步:创建Tomcat服务器的密钥对

~$ openssl genrsa -out tomcat-server.key 2048

   # Use common name = <Give IP address>, department = Tomcat Server CSR
~$ openssl req -new -sha256 -config ~/openssl/openssl.cnf -key tomcat-server.key -out tomcat-server.csr
~$ openssl x509 -req -sha256 -days 36520 -in tomcat-server.csr -signkey tomcat-server.key -CA ~/openssl/CA/certs/karun-tomcat-root-ca.crt -CAkey ~/openssl/CA/private/karun-tomcat-root-ca.key -CAcreateserial -out tomcat-server.crt 
~$ openssl pkcs12 -export -name karun-tomcat-server-cert -in tomcat-server.crt -out tomcat-server.p12 -inkey tomcat-server.key -CAfile ~/openssl/CA/certs/karun-tomcat-root-ca.crt -caname karun-root -chain

~$ keytool -importkeystore -destkeystore tomcat-server.jks -srckeystore tomcat-server.p12 -srcstoretype pkcs12 -alias karun-tomcat-server-cert

~$ keytool -import -alias karun-root -keystore tomcat-server.jks -trustcacerts -file ~/openssl/CA/certs/karun-tomcat-root-ca.crt

# **(LATER)** Run this once client cert is generated
~$ keytool -importkeystore -alias karun-tomcat-client-cert -srckeystore ~/client-certs/tomcat-client.p12 -srcstoretype PKCS12 -destkeystore tomcat-server.jks -deststoretype JKS

# **(LATER)** Run this once tomcat server started successfully
~$ openssl s_client -connect localhost:8443 -cert ~/client-certs/tomcat-client.crt -key ~/client-certs/tomcat-client.key -debug -showcerts 

第3步:创建客户端密钥对

~$ openssl genrsa -out tomcat-client.key 2048
  # Use common name = <tomcat-user.xml's user say 'admin'>, department = Tomcat Client CSR
~$ openssl req -new -sha256 -config ~/openssl/openssl.cnf -key tomcat-client.key -out tomcat-client.csr
~$ openssl x509 -req -sha256 -days 36520 -in tomcat-client.csr -signkey tomcat-client.key -CA ~/openssl/CA/certs/karun-tomcat-root-ca.crt -CAkey ~/openssl/CA/private/karun-tomcat-root-ca.key -CAcreateserial -out tomcat-client.crt 
~$ openssl pkcs12 -export -name karun-tomcat-client-cert -in tomcat-client.crt -out tomcat-client.p12 -inkey tomcat-client.key -CAfile ~/openssl/CA/certs/karun-tomcat-root-ca.crt -caname karun-root -chain
~$ (optional step) keytool -importkeystore -destkeystore tomcat-client.jks -srckeystore tomcat-client.p12 -srcstoretype pkcs12 -alias karun-tomcat-client-cert
~$ (optional step) keytool -import -alias root -keystore tomcat-client.jks -trustcacerts -file ~/openssl/CA/certs/karun-tomcat-root-ca.crt

第4步:Tomcat更改

# Make this change in server.xml of tomcat server
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
           maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
           keystoreFile="/opt/tomcat/openssl-certs/tomcat-server.jks"
           keystorePass="password"
           keyAlias="karun-tomcat-server-cert"
           truststoreFile="/opt/tomcat/openssl-certs/tomcat-server.jks"
           truststorePass="password"
           clientAuth="true" sslProtocol="TLS" />

第5步:重启Tomcat Server&amp;&amp;检查日志以确保启动时没有错误

第6步:将客户端证书上传到浏览器

在您的浏览器中,例如:firefox,导航首选项 - &gt;高级 - &gt;证书 - &gt;查看证书 - &gt;您的证书

导入&#34; tomcat-client.p12&#34;

https://<tomcat ip>:8443/

<强>参考

http://pages.cs.wisc.edu/~zmiller/ca-howto/

http://www.area536.com/projects/be-your-own-certificate-authority-with-openssl/

答案 3 :(得分:-1)

我会尝试以下步骤

  1. 根据您在8443上配置的内容打开容器。
  2. 使用-Djavax.net.debug = SSL
  3. 运行客户端应用程序

    该命令将清空PILES信息。您需要检查的是服务器正在显示它将接受相互身份验证的CA列表。如果列出的CA不包含您的证书,则客户端将不知道如何找到服务器的匹配项。

    使用openssl命令&#39; s_client&#39;这可以更轻松。

    openssl s_client -connect localhost:8443 -showcerts
    

    这将格式化一些在调试它的价值中无法估量的信息。

    如果服务器没有显示&#34;可接受的&#34;在生成证书集时,您将不得不做一些魔术。

    让我知道你发现了什么,我希望能引导你朝着正确的方向前进。

    OP添加了其他信息

    好的,以下是您的一个问题:

    ---
    no peer certificate available
    ---
    No client certificate CA names sent
    ---
    SSL handshake has read 7 bytes and written 263 bytes
    ---
    

    立即跳出两件事

    1. 服务器没有对等证书
    2. 没有列出客户端CA名称
    3. 所以对于(1):

      1. 确保你的密钥库确实有别名&#39; tomcat&#39;在其中使用keytool。
      2. tomcat中的商店/密钥密码是傻瓜。为了理智,将keystorePassword和keyPassword属性添加到具有相同值的连接器。 documentation for Tomcat 7表示如果未设置keystorePass将默认为keyPass。如果keyPass和keystorePass相同,则仅设置keyPass属性。
      3. 现在(2)我们确实需要让(1)先工作 - 所以要开始运行,我们会在那时看到我们的位置。