当前位置: 首页 > 知识库问答 >
问题:

Java HTTPS客户端在curl成功时SSL握手失败

马宜民
2023-03-14

我所拥有的是一个在Dropwizard之上实现的服务器,它需要接受传入的HTTPS连接,并使用附加的证书来唯一标识客户端。我目前在开发过程中使用所有自签名证书。服务器证书对是使用链根对->中间对->服务器对创建的。服务器的P12是使用中间证书和服务器证书加上服务器私钥的串联来创建的。然后它被添加到一个空的JKS中,并成为服务器的密钥库。

我分别创建了两个客户端证书,一个使用相同的中间对作为基础,另一个作为纯独立的证书对。这两个证书对的x509公钥部分被添加到JKS文件中,并成为服务器的信任库。Dropwizard配置如下:

type: "https"
port: "9843"
keyStorePath: "keystore.jks"
keyStorePassword: "changeme"
keyStoreType: "JKS"
trustStorePath: "truststore.jks"
trustStorePassword: "changeme"
trustStoreType: "JKS"
allowRenegotiation: false
validateCerts: false
validatePeers: false
needClientAuth: true
wantClientAuth: true

我可以使用curl和以下任一客户端证书对连接到服务器:

curl -v --cert client.pem --key client.key -k https://localhost:9843/v1/ld 
*** CertificateRequest
Cert Types: RSA, DSS, ECDSA
Supported Signature Algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA256withDSA, SHA224withECDSA, SHA224withRSA, SHA224withDSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA
Cert Authorities:
<CN=*.me.com, O=Me, ST=Massachusetts, C=US>
<O=Internet Widgits Pty Ltd, ST=Massachusetts, C=US>
*** ServerHelloDone
dw-51, WRITE: TLSv1.2 Handshake, length = 3536
dw-44, READ: TLSv1.2 Handshake, length = 1047
*** Certificate chain
chain [0] = [
[
  Version: V3
  Subject: O=Internet Widgits Pty Ltd, L=North Reading, ST=Massachusetts, C=US
  Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5

  Key:  Sun RSA public key, 2048 bits
  modulus: 23250299629324311533731283912176366463399376328149948822580485256237233115567136794461732268017120297060017586981907979910958857247642884566364833267711927344361604478514119965230314679194017013023991389216461419030751049820266939279047536006291610734616600760688907006770883510297954698233112783686968024400749969025850008781641616624298935923926427096257861170476293580684942956111432790304698635393966967864288730561678135798437678912431564767611000006312358137647455886578135011989168265295083928014176435879778838966450081419161406209555593636745048857672445188811541416453143809594265089422302064600885289819601
  public exponent: 65537
  Validity: [From: Wed Dec 05 13:52:49 EST 2018,
               To: Thu Dec 05 13:52:49 EST 2019]
  Issuer: O=Internet Widgits Pty Ltd, ST=Massachusetts, C=US
  SerialNumber: [    8174655c c8387da4]

Certificate Extensions: 3
...

到目前为止还好。接下来,我尝试使用Java客户机连接到我的服务器,该客户机使用相同的证书对,组合在一个P12文件中。Java代码如下:

char[] password = "changeme".toCharArray();
KeyStore keystore = KeyStore.getInstance("PKCS12");
try (FileInputStream fileInputStream = new FileInputStream("client.p12")) {
    keystore.load(fileInputStream, password);
}

SSLContext sslContext = 
        SSLContexts.custom()
                   .loadKeyMaterial(keystore, password)
                   .loadTrustMaterial(null, (chain, authType) -> true)
                   .build();

return HttpClients.custom()
                  .setSSLContext(sslContext)
                  .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                  .build();

但是当此客户端尝试连接服务器时,会记录以下内容:

*** CertificateRequest
Cert Types: RSA, DSS, ECDSA
Supported Signature Algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA256withDSA, SHA224withECDSA, SHA224withRSA, SHA224withDSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA
Cert Authorities:
<CN=*.me.com, O=Me, ST=Massachusetts, C=US>
<O=Internet Widgits Pty Ltd, ST=Massachusetts, C=US>
*** ServerHelloDone
Warning: no suitable certificate found - continuing without client authentication
*** Certificate chain
<Empty>
***

我还尝试使用了用sslContext初始化的SSLConnectionSocketFactory,以及为“https”注册socketFactory的注册表 。什么都没起作用。我完全不知道为什么curl接受证书授权并发送客户机证书,而java httpClient不这样做。

KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
try (FileInputStream fileInputStream = new FileInputStream("server.cert.pem")) {
    try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(IOUtils.toByteArray(fileInputStream))) {
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
        Certificate certificate = certificateFactory.generateCertificate(byteArrayInputStream);
        trustStore.setCertificateEntry("server", certificate);
    }
}

SSLContext sslContext =
        SSLContexts.custom()
                   .loadKeyMaterial(keystore, password)
                   .loadTrustMaterial(trustStore, (chain, authType) -> true)
                   .build();

共有1个答案

沈高峻
2023-03-14

因此,我最终完全重新处理了生成证书的方式,并且能够使工作正常进行,但有一个警告:这取决于证书的生成方式。

可以使用Java客户机、curl和Postman:

openssl genrsa -aes256 -out private/${SVRNAME}.key.pem 2048
openssl req -config ${CONFIGDIR}/openssl.cnf \
      -new -x509 -days 7300 -sha256 -extensions v3_ca \
      -key private/${SVRNAME}.key.pem \
      -out certs/${SVRNAME}.cert.pem

可以使用curl和Postman但不能使用Java客户机:

openssl req -newkey rsa:2048 -nodes \
      -keyout private/${CLINAME}.key.pem \
      -x509 -days 365 -out certs/${CLINAME}.cert.pem
 类似资料:
  • 我已经能够通过HTTP使用Eureka+ZUUL+Ribbon+Config Server设置并成功验证Spring cloud设置。 然而,当我尝试转移到HTTPS时,单个服务在HTTPS上运行良好,但Eureka客户端发现却失败了。

  • 我想使用Netty框架创建一个安全的websocket客户端 - 服务器通信。我看了一下网络示例,有一个使用网络索克SSL服务器的示例:https://github.com/netty/netty/tree/master/example/src/main/java/io/netty/example/http/websocketx/sslserver 还有一个例子是websocket客户端,但没有s

  • 问题内容: 尝试获取网页: 获取https://www.fl.ru/:远程错误:握手失败。 如果我尝试获取另一个HTTPS页面-一切正常。 问题答案: 该服务器仅支持一些弱密码: 如果确实必须连接到该服务器,则Go会支持列表中的最后一个密码,但默认情况下不支持。使用新的tls.Config创建一个客户端,并指定所需的密码:

  • 尝试获取网页: 收到https://www.fl.ru/:远程错误:握手失败。 如果我尝试获取另一个HTTPS页面,一切都可以。

  • 我有一个客户端-服务器应用程序(Android客户端、Apache Http服务器),通过相互身份验证(TLS 1.2)进行通信。问题是:有时连接(登录)会因SSL错误而失败。 这是有效的: 注册客户端证书 登录 这是行不通的: 注册客户证书 注意:在步骤4之后杀死应用程序,然后启动它并执行步骤5工作。 我能想到的可能解释是: 正在重用一些旧资源(如旧客户端证书)。看起来所有相关的东西(OkHtt

  • 我不知道我到底需要在哪里包含客户机证书。现在,我的第一个问题是我不信任服务器。我尝试使用默认的Java密钥库文件(cacerts),其中包含Thawte和Digicert,这些是我试图与之通信的服务器的根权限。我使用