2016-05-16 70 views
2

我對這個ssl和證書很新。我有一個jks文件,它由服務器信任的一些證書組成。我正在嘗試從jks文件讀取所有證書並將其返回給getAcceptedIssuers()方法。證書的類型爲X509Certificate。 我已經實現的方法正確讀取jks文件並創建一個X509Certificate證書的數組列表。接下來,當我嘗試到ArrayList以數組轉換,我得到這個例外錯誤[Ljava.lang.Object;不能轉換爲[Ljava.security.cert.X509Certificate將X509Certificate的陣列列表轉換爲陣列時

[Ljava.lang.Object; cannot be cast to [Ljava.security.cert.X509Certificate; 
    at com.sample.ssl.GetCertificates.loadCertificatesFromCompanJks(GetCertificates.java:125) 
    at com.sample.ssl.GetCertificates$1.getAcceptedIssuers(GetCertificates.java:44) 
    at sun.security.ssl.AbstractTrustManagerWrapper.checkAlgorithmConstraints(Unknown Source) 
    at sun.security.ssl.AbstractTrustManagerWrapper.checkAdditionalTrust(Unknown Source) 
    at sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(Unknown Source) 
    at sun.security.ssl.ClientHandshaker.serverCertificate(Unknown Source) 
    at sun.security.ssl.ClientHandshaker.processMessage(Unknown Source) 
    at sun.security.ssl.Handshaker.processLoop(Unknown Source) 
    at sun.security.ssl.Handshaker.process_record(Unknown Source) 
    at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source) 
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source) 
    at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source) 
    at sun.security.ssl.SSLSocketImpl.getSession(Unknown Source) 
    at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:91) 
    at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:397) 
    at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:148) 
    at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:149) 
    at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:121) 
    at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:573) 
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:425) 
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820) 
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:754) 
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:732) 
    at com.sample.ssl.GetCertificates.postMessage(GetCertificates.java:82) 
    at com.sample.ssl.GetCertificates.main(GetCertificates.java:138) 

我的代碼如下

public class GetCertificates { 
    static private TrustManager[] trustmgr = new TrustManager[]{new X509TrustManager() { 

     private X509Certificate[] certs = null; 

     public void checkClientTrusted(X509Certificate[] certs, String authType) { 
      System.out.println("checkClientTrusted"); 
     } 

     public void checkServerTrusted(X509Certificate[] certs, String authType) { 
      System.out.println("checkServerTrusted"); 
     } 

     public X509Certificate[] getAcceptedIssuers() { 
      System.out.println("getAcceptedIssuers"); 
      certs = loadCertificatesFromCompanJks("C:/Users/vinod/Desktop/keystore.jks", "mypassword"); 
      // return new 
      // X509Certificate[]{}; 
      return certs; 
     } 
    }}; 

    public void postMessage() { 
     try { 
      // here I prepare Url to execute and make a call 
     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } 
    } 

    public static X509Certificate[] loadCertificatesFromCompanJks(String jksPath, String keyStorePassword) { 
     try { 
      X509Certificate X509Certificate[] = null; 
      Certificate[] certs = null; 

      ArrayList<X509Certificate> serverCerts = new ArrayList<X509Certificate>(); 
      FileInputStream is = new FileInputStream(jksPath); 
      KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType()); 
      String password = keyStorePassword; 
      keystore.load(is, password.toCharArray()); 

      Enumeration e = keystore.aliases(); 
      for (; e.hasMoreElements();) { 

       String alias = (String) e.nextElement(); 
       Certificate cert = keystore.getCertificate(alias); 
       X509Certificate cert1 = (X509Certificate) cert; 
       serverCerts.add(cert1); 
      } 
      is.close(); 
      System.out.println("Number of server certificates : " + serverCerts.size()); 
      X509Certificate = (java.security.cert.X509Certificate[]) serverCerts.toArray(); 
      return X509Certificate; 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 

    public static void main(String[] args) { 
     new GetCertificates().postMessage(); 
    } 
} 

回答

3

你的錯誤是在這裏:

X509Certificate = (java.security.cert.X509Certificate[]) serverCerts.toArray(); 

那的toArray()超載將返回Object[]Object[]不能轉換到不同的陣列類型。

把上面一行是:

X509Certificate = serverCerts.toArray(new X509Certificate[serverCerts.size()]); 

在這裏,你都分配正確的類型和大小的數組,並將它傳遞給toArray從列表中填充。

(你也可以寫這個...

X509Certificate = serverCerts.toArray(new X509Certificate[0]); 

...但是,這會導致不必要的分配。請閱讀toArray(...)以更好地理解的javadoc。(不可否認,那成本額外的內存分配是小,你可以通過傳遞一個預先分配/共享零大小的數組避免它。))


當你在它,改變你的變量名,以符合Java的風格約定。在同一行代碼中對類型和變量使用相同的標識符是非常令人困惑的!

+0

感謝@Stephen。這條線就像魅力一樣。 – user2703788

0

變化

 X509Certificate = (java.security.cert.X509Certificate[]) serverCerts.toArray(); 

 X509Certificate = serverCerts.toArray(new java.security.cert.X509Certificate[0]); 

因爲toArray返回不能b的Object [] Ë轉換爲X509證書[]甚至數組的每一個元素都可以轉換爲X509證書

0

你想要投的是數組的元素而不是數組本身,這就是爲什麼鑄造失敗。當你從列表中做一個沒有指定類型的toArray時,你會得到一個Object數組,並且雖然這些對象的類型是X509Certificate,所以你可以逐個向上轉換它們,但是你不能轉換數組本身。如果您嘗試投射,那麼您將遇到此異常。您的列表需要轉換爲X509Certificate類型的元素數組。

類似於Java 8的替代,你可以這樣做:

X509Certificate[] x509Certificates = serverCerts.parallelStream().toArray(X509Certificate[]::new); 

我也建議使用首字母大寫符號儘可能保持。您使用大寫字母作爲變量名的第一個字母。它也應該更具描述性,因爲您要返回一組證書,而不僅僅是一個。

此:

X509Certificate應該是這樣的x509Certificates