Spring Boot使用自签名证书导致SSL对等握手失败

时间:2018-01-03 04:24:44

标签: java macos curl spring-boot keytool

我创建了GitHub project that perfectly reproduces这里解释的一切。

我正在构建一个Spring Boot应用程序(带有一个嵌入式Jetty Web容器),并且我试图让它在本地运行时提供自签名的OpenSSL证书(当在登台或prod环境中运行时,该应用程序将为root提供服务CA签名证书。

因此,要创建SSL功能,首先我通过发出:

创建public key/CSR
openssl req -x509 -newkey rsa:4096 -keyout myapp-key.pem -out myapp-csr.pem -days 3650

然后我创建了JKS并导入了我的公钥,如下所示:

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 Boot应用程序:

./gradlew build && java -Dspring.config=. -jar build/libs/spring-boot-troubleshooting.jar

到目前为止一切顺利 - 启动时没有错误/异常/警告。然后我打开一个新终端并运行:

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

如果我切换回应用程序运行的终端,我现在在控制台输出中看到这个:

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,但坦率地说,我甚至不确定从哪里开始寻找。我创建公钥/私钥对的方式有问题吗?我将公钥/ CSR导入JKS文件的方式有问题吗?我配置的任何方面都有问题吗?

3 个答案:

答案 0 :(得分:1)

要执行SSL握手服务器,密钥库必须包含公共证书和私钥。最简单的方法是使用私钥和证书创建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

所以基本上你的配置是正确的,除了在密钥库中缺少私钥。

答案 1 :(得分:1)

@EJP很好地解释了根本原因。您的myapp.jks文件中没有私钥。

我可以详细说明解决方案。有3个解决方案。我用你的代码和java 8测试了它们。

  1. 只有keytool - 最快的一个

    删除现有的myapp.jks并使用这些参数通过keytool重新生成。

      

    keytool -genkeypair -dname“cn =姓名姓氏,ou = MyUnit,o = MyOrg,c = US”-alias myorg -keypass 123456 -storepass 123456 -validity 365 -keyalg RSA -keystore myapp.jks

  2. 只有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'

  3. 它们的组合(现行方法)。

    通过名为“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

答案 2 :(得分:-1)

这一切都没有意义。

  • 您根本不需要使用openssl
  • CSR不是证书,更不用说公钥了。
  • 将CSR导入KeyStore的结果不是有效的KeyStore,因为没有私钥。

您需要使用keytool,而不是其他内容,如下所示:

  1. keytool -genkey ...
  2. keytool -selfcert ...

    两次使用相同的别名。

  3. keytool -export ...

  4. keytool -import ...进入客户&#39; truststore 文件。