user2703788 user2703788 - 6 months ago 18
Java Question

Error [Ljava.lang.Object; cannot be cast to [Ljava.security.cert.X509Certificate when converting an arraylist of X509Certificate to array

I am very new to this ssl and certificates. I have a jks file which consists of some certificates which server trusts. I am trying to read all the certificates from the jks file and return it to getAcceptedIssuers() method. The certificates are of type X509Certificate.
The method which I have implemented reads the jks file properly and creates an arraylist of X509Certificate certificates. Next when I try to convert the arraylist to array, I get this exception

[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)


My code is as Follows

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();
}
}

Answer

Your mistake is here:

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

That overload of toArray() will return an Object[] and an Object[] CANNOT be cast to a different array type.

Change that line to this:

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

Here, you are allocating the array of the correct type and size, and passing it to toArray to be filled from the list.

(You could also write this ...

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

... but that will result in an unnecessary allocation. Please read the javadocs for toArray(...) for a better understanding. (Admittedly, the cost of that extra allocation is small, and you could avoid it by passing a pre-allocated / shared zero-sized array.) )


While you are at it, change your variable names to conform to the Java style conventions. It is horribly confusing to use the same identifier for a type and a variable in the same line of code!

Comments