Получаване на всеки клиентски сертификат в SSL-Handshake

Използвам Netty на Android и от страната на сървъра, за да установя защитена с SSL връзка с удостоверяване на клиента. Сега имам затруднения при свързването с тези сертификати, тъй като SSLEngine ги отхвърля поради "нулева верига от сертификати".

Това е, което направих от страната на сървъра. Настроих SSLContext с подписан сървърен сертификат (клиентът знае CA, така че може да потвърди този).

За да накарам сървъра да приема всякакви сертификати от клиенти (тъй като всички те са самоподписани), внедрих DummyTrustManager, който просто ще приеме всички.

private static class DummyTrustManager implements X509TrustManager
    {
        private X509Certificate[] mCerts;

        public DummyTrustManager(Certificate[] pCerts)
        {
            // convert into x509 array
            mCerts = new X509Certificate[pCerts.length];
            for(int i = 0; i < pCerts.length; i++)
            {
                mCerts[i] = (X509Certificate)pCerts[i];
            }
        }

        @Override
        public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException{}

        @Override
        public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException{}

        @Override
        public X509Certificate[] getAcceptedIssuers()
        {
            return mCerts;
            //return new X509Certificate[0];
        }
    }

Въпросът е, че не съм съвсем сигурен за метода getAcceptedIssuers().

  • Ако върна празен масив, двоичният файл openssl (който използвам за проверка на правилната настройка) се проваля поради празен списък AcceptedIssuers.

  • Ако добавя веригата сертификати на текущия сървър, тя ще работи поне за клиентски сертификати, които са подписани от същия ca, но не и с такива, които са самоподписани (от което се нуждая).

Но може би правя нещо нередно от страна на клиента:

        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(null);

        keyStore.setEntry("user_certificate", new KeyStore.PrivateKeyEntry(mPrivate, new Certificate[]{mClientCert}), this);
        keyStore.setCertificateEntry("server_certificate", mServerCert);

Също така направих някои проучвания и от това, което разбрах досега: Клиентът има валидна верига от сертификати, но не го изпраща, защото сървърът му казва, че приема само издателите, изброени от сървъра.

Ако това е правилно, тогава как мога да преодолея този проблем?

Мислех за отделен самоподписан CA, който се доставя на всички клиенти и който също е посочен в списъка на приетите от сървъра издатели. Всеки клиент използва този CA, за да подпише свой собствен сертификат. Не виждам проблем със сигурността в това. Или има по-добро решение?


person Chris    schedule 14.05.2013    source източник
comment
Нещо не е наред тук. Използването на клиентско удостоверяване и приемането на който и да е клиентски сертификат взаимно си противоречат. Защо изобщо да използвате удостоверяване на клиента, ако не ви интересува кои са клиентите или дали имат валидни сертификати? Забележка: не се нуждаете от OpenSSL: Java е пълна с крипто API.   -  person user207421    schedule 14.05.2013
comment
Използвам клиентския сертификат като токен за влизане. Неизвестните сертификати ще бъдат свързани като нови клиенти и регистрирани. Така че има причина да има и двете. И за съжаление Java няма пълен крипто пакет. Дори трябва да използвам Bouncycastle само за създаване на самоподписани сертификати от страна на клиента. Използвах openssl само заради неговия s_client параметър, който ви позволява да проверите дали вашето SSL ръкостискане работи добре.   -  person Chris    schedule 15.05.2013


Отговори (1)


Тъй като нямаше отговор за по-дълъг период, ще дам кратък преглед на това как ще разреша това засега.

Създадох друг CA, който не е подписан от нито един доверен CA. Всъщност е самоподписано. Този CA се дава на всички клиенти, за да подписват собствените си сертификати. Защо? Тъй като по този начин мога да кажа на сървъра да изпрати този CA като единствения приет getAcceptedIssuers(). Това не е предназначено да даде ниво на авторитет. Начинът, по който проверявам клиентите, е само по техния публичен ключ, така че там няма риск за сигурността.

Трябва само да бъдете много внимателни, за да не смесвате вашите TrustedManagers и SSLContext екземпляри.

person Chris    schedule 22.05.2013
comment
Рискът за сигурността е, че CA ще изтече от един от вашите клиенти към някой, който не е платил, или каквото и да е, от което се опитвате да се защитите. Наистина си постигнал много малко тук. - person user207421; 23.05.2013
comment
Както е споменато по-рано. Не използвам SSL по начина, по който го правят повечето хора. Трябва да установя връзка, при която клиентът използва публичен ключ вместо потребителско име/парола. Бих могъл дори да изключа всеки издател, тъй като проверявам всеки клиент по неговия публичен ключ, а не по издателя. Публичният CA е само начин за измама (който бих искал да пропусна, ако мога, за което беше въпросът ми) Java, защото в противен случай клиентската страна изобщо не изпраща никакъв сертификат. Всеки публичен ключ, който не познавам, се представя като нов и може да се регистрира на моя сървър. - person Chris; 23.05.2013