Skip to content

Instantly share code, notes, and snippets.

@showsky
Created October 12, 2015 09:02
Show Gist options
  • Select an option

  • Save showsky/3af3d2fd041622c80f75 to your computer and use it in GitHub Desktop.

Select an option

Save showsky/3af3d2fd041622c80f75 to your computer and use it in GitHub Desktop.
Certificate pinning

Certificate pinning

  1. The CA that issued the server certificate was unknown
  2. The server certificate wasn't signed by a CA, but was self signed
  3. 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


自行產生 key store 把 CA 放進去加上密碼

Android 只支援 BKS 的 store type

  1. Download: http://downloads.bouncycastle.org/java/bcprov-ext-jdk15on-150.jar

  2. copy bcprov-ext-jdk15on-150.jar to $JAVA_HOME/jre/lib/ext

  3. edit file $JAVA_HOME/jre/lib/security/java.security

    add security.provider.11=org.bouncycastle.jce.provider.BouncyCastleProvider

  4. 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
  1. put file keystore to assets/ folder

  2. 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());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment