Restlet javax.net.ssl.SSLHandshakeException:null cert chain

vik*_*s27 10 java ssl restlet sslhandshakeexception restlet-2.3.1

我正在本地测试客户端和服务器之间的SSL通信.所以我使用OpenSSL命令生成证书.在cacert文件中添加了此证书.还生成.p12文件.

我在服务器和客户端使用相同的.p12文件.这是服务器代码

Server server = component.getServers().add(Protocol.HTTPS, port);
Series<Parameter> params = server.getContext().getParameters();

params.add("keystorePath", ".p12 file path");
params.add("keystoreType", "PKCS12");
params.add("needClientAuthentication","true");

component.getDefaultHost().attach("", "/AA"), new AAClass());
component.start();
Run Code Online (Sandbox Code Playgroud)

这是客户端代码:

Client client = trustAllCerts();
clientResource = new ClientResource(url);
clientResource.setNext(client);
try{
      clientText = clientResource.post"");
 }
 catch(ResourceException e){
    e.printStackTrace();
 }

public Client trustAllCerts() {
    Client client = null;
    try {
        client = new Client(new Context(), Protocol.HTTPS);
        Context context = client.getContext();


        final SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
        context.getAttributes().put("sslContextFactory", new SslContextFactory() {
            public void init(Series<Parameter> parameters) {

            }

            public SSLContext createSslContext() {
                return sslContext;
            }
        });
        TrustManager tm = new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        context.getAttributes().put("hostnameVerifier", new HostnameVerifier() {                
            @Override
            public boolean verify(String arg0, SSLSession arg1) {
                return true;
            }

        });         

        sslContext.init(null, new TrustManager[] { tm }, null);         

    } catch (KeyManagementException e) {
        LOGGER.error("Exception in Key Management" + e);
    } catch (NoSuchAlgorithmException e) {
        LOGGER.error("Exception in Algorithm Used" + e);
    }
    return client;
}
Run Code Online (Sandbox Code Playgroud)

我得到以下异常:

Restlet-1299242, fatal error: 42: null cert chain
javax.net.ssl.SSLHandshakeException: null cert chain
%% Invalidated:  [Session-25, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256]
Restlet-1299242, SEND TLSv1.2 ALERT:  fatal, description = bad_certificate
Restlet-1299242, WRITE: TLSv1.2 Alert, length = 2
Restlet-1299242, fatal: engine already closed.  Rethrowing javax.net.ssl.SSLHandshakeException: null cert chain
Restlet-1299242, called closeInbound()
Restlet-1299242, fatal: engine already closed.  Rethrowing javax.net.ssl.SSLException: Inbound closed before receiving peer's close_notify: possible truncation attack?
Restlet-1299242, called closeOutbound()
Restlet-1299242, closeOutboundInternal()
Run Code Online (Sandbox Code Playgroud)

我尝试使用System.setProperty()添加密钥库和信任库,但它不起作用.

请帮忙.提前致谢.

bhd*_*rkn 9

首先,让我们创建一个JKS格式的密钥库.PKCS12通常用于浏览器,默认的java应用程序使用JKS(据我所知).Java也支持PKCS12,但我不知道它的确切参数.

准备JKS文件

让我们查看我们的PKCS12文件并获取我们想要提取JKS文件的证书别名.

keytool -list \
        -keystore [*.p12 file] \
        -storepass [password] \
        -storetype PKCS12 \
        -v
Run Code Online (Sandbox Code Playgroud)

请注意要导出的别名.现在让我们创建一个JKS文件.

keytool -keystore [*.jks file path] -genkey -alias client
Run Code Online (Sandbox Code Playgroud)

这会问一堆问题.你可以随意填写它们.现在,您可以将别名从*.p12文件导出到*.jks文件.

keytool -importkeystore \
        -srckeystore [*.p12 file path] \
        -srcstoretype pkcs12 \
        -srcalias [alias from first command] \
        -destkeystore [*.jks file path] \
        -deststoretype jks \
        -deststorepass [*.jks file password] \
        -destalias [new alias]
Run Code Online (Sandbox Code Playgroud)

如果您没有任何PKCS12文件,或者您的证书是CER,DER或PEM格式,则可以使用以下命令将证书添加到密钥库.

keytool -import \
        -alias [new alias] \
        -keystore [*.jks file path] \
        -file [*.DER file path]
Run Code Online (Sandbox Code Playgroud)

请确保您已导入,您的证书,证书提供商的证书(中间证书)和根证书.

现在,您可以检查您的JKS文件是否包含您需要的所有证书.

keytool -list \
        -keystore [*.jks file path] \
        -storepass [password] \
        -storetype jks \
        -v
Run Code Online (Sandbox Code Playgroud)

设置服务器

您可以在客户端和服务器端使用JKS文件.根据Restlet文档,您可以使用这样的JKS文件来提供HTTPS连接.

Server server = component.getServers().add(Protocol.HTTPS, port);  
Series<Parameter> parameters = server.getContext().getParameters();
parameters.add("sslContextFactory","org.restlet.engine.ssl.DefaultSslContextFactory");
parameters.add("keyStorePath", "*.jks file");
parameters.add("keyStorePassword", "password");
parameters.add("keyPassword", "password");
parameters.add("keyStoreType", "JKS");
Run Code Online (Sandbox Code Playgroud)

之后,如果您从浏览器检查端口,则必须看到安全标志.或者您可以使用一些在线工具(如此)来检查您的证书.

设置客户端

现在让我们来看看客户端.由于您正在开发应用程序的两端,因此您可以使用已创建的JKS文件.

Context con = new Context();
Series<Parameter> clParameters = con.getParameters();
clParameters.add("truststorePath", "*.jks file");
clParameters.add("truststorePassword", "password");
clParameters.add("truststoreType", "JKS");
Client restletClient = new Client(con, Protocol.HTTPS);
Run Code Online (Sandbox Code Playgroud)

在测试时或在其他情况下,您的证书主机名和实际主机名可能不匹配.要禁用主机名检查,可以将此块添加到应用程序中.

static{
    javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
    new javax.net.ssl.HostnameVerifier(){

        public boolean verify(String hostname,
                javax.net.ssl.SSLSession sslSession ) {
            return true ;
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

一些想法

由于我无法在我的语言环境中测试它,因此我不确定您的客户端和服务器JKS文件必须是否相同.您可能只需要将自己的证书添加到server.jks.SSL和证书对我来说总是很棘手.经过一些试验和错误,我通常会让它工作.我希望这能帮到您.

此外,您可能还需要考虑使用反向代理类型的Web服务器,如Apache2或Nginx.如果要使用它们,则必须将证书合并到单个文件中.如果查看证书文件,您会看到每个文件(您自己的证书,中间证书和根证书)都是这样的

-----BEGIN CERTIFICATE-----
MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUA...
....
-----END CERTIFICATE-----
Run Code Online (Sandbox Code Playgroud)

您只需将一个添加到另一个即可创建合并证书.而不是使用该证书来结束Apache2或Nginx上的SSL.这就是我通常做的事情.但是在客户端,您仍然需要创建JKS文件.

  • 我尝试了您的建议,但仍然遇到相同的异常。 (2认同)

use*_*421 5

我在服务器和客户端使用相同的 .p12 文件

这已经是一个错误。客户端和服务器是不同的身份,不应具有相同的私钥、公钥或证书。

我建议你放弃所有 OpenSSL 的东西,然后重新开始keytool,如下所示:

  1. 在服务器端,生成密钥对和证书请求;签字;使用-trustcacerts选项导入签名者的证书链;并使用创建密钥对和 CSR 时使用的相同别名导入签名证书
  2. 在客户端,同上,但使用(当然)不同的密钥库文件。
  3. 你完成了。把...忘了吧

    • 开放式SSL
    • PKCS#12
    • 自签名证书
    • 所有形式的trustAllCerts、自定义的TrustManagers和任何类型的自定义代码
    • 对服务器和客户端使用相同的密钥对/证书
    • 将服务器证书导入客户端,反之亦然
    • 除标识javax.net.ssl.keyStorejavax.net.ssl.keyStorePassword
    • 在密钥对或导入的签名证书上设置密码。

步骤 (1) 和 (2) 是打算如何完成的。离开那些,你就会陷入麻烦和冲突。