Ich möchte eine App erstellen, die mit einem Server verbindet. Dieser Server verwendet die SSL-Clientauthentifizierung. Der Benutzer der App sollte in der Lage sein, das Zertifikat auszuwählen und dessen Verwendung zuzulassen, so wie es in der Browser-App implementiert ist.SSL-Client-Authentifizierung in Android 4.x
In der Browser-App funktioniert die Authentifizierung wie erwartet, so dass das Zertifikat, das ich verwende, gültig ist.
Wenn ich versuche, in meiner App zu verbinden bekomme ich folgende Fehler:
javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException:
SSL handshake terminated: ssl=0x2a2d3b38:
Failure in SSL library, usually a protocol error
error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure
(external/openssl/ssl/s3_pkt.c:1290 0x2a2df880:0x00000003)
ich die Android-Dokumentation für meine Implementierung zu folgen versucht.
Hier ist der Code meiner Probe Aktivität:
public class ClientCertificateActivity extends Activity implements
KeyChainAliasCallback {
protected static final String TAG = "CERT_TEST";
private String alias;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
choseCertificate();
LinearLayout layout = new LinearLayout(this);
Button connectToServer = new Button(this);
connectToServer.setText("Try to connect to Server");
connectToServer.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
connectToServer.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
connectToServer();
}
});
layout.addView(connectToServer);
addContentView(layout, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
}
protected void connectToServer() {
final Context ctx = this;
new AsyncTask<Void, Void, Boolean>() {
private Exception error;
@Override
protected Boolean doInBackground(Void... arg) {
try {
PrivateKey pk = KeyChain.getPrivateKey(ctx, alias);
X509Certificate[] chain = KeyChain.getCertificateChain(ctx,
alias);
KeyStore keyStore = KeyStore.getInstance("AndroidCAStore");
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory
.getDefaultAlgorithm());
tmf.init(keyStore);
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
URL url = new URL("https://usecert.example.com/");
HttpsURLConnection urlConnection = (HttpsURLConnection) url
.openConnection();
urlConnection.setSSLSocketFactory(context
.getSocketFactory());
InputStream in = urlConnection.getInputStream();
return true;
} catch (Exception e) {
e.printStackTrace();
error = e;
return false;
}
}
@Override
protected void onPostExecute(Boolean valid) {
if (error != null) {
Toast.makeText(ctx, "Error: " + error.getMessage(),
Toast.LENGTH_LONG).show();
return;
}
Toast.makeText(ctx, "Success: ", Toast.LENGTH_SHORT).show();
}
}.execute();
}
protected void choseCertificate() {
KeyChain.choosePrivateKeyAlias(this, this,
new String[] { "RSA", "DSA" }, null, "m.ergon.ch", 443, null);
}
@Override
public void alias(String alias) {
this.alias = alias;
}
}
Die Ausnahme bei urlConnection.getInputStream();
geworfen Hier wird die Erfassung des Handshake zwischen dem Server und dem c lient.
Vielen Dank für Anregungen und Tipps.
Danke für diesen Tipp. Aber wie kann ich einen solchen KeyManager mit meinem privaten Schlüssel erstellen? Dieser Teil fehlt im Beispiel unter [Android Doc für HttpsURLConnection] (http://developer.android.com/reference/javax/net/ssl/HttpsURLConnection.html) – surffan
Es scheint keinen direkten Weg zu geben Dies. Sie müßten 'X509KeyManager' implementieren, um Ihren' PrivateKey' und einen fest codierten Alias zurückzugeben. Sie sollten die serverbezogenen Methoden nicht implementieren müssen. http://developer.android.com/reference/javax/net/ssl/X509KeyManager.html –
Siehe aktualisierte Antwort für Beispielcode. –