2014-09-09 4 views
1

Я реализовал сервер (Netty 3.6.6, Java 6), который принимает соединения SSL/TLS и требуется для аутентификации цепочки сертификатов клиента. У меня есть общий центр сертификации в моем доверенном магазине. Запрещая описанный здесь случай, SSL-реализация сервера в основном работает. Учитывая действительный подписанный сертификат (который работает для подключения к другим серверам), я могу успешно подключиться к серверу с:Java SSL-сервер, не принимающий промежуточную цепочку сертификатов

openssl s_client -connect 127.0.0.1 -key test.key -cert test.pem -CAfile capath.pem 

Если, однако, сертификат и промежуточные объединяются вместе, и я связываю с:

openssl s_client -connect 127.0.0.1 -key test.key -cert all.pem 

затем я получаю unable to find valid certification path to requested target брошен; Я ожидаю, что этот подход будет работать.

Мой код (сокращенно):

public class MySslConnectionHandler extends FrameDecoder { 
    // this class is added into the netty ChannelPipeline (not shown) 

    private SSLContext sslContext; 

    public MySslConnectionHandler() { 
     KeyStore clientKeyStore = KeyStore.getInstance('JKS'); 
     clientKeyStore.load(new FileInputStream(trustStoreFilename), trustStorePassword); 

     PKIXSSLContextFactory contextFactory = new PKIXSSLContextFactory(serverKeyStore, keyStorePassword, clientKeyStore, true); 

     this.sslContext = contextFactory.buildSSLContext(); 
    } 

    @Override 
    protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { 
     SSLEngine engine = sslContext.createSSLEngine(); 
     engine.setUseClientMode(false); 
     engine.setNeedClientAuth(true); 
     engine.setEnabledProtocols(new String[] {"TLSv1","SSLv3"}); 

     SslHandler sslHandler = new SslHandler(engine); 
     sslHandler.setEnableRenegotiation(false); 

     ChannelFuture handshakeFuture = sslHandler.handshake(); 
     handshakeFuture.addListener(new MySslHandshakeListener(engine)); 

     return buffer.readBytes(buffer.readableBytes()); 
    } 
} 

Что я делаю неправильно? Наши клиенты сообщают, что это поведение отличается от других используемых ими серверов, поэтому я не хочу, чтобы это вызывало у них проблемы; это разумно? (Обширный прибегая к помощи не помогло ...)

Спасибо :-)

ответ

1

Ваши ожидания не так. openssl s_client -cert file использует только первый сертификат, который должен быть сертификатом клиента. Ввод дополнительных сертификатов, цепочек или других файлов в этот файл игнорируется. В результате s_client (через клиент libssl) отправляет незавершенную цепочку. Обычно сервер не может проверить это.

Хотя -CAfile и/или -CAdir описан как обеспечение корней для s_client для проверки равноправного (сервер) серто, libssl также использует доверенный сертификаты, чтобы заполнить цепочку он посылает при необходимости и возможность; очевидно, у вас есть ваш сертификат (ы) цепи в cacert.pem, и это произошло.

Я предполагаю, что ваши клиенты не используют s_client, так как он имеет очень ограниченную способность отправлять и получать подходящие данные. Если вы или кто-то написал или написал реальное приложение с помощью libssl, вы можете установить целую цепочку, вызвав SSL_CTX_use_certificate_chain_file вместо SSL_CTX_use_certificate_file, или вы можете построить цепочку из отдельных сертификатов с помощью SSL_CTX_add_extra_chain_cert. (Если у вас есть только один промежуточный, они практически эквивалентны.) Не говоря уже о том, что вы можете делать на других языках, таких как Java, perl и dotNET. s_client разработан как инструмент для тестирования и отладки и не делает этого; это только use_certificate, который использует только первый сертификат.

Предостережение: все это для OpenSSL через 1.0.1. 1.0.2 теперь в бета-версии объявлены изменения в проверке сертификата и цепи, которые я еще не изучил. Хотя на основе прошлой практики я уверенно ожидаю, что по умолчанию будет по-прежнему соответствовать прежним.

Если вам действительно нужен сервер Java для приема клиента, отправляющего неполную цепочку (для которой не требуется), вы можете перенести первый промежуточный элемент, который не был отправлен (который является первым промежуточным периодом) в доверенном сервере , Но я верю (не могу легко проверить), в этом случае Java полностью игнорирует остальную часть цепочки, поэтому вам придется контролировать вручную или другими способами, например. отмена.

+0

Благодарим за это.Команды openssl - это то, что коллега использовал для тестирования сервера, и дать пользователю достаточно информации, чтобы они могли исправить свою (неизвестную) реализацию. Теперь я понимаю, что эти проблемы - это разные проблемы. Без реализации пользователя я не могу быть уверен, что могу воспроизвести их точную проблему; учитывая, что они прекрасно соединяются с другими серверами, либо у нас есть ошибка, либо другие серверы как-то менее строгие. Tricky! Спасибо за вашу помощь. – Liche

+0

Почему вы верите, что Java будет игнорировать остальную цепь? Он должен установить путь от фактического сертификата клиента через цепочку до сертификата в доверительном магазине. Как это игнорируется? – EJP

+0

@EJP, если фактическая цепочка SheepMolly/Shepherd1/WoollyRoot и вы ставите Shepherd1 в truststore (потому что несовместимый одноранговый узел отправляет SheepMolly), тогда появляется Java, который построит цепочку SheepMolly - Shepherd1 и остановится там, потому что Shepherd1 доверен, в соответствии с «HandshakeCompletedEvent.getPeerCertificates». Но на самом деле Shepherd1, возможно, был отозван, и релейер, который смотрел на всю цепочку, мог бы обнаружить это. –

Смежные вопросы