Since ICS Android supports unified access to the system keystore and trusted CAs via the KeyChain API.
It is quite nice but is giving me following trouble when I try to use a private key from this source for client cert authentication.
I checked some answers here and the best thing that I found was: Android 4.0 SSL Authentication
It refers to 4.0 and provides following coding:
Update – this coding is WRONG – it will not work in 4.1+
String alias = "test";
KeyStore memoryKeyStore = KeyStore.getInstance("BKS");
memoryKeyStore.load(null);
X509Certificate[] chain = KeyChain.getCertificateChain(getApplicationContext(),alias);
PrivateKey key = KeyChain.getPrivateKey(getApplicationContext(),alias);
memoryKeyStore.setKeyEntry(alias, key.getEncoded(), chain);
this is however not working in 4.1 because the PrivateKey object returned by KeyChain.getPrivateKey() returns null when the getEncoded() method is called and the KeyStore cannot be initialized.
Is there any other way to do this in 4.1?
Update – here the correct way to define your own implementation of KeyStore and KeyStoreSpi
Here the sample implementation of KeyStore and KeyStoreSpi:
KeyStoreSpi implementation:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Key;
import java.security.KeyStoreException;
import java.security.KeyStoreSpi;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.security.PrivateKey;
public class KeyChainProxy extends KeyStoreSpi {
private String alias = null;
private PrivateKey privateKey = null;
private Certificate[] certChain = null;
public KeyChainProxy(String alias, PrivateKey privateKey, Certificate[] certChain) {
this.alias = alias;
this.privateKey = privateKey;
this.certChain = certChain;
}
@Override
public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException, UnrecoverableKeyException {
return privateKey;
}
@Override
public Certificate[] engineGetCertificateChain(String alias) {
return certChain;
}
@Override
public Certificate engineGetCertificate(String alias) {
return certChain[0];
}
@Override
public Date engineGetCreationDate(String alias) {
return new Date();
}
@Override
public void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain) throws KeyStoreException {
throw new KeyStoreException("Not Implemented");
}
@Override
public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) throws KeyStoreException {
throw new KeyStoreException("Not Implemented");
}
@Override
public void engineSetCertificateEntry(String alias, Certificate cert) throws KeyStoreException {
throw new KeyStoreException("Not Implemented");
}
@Override
public void engineDeleteEntry(String alias) throws KeyStoreException {
throw new KeyStoreException("Not Implemented");
}
@Override
public Enumeration<String> engineAliases() {
List<String> list = new ArrayList<String>();
list.add(alias);
return Collections.enumeration(list);
}
@Override
public boolean engineContainsAlias(String alias) {
return alias != null && alias.equals(this.alias);
}
@Override
public int engineSize() {
return 1;
}
@Override
public boolean engineIsKeyEntry(String alias) {
return true;
}
@Override
public boolean engineIsCertificateEntry(String alias) {
return false;
}
@Override
public String engineGetCertificateAlias(Certificate cert) {
return null;
}
@Override
public void engineStore(OutputStream stream, char[] password) throws IOException, NoSuchAlgorithmException, CertificateException {
}
@Override
public void engineLoad(InputStream stream, char[] password) throws IOException, NoSuchAlgorithmException, CertificateException {
}
}
KeyStore implemenation:
import java.security.KeyStore;
import java.security.KeyStoreSpi;
import java.security.Provider;
public class KeyChainKeystore extends KeyStore {
public KeyChainKeystore(KeyStoreSpi keyStoreSpi, Provider provider, String type) {
super(keyStoreSpi, provider, type);
try {
load(null, null);
} catch (Exception e) {
// ignore - our spi doesn't do anything
}
}
}
Thank you
Vasil
The KeyChain is designed to protect your private keys.
Therefore you can get a reference to a private key and use that private key within your app for authentication, encryption, … but you never get access to the actual private key data.
Hence you can not export the private key – which is what you are trying to do.