HTTPS-соединение с клиентским сертификатом в приложении для Android

Я пытаюсь заменить текущее соединение HTTP соединением HTTPS в приложении для Android, которое я пишу. Необходима дополнительная безопасность HTTPS-соединения, и поэтому я не могу игнорировать этот шаг.

У меня есть следующее:

Сервер, настроенный для установления соединения HTTPS и требующий сертификат клиентаЭтот сервер имеет сертификат, выданный стандартным крупномасштабным центром сертификации. Короче говоря, если я получаю доступ к этому соединению через браузер в Android, оно работает нормально, потому что хранилище доверенных сертификатов устройств распознает CA. (Так что это не самоподписанный)Сертификат клиента, который по сути является самоподписанным. (Выдается внутренним центром сертификации)Приложение для Android, которое загружает этот клиентский сертификат и пытается подключиться к вышеупомянутому серверу, но имеет следующие проблемы / свойства:Клиент может подключиться к серверу, когда сервер настроен нане требуется сертификат клиента. В основном, если я используюSSLSocketFactory.getSocketFactory() соединение работает нормально, но сертификат клиента является обязательной частью спецификации этого приложения, поэтому:Клиент производитjavax.net.ssl.SSLPeerUnverifiedException: No peer certificate исключение, когда я пытаюсь соединиться с моим обычаемSSLSocketFactory, но я не совсем уверен, почему. Это исключение кажется немного двусмысленным после поиска в Интернете различных решений для этого.

Вот соответствующий код для клиента:

SSLSocketFactory socketFactory = null;

public void onCreate(Bundle savedInstanceState) {
    loadCertificateData();
}

private void loadCertificateData() {
    try {
        File[] pfxFiles = Environment.getExternalStorageDirectory().listFiles(new FileFilter() {
            public boolean accept(File file) {
                if (file.getName().toLowerCase().endsWith("pfx")) {
                    return true;
                }
                return false;
            }
        });

        InputStream certificateStream = null;
        if (pfxFiles.length==1) {
            certificateStream = new FileInputStream(pfxFiles[0]);
        }

        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        char[] password = "somePassword".toCharArray();
        keyStore.load(certificateStream, password);

        System.out.println("I have loaded [" + keyStore.size() + "] certificates");

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

        socketFactory = new SSLSocketFactory(keyStore);
    } catch (Exceptions e) {
        // Actually a bunch of catch blocks here, but shortened!
    }
}

private void someMethodInvokedToEstablishAHttpsConnection() {
    try {
        HttpParams standardParams = new BasicHttpParams();
        HttpConnectionParams.setConnectionTimeout(standardParams, 5000);
        HttpConnectionParams.setSoTimeout(standardParams, 30000);

        SchemeRegistry schRegistry = new SchemeRegistry();
        schRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        schRegistry.register(new Scheme("https", socketFactory, 443));
        ClientConnectionManager connectionManager = new ThreadSafeClientConnManager(standardParams, schRegistry);

        HttpClient client = new DefaultHttpClient(connectionManager, standardParams);
        HttpPost request = new HttpPost();
        request.setURI(new URI("https://TheUrlOfTheServerIWantToConnectTo));
        request.setEntity("Some set of data used by the server serialized into string format");
        HttpResponse response = client.execute(request);
        resultData = EntityUtils.toString(response.getEntity());
    } catch (Exception e) {
        // Catch some exceptions (Actually multiple catch blocks, shortened)
    }
}

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

У меня есть две теории относительно того, что я упускаю при чтении о соединениях HTTPS / SSL, но так как это действительно мой первый набег, я немного озадачен тем, что мне действительно нужно для решения этой проблемы.

Первая возможность, насколько я могу судить, заключается в том, что мне нужно настроить SSLSocketFactory с хранилищем доверенных сертификатов устройств, которое включает все стандартные промежуточные и конечные центры сертификации. То есть устройство по умолчаниюSSLSocketFactory.getSocketFactory() загружает некоторый набор CA в хранилище доверенных сертификатов фабрики, которое используется, чтобы доверять серверу, когда он отправляет свой сертификат, и это то, что терпит неудачу в моем коде, потому что у меня не правильно загружено хранилище доверия. Если это правда, как мне лучше всего загрузить эти данные?

Вторая возможность связана с тем, что сертификат клиента самоподписан (или выдан внутренним центром сертификации - исправьте меня, если я ошибаюсь, но это действительно одно и то же, для всех целей и задач здесь) , Это на самом делеэто хранилище доверенных сертификатов, которое мне не хватает, и в основном мне нужно предоставить серверу способ проверить сертификат с помощью внутреннего ЦС, а также проверить, действительно ли этот внутренний ЦС«Надёжный», Если это правда, что именно я ищу? Я видел некоторые ссылки на это, что заставляет меня верить, что это может быть моей проблемой, как вВот, но я действительно не уверен. Если это действительно моя проблема, что бы я попросил у человека, который поддерживает внутренний центр сертификации, и затем, как бы я добавил это к своему коду, чтобы мое HTTPS-соединение работало?

Третье, и, надеюсь, менее возможное решение, заключается в том, что я совершенно ошибаюсь по поводу некоторого момента здесь и пропустил важный шаг или полностью пренебрегаю частью HTTPS / SSL, о которой я просто пока не знаю. Если это так, не могли бы вы дать мне какое-то направление, чтобы я мог пойти и узнать, что мне нужно учить?

Спасибо за чтение!

Ответы на вопрос(5)

Ваш ответ на вопрос