首页 文章

面对javax.net.ssl.SSLHandshakeException:实现SSL双向身份验证时收到致命警报:bad_certificate问题

提问于
浏览
1

我正致力于 SSL two way authentication using self signed certificates . 我为 client(client-keystore.jks)server(server-keystore.jks) 创建了两个密钥库,将证书从密钥库导出并导入客户端证书到服务器密钥库和服务器证书到客户端密钥库 . 并在 server.xml 中更新了所需的连接器条目,并将这两个证书添加到java信任库 cacerts .

Java客户端代码:

KeyStore trustStore = KeyStore.getInstance("JKS", "SUN");
            trustStore.load(SSLImplemetation.class.getResourceAsStream("C:/Program Files/Java/jdk1.7.0_79/jre/lib/security/cacerts"), "changeit".toCharArray());
            String alg = KeyManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory fac = TrustManagerFactory.getInstance(alg);
            fac.init(trustStore);


            KeyStore keystore = KeyStore.getInstance("JKS", "SUN");
            keystore.load(SSLImplemetation.class.getResourceAsStream("<dir path>/client-keystore.jks"), "test".toCharArra());
            String keyAlg = KeyManagerFactory.getDefaultAlgorithm();
            KeyManagerFactory keyFac = KeyManagerFactory.getInstance(keyAlg);
            keyFac.init(keystore, "test".toCharArray());

                SSLContext ctx = SSLContext.getInstance("TLS", "SunJSSE");
            ctx.init(keyFac.getKeyManagers(),fac.getTrustManagers(), new SecureRandom());

            SslContextedSecureProtocolSocketFactory secureProtocolSocketFactory = new SslContextedSecureProtocolSocketFactory(ctx);
            Protocol.registerProtocol("https", new Protocol("https", (ProtocolSocketFactory) secureProtocolSocketFactory, 8443));

            CloseableHttpClient httpClient = HttpClientBuilder.create().build();
            HttpPost request = new HttpPost("<rest service url>");

JSONObject obj = new JSONObject();
StringEntity params =new StringEntity(obj.toString());  

     request.addHeader("content-type", "application/json");
     request.setEntity(params);
     HttpResponse response = httpClient.execute(request);
     System.out.println(response.getStatusLine());

server.xml中:

<Connector
       protocol="org.apache.coyote.http11.Http11Protocol"
       port="8443" maxThreads="200" scheme="https" secure="true" SSLEnabled="true"
             clientAuth="true" sslProtocol="TLS"
             keystoreFile="<dir path>/server-keystore.jks" keystorePass="test"
             truststoreFile="C:/Program Files/Java/jdk1.7.0_79/jre/lib/security/cacerts"
             truststorePass="changeit" />

我是SSl的新手,所以有点困惑 . 任何帮助,将不胜感激 .

1 回答

  • 0

    下面的代码对我来说很好,在创建了两个客户端和服务器密钥库并将证书放入java信任库之后,我使用了以下代码进行SSL相互认证 .

    static final private String KEY_STORE = "D:/sslcertificates/client-keystore.jks";
        static final private String KEY_STORE_TYPE = "JKS";
        static final private String KEY_STORE_PASS = "test";
    
            public static void main(String[] args) throws JSONException{
    
              try {
                  URL url = new URL("<rest service url>");   
                  HttpsURLConnection  conn = (HttpsURLConnection) url.openConnection();
    

    conn.setHostnameVerifier(new HostnameVerifier(){

    public boolean verify(String hostname,
                                              javax.net.ssl.SSLSession sslSession) {
                            if (hostname.equals("<hostname>")) {
                                return true;
                            }
                            return false;
                        }
                    });
    
    
                    conn.setDoOutput(true);
                    conn.setRequestMethod("POST");
                    conn.setRequestProperty("Content-Type", "application/json");
                  try
                  {
                  KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509","SunJSSE");
                  KeyStore ks = KeyStore.getInstance(KEY_STORE_TYPE);
                  File cert = new File(KEY_STORE);
                  InputStream stream = new FileInputStream(cert);
                  ks.load(stream, KEY_STORE_PASS.toCharArray());
                  stream.close();
                  kmf.init(ks,KEY_STORE_PASS.toCharArray());
    
                  SSLContext context = SSLContext.getInstance("TLS");
                  context.init(kmf.getKeyManagers(),null, new SecureRandom());            
                  SSLSocketFactory factory = context.getSocketFactory();               
                  conn.setSSLSocketFactory(factory);
    
                  }
                  catch(Exception e)
                  {
                      System.out.println(e);
                  }
    
                JSONObject obj = new JSONObject();
                 obj.put("id","abc");
                 obj.put("name","surya");
                 obj.put( "domain","IT");     
                 String input=obj.toString();
    
             //send request to server....            
    
                 OutputStream os = conn.getOutputStream();
                 os.write(input.getBytes());
                 os.flush();
                BufferedReader br = new BufferedReader(new InputStreamReader(
                        (conn.getInputStream())));
    
                String output;
                System.out.println("Output from Server .... \n");
                while ((output = br.readLine()) != null) {
                    System.out.println(output);
                }
                 System.out.println("Response code: "+conn.getResponseCode());
                  System.out.println("Response message: "+conn.getResponseMessage());
                conn.disconnect();
    
              } catch (MalformedURLException e) {
    
                e.printStackTrace();
    
              } catch (IOException e) {
    
                e.printStackTrace();
    
             }
    
            }
    

    在server.xml

    <Connector
       protocol="org.apache.coyote.http11.Http11Protocol"
       port="8443" maxThreads="200" scheme="https" secure="true"   SSLEnabled="true"
       clientAuth="true" sslProtocol="TLS"
        keystoreFile="<dir path>/server-keystore.jks" keystorePass="test"/>
    

    NOTE: Set HostnameVerifier in HttpsURLConnection object and CN of client and server keystore should be host name.

    如果有更好的解决方案,请建议 .

相关问题