【发布时间】:2012-11-02 01:41:42
【问题描述】:
由于 ICS Android 支持通过 KeyChain API 统一访问系统密钥库和受信任的 CA。
这很好,但是当我尝试使用来自该来源的私钥进行客户端证书身份验证时,给我带来了麻烦。
我在这里检查了一些答案,我发现最好的答案是:Android 4.0 SSL Authentication
参考4.0,提供如下编码:
更新 - 这个编码是错误的 - 它不能在 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);
这在 4.1 中不起作用,因为 KeyChain.getPrivateKey() 返回的 PrivateKey 对象在调用 getEncoded() 方法并且无法初始化 KeyStore 时返回 null。
在 4.1 中有没有其他方法可以做到这一点?
更新 - 这里是定义您自己的 KeyStore 和 KeyStoreSpi 实现的正确方法 这里是 KeyStore 和 KeyStoreSpi 的示例实现:
KeyStoreSpi 实现:
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 实现:
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
}
}
}
谢谢
瓦西尔
【问题讨论】:
-
您能解释一下接下来如何使用这两个自定义类吗?我正在努力解决同样的问题......
-
我想通了。这是为寻找最后一块的人准备的: KeyChainProxy keyChainProxy = new KeyChainProxy("your-alias", yourKey, yourChain); KeyChainKeystore keyChainKeystore = new KeyChainKeystore(keyChainProxy, null, "type-of-keystore-you-want");
-
就是这样。您可以从钥匙串中制作一个 SPI 并使用它来初始化密钥库。然后,您可以在 ssl 调用中将此密钥库用作客户端证书。