Jan Veselý Jan Veselý - 5 months ago 23
Android Question

Proper way to store certificates in android and their management in future

I have one .pfx a and .cer certificate. The first one is for signing data and the second one is for opening SSL.

How should I store certificates in android?


  • should I put them in Keystore in res/raw or in assets?

  • should I store them as single files in res/assets?

  • What is most efficient way to store them in order to manage future changes?



My current way of doing so:

// Create Keystore containing servers certificate
KeyStore keyStore = KeyStore.getInstance("BKS");

// Different versions of Android use different BKSs
// Need to export both versions using Portacle (1.9 worked for me)
int bks_version;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
bks_version = R.raw.keystore; //The BKS file
} else {
bks_version = R.raw.keystorev1; //The BKS (v-1) file
}

keyStore.load(activity.getResources().openRawResource(bks_version), "password");

Answer

I wrote a class which manages my certificates such as CAs for SSL and PFX or P12 for personal signatures.

I used internal storage and built in KeyStore. If you are wondering where I got and alias for PFX, you have to know it, I haven't figure out a better way how to handle this problem in Android yet.

public class CertificateManager {
private static final String CUSTOMER_CERTIFICATE_STORE = "CustomerKeyStore.keystore";
private static final String CUSTOMER_CERTIFICATE_ALIAS = "CZ1212121218";
private static final String CUSTOMER_KS_PASSWORD = "eet";

private static final String SERVER_CERTIFICATE_STORE = "ServerKeyStore.keystore";
private static final String SERVER_CERTIFICATE_ALIAS = "ca";
private static final String SERVER_KS_PASSWORD = "eet";

/**
 *  Get Customer's Keystore, containing personal certificate.
 * @param context
 * @return Customer's Keystore
 */
private static KeyStore getCustomerKeystore(Context context){
    try {
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        // Load Keystore form internal storage
        FileInputStream fis = context.openFileInput(CUSTOMER_CERTIFICATE_STORE);
        keyStore.load(fis, CUSTOMER_KS_PASSWORD.toCharArray());
        return  keyStore;
    } catch (Exception e) {
        e.printStackTrace();
        throw new RuntimeException("Keystore not found.");
    }
}

/**
 * Get customer's certificate for signature.
 * @param context
 * @return Customer's certificate
 */
public static X509Certificate getCustomersCertificate(Context context){
    try {
        KeyStore keyStore= getCustomerKeystore(context);

        KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(
                        CUSTOMER_CERTIFICATE_ALIAS,
                        new KeyStore.PasswordProtection(CUSTOMER_KS_PASSWORD.toCharArray())
        );

        return  (X509Certificate) keyEntry.getCertificate();
    } catch (Exception e) {
        // Keystore not found ask user for uploading his certificate.
        e.printStackTrace();
        throw new RuntimeException("Wrong KeyStore");
    }
}

/**
 * Get customer's PrivateKey for encryption.
 * @param context
 * @return customer's PrivateKey
 */
public static PrivateKey getCustomersPrivateKey(Context context){
    try {
        KeyStore keyStore= getCustomerKeystore(context);

        //return customer's certificate
        return (PrivateKey)keyStore.getKey(CUSTOMER_CERTIFICATE_ALIAS, CUSTOMER_KS_PASSWORD.toCharArray());
    } catch (Exception e) {

        e.printStackTrace();
        throw new RuntimeException("Wrong KeyStore");
    }
}

/**
 * Loads Customer .p12 or .pfx certificate to keystore with password to Internal Storage
 * @param context
 * @return customer's PrivateKey
 */
public static void loadCustomerCertificate(Context context, InputStream inputStream) throws Exception{
    KeyStore keyStore = KeyStore.getInstance("pkcs12");
    keyStore.load(inputStream, CUSTOMER_KS_PASSWORD.toCharArray());

    //Save KeyStore in Internal Storage
    FileOutputStream fos = context.openFileOutput(CUSTOMER_CERTIFICATE_STORE, Context.MODE_PRIVATE);
    keyStore.store(fos, CUSTOMER_KS_PASSWORD.toCharArray());
    fos.close();
}

/**
 * Server certificate for SLL communication
 * @param context
 * @return HTTPS TrustStore
 */
public static KeyStore getServerKeystore(Context context){
    try {
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());

        // Load Keystore form internal storage
        FileInputStream fis = context.openFileInput(SERVER_CERTIFICATE_STORE);
        keyStore.load(fis, SERVER_KS_PASSWORD.toCharArray());
        return  keyStore;
    } catch (Exception e) {
        e.printStackTrace();
        throw new RuntimeException("Keystore not found.");
    }
}

/**
 * Load Server certificate for SLL communication
 * @param context
 * @param inputStream server trusted CAs
 */
public static void loadServerKeystore(Context context, InputStream inputStream) throws Exception{
    // Load CAs from an InputStream
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    Certificate ca = cf.generateCertificate(inputStream);
    inputStream.close();

    // Create a KeyStore containing our trusted CAs
    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    keyStore.load(null, null);
    keyStore.setCertificateEntry(SERVER_CERTIFICATE_ALIAS, ca);

    // Save keystore to Internal Storage.
    FileOutputStream fos = context.openFileOutput(SERVER_CERTIFICATE_STORE, Context.MODE_PRIVATE);
    keyStore.store(fos, SERVER_KS_PASSWORD.toCharArray());
    fos.close();
}