Created
May 30, 2018 09:05
-
-
Save eugeneek/acd04c70e08c5d603a6487891b332cd5 to your computer and use it in GitHub Desktop.
SSL connection helper classes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.eugeneek; | |
import android.content.Context; | |
import android.support.annotation.RawRes; | |
import android.util.Base64; | |
import java.io.ByteArrayInputStream; | |
import java.io.ByteArrayOutputStream; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.security.InvalidAlgorithmParameterException; | |
import java.security.InvalidKeyException; | |
import java.security.KeyFactory; | |
import java.security.KeyStore; | |
import java.security.KeyStoreException; | |
import java.security.NoSuchAlgorithmException; | |
import java.security.NoSuchProviderException; | |
import java.security.PrivateKey; | |
import java.security.PublicKey; | |
import java.security.SignatureException; | |
import java.security.cert.CertPath; | |
import java.security.cert.CertPathValidator; | |
import java.security.cert.CertPathValidatorException; | |
import java.security.cert.Certificate; | |
import java.security.cert.CertificateException; | |
import java.security.cert.CertificateFactory; | |
import java.security.cert.PKIXParameters; | |
import java.security.cert.TrustAnchor; | |
import java.security.cert.X509Certificate; | |
import java.security.spec.InvalidKeySpecException; | |
import java.security.spec.PKCS8EncodedKeySpec; | |
import java.util.Collections; | |
import java.util.List; | |
import java.util.Set; | |
import timber.log.Timber; | |
public class CertUtils { | |
public static Certificate getCertificateFromRaw(Context context, @RawRes int rawResId) throws | |
IOException, CertificateException { | |
CertificateFactory cf = CertificateFactory.getInstance("X.509"); | |
InputStream cert = null; | |
try { | |
cert = context.getResources().openRawResource(rawResId); | |
return cf.generateCertificate(cert); | |
} catch (CertificateException e) { | |
Timber.e(e); | |
} finally { | |
if (cert != null) { | |
cert.close(); | |
} | |
} | |
return null; | |
} | |
public static PrivateKey getPrivateKeyFromRaw(Context context, @RawRes int rawResId) | |
throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchProviderException { | |
InputStream inputStream = context.getResources().openRawResource(rawResId); | |
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); | |
byte buf[] = new byte[1024]; | |
int len; | |
try { | |
while ((len = inputStream.read(buf)) != -1) { | |
outputStream.write(buf, 0, len); | |
} | |
outputStream.close(); | |
inputStream.close(); | |
} catch (IOException e) { | |
Timber.e(e); | |
return null; | |
} | |
String keyPemStr = outputStream.toString() | |
.replace("-----BEGIN RSA PRIVATE KEY-----\n", "") | |
.replace("-----END RSA PRIVATE KEY-----", "") | |
.replace("\n", ""); | |
byte[] keyBytes = Base64.decode(keyPemStr, Base64.NO_WRAP); | |
KeyFactory kf = KeyFactory.getInstance("RSA", "BC"); | |
return kf.generatePrivate(new PKCS8EncodedKeySpec(keyBytes)); | |
} | |
public static KeyStore getClientCertKeyStore(String certStr, byte[] key) throws KeyStoreException, | |
CertificateException, NoSuchAlgorithmException, IOException, InvalidKeySpecException { | |
Certificate certificate = CertUtils.createCertFromString(certStr); | |
PrivateKey privateKey = privateKeyFromByteArray(key); | |
return getClientCertKeyStore(certificate, privateKey); | |
} | |
public static KeyStore getClientCertKeyStore(Certificate certificate, PrivateKey privateKey) | |
throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException { | |
KeyStore keyStore = KeyStore.getInstance("PKCS12"); | |
keyStore.load(null, null); | |
keyStore.setCertificateEntry("alias", certificate); | |
keyStore.setKeyEntry("alias", privateKey, null, new Certificate[]{certificate}); | |
return keyStore; | |
} | |
static boolean validateCertificate(Context context, @RawRes int rootCertResId, | |
String cert) { | |
try { | |
X509Certificate root = (X509Certificate) getCertificateFromRaw(context, rootCertResId); | |
X509Certificate candidate = createCertFromString(cert); | |
return validateKeyChain(candidate, root); | |
} catch (IOException | CertificateException | NoSuchAlgorithmException | |
| InvalidAlgorithmParameterException | NoSuchProviderException e) { | |
Timber.e(e); | |
} | |
return false; | |
} | |
private static boolean validateKeyChain(X509Certificate client, | |
X509Certificate... trustedCerts) | |
throws CertificateException, InvalidAlgorithmParameterException, | |
NoSuchAlgorithmException, NoSuchProviderException { | |
boolean found = false; | |
int i = trustedCerts.length; | |
CertificateFactory cf = CertificateFactory.getInstance("X.509"); | |
TrustAnchor anchor; | |
Set anchors; | |
CertPath path; | |
List list; | |
PKIXParameters params; | |
CertPathValidator validator = CertPathValidator.getInstance("PKIX"); | |
while (!found && i > 0) { | |
anchor = new TrustAnchor(trustedCerts[--i], null); | |
anchors = Collections.singleton(anchor); | |
list = Collections.singletonList(client); | |
path = cf.generateCertPath(list); | |
params = new PKIXParameters(anchors); | |
params.setRevocationEnabled(false); | |
if (client.getIssuerDN().equals(trustedCerts[i].getSubjectDN())) { | |
try { | |
validator.validate(path, params); | |
if (isSelfSigned(trustedCerts[i])) { | |
found = true; | |
} else if (!client.equals(trustedCerts[i])) { | |
found = validateKeyChain(trustedCerts[i], trustedCerts); | |
} | |
} catch (CertPathValidatorException e) { | |
Timber.e(e); | |
} | |
} | |
} | |
return found; | |
} | |
private static boolean isSelfSigned(X509Certificate cert) | |
throws CertificateException, NoSuchAlgorithmException, | |
NoSuchProviderException { | |
try { | |
PublicKey key = cert.getPublicKey(); | |
cert.verify(key); | |
return true; | |
} catch (SignatureException sigEx) { | |
return false; | |
} catch (InvalidKeyException keyEx) { | |
return false; | |
} | |
} | |
private static X509Certificate createCertFromString(String cert) throws CertificateException, | |
IOException { | |
CertificateFactory cf = CertificateFactory.getInstance("X.509"); | |
InputStream in = new ByteArrayInputStream(Base64.decode(cert, Base64.NO_WRAP)); | |
X509Certificate certificate = (X509Certificate) cf.generateCertificate(in); | |
in.close(); | |
return certificate; | |
} | |
private static PrivateKey privateKeyFromByteArray(byte[] key) throws InvalidKeySpecException, | |
NoSuchAlgorithmException { | |
KeyFactory kf = KeyFactory.getInstance("RSA"); | |
return kf.generatePrivate(new PKCS8EncodedKeySpec(key)); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.eugeneek; | |
import java.io.IOException; | |
import java.security.KeyManagementException; | |
import java.security.KeyStore; | |
import java.security.KeyStoreException; | |
import java.security.NoSuchAlgorithmException; | |
import java.security.SecureRandom; | |
import java.security.UnrecoverableEntryException; | |
import java.security.cert.Certificate; | |
import java.security.cert.CertificateException; | |
import java.util.Arrays; | |
import javax.net.ssl.KeyManager; | |
import javax.net.ssl.KeyManagerFactory; | |
import javax.net.ssl.SSLContext; | |
import javax.net.ssl.SSLSocketFactory; | |
import javax.net.ssl.TrustManager; | |
import javax.net.ssl.TrustManagerFactory; | |
import javax.net.ssl.X509TrustManager; | |
public class HttpsHelper { | |
static SSLSocketFactory getSslSocketFactory(Certificate serverCertificate, KeyStore clientKeyStore) | |
throws CertificateException, UnrecoverableEntryException, NoSuchAlgorithmException, | |
IOException, KeyManagementException, KeyStoreException { | |
return getSSLContext(serverCertificate, clientKeyStore).getSocketFactory(); | |
} | |
static X509TrustManager getTrustManager(Certificate serverCertificate) throws CertificateException, | |
NoSuchAlgorithmException, KeyStoreException, IOException { | |
TrustManager[] trustManagers = getTrustManagers(serverCertificate); | |
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) { | |
throw new IllegalStateException("Unexpected default trust managers:" | |
+ Arrays.toString(trustManagers)); | |
} | |
return (X509TrustManager) trustManagers[0]; | |
} | |
public static SSLContext getSSLContext(Certificate serverCertificate, KeyStore keyStore) | |
throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, | |
KeyManagementException, UnrecoverableEntryException { | |
SecureRandom random = new SecureRandom(); | |
KeyManager[] keyManagers = keyStore != null ? getKeyManagers(keyStore) : null; | |
SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); | |
sslContext.init(keyManagers, getTrustManagers(serverCertificate), random); | |
return sslContext; | |
} | |
private static TrustManager[] getTrustManagers(Certificate serverCertificate) throws KeyStoreException, | |
NoSuchAlgorithmException, IOException, CertificateException { | |
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); | |
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); | |
tmf.init(getServerTrustKeyStore(serverCertificate)); | |
return tmf.getTrustManagers(); | |
} | |
private static KeyStore getServerTrustKeyStore(Certificate serverCertificate) throws IOException, | |
CertificateException, KeyStoreException, NoSuchAlgorithmException { | |
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); | |
keyStore.load(null, null); | |
keyStore.setCertificateEntry("ca", serverCertificate); | |
return keyStore; | |
} | |
private static KeyManager[] getKeyManagers(KeyStore keyStore) throws NoSuchAlgorithmException, | |
KeyStoreException, UnrecoverableEntryException { | |
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("X509"); | |
keyManagerFactory.init(keyStore, null); | |
return keyManagerFactory.getKeyManagers(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment