spring boot双向SSL验证问题及解决

最近在做服务端、客户端SSL双向验证的问题,启动后,发现报错,如下:

trustAnchors parameter must be non-empty

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

org.apache.catalina.LifecycleException: Protocol handler start failed
at org.apache.catalina.connector.Connector.startInternal(Connector.java:1008) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.catalina.core.StandardService.addConnector(StandardService.java:227) [tomcat-embed-core-9.0.21.jar:9.0.21]
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.addPreviouslyRemovedConnectors(TomcatWebServer.java:263) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]
at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.start(TomcatWebServer.java:195) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.startWebServer(ServletWebServerApplicationContext.java:296) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.finishRefresh(ServletWebServerApplicationContext.java:162) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:552) [spring-context-5.1.8.RELEASE.jar:5.1.8.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:742) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:389) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:311) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1213) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1202) [spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE]
at com.lambda.verify.VerifyApplication.main(VerifyApplication.java:10) [classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_201]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_201]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_201]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_201]
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-2.1.6.RELEASE.jar:2.1.6.RELEASE]
Caused by: java.lang.IllegalArgumentException: the trustAnchors parameter must be non-empty
at org.apache.tomcat.util.net.AbstractJsseEndpoint.createSSLContext(AbstractJsseEndpoint.java:99) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.tomcat.util.net.AbstractJsseEndpoint.initialiseSsl(AbstractJsseEndpoint.java:71) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.tomcat.util.net.NioEndpoint.bind(NioEndpoint.java:218) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.tomcat.util.net.AbstractEndpoint.bindWithCleanup(AbstractEndpoint.java:1124) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.tomcat.util.net.AbstractEndpoint.start(AbstractEndpoint.java:1210) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.coyote.AbstractProtocol.start(AbstractProtocol.java:585) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.catalina.connector.Connector.startInternal(Connector.java:1005) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
... 19 common frames omitted
Caused by: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
at java.security.cert.PKIXParameters.setTrustAnchors(PKIXParameters.java:200) ~[na:1.8.0_201]
at java.security.cert.PKIXParameters.<init>(PKIXParameters.java:157) ~[na:1.8.0_201]
at java.security.cert.PKIXBuilderParameters.<init>(PKIXBuilderParameters.java:130) ~[na:1.8.0_201]
at org.apache.tomcat.util.net.SSLUtilBase.getParameters(SSLUtilBase.java:491) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.tomcat.util.net.SSLUtilBase.getTrustManagers(SSLUtilBase.java:422) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.tomcat.util.net.SSLUtilBase.createSSLContext(SSLUtilBase.java:247) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
at org.apache.tomcat.util.net.AbstractJsseEndpoint.createSSLContext(AbstractJsseEndpoint.java:97) ~[tomcat-embed-core-9.0.21.jar:9.0.21]
... 25 common frames omitted

原因:

因为配置的trust-store证书中没有 trustedCertEntry,因此,出现此错误。

在导入root.cer之前,查看server.jks:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
keytool -list -v -keystore server.jks
输入密钥库口令:
密钥库类型: jks
密钥库提供方: SUN

您的密钥库包含 1 个条目

别名: server
创建日期: 2019-6-27
条目类型: PrivateKeyEntry
证书链长度: 1
证书[1]:
所有者: CN=guotie, OU=dev, O=lambda, L=NJ, ST=JS, C=CN
发布者: CN=guotie, OU=dev, O=lambda, L=NJ, ST=JS, C=CN
序列号: 6fe81fc6
有效期为 Thu Jun 27 10:30:40 CST 2019 至 Wed Sep 25 10:30:40 CST 2019
证书指纹:
MD5: 25:93:E9:E6:F6:78:85:95:D2:99:8F:61:2D:F4:D5:4E
SHA1: F0:6C:5A:64:3C:7E:E2:78:A9:8C:53:20:56:31:42:09:63:22:38:65
SHA256: BC:87:37:F3:B2:87:1B:07:CD:28:9C:9A:99:73:21:3D:38:0C:E5:29:CE:4B:BD:27:0B:97:DC:9E:DA:94:CB:34
签名算法名称: SHA256withDSA
主体公共密钥算法: 2048 位 DSA 密钥
版本: 3

扩展:

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: E4 81 90 A1 9E 1F 81 67 DC 17 A9 71 D8 37 32 3F .......g...q.72?
0010: 7C B3 7B 4D ...M
]
]



*******************************************
*******************************************



Warning:
JKS 密钥库使用专用格式。建议使用 "keytool -importkeystore -srckeystore server.jks -destkeystore server.jks -deststoretype pkcs12" 迁移到行业标准格式 PKCS12。

导入root.cer到server.jks:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
keytool -importcert -alias root -file root.cer -keystore server.jks
输入密钥库口令:
所有者: CN=guotie, OU=lambda, O=lambda, L=NanJing, ST=Jiangsu, C=CN
发布者: CN=guotie, OU=lambda, O=lambda, L=NanJing, ST=Jiangsu, C=CN
序列号: 10f60cab
有效期为 Thu Jun 27 10:29:30 CST 2019 至 Wed Sep 25 10:29:30 CST 2019
证书指纹:
MD5: 42:B7:10:5C:93:28:4D:41:4D:64:75:AC:55:A2:18:76
SHA1: FA:6F:D5:7C:B3:46:F8:92:AD:BA:55:D4:2D:7B:8D:22:BA:AC:72:D8
SHA256: 27:C2:59:FD:A8:3B:EB:DB:60:7C:9C:68:08:2D:AD:F3:1D:8B:ED:23:DC:3B:C1:62:EF:4A:21:B6:DA:95:4B:C8
签名算法名称: SHA256withDSA
主体公共密钥算法: 2048 位 DSA 密钥
版本: 3

扩展:

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: E6 66 2A 75 2A 5A DC AF F2 37 E7 DD AF 69 C7 3B .f*u*Z...7...i.;
0010: B1 F4 60 BA ..`.
]
]

是否信任此证书? [否]: y
证书已添加到密钥库中

导入root.cer后,查看server.jks:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
keytool -list -v -keystore server.jks
输入密钥库口令:
密钥库类型: jks
密钥库提供方: SUN

您的密钥库包含 2 个条目

别名: root
创建日期: 2019-6-27
条目类型: trustedCertEntry

所有者: CN=guotie, OU=lambda, O=lambda, L=NanJing, ST=Jiangsu, C=CN
发布者: CN=guotie, OU=lambda, O=lambda, L=NanJing, ST=Jiangsu, C=CN
序列号: 10f60cab
有效期为 Thu Jun 27 10:29:30 CST 2019 至 Wed Sep 25 10:29:30 CST 2019
证书指纹:
MD5: 42:B7:10:5C:93:28:4D:41:4D:64:75:AC:55:A2:18:76
SHA1: FA:6F:D5:7C:B3:46:F8:92:AD:BA:55:D4:2D:7B:8D:22:BA:AC:72:D8
SHA256: 27:C2:59:FD:A8:3B:EB:DB:60:7C:9C:68:08:2D:AD:F3:1D:8B:ED:23:DC:3B:C1:62:EF:4A:21:B6:DA:95:4B:C8
签名算法名称: SHA256withDSA
主体公共密钥算法: 2048 位 DSA 密钥
版本: 3

扩展:

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: E6 66 2A 75 2A 5A DC AF F2 37 E7 DD AF 69 C7 3B .f*u*Z...7...i.;
0010: B1 F4 60 BA ..`.
]
]



*******************************************
*******************************************


别名: server
创建日期: 2019-6-27
条目类型: PrivateKeyEntry
证书链长度: 1
证书[1]:
所有者: CN=guotie, OU=dev, O=lambda, L=NJ, ST=JS, C=CN
发布者: CN=guotie, OU=dev, O=lambda, L=NJ, ST=JS, C=CN
序列号: 6fe81fc6
有效期为 Thu Jun 27 10:30:40 CST 2019 至 Wed Sep 25 10:30:40 CST 2019
证书指纹:
MD5: 25:93:E9:E6:F6:78:85:95:D2:99:8F:61:2D:F4:D5:4E
SHA1: F0:6C:5A:64:3C:7E:E2:78:A9:8C:53:20:56:31:42:09:63:22:38:65
SHA256: BC:87:37:F3:B2:87:1B:07:CD:28:9C:9A:99:73:21:3D:38:0C:E5:29:CE:4B:BD:27:0B:97:DC:9E:DA:94:CB:34
签名算法名称: SHA256withDSA
主体公共密钥算法: 2048 位 DSA 密钥
版本: 3

扩展:

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: E4 81 90 A1 9E 1F 81 67 DC 17 A9 71 D8 37 32 3F .......g...q.72?
0010: 7C B3 7B 4D ...M
]
]



*******************************************
*******************************************

生成符合规范的CA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
###################################################################################################################
# 生成ca pair
keytool -genkeypair -alias ca -keyalg RSA -keysize 4096 -validity 3650 -keystore ca.jks

# 查看证书
keytool -list -v -keystore ca.jks

# 导出公钥证书
keytool -export -alias ca -keystore ca.jks -rfc -file ca.cer

# 将证书导入到truststore
keytool -import -v -trustcacerts -alias ca -file ca.cer -keystore truststore.jks

# 格式转换为p12
keytool -importkeystore -srckeystore ca.jks -destkeystore ca.jks -deststoretype pkcs12
keytool -importkeystore -srckeystore truststore.jks -destkeystore truststore.jks -deststoretype pkcs12

# 删除旧文件
rm ca.jks.old truststore.jks.old

上面生成的truststore.jks就是spring boot中配置的trust证书部分:

1
2
3
4
5
server.ssl.trust-store=classpath:truststore.jks
server.ssl.trust-store-password=xxxxx
server.ssl.client-auth=need
server.ssl.trust-store-type=JKS
server.ssl.trust-store-provider=SUN

参考资料:

https://www.ibm.com/developerworks/cn/java/j-lo-socketkeytool/index.html

https://yushan.iteye.com/blog/434955

生成tomcat的CA证书:

https://my.oschina.net/u/3757195/blog/3031159