如何使用Apache客户端和KeyChain API从Android 4.1进行客户端证书身份验证

时间:2012-11-13 15:48:41

标签: android ssl keystore

由于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中不起作用,因为当调用getEncoded()方法并且无法初始化KeyStore时,KeyChain.getPrivateKey()返回的PrivateKey对象返回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
    }
  }

}

谢谢

瓦西

1 个答案:

答案 0 :(得分:3)

KeyChain旨在保护您的私钥。

因此,您可以获取对私钥的引用,并在您的应用程序中使用该私钥进行身份验证,加密......但您永远无法访问实际的私钥数据。

因此,您无法导出私钥 - 这就是您要尝试的内容。