javaandroidsslx509certificatetruststore

Using a PrivateKey, PublicKey and Certificate objects to setup an SSLContext


I have valid PrivateKey, PublicKey and Certificate objects created that I need to be able to use to create an SSLContext for use with a HttpsURLConnection. The reason I need to do it this way is because a requirement is to store the private key, public key and certificate as text within string variables. I have included a short excerpt of the code I'm using.

PrivateKey privKey = loadPrivateKey("REDACTED");
PublicKey publicKey = loadPublicKey("REDACTED");
X509Certificate cert = convertToX509Certificate("REDACTED");

sslContext = ???

     URL obj = new URL("https://www.example.com/WS");
     HttpsURLConnection connection = (HttpsURLConnection) obj.openConnection();


     connection.setSSLSocketFactory(sslContext.getSocketFactory());


 public static PublicKey loadPublicKey(String stored) throws GeneralSecurityException {
        byte[] data = Base64.decode(stored, 0).toString().getBytes();;
        X509EncodedKeySpec spec = new X509EncodedKeySpec(data);
        KeyFactory fact = KeyFactory.getInstance("DSA");
        return fact.generatePublic(spec);
    }


    public static PrivateKey loadPrivateKey(String key64) throws GeneralSecurityException {
        byte[] clear = Base64.decode(key64, 0).toString().getBytes();
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(clear);
        KeyFactory fact = KeyFactory.getInstance("DSA");
        PrivateKey priv = fact.generatePrivate(keySpec);
        Arrays.fill(clear, (byte) 0);
        return priv;
    }

    public X509Certificate convertToX509Certificate(String pem) throws CertificateException, IOException {
        X509Certificate cert = null;
        StringReader reader = new StringReader(pem);
        PEMReader pr = new PEMReader(reader);
        cert = (X509Certificate)pr.readObject();
        return cert;
    }

Solution

  • The easiest way is to still use a keystore, but instead of reading one from disk, create one on the fly:

    ByteArrayInputStream is = new FileInputStream(certificateString);
    KeyStore keyStore = KeyStore.getInstance("PKCS12");
    keyStore.load(is, clientCertPassword.toCharArray());
    
    KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
    kmf.init(keyStore, clientCertPassword.toCharArray());
    KeyManager[] keyManagers = kmf.getKeyManagers();
    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(keyManagers, null, null);
    

    For a full example of using a self-signed client certificate in an Android app (with a matching self-signed server certificate), you can take a look at a blog post that I did a back in 2013: http://chariotsolutions.com/blog/post/https-with-client-certificates-on