2012-11-13 25 views
1

由於ICS Android支持通過KeyChain API統一訪問系統密鑰庫和可信CA.如何使用Apache客戶端和KeyChain API從Android 4.1進行客戶端證書驗證

這是相當不錯的,但當我嘗試使用此源的私鑰用於客戶端證書認證時,給我帶來了以下麻煩。

我這裏查了一些答案,我發現最好的事情是: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()返回的專用密鑰對象時的getEncoded()方法被調用和密鑰庫不能被初始化返回null。

4.1還有其他的方法嗎?

更新 - 在這裏正確的方式來定義自己的實現密鑰存儲和KeyStoreSpi 這裏的示例實現密鑰存儲和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 { 

    } 

} 

密鑰庫實行:

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 
    } 
    } 

}

謝謝

瓦西

+0

你能解釋下你如何使用這兩個自定義類嗎?我正在努力解決同樣的問題... – Sandra

+0

我想通了。這裏是尋找這個最後一塊的人:KeyChainProxy keyChainProxy = new KeyChainProxy(「your-alias」,yourKey,yourChain); KeyChainKeystore keyChainKeystore = new KeyChainKeystore(keyChainProxy,null,「type-of-keystore-you-want」); – Sandra

+0

這就是主意。您可以從鑰匙串中創建一個SPI並使用它來初始化密鑰庫。然後,您可以在ssl調用中將此密鑰庫用作客戶端證書。 – vap78

回答

2

鑰匙串是爲了保護你的私鑰。

因此,您可以獲得對私鑰的引用,並在您的應用中使用該私鑰進行身份驗證,加密......但您永遠無法訪問實際的私鑰數據。

因此,您不能導出私鑰 - 這是您正在嘗試執行的操作。

+0

你說的話似乎正確但是......那麼爲什麼Apache客戶端需要一個明確的KeyStore對象才能執行客戶端證書身份驗證? Android的可信CA通過'KeyStore.getInstance(「AndroidCAStore」)作爲KeyStore對象提供,但私鑰不是。 – vap78

+0

似乎接口不能很好地協同工作。但是沒有任何地方說它必須是一個BKS KeyStore實例。您可以嘗試實現您自己的KeyStoreSpi實例,該實例僅包含您從KeyChain獲得的PrivateKey。如果只用鑰匙,它可能會起作用。 – Robert

+0

將嘗試此操作並更新結果的問題 - 感謝您的幫助。 – vap78