あなたは証明書が必要なエイリアスによって参照されURLConnection
で使用されるSSLContext
を設定するには、X509ExtendedKeyManager
を拡張する前にAndroidのキーチェーン(システムのキーストア)に設置された証明書を使用することができます。クロムの使用のようなダイアログで選択のためにユーザに促すために:
KeyChain.choosePrivateKeyAlias(this, this, // Callback
new String[] {"RSA", "DSA"}, // Any key types.
null, // Any issuers.
null, // Any host
-1, // Any port
DEFAULT_ALIAS);
これは、カスタムKeyManager
を使用してSSL接続を設定するためのコードです。デフォルトのTrustManager
とHostnameVerifier
が使用されます。サーバーは、Androidのデフォルトのトラストストアに存在していない自己署名証明書を使用している場合は、あなたが持っている最後に、ここで
//Configure trustManager if needed
TrustManager[] trustManagers = null;
//Configure keyManager to select the private key and the certificate chain from KeyChain
KeyManager keyManager = KeyChainKeyManager.fromAlias(
context, mClientCertAlias);
//Configure SSLContext
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(new KeyManager[] {keyManager}, trustManagers, null);
//Perform the connection
URL url = new URL(versionUrl);
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
//urlConnection.setHostnameVerifier(hostnameVerifier); //Configure hostnameVerifier if needed
urlConnection.setConnectTimeout(10000);
InputStream in = urlConnection.getInputStream();
を(すべての証明書を信頼することは推奨されません)から抽出されたカスタムX509ExtendedKeyManager
の完全な実装にそれらを設定する必要がありますクライアント証明書の選択を担当するhereおよびhere私は必要なコードを抽出しました。
public static class KeyChainKeyManager extends X509ExtendedKeyManager {
private final String mClientAlias;
private final X509Certificate[] mCertificateChain;
private final PrivateKey mPrivateKey;
/**
* Builds an instance of a KeyChainKeyManager using the given certificate alias.
* If for any reason retrieval of the credentials from the system {@link android.security.KeyChain} fails,
* a {@code null} value will be returned.
*/
public static KeyChainKeyManager fromAlias(Context context, String alias)
throws CertificateException {
X509Certificate[] certificateChain;
try {
certificateChain = KeyChain.getCertificateChain(context, alias);
} catch (KeyChainException e) {
throw new CertificateException(e);
} catch (InterruptedException e) {
throw new CertificateException(e);
}
PrivateKey privateKey;
try {
privateKey = KeyChain.getPrivateKey(context, alias);
} catch (KeyChainException e) {
throw new CertificateException(e);
} catch (InterruptedException e) {
throw new CertificateException(e);
}
if (certificateChain == null || privateKey == null) {
throw new CertificateException("Can't access certificate from keystore");
}
return new KeyChainKeyManager(alias, certificateChain, privateKey);
}
private KeyChainKeyManager(
String clientAlias, X509Certificate[] certificateChain, PrivateKey privateKey) {
mClientAlias = clientAlias;
mCertificateChain = certificateChain;
mPrivateKey = privateKey;
}
@Override
public String chooseClientAlias(String[] keyTypes, Principal[] issuers, Socket socket) {
return mClientAlias;
}
@Override
public X509Certificate[] getCertificateChain(String alias) {
return mCertificateChain;
}
@Override
public PrivateKey getPrivateKey(String alias) {
return mPrivateKey;
}
@Override
public final String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
// not a client SSLSocket callback
throw new UnsupportedOperationException();
}
@Override
public final String[] getClientAliases(String keyType, Principal[] issuers) {
// not a client SSLSocket callback
throw new UnsupportedOperationException();
}
@Override
public final String[] getServerAliases(String keyType, Principal[] issuers) {
// not a client SSLSocket callback
throw new UnsupportedOperationException();
}
}
}
私はそれをテストしませんでした。エラーを報告してください!
以前にAndroid KeyChain(システムキーストア)にインストールされていた証明書を使用するのか、それとも 'HttpsURLConnection'に証明書を直接渡しますか? – pedrofb
KeyChainから以前にインストールした証明書を使用したいと思います。資格情報を使用してインストールされました。 "VPN and apps" – kerosene