- The CA that issued the server certificate was unknown
- The server certificate wasn't signed by a CA, but was self signed
- The server configuration is missing an intermediate CA
Ref: https://developer.android.com/training/articles/security-ssl.html#UnknownCa
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// From https://www.washington.edu/itconnect/security/ca/load-der.crt
InputStream caInput = new BufferedInputStream(new FileInputStream("load-der.crt"));
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
// Tell the URLConnection to use a SocketFactory from our SSLContext
URL url = new URL("https://certs.cac.washington.edu/CAtest/");
HttpsURLConnection urlConnection =
(HttpsURLConnection)url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();
copyInputStreamToOutputStream(in, System.out);Flow: load Crt file --> keystore -> TrustManager
Android 只支援 BKS 的 store type
-
Download: http://downloads.bouncycastle.org/java/bcprov-ext-jdk15on-150.jar
-
copy bcprov-ext-jdk15on-150.jar to $JAVA_HOME/jre/lib/ext
-
edit file $JAVA_HOME/jre/lib/security/java.security
add security.provider.11=org.bouncycastle.jce.provider.BouncyCastleProvider
-
generate keystore
keytool -import -alias lindawang
-file certificate-211169.crt
-keystore app.keystore
-storetype BKS
-provider org.bouncycastle.jce.provider.BouncyCastleProvider
-providerpath /path/to/bouncycastle.jar
-
put file keystore to assets/ folder
-
Exmaple OkHttp network library
private final static String PASSWORD = "qazwsxedc";
private final static String KEYSTORE_FILENAME = "app.keystore";
private final static String STORE_TYPE = "BKS";
private final static String API_URL = "xxxx";
OkHttpClient okHttpClient = new OkHttpClient();
InputStream input = new BufferedInputStream(getAssets().open(KEYSTORE_FILENAME));
KeyStore keyStore = KeyStore.getInstance(STORE_TYPE);
keyStore.load(input, PASSWORD.toCharArray());
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
okHttpClient.setSslSocketFactory(context.getSocketFactory());
Request request = new Request.Builder()
.url("https://api.feebee.com.tw/v1/android_upgrade.php?version_name=v1.1.0&version_code=2015072001")
.build();
Response response = okHttpClient.newCall(request).execute();
for (Certificate certificate : response.handshake().peerCertificates()) {
Log.w(TAG, CertificatePinner.pin(certificate));
}
Log.d(TAG, "Response: " + response.body().string());