开发时我们常常使用JDK自带的keytool工具来创建自签发的证书,并保存到密钥库文件中。如果要把一个密钥库导入到另一个密钥库(比如到另一台机器上安装,同时又不想用覆盖文件的方式),那该怎么操作呢?
比如,我们从aaa.jks里把别名为tomcat的内容导入到bbb.jks里。一个错觉是先从aaa.jks导出证书、再导入到bbb.jks里。
为说明错误情况,我们从头做起。先生成别名为tomcat的证书,并保存到aaa.jks里:
keytool -keystore aaa.jks -genkey -keyalg RSA -alias tomcat
然后把证书导出到tomcat.cert文件:
keytool -keystore aaa.jks -export -file tomcat.cert -alias tomcat
接着把tomcat.cert导入到bbb.jks里:
keytool -keystore bbb.jks -import -file tomcat.cert -alias tomcat
为验证这种做法的错误性,我们可分别用aaa.jks和bbb.jks来启动Tomcat服务器,看看能不能启动成功。由于我们仅仅是出于验证的目的,因此无需在Tomcat的webapps目录里放进应用的war包文件。
先用aaa.jks来启动Tomcat。修改Tomcat的conf\server.xml文件为:
<Connector port&#61;"8443" protocol&#61;"org.apache.coyote.http11.Http11Protocol" SSLEnabled&#61;"true"maxThreads&#61;"150" scheme&#61;"https" secure&#61;"true"clientAuth&#61;"false" sslProtocol&#61;"TLS"keystoreFile&#61;"aaa.jks"keystorePass&#61;"changeit" />
请把上面的aaa.jks输入为实际的全路径名&#xff08;比如d:\aaa.jks&#xff09;。完成后启动Tomcat&#xff0c;此时Tomcat应能够成功启动。
确认成功后请关闭Tomcat&#xff0c;接下来我们把上面的aaa.jks换为bbb.jks&#xff0c;保存后重新启动Tomcat。Tomcat将报异常&#xff1a;
严重: Failed to initialize connector [Connector[HTTP/1.1-8443]]
org.apache.catalina.LifecycleException: Failed to initialize component [Connector[HTTP/1.1-8443]]at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:106)at org.apache.catalina.core.StandardService.initInternal(StandardService.java:559)at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102)at org.apache.catalina.core.StandardServer.initInternal(StandardServer.java:814)at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102)at org.apache.catalina.startup.Catalina.load(Catalina.java:633)at org.apache.catalina.startup.Catalina.load(Catalina.java:658)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)at java.lang.reflect.Method.invoke(Method.java:597)at org.apache.catalina.startup.Bootstrap.load(Bootstrap.java:281)at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:450)
Caused by: org.apache.catalina.LifecycleException: Protocol handler initialization failedat org.apache.catalina.connector.Connector.initInternal(Connector.java:983)at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102)... 12 more
Caused by: java.io.IOException: Alias name tomcat does not identify a key entryat org.apache.tomcat.util.net.jsse.JSSESocketFactory.getKeyManagers(JSSESocketFactory.java:567)at org.apache.tomcat.util.net.jsse.JSSESocketFactory.getKeyManagers(JSSESocketFactory.java:505)at org.apache.tomcat.util.net.jsse.JSSESocketFactory.init(JSSESocketFactory.java:449)at org.apache.tomcat.util.net.jsse.JSSESocketFactory.createSocket(JSSESocketFactory.java:158)at org.apache.tomcat.util.net.JIoEndpoint.bind(JIoEndpoint.java:393)at org.apache.tomcat.util.net.AbstractEndpoint.init(AbstractEndpoint.java:610)at org.apache.coyote.AbstractProtocol.init(AbstractProtocol.java:429)at org.apache.coyote.http11.AbstractHttp11JsseProtocol.init(AbstractHttp11JsseProtocol.java:119)at org.apache.catalina.connector.Connector.initInternal(Connector.java:981)... 13 more
为什么用bbb.jks启动不了呢&#xff1f;为此我们分别检查一下aaa.jks和bbb.jks里的内容。
下面是aaa.jks里的内容&#xff1a;
keytool -keystore aaa.jks -list -alias tomcat
输入keystore密码&#xff1a;
tomcat, 2012-12-2, PrivateKeyEntry,
认证指纹 (MD5)&#xff1a; 20:E1:74:4B:0B:35:33:FF:BE:2D:9D:B5:31:AB:3B:DE
下面是bbb.jks里的内容&#xff1a;
keytool -keystore bbb.jks -list -alias tomcat
输入keystore密码&#xff1a;
tomcat, 2012-12-2, trustedCertEntry,
认证指纹 (MD5)&#xff1a; 20:E1:74:4B:0B:35:33:FF:BE:2D:9D:B5:31:AB:3B:DE
从上面两个输出中可见其差别&#xff0c;一个是PrivateKeyEntry&#xff0c;另一个是trustedCertEntry。
其实&#xff0c;密钥库里保存了两类信息&#xff0c;一类是私钥&#xff0c;另一类是证书。证书里只有公钥。上面导出的tomcat.cert文件为证书文件&#xff0c;里面没有私钥。因此当我们再导入到bbb.jks时&#xff0c;导进去的只有证书、没有对应的私钥。而服务器需要用私钥与客户端的公钥通讯&#xff0c;因此Tomcat报了上面的异常。
那么我们该如何正确操作呢&#xff1f;方法有很多&#xff0c;最常用的方法是不用keytool来生成证书和私钥&#xff0c;而改用openssl工具。不过本文的目的是只用keytool来操作。
其实操作很简单&#xff1a;
keytool -importkeystore -deststorepass changeit -destkeypass changeit -destkeystore bbb.jks -deststoretype jks -srckeystore aaa.jks -srcstoretype jks -srcstorepass changeit -alias tomcat
这个bbb.jks就包含了别名为tomcat的私钥和证书了。如果不放心可再用启动Tomcat的方法去验证一下。
最后要说明的是&#xff0c;如果在keytool中不指定storetype、srcstoretype、deststoretype参数则也默认为jks。