fixed certificate pinning

This commit is contained in:
Adithya Abraham Philip
2015-06-07 21:44:15 +05:30
parent 25d07d173c
commit 731ec3382e
2 changed files with 41 additions and 14 deletions

View File

@@ -19,7 +19,6 @@ package org.sufficientlysecure.keychain.util;
import android.content.res.AssetManager;
import com.squareup.okhttp.CertificatePinner;
import com.squareup.okhttp.OkHttpClient;
import org.sufficientlysecure.keychain.Constants;
@@ -76,7 +75,7 @@ public class TlsHelper {
}
}
public static URLConnection openConnection(URL url) throws IOException, TlsHelperException {
public static URLConnection opeanConnection(URL url) throws IOException, TlsHelperException {
if (url.getProtocol().equals("https")) {
for (String domain : sStaticCA.keySet()) {
if (url.getHost().endsWith(domain)) {
@@ -87,27 +86,54 @@ public class TlsHelper {
return url.openConnection();
}
public static void pinCertificateIfNecessary(OkHttpClient client, URL url) throws TlsHelperException {
public static void pinCertificateIfNecessary(OkHttpClient client, URL url) throws TlsHelperException, IOException {
if (url.getProtocol().equals("https")) {
for (String domain : sStaticCA.keySet()) {
if (url.getHost().endsWith(domain)) {
pinCertificate(sStaticCA.get(domain), domain, client);
pinCertificate(sStaticCA.get(domain), client);
}
}
}
}
public static void pinCertificate(byte[] certificate, String hostName, OkHttpClient client)
throws TlsHelperException {
/**
* Modifies the client to accept only requests with a given certificate. Applies to all URLs requested by the
* client.
* Therefore a client that is pinned this way should be used to only make requests to URLs with passed certificate.
* TODO: Refactor - More like SSH StrictHostKeyChecking than pinning?
*
* @param certificate certificate to pin
* @param client OkHttpClient to enforce pinning on
* @throws TlsHelperException
* @throws IOException
*/
private static void pinCertificate(byte[] certificate, OkHttpClient client)
throws TlsHelperException, IOException {
// We don't use OkHttp's CertificatePinner since it depends on a TrustManager to verify it too. Refer to
// note at end of description: http://square.github.io/okhttp/javadoc/com/squareup/okhttp/CertificatePinner.html
// Creating our own TrustManager that trusts only our certificate eliminates the need for certificate pinning
try {
// Load CA
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate ca = cf.generateCertificate(new ByteArrayInputStream(certificate));
String pin = CertificatePinner.pin(ca);
Log.e("PHILIP", "" + ca.getPublicKey() + ":" + pin);
client.setCertificatePinner(new CertificatePinner.Builder().add(hostName, pin).build());
} catch (CertificateException e) {
// 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);
client.setSslSocketFactory(context.getSocketFactory());
} catch (CertificateException | KeyStoreException | KeyManagementException | NoSuchAlgorithmException e) {
throw new TlsHelperException(e);
}
}