Как использовать самоподписанный SSL-сертификат в Android

Эта штука беспокоит меня уже пару дней. Я прочитал много других вопросов по всей этой проблеме и до сих пор не смог продолжить.

Я создал простое тестовое приложение только для проверки SSL на Android. Приложение имеет только одну кнопку, и при нажатии приложение пытается отправить «Hello World» через зашифрованное соединение SSL на мой тестовый сервер, который затем отвечает точно такой же фразой.

Сначала я создал тестовый ключ и тестовый сертификат для своего сервера, используя openssl. Затем я следовал инструкциям, показанным в блог Сумасшедшего Боба< /а>. Я получил провайдера Bouncy Castle прямо с сайта Bouncy Castle, создал доверенное хранилище ключей, как показано в блоге Crazy Bob, и, как я полагаю, все сделал правильно.

Когда я попытался запустить свой код, я получил исключение «IOException: Wrong version of key store». Затем я нашел этот вопрос в StackOverflow. Там было предложено попробовать использовать более старые провайдеры Bouncy Castle, а не новейшие bcprov-jdk15on-147.jar. Помня об этом, я продолжил и фактически перепробовал всех bcprovider от jdk13-146 до jdk16-146. Тем не менее каждый раз я получал одно и то же «IOExcpetion: неправильная версия хранилища ключей». исключение.

Затем я нашел еще один вопрос о похожей проблеме на StackOverflow. Там кому-то удалось избавиться от этого исключения, используя ключ размером 512 бит вместо ключа размером 1024. Ну, я попробовал и ничего не добился, но то же исключение.

Вот и я сейчас, думаю, что делать дальше. У меня в значительной степени заканчиваются идеи и результаты поиска Google.

Мой веб-код представляет собой 1 на 1 копию кода сумасшедшего боба, и, кроме того, приложение имеет только класс активности, который обрабатывает только кнопку. Я пытаюсь реализовать это на уровне API 7.

Любая помощь будет принята с благодарностью. Спасибо.


person zaplec    schedule 01.06.2012    source источник
comment
Если вы переместите свой целевой API на что-то вроде 10 или 14, он начнет работать? При работе со старыми уровнями API неплохо протестировать новые, чтобы убедиться, что это не проблема совместимости.   -  person matt5784    schedule 01.06.2012
comment
Мне нужно создать .pemfile для моего проекта Android для дерева мозга. Я установил openssl и запустил следующую команду: openssl› s_client -connect $xxx.xxx.xx:443 2›&1 | \ sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' › mycert.pem, но я получаю сообщение об ошибке в s_client. пожалуйста, помогите мне. Я получаю команду из блога Crazy Bob.   -  person M.A.Murali    schedule 22.11.2013


Ответы (3)


2 варианта:

  1. Вы можете делать то, что делаете, и создавать свое собственное хранилище ключей, и я сделал это, вот инструкции из моего кода, который я сохранил (потому что это заняло так много времени, чтобы заставить его работать):

    Чтобы сгенерировать ПКС:

    1. Created cert in IIS7 and then exported as pfx. Follow instruction on SelfSSL: http://www.robbagby.com/iis/self-signed-certificates-on-iis-7-the-easy-way-and-the-most-effective-way/ 1a. Download tool: http://cid-3c8d41bb553e84f5.skydrive.live.com/browse.aspx/SelfSSL 1b. Run: SelfSSL /N:CN=mydomainname /V:1000 /S:1 /P:8081 I use port 8181 on my server 1c. Export from IIS manager to cert.pfx
    2. Запустите командную строку в SSL, чтобы преобразовать файл в X.509: openssl pkcs12 -in C:\cert.pfx -out C:\cert.cer -nodes
    3. Отредактируйте файл и удалите все, кроме -----BEGIN.... END CERTIFICATE----- ВАЖНО! Это работало, когда я получил правильное (5) количество тире и поместил теги и данные в отдельные строки.
    4. используйте кейтул. C:\Java\JDK\bcprov.jar загружался отдельно C:\Users>keytool -import -v -trustcacerts -alias key_alias -file C:\cert.cer -keystore C:\mystore.bks -storetype BKS -provider org .bouncycastle.jce.provider.BouncyCastleProvider -providerpath C:\Java\JDK\bcprov.jar -storepass 123456
  2. Создайте TRUST ALL KeyStore и забудьте обо всем этом. В принципе, вы можете использовать любой SSL без ошибок. Просто отключите его в продакшне, если вам действительно не все равно. Вот код, который я использую для подготовки клиента SSL (при условии, что вы используете клиент Apache Http)

    private HttpClient getHttpClient()
    {
        HttpParams params = new BasicHttpParams();
    
        //Set main protocol parameters
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
        HttpProtocolParams.setUseExpectContinue(params, true);
    
        // Turn off stale checking.  Our connections break all the time anyway, and it's not worth it to pay the penalty of checking every time.
        HttpConnectionParams.setStaleCheckingEnabled(params, false);
        // FIX v2.2.1+ - Set timeout to 30 seconds, seems like 5 seconds was not enough for good communication
        HttpConnectionParams.setConnectionTimeout(params, 30 * 1000);
        HttpConnectionParams.setSoTimeout(params, 30 * 1000);
        HttpConnectionParams.setSocketBufferSize(params, 8192);
    
        // Don't handle redirects -- return them to the caller.  Our code often wants to re-POST after a redirect, which we must do ourselves.
        HttpClientParams.setRedirecting(params, false);
    
        // Register our own "trust-all" SSL scheme
        SchemeRegistry schReg = new SchemeRegistry();
        try
        {
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            trustStore.load(null, null);
    
            TrustAllSSLSocketFactory sslSocketFactory = new TrustAllSSLSocketFactory(trustStore);
            sslSocketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    
            Scheme sslTrustAllScheme = new Scheme("https", sslSocketFactory, 443);
            schReg.register(sslTrustAllScheme);
        }
        catch (Exception ex)
        {
            LogData.e(LOG_TAG, ex, LogData.Priority.None);
        }
    
        ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params,schReg);
        return new DefaultHttpClient(conMgr, params);
    }
    
person katit    schedule 12.06.2012
comment
Если я использую параметр ДОВЕРЯТЬ ВСЕМ, означает ли это, что только мое приложение доверяет всем сайтам? Другими словами, я просто пытаюсь убедиться, что это никак не повлияет на другие приложения на телефоне. URL-адрес, который использует мое приложение, жестко запрограммирован, поскольку он никогда не меняется, и поэтому может быть безопасно разрешить приложению доверять всем сайтам, поскольку оно никогда не попытается подключиться к какому-либо недоверенному сайту. - person zaplec; 13.06.2012
comment
Да, вы только устанавливаете доверие ко всем сертификатам для этого конкретного соединения. Другие приложения не будут затронуты - person katit; 13.06.2012
comment
Это решение «доверие ко всем» работает, но оставляет возможные приложения уязвимыми для атак «человек посередине». Для целей тестирования это нормально, но я думаю, что мне нужно продолжить борьбу за то, чтобы SSL работал только с одним доверенным сайтом :) - person zaplec; 14.06.2012
comment
Я дал вам инструкции в # 1. Это работало для меня. Я переключилась на доверие позже, потому что мужчины посередине для меня не проблема. - person katit; 14.06.2012
comment
Да, я проверил ваши инструкции в № 1, но я все еще получаю исключение «Неправильная версия хранилища ключей», даже если я следую вашим инструкциям. Я перейду на Java 1.6 или Java 1.5 и попробую еще раз, потому что до сих пор я использовал Java 1.7. Надеюсь, это поможет. - person zaplec; 14.06.2012

Это похоже на мой вопрос когда я пытаюсь запросить EWS. Вы можете перейти по этой ссылке и загрузите пример исходного кода, затем измените его, как мой ответ. Надеюсь это поможет!

Обновление:
У меня сработала следующая команда (пробовал около 2 месяцев назад):

  C:\OpenSSL-Win32\bin>keytool -importcert -v -trustcacerts -file "d:/cer.cer" 
  -alias parkgroup_restful -keystore "D:/parkgroup-ws-client.bks" 
  -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath 
 "D:/bcprov-jdk16-145.jar" -storetype BKS -storepass 1234567

  .... /**It should show the result here**/

   Trust this certificate? [no]:  yes
   Certificate was added to keystore
   [Storing D:/parkgroup-ws-client.bks]

   C:\OpenSSL-Win32\bin>keytool -list -keystore "D:/parkgroup-ws-client.bks" -provi
   der org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "D:/bcprov-
   jdk16-145.jar" -storetype BKS -storepass 1234567

   Keystore type: BKS
   Keystore provider: BC

   Your keystore contains 1 entry

   parkgroup_restful, Apr 10, 2012, trustedCertEntry,
   Certificate fingerprint (MD5): 36:47:88:62:23:1C:F3:52:17:BE:7A:A9:94:56:19:18

Как видите, я использую bcprov-jdk16-145.jar и openssl lib. Вы можете попробовать.
Другой инструмент для создания хранилища ключей: http://portecle.sourceforge.net/

person R4j    schedule 01.06.2012
comment
Спасибо за ссылки, но все еще не смог преодолеть неправильную версию исключения хранилища ключей. - person zaplec; 08.06.2012
comment
Я не уверен, действительно ли я понимаю, что вы делаете с первой строкой, поскольку мне кажется, что вы никогда не используете PEM, который вы там создаете. Можете ли вы объяснить это немного? В противном случае ваше решение очень похоже на то, что я пробовал. Я пробовал bcprov-jdk16-145.jar (плюс другие версии) и openssl. - person zaplec; 11.06.2012
comment
Я рекомендую вам проверить файл сертификата, потому что у меня такая же проблема. Затем я пытаюсь использовать другой файл, это сработало. - person R4j; 12.06.2012

Что ж, я тоже столкнулся с такой же ситуацией, и для ее решения я воспользовался помощью в том же сообщении в блоге (http://nelenkov.blogspot.in/2011/12/using-custom-certificate-trust-store-on.html), указанный R4j . Ниже приведены необходимые шаги:

  1. Создать собственный доверенное хранилище: я использовал Portecle для создания хранилища ключей и импортировал в него сертификат открытого ключа с моего сервера.
  2. Создайте собственное хранилище ключей с помощью пары ключей: keytool -genkeypair -alias sample -keyalg RSA -sigalg SHA1withRSA -dname "CN=Nazgul, OU=Assault, O=Sauron Enterprises, L=Mordor, ST=Middle Earth, C=ME" -keypass welcome123 -validity 365 -storetype pkcs12 -keystore g:\mordor_key_store.pfx -storepass welcome123 -keysize 2048
  3. Затем вы используете их, как указано в блоге nelkov. Вам также может понадобиться создать собственный AbstractVerifier на тот случай, если вы окажетесь в ситуации, когда сертификат выдан для abc.com, а Verifier отклонит www.abc.com.
  4. Наконец, чтобы создать безопасный HTTPClient, вы можете сделать что-то вроде этого:

            public static DefaultHttpClient getSecureHttpClient(){
        SchemeRegistry schemeRegistry = new SchemeRegistry();
        SSLContext sslContext = null;
        try {
            sslContext = createSslContext(true);
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        }
        final X509HostnameVerifier delegate = new BrowserCompatHostnameVerifier();
        MySSLSocketFactory socketFactory = new MySSLSocketFactory(sslContext, delegate);
        schemeRegistry.register(new Scheme("https", socketFactory, 443));
    
        DefaultHttpClient client = new DefaultHttpClient();
        HttpParams params = client.getParams();
        client = new DefaultHttpClient(new ThreadSafeClientConnManager(params,
                schemeRegistry), params){
            protected HttpParams determineParams(HttpRequest req) {
                HttpParams params = req.getParams(); // req is an HttpRequest object
                HttpConnectionParams.setSoTimeout(params, 60000);
                HttpConnectionParams.setConnectionTimeout(params, 60000);
                return params;
            }
        };
    
        return client;
    }
    

Подробные причины моего выбора вы можете найти в этом сообщении http://fuking-android.quora.com/Implement-HTTPS-for-android-apps-a-novices-tale.

person venom.unleashed    schedule 06.02.2013