Клиентский сертификат не работает с Android - Как отлаживать?

Я пытаюсь реализовать обмен клиентскими сертификатами для приложения Android, но пока без особого успеха - и кажется, что эта функция, если вообще возможно, очень сложна. Полный поток, который я реализую, описан в моем предыдущем вопросе.

Я следовал там коду и коду из этого поста в блоге, описывая тот же сценарий, более или менее, безрезультатно.

Что не работает: открытие SSL-соединения (HttpsURLConnection) между клиентом Android и сервером заставляет сервер возвращать код состояния 403.
AFAIK, это 403, потому что сервер не получает или не доверяет клиентскому сертификату, который он получает, и я не уверен, как его отладить.

Что работает:

  • Создание запроса PKCS#10, отправка его в CA и получение подписанного PKCS # 7 (P7B)
  • Сохранение полученного P7B с закрытым ключом в хранилище ключей и его экспорт в PKCS # 12 (P12)
  • (Самое неприятное): выбрать P12 с устройства, установить его в Windows, связаться с сервером и получить согласованный (200 HTTP-OK) ответ.

Что я изменил: из примеров кода, которые я получил ( отсюда и здесь), мне пришлось изменить несколько вещей. Я использую HttpsURLConnection, а не OkHttpClient, так как там использовался @Than (но это не должно иметь значения), я не могу предоставить сертификаты, как это сделал Rich Freedman (у него был сертификат, и я получаю его через PKCS#10 и #7), поэтому я создал CustomTrustManager, который будет доверять сертификату сервера, и по этой причине я использую SpongyCastle (v1.5.0.0, если это важно, установите в качестве поставщика, вставленного в 0), а также не сохраняю сертификат, но все сделано в памяти.

Вопрос в том, что делать дальше:

  • Как я могу сказать, что ожидает сервер (клиент-сертификат мудрый)?
  • Как я могу узнать, какие клиентские сертификаты (если таковые имеются) отправляются на сервер?
  • Как отладить этот сценарий в целом? (Прокси, такие как Fiddler, бесполезны для базового SSL)

Спасибо!

1 ответ

Решение

Это не очень хороший ответ, но здесь слишком много информации, чтобы опубликовать его в качестве комментария.

Для ведения журнала, отладки вы можете создать свой собственный X509KeyManager который использует обычный менеджер ключей, полученный из KeyManagerFactory:

@DebugLog аннотация взята из библиотеки Хьюго, созданной Джейком Уортоном. Он печатает аргументы функции и что она возвращает. Вы можете использовать обычный Log.d или что угодно.

например:

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

И использовать его для инициации 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);

Вы увидите, какой метод вызывается, какие аргументы (полученные из сертификата serwer), а также какой сертификат и закрытый ключ возвращает ваш менеджер ключей.

Другие вопросы по тегам