【问题标题】:Facing javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate issue while implementing SSL two way authentication面对 javax.net.ssl.SSLHandshakeException:收到致命警报:在实施 SSL 双向身份验证时出现 bad_certificate 问题
【发布时间】:2016-08-14 02:14:22
【问题描述】:

我正在研究使用自签名证书的 SSL 双向身份验证。 我为 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 的新手,所以有点困惑。 任何帮助将不胜感激。

【问题讨论】:

    标签: java ssl network-programming openssl keytool


    【解决方案1】:

    下面的代码对我来说很好,在创建两个客户端和服务器密钥库并将证书都放入 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();
    
             }
    
            }
    

    服务器.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"/>
    

    注意:在 HttpsURLConnection 对象中设置 HostnameVerifier,客户端和服务器密钥库的 CN 应该是主机名。

    如果有更好的解决方案,请提出建议。

    【讨论】:

      猜你喜欢
      • 2013-07-08
      • 1970-01-01
      • 1970-01-01
      • 2016-07-22
      • 2023-04-07
      • 2015-10-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多