Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
673 views
in Technique[技术] by (71.8m points)

ssl - Client Certificate not working from Android - How to debug?

I'm trying to implement a Client Certificates communication for an Android App, so far without much success - and it seems that this feature is, if at all possible, very hard. The full flow I'm implementing is described in my previous question.

I followed the code there and code from this blog post, describing the same scenario, more or less, without results.

What doesn't work: Opening an SSL Connection (HttpsURLConnection) between the Android Client and the Server causes the server to return an 403 status code.
AFAIK, this 403 is because the server doesn't get or doesn't trust the Client Certificate that it gets, and I'm not sure how to debug it.

What does work:

  • Creating a PKCS#10 request, sending it to the CA and getting a signed PKCS#7 (P7B)
  • Storing the received P7B with the private key in a KeyStore, and exporting it to a PKCS#12 (P12)
  • (Most annonying) picking the P12 from the device, installing it on windows, contacting the server and getting a coherent (200 HTTP-OK) response.

What I've changed: From the code samples I got (from here and here), I had to change a few things. I'm using HttpsURLConnection and not OkHttpClient as @Than used there (but it shouldn't matter), I can't provide the Certificates as Rich Freedman did (he had the certificate, and I'm obtaining it via PKCS#10 and #7), so I've created a CustomTrustManager that would trust the server's certificate, and for this reason I use SpongyCastle (v1.5.0.0 if it matters, set as a provider inserted at 0) and also don't persist the certificate, but all is done in-memory.

Question is what to do next:

  • How can I tell what the server is expecting (client-certificate wise)?
  • How can I tell which client certificates (if any) is being sent to the server?
  • How to debug this scenario in general? (Proxies such as Fiddler are useless for the underlying SSL)

Thanks!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It's not good answer, but there is too much in here to post it as comment.

For logging, debugging you can create your own X509KeyManager which uses normal key manager obtained from KeyManagerFactory:

@DebugLog annotation comes from Hugo library created by Jake Wharton. It prints function arguments and what it return. You can use normal Log.d or whatever you want.

ex:

class MyKeyManager implements X509KeyManager {

    private final X509KeyManager keyManager;

    MyKeyManager(X509KeyManager keyManager) {
        this.keyManager = keyManager;
    }

    @DebugLog
    @Override
    public String chooseClientAlias(String[] strings, Principal[] principals, Socket socket) {
        return this.keyManager.chooseClientAlias(strings, principals, socket);
    }

    @DebugLog
    @Override
    public String chooseServerAlias(String s, Principal[] principals, Socket socket) {
        return keyManager.chooseServerAlias(s, principals, socket);
    }

    @DebugLog
    @Override
    public X509Certificate[] getCertificateChain(String s) {
        return keyManager.getCertificateChain(s);
    }

    @DebugLog
    @Override
    public String[] getClientAliases(String s, Principal[] principals) {
        return keyManager.getClientAliases(s, principals);
    }

    @DebugLog
    @Override
    public String[] getServerAliases(String s, Principal[] principals) {
        return keyManager.getServerAliases(s, principals);
    }

    @DebugLog
    @Override
    public PrivateKey getPrivateKey(String s) {
        return keyManager.getPrivateKey(s);
    }
}

And use it to init SSLContext

KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, password);

final X509KeyManager origKm = (X509KeyManager) kmf.getKeyManagers()[0];
X509KeyManager km = new MyKeyManager(origKm);

SSLContext sslCtx = SSLContext.getInstance("TLS");
sslCtx.init(new KeyManager[]{km}, tmf.getTrustManagers(), null);

You will see which method are called, what are the arguments (obtained from serwer certificate) and which certificate and private key your keymanager returns.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...