2016-06-07 117 views
0

所以我也遇到了下面的java代码来检索和导入由服务器发布的证书并将它们导入到信任库中。获取并安装SSL证书

import javax.net.ssl.*; 
import java.io.*; 
import java.security.KeyStore; 
import java.security.MessageDigest; 
import java.security.cert.CertificateException; 
import java.security.cert.X509Certificate; 

/** 
* Class used to add the server's certificate to the KeyStore 
* with your trusted certificates. 
*/ 
public class InstallCert { 

    public static void main(String[] args) throws Exception { 
     String host; 
     int port; 
     char[] passphrase; 
     if ((args.length == 1) || (args.length == 2)) { 
      String[] c = args[0].split(":"); 
      host = c[0]; 
      port = (c.length == 1) ? 443 : Integer.parseInt(c[1]); 
      String p = (args.length == 1) ? "changeit" : args[1]; 
      passphrase = p.toCharArray(); 
     } else { 
      System.out.println("Usage: java InstallCert [:port] [passphrase]"); 
      return; 
     } 

     File file = new File("jssecacerts"); 
     if (file.isFile() == false) { 
      char SEP = File.separatorChar; 
      File dir = new File(System.getProperty("java.home") + SEP 
        + "lib" + SEP + "security"); 
      file = new File(dir, "jssecacerts"); 
      if (file.isFile() == false) { 
       file = new File(dir, "cacerts"); 
      } 
     } 
     System.out.println("Loading KeyStore " + file + "..."); 
     InputStream in = new FileInputStream(file); 
     KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); 
     ks.load(in, passphrase); 
     in.close(); 

     SSLContext context = SSLContext.getInstance("TLS"); 
     TrustManagerFactory tmf = 
       TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 
     tmf.init(ks); 
     X509TrustManager defaultTrustManager = (X509TrustManager) tmf.getTrustManagers()[0]; 
     SavingTrustManager tm = new SavingTrustManager(defaultTrustManager); 
     context.init(null, new TrustManager[]{tm}, null); 
     SSLSocketFactory factory = context.getSocketFactory(); 

     System.out.println("Opening connection to " + host + ":" + port + "..."); 
     SSLSocket socket = (SSLSocket) factory.createSocket(host, port); 
     socket.setSoTimeout(10000); 
     try { 
      System.out.println("Starting SSL handshake..."); 
      socket.startHandshake(); 
      socket.close(); 
      System.out.println(); 
      System.out.println("No errors, certificate is already trusted"); 
     } catch (SSLException e) { 
      System.out.println(); 
      e.printStackTrace(System.out); 
     } 

     X509Certificate[] chain = tm.chain; 
     if (chain == null) { 
      System.out.println("Could not obtain server certificate chain"); 
      return; 
     } 

     BufferedReader reader = 
       new BufferedReader(new InputStreamReader(System.in)); 

     System.out.println(); 
     System.out.println("Server sent " + chain.length + " certificate(s):"); 
     System.out.println(); 
     MessageDigest sha1 = MessageDigest.getInstance("SHA1"); 
     MessageDigest md5 = MessageDigest.getInstance("MD5"); 
     for (int i = 0; i < chain.length; i++) { 
      X509Certificate cert = chain[i]; 
      System.out.println 
        (" " + (i + 1) + " Subject " + cert.getSubjectDN()); 
      System.out.println(" Issuer " + cert.getIssuerDN()); 
      sha1.update(cert.getEncoded()); 
      System.out.println(" sha1 " + toHexString(sha1.digest())); 
      md5.update(cert.getEncoded()); 
      System.out.println(" md5  " + toHexString(md5.digest())); 
      System.out.println(); 
     } 

     System.out.println("Enter certificate to add to trusted keystore or 'q' to quit: [1]"); 
     String line = reader.readLine().trim(); 
     int k; 
     try { 
      k = (line.length() == 0) ? 0 : Integer.parseInt(line) - 1; 
     } catch (NumberFormatException e) { 
      System.out.println("KeyStore not changed"); 
      return; 
     } 

     X509Certificate cert = chain[k]; 
     String alias = host + "-" + (k + 1); 
     ks.setCertificateEntry(alias, cert); 

     OutputStream out = new FileOutputStream("jssecacerts"); 
     ks.store(out, passphrase); 
     out.close(); 

     System.out.println(); 
     System.out.println(cert); 
     System.out.println(); 
     System.out.println 
       ("Added certificate to keystore 'jssecacerts' using alias '" 
         + alias + "'"); 
    } 

    private static final char[] HEXDIGITS = "abcdef".toCharArray(); 

    private static String toHexString(byte[] bytes) { 
     StringBuilder sb = new StringBuilder(bytes.length * 3); 
     for (int b : bytes) { 
      b &= 0xff; 
      sb.append(HEXDIGITS[b >> 4]); 
      sb.append(HEXDIGITS[b & 15]); 
      sb.append(' '); 
     } 
     return sb.toString(); 
    } 

    private static class SavingTrustManager implements X509TrustManager { 

     private final X509TrustManager tm; 
     private X509Certificate[] chain; 

     SavingTrustManager(X509TrustManager tm) { 
      this.tm = tm; 
     } 

     public X509Certificate[] getAcceptedIssuers() { 
      throw new UnsupportedOperationException(); 
     } 

     public void checkClientTrusted(X509Certificate[] chain, String authType) 
       throws CertificateException { 
      throw new UnsupportedOperationException(); 
     } 

     public void checkServerTrusted(X509Certificate[] chain, String authType) 
       throws CertificateException { 
      this.chain = chain; 
      tm.checkServerTrusted(chain, authType); 
     } 
    } 
} 

在第一次运行时,我得到了服务器发布2个证书,我将其导入到我的信任没有问题(我可以看到通过密钥工具的信任的的证书)。然而,在第二次运行时,我期望得到“没有错误,证书已经被信任”的输出,但是相反,我得到如下的UnsupportedOperationException,从内部类的getAcceptedIssuers()方法传播,然后再次提示导入证书。 有人可以帮我理解为什么吗?

Starting SSL handshake... 

javax.net.ssl.SSLException: java.lang.UnsupportedOperationException 
     at sun.security.ssl.Alerts.getSSLException(Alerts.java:208) 
     at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1904) 
     at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1862) 
     at sun.security.ssl.SSLSocketImpl.handleException(SSLSocketImpl.java:1845) 
     at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1366) 
     at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1343) 
     at LDAPCerts.start(LDAPCerts.java:41) 
     at LDAPCerts.main(LDAPCerts.java:15) 
Caused by: java.lang.UnsupportedOperationException 
     at LDAPCerts$SavingTrustManager.getAcceptedIssuers(LDAPCerts.java:126) 
     at sun.security.ssl.AbstractTrustManagerWrapper.checkAlgorithmConstraints(SSLContextImpl.java:998) 
     at sun.security.ssl.AbstractTrustManagerWrapper.checkAdditionalTrust(SSLContextImpl.java:944) 
     at sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(SSLContextImpl.java:886) 
     at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1428) 
     at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:209) 
     at sun.security.ssl.Handshaker.processLoop(Handshaker.java:901) 
     at sun.security.ssl.Handshaker.process_record(Handshaker.java:837) 
     at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1023) 
     at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1332) 
     at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1359) 
     ... 3 more 

回答

0

创建jssecacerts文件后,将其复制到$ JAVA_HOME/jre/lib/security /目录并重试。

UPDATE:

嗯,这是没有必要的,但这时就需要由JVM系统参数来指定位置:

-Djavax.net.ssl.trustStore= 

请参阅位置如何确定。从Oracle guide摘自:

  1. 如果系统属性:javax.net.ssl.trustStore中

定义,那么的TrustManagerFactory尝试查找使用 由系统指定的文件名的文件属性,并将该文件用于 KeyStore。如果还定义了javax.net.ssl.trustStorePassword系统属性 ,则在打开信任库之前,其值将用于检查信任库中数据的完整性 。

如果定义了javax.net.ssl.trustStore 但指定的文件不存在,那么将创建一个使用空密钥库的默认 TrustManager。

  • 如果未指定javax.net.ssl.trustStore中系统属性中,然后 如果文件/ LIB /安全/ jssecacerts
  • 存在,该文件是用过的。 (有关什么是指信息的安装目录 )。否则,

  • 如果 文件/ LIB /安全/ cacerts中
  • 存在,该文件是用过的。

    +0

    嗨Laszlo,谢谢你的回答。实际上,我正在使用不同路径下的自定义信任库来读取和写入发布的证书。为什么我需要把它放在$ JAVA_HOME/jre/lib/security/dir中?我无法将信任库存储在其他地方并使用我的应用程序吗? – GeorgeK

    +0

    请参阅我的更新。 –

    +0

    再次感谢Laszlo,我确实尝试通过传递三个-D属性来尝试运行该程序:'java -Djavax.net.ssl。trustStore =/path/to/my/truststore -Djavax.net.ssl.trustStoreType = jks -Djavax.net.ssl.trustStorePassword = changeit -Djavax.net.ssl.debug = all LDAPCerts' 但是异常仍然存在... – GeorgeK