2011-02-06 6 views
2

У меня есть тривиальная защищенная сокета сервер-клиентская программа.
Для сертификатов сервера я создал хранилище ключей, использующее keytool.
При попытке подключиться к серверу с помощью моего клиента я получаю эти исключения:
В сервере:java secure socket без аутентификации?

Exception in thread "main" javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown 

В клиенте:

Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source) 

Если я правильно понимаю, эти исключения вызваны из-за того, что я использую сертификаты, которые я создал.
Мой вопрос:
Если я установил в разрешенных наборах шифров, как на сервере, так и на клиенте, все комплекты * _anon * cipher, не должны ли это решить проблему?
Я имею в виду, если я включу шифрованные комплекты *_anon_*, тогда никакой аутентификации не потребуется, следовательно, никаких исключений.
Это правильно?
Потому что у меня все еще есть исключения. Я попытался включить в разрешенные шифры все включенные + _anon. Нет успеха. Я попытался установить только те Анон и получил новое исключение:

Exception in thread "main" java.lang.IllegalArgumentException: Name must not be null 

Может кто-то пожалуйста, объясните, почему я получаю эти исключения, с Anon шифров?
Примечание:
Если я устанавливаю на клиенте свойство системы javax.net.ssl.trustStore указывая на хранилище я создал и используется на моем сервере, связь отлично!
Программа работает без каких-либо исключений, и данные отправляются нормально, от клиента к серверу.


UPDATE:
Это фрагмент кода я использую, чтобы включить Анон шифры (я сделал это для сервера и клиентской части):

String[] supported = server.getSupportedCipherSuites(); 
String[] anonCipherSuitesSupported = new String[supported.length]; 
int count = 0; 

for(int i = 0; i < supported.length; i++) 
{ 
    if(supported[i].indexOf("_anon_") > 0) 
    { 
     anonCipherSuitesSupported[count++] = supported[i]; 
    } 
} 

String[] oldEnabled = server.getEnabledCipherSuites(); 
String[] newEnabled = new String[oldEnabled.length + count]; 
System.arraycopy(oldEnabled, 0, newEnabled, 0, oldEnabled.length); 
System.arraycopy(anonCipherSuitesSupported, 0, newEnabled, oldEnabled.length, count); 
server.setEnabledCipherSuites(newEnabled); 

Трассировка стека на стороне клиента :

Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.AppOutputStream.write(Unknown Source) 
    at sun.nio.cs.StreamEncoder.writeBytes(Unknown Source) 
    at sun.nio.cs.StreamEncoder.implFlushBuffer(Unknown Source) 
    at sun.nio.cs.StreamEncoder.implFlush(Unknown Source) 
    at sun.nio.cs.StreamEncoder.flush(Unknown Source) 
    at java.io.OutputStreamWriter.flush(Unknown Source) 
    at com.client.SSLClient1.main(SSLClient1.java:58) 
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 
    at sun.security.validator.PKIXValidator.doBuild(Unknown Source) 
    at sun.security.validator.PKIXValidator.engineValidate(Unknown Source) 
    at sun.security.validator.Validator.validate(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source) 
    ... 14 more 
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source) 
    at java.security.cert.CertPathBuilder.build(Unknown Source) 
    ... 20 more 

и на стороне сервера:

Exception in thread "main" javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown 
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readDataRecord(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.AppInputStream.read(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.AppInputStream.read(Unknown Source) 
    at com.server.SecureOrderTaker.main(SecureOrderTaker.java:92) 

Теперь, если я просто сделать:

server.setEnabledCipherSuites(anonCipherSuitesSupported); 

Так что только Анон шифров включены я получаю:

Exception in thread "main" java.lang.IllegalArgumentException: Name must not be null 
    at com.sun.net.ssl.internal.ssl.CipherSuite.valueOf(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.CipherSuiteList.<init>(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.SSLServerSocketImpl.setEnabledCipherSuites(Unknown Source) 
    at com.server.SecureOrderTaker.main(SecureOrderTaker.java:82) 

Спасибо

ответ

5

Вы правы, *_anon_* шифры используются для полного неаутентифицированного соединения (оба сервера и клиент анонимны). С этими наборами шифров сертификат не требуется.Я написал небольшой код для проверки:

ServerSocketFactory sf = SSLServerSocketFactory.getDefault(); 
final SSLServerSocket socket = (SSLServerSocket)sf.createServerSocket(443); 
System.out.println(Arrays.toString(socket.getSupportedCipherSuites())); 
System.out.println(Arrays.toString(socket.getEnabledCipherSuites())); 

socket.setEnabledCipherSuites(new String[] {"SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA"}); 

Thread t = new Thread() { 
    public void run() { 
     try { 
      Socket client = socket.accept(); 
      client.getOutputStream().write("Hello World\n".getBytes("ASCII")); 
      client.close(); 
     } catch (IOException ioe) { 
     } 
    } 
}; 

t.start(); 
Thread.sleep(2000); 
SSLSocket client = (SSLSocket) SSLSocketFactory.getDefault().createSocket("localhost", 443); 
client.setEnabledCipherSuites(new String[] {"SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA"}); 
InputStream in = client.getInputStream(); 
byte[] data = new byte[1024]; 
int len = in.read(data); 
System.out.println(new String(data, 0, len)); 

Я знаю, что этот код не является совершенным, но я успешно обмениваться данными между клиентом и сервером. Возможно, ваш сервер или клиентский сокет не настроен правильно. Можете ли вы дать полный стек, который у вас есть?

Обратите внимание, что эти шифры являются устаревшими, так как они уязвимы для нападений «человек в середине».

ОБНОВЛЕНИЕ: Я нашел проблему. Длина массива anonCipherSuitesSupported слишком велика. Поэтому после добавления *_anon_* массив заканчивается связкой значений null. И реализация, похоже, не принимает null в списке разрешенных шифров.

String[] supported = server.getSupportedCipherSuites(); 
List<String> list= new ArrayList<String>(); 

for(int i = 0; i < supported.length; i++) 
{ 
    if(supported[i].indexOf("_anon_") > 0) 
    { 
     list.add(supported[i]); 
    } 
} 
String[] anonCipherSuitesSupported = list.toArray(new String[0]); 
+1

Я обновил сообщение – Cratylus

+0

И обновляю ответ. – Jcs

+0

Вы правы! Если я включил только анонимные шифры, как в клиенте, так и на сервере, изменив код, как вы говорите, он работает. Но для той части, где я размещаю как включенную набор анонных шифров вместе с текущим, нет проблемы с размером массива. Но это не работает. Значит ли это, что шифры non anon принимают предварительную оценку? – Cratylus

0

Вы имеете дело с созданными вами сертификатами, то есть вы являетесь Органом сертификации.

Ваша проблема заключается в том, что для того, чтобы обе стороны пожимали друг другу руки и общались, им нужно доверять друг другу сертификаты. Доверие устанавливается путем построения цепочки из сертификата до ЦС, чтобы убедиться, что конкретная сторона доверяет этому ЦС (некоторые дополнительные шаги, такие как проверка того, не был ли отозван сертификат, также могут быть на месте). Большинство основных ЦС доверяют по умолчанию в Java. В вашем случае ваш собственный CA не является.

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

Посмотрите here на общую информацию о SSL/TLS.

Если вы имеете дело с взаимным доверием, то ваш сервер должен доверять CA, который также выдал ваш сертификат клиента.

+0

Я включаю анонные шифры. Так что не будет никакой аутентификации/проверки сертификата. По крайней мере, это то, что я ожидаю. – Cratylus