Spring 引导导致使用自签名证书的 SSL 对等握手失败
Spring Boot causes SSL peer handshake failure with self-signed certs
我创建了一个 GitHub project that perfectly reproduces 这里解释的一切。
我正在构建一个 Spring 引导应用程序(带有嵌入式 Jetty Web 容器),并试图让它在本地 运行 时提供自签名的 OpenSSL 证书(当 运行在暂存或生产环境中,应用程序将提供根 CA 签名证书)。
因此,为了创建 SSL 功能,我首先创建了 public key/CSR,方法是:
openssl req -x509 -newkey rsa:4096 -keyout myapp-key.pem -out myapp-csr.pem -days 3650
然后我创建了 JKS 并像这样导入了我的 public 密钥:
keytool -importcert -trustcacerts -file myapp-csr.pem -alias myorg -keystore myapp.jks
然后我用 SSL 属性更新了我的 application.yml
:
ssl:
key-store: 'myapp.jks'
key-store-password: '123456'
key-password: '123456'
然后我 运行 我的 Spring 启动应用程序:
./gradlew build && java -Dspring.config=. -jar build/libs/spring-boot-troubleshooting.jar
到目前为止一切顺利 -- 启动时没有 errors/exceptions/warnings。然后我打开一个新终端和 运行:
curl -k -H "Content-Type: application/json" -X GET https://localhost:9200/health
curl: (35) SSL peer handshake failed, the server most likely requires a client certificate to connect
如果我切换回应用 运行ning 所在的终端,我现在会在控制台输出中看到:
06:14:00.149 [qtp1706099897-15] WARN org.eclipse.jetty.http.HttpParser - Illegal character 0x16 in state=START for buffer HeapByteBuffer@5b876b3[p=1,l=175,c=8192,r=174]={\x16<<<\x03\x01\x00\xAa\x01\x00\x00\xA6\x03\x03ZL\xBa\xF8T\x86r...\x00\x05\x01\x00\x00\x00\x00\x00\x12\x00\x00\x00\x17\x00\x00>>>-Type: applicatio...\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}
-k
是有意忽略 SSL 因为这是一个自签名证书。我试过使用和不使用 -k
,结果是一样的。
我看到了 evidence that this could be a MacOS issue for some reason,但坦率地说,我什至不确定从哪里开始寻找。我创建 public/private 密钥对的方式有问题吗?我将 public key/CSR 导入 JKS 文件的方式有问题吗?我的配置还有其他问题吗?
None 这个说得有道理。
- 您根本不需要使用
openssl
。
- CSR 不是证书,更不是 public 密钥。
- 将 CSR 导入 KeyStore 的结果不是有效的 KeyStore,因为没有私钥。
你只需要用到keytool
,别的不说,如下:
keytool -genkey ...
keytool -selfcert ...
两次使用相同的别名。
keytool -export ...
keytool -import ...
进入客户的 truststore 文件。
要执行 SSL 握手,服务器密钥库必须同时包含 public 证书和私钥。最简单的方法是用私钥和证书创建一个 p12
包,然后使用 importkeystore
命令一次导入它们。
openssl req -x509 -newkey rsa:4096 -keyout myapp-key.pem -out myapp-csr.pem -days 3650 -subj '/CN=localhost'
openssl pkcs12 -export -in myapp-csr.pem -inkey myapp-key.pem -out keystore.p12
keytool -importkeystore -deststorepass 123456 -destkeystore keystore.jks -srckeystore keystore.p12 -srcstoretype PKCS12
现在您可以使用 curl
查询您的服务器了。
curl -k -H "Content-Type: application/json" -X GET https://localhost:9200/health
curl --cacert myapp-csr.pem -H "Content-Type: application/json" https://localhost:9200/health
所以基本上你的配置是正确的,除了在密钥库中缺少私钥。
@EJP 很好地解释了根本原因。您的 myapp.jks 文件中没有私钥。
我可以把解决方法说的很详细。有3种解决方案。我用你的代码和 java 8.
测试了它们
只有 keytool - 最快的
删除现有 myapp.jks 并使用这些参数通过 keytool 重新生成。
keytool -genkeypair -dname "cn=Name Surname, ou=MyUnit, o=MyOrg, c=US" -alias myorg -keypass 123456 -storepass 123456 -validity 365 -keyalg RSA -keystore myapp.jks
仅 openssl
通过名为"myapp.p12".
的openssl创建pkcs文件
openssl pkcs12 -inkey myapp-key.pem -in myapp-csr.pem -export -out myapp.p12;
将 application.yml 密钥库:'myapp.jks' 更改为密钥库:'myapp.p12'
它们的组合(当前方法)。
通过名为 "myapp.p12" 的 openssl 创建 pkcs 文件。
openssl pkcs12 -inkey myapp-key.pem -in myapp-csr.pem -export -out myapp.p12;
导入jks文件
keytool -importkeystore -srckeystore myapp.p12 -srcstoretype pkcs12 -destkeystore myapp.jks -deststoretype JKS
我创建了一个 GitHub project that perfectly reproduces 这里解释的一切。
我正在构建一个 Spring 引导应用程序(带有嵌入式 Jetty Web 容器),并试图让它在本地 运行 时提供自签名的 OpenSSL 证书(当 运行在暂存或生产环境中,应用程序将提供根 CA 签名证书)。
因此,为了创建 SSL 功能,我首先创建了 public key/CSR,方法是:
openssl req -x509 -newkey rsa:4096 -keyout myapp-key.pem -out myapp-csr.pem -days 3650
然后我创建了 JKS 并像这样导入了我的 public 密钥:
keytool -importcert -trustcacerts -file myapp-csr.pem -alias myorg -keystore myapp.jks
然后我用 SSL 属性更新了我的 application.yml
:
ssl:
key-store: 'myapp.jks'
key-store-password: '123456'
key-password: '123456'
然后我 运行 我的 Spring 启动应用程序:
./gradlew build && java -Dspring.config=. -jar build/libs/spring-boot-troubleshooting.jar
到目前为止一切顺利 -- 启动时没有 errors/exceptions/warnings。然后我打开一个新终端和 运行:
curl -k -H "Content-Type: application/json" -X GET https://localhost:9200/health
curl: (35) SSL peer handshake failed, the server most likely requires a client certificate to connect
如果我切换回应用 运行ning 所在的终端,我现在会在控制台输出中看到:
06:14:00.149 [qtp1706099897-15] WARN org.eclipse.jetty.http.HttpParser - Illegal character 0x16 in state=START for buffer HeapByteBuffer@5b876b3[p=1,l=175,c=8192,r=174]={\x16<<<\x03\x01\x00\xAa\x01\x00\x00\xA6\x03\x03ZL\xBa\xF8T\x86r...\x00\x05\x01\x00\x00\x00\x00\x00\x12\x00\x00\x00\x17\x00\x00>>>-Type: applicatio...\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}
-k
是有意忽略 SSL 因为这是一个自签名证书。我试过使用和不使用 -k
,结果是一样的。
我看到了 evidence that this could be a MacOS issue for some reason,但坦率地说,我什至不确定从哪里开始寻找。我创建 public/private 密钥对的方式有问题吗?我将 public key/CSR 导入 JKS 文件的方式有问题吗?我的配置还有其他问题吗?
None 这个说得有道理。
- 您根本不需要使用
openssl
。 - CSR 不是证书,更不是 public 密钥。
- 将 CSR 导入 KeyStore 的结果不是有效的 KeyStore,因为没有私钥。
你只需要用到keytool
,别的不说,如下:
keytool -genkey ...
keytool -selfcert ...
两次使用相同的别名。
keytool -export ...
keytool -import ...
进入客户的 truststore 文件。
要执行 SSL 握手,服务器密钥库必须同时包含 public 证书和私钥。最简单的方法是用私钥和证书创建一个 p12
包,然后使用 importkeystore
命令一次导入它们。
openssl req -x509 -newkey rsa:4096 -keyout myapp-key.pem -out myapp-csr.pem -days 3650 -subj '/CN=localhost'
openssl pkcs12 -export -in myapp-csr.pem -inkey myapp-key.pem -out keystore.p12
keytool -importkeystore -deststorepass 123456 -destkeystore keystore.jks -srckeystore keystore.p12 -srcstoretype PKCS12
现在您可以使用 curl
查询您的服务器了。
curl -k -H "Content-Type: application/json" -X GET https://localhost:9200/health
curl --cacert myapp-csr.pem -H "Content-Type: application/json" https://localhost:9200/health
所以基本上你的配置是正确的,除了在密钥库中缺少私钥。
@EJP 很好地解释了根本原因。您的 myapp.jks 文件中没有私钥。
我可以把解决方法说的很详细。有3种解决方案。我用你的代码和 java 8.
测试了它们只有 keytool - 最快的
删除现有 myapp.jks 并使用这些参数通过 keytool 重新生成。
keytool -genkeypair -dname "cn=Name Surname, ou=MyUnit, o=MyOrg, c=US" -alias myorg -keypass 123456 -storepass 123456 -validity 365 -keyalg RSA -keystore myapp.jks
仅 openssl
通过名为"myapp.p12".
的openssl创建pkcs文件openssl pkcs12 -inkey myapp-key.pem -in myapp-csr.pem -export -out myapp.p12;
将 application.yml 密钥库:'myapp.jks' 更改为密钥库:'myapp.p12'
它们的组合(当前方法)。
通过名为 "myapp.p12" 的 openssl 创建 pkcs 文件。
openssl pkcs12 -inkey myapp-key.pem -in myapp-csr.pem -export -out myapp.p12;
导入jks文件
keytool -importkeystore -srckeystore myapp.p12 -srcstoretype pkcs12 -destkeystore myapp.jks -deststoretype JKS