2013-04-04 5 views
3

У меня возникла эта большая проблема, и я не могу найти ответ на google, поэтому я пытаюсь написать здесь.Apache HttpClient 4.2.3 - SSLException: имя хоста в сертификате не соответствует

Я разрабатываю клиент веб-сервиса. Чтобы подключиться к веб-службе, мне нужно создать ssl-канал с аутентификацией клиента и использовать прокси-сервер (вызов должен выполняться из белого списка). Для этого я использую библиотеку HttpClient 4.2.3 с Java 1.5 (режим совместимости с 1.4) в среде WebSphere 6.1.

Будучи связанным с работой, я удалить все ссылки на фактические вебах-службу, я звоню, чтобы вы найдете некоторые странные имена переменного/хоста/класса здесь и там :)

Я настроил соединение, как этот

// Costruzione del proxy 
    Resources res = new Resources(); 
    String proxyHost = res.get(PROXY_HOST); 
    int proxyPort = Integer.parseInt(res.get(PROXY_PORT)); 

    HttpHost proxy = new HttpHost(proxyHost, proxyPort); 


    // Costruzione del post method 
    String serviceUrl = "https://" + someHost + meth.getServiceURL(); 
    HttpPost post = new HttpPost(serviceUrl); 
    post.addHeader("Content-Type", "text/xml"); 

    String soapAction = "https://" + someHost + meth.getAction(); 
    post.addHeader("SOAPAction", soapAction); 

    AbstractHttpEntity postBody = new StringEntity(soapEnvelope); 
    post.setEntity(postBody); 


    // Costruzione dell'ambiente di chiamata HTTPS 
    SSLSocketFactory sslSocketFactory = new SSLSocketFactory(keyStore, res.get(KEY_STORE_PASS_CONF), trustStore); 
    Scheme httpsScheme = new Scheme("https", HTTPS_PORT, sslSocketFactory); 

    Scheme httpScheme = new Scheme("http", HTTP_PORT, PlainSocketFactory.getSocketFactory()); 

    final SchemeRegistry schemeRegistry = new SchemeRegistry(); 
    schemeRegistry.register(httpScheme); 
    schemeRegistry.register(httpsScheme); 

    PoolingClientConnectionManager connManager = new PoolingClientConnectionManager(schemeRegistry); 

    HttpParams params = new BasicHttpParams(); 

    HttpClient client = new DefaultHttpClient(connManager, params); 
    client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy); 


    // CHIAMATA A MEF 
    HttpResponse resp = client.execute(post); 

хранилище ключи и доверенные сертификаты было загружено из файла

File ksFile = new File(res.get(KEY_STORE_PATH_CONF)); 
File tsFile = new File(res.get(TRUST_STORE_PATH_CONF)); 
InputStream ksInput, tsInput; 

try { 
    ksInput = new FileInputStream(ksFile); 
    tsInput = new FileInputStream(tsFile); 
} catch ... {} 

KeyStore keyStore, trustStore; 
try { 
    String ksPassword = res.get(KEY_STORE_PASS_CONF); 
    String tsPassword = res.get(TRUST_STORE_PASS_CONF); 

    keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); 
    keyStore.load(ksInput, ksPassword.toCharArray()); 

    trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); 
    trustStore.load(tsInput, tsPassword.toCharArray()); 
} catch ... {} 

Когда я пытаюсь вызвать метод client.execute, это дает мне это исключение

javax.net.ssl.SSLException: hostname in certificate didn't match: <right.host.it> != <unknown.host.it> 
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java) 
at org.apache.http.conn.ssl.BrowserCompatHostnameVerifier.verify(BrowserCompatHostnameVerifier.java) 
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java) 
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java) 
at org.apache.http.conn.ssl.SSLSocketFactory.createLayeredSocket(SSLSocketFactory.java:628) 
at org.apache.http.impl.conn.DefaultClientConnectionOperator.updateSecureConnection(DefaultClientConnectionOperator.java:232) 
at org.apache.http.impl.conn.ManagedClientConnectionImpl.layerProtocol(ManagedClientConnectionImpl.java:401) 
at org.apache.http.impl.client.DefaultRequestDirector.establishRoute(DefaultRequestDirector.java:842) 
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:649) 
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:480) 
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906) 
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805) 
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java) 
at my.class.package.MyClass.callWs(MyWebService.java) 

Есть некоторые странные вещи, которые я заметил:

  • неизвестный хост в сообщении исключения из той же области правого, так что принимается обязательно с сертификатом этой компании
  • Я попытался отладить вызов, и похоже, что он принимает другие сертификаты. Адрес unknown.host.it берется из CN сертификата x509 (см. Отладку), и оба сертификата в файле хранилища ключей содержат другие CN. Более того, у меня есть два сертификата в моем хранилище ключей и когда вызывается первый метод AbstractVerifier.verify, в параметрах вызова есть три сертификата, один из которых содержит строку unknown.host.it в CN
  • Фактически, t найти строку unknown.host.it в любом сертификате в моем распоряжении

Проблема, вероятно, в том, что я не знаю, как работает SSL, поэтому, если вы видите совершенно неправильную вещь в том, что я сказал, это, вероятно, ключ для решения моей проблемы.

Вы можете мне помочь? Спасибо большое!

#

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

SSLSocketFactory sslSocketFactory = new SSLSocketFactory(keyStore, res.get(KEY_STORE_PASS_CONF), trustStore); 
    sslSocketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); 

Сейчас она проходит проверку имени хоста (сюрприз-сюрприз :)), но все же дает мне 403-Запретный ошибку. Владелец сервиса говорит, что я звоню из белого списка, поэтому проблема заключается, я полагаю, в том, что сервер меня не узнает. Говорят, я не вручаю сертификат.

Мой способ добавить сертификат в конструктор SSLSocketFactory, где я передаю хранилище ключей с моим сертификатом внутри. Должен ли я указывать на HttpClient, который я хочу самостоятельно идентифицировать на сервере, когда вы подтверждаете связь?

Спасибо :)

+0

Я нашел временное решение, активировав надежный верификатор имени хоста (например, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER). Я знаю, что это не правильное решение, но у меня будет время решить эту проблему. Проблема в том, что HTTP продолжает возвращать мне 403-запрещенную ошибку. Я вызвал службу поддержки, и они говорят, что я звоню из белого списка (так работает прокси), но по какой-то причине взаимная аутентификация не работает. – CodingMonkey

+0

Связанный: http://stackoverflow.com/q/7256955/435605 –

ответ

3

Вполне вероятно, что ваш сервер использует сервер Имя Indication (SNI), чтобы служить два имени хоста на тот же IP-адрес (и порт).

Вы можете проверить это с помощью openssl, указав имя сервера явно. Например, эти две команды будут подключены к одному IP-адресу, но запросить различные имена хостов и служат различные сертификаты:

openssl s_client -connect www.google.co.uk:443 -servername www.google.co.uk 

openssl s_client -connect www.google.co.uk:443 -servername www.google.com 

Java поддерживает только SNI на стороне клиента в данный момент, и только с Java 7.

+0

Я использую Java 5 :) , но он действительно работал один раз ... он просто остановился, чтобы сделать это, и я все еще удивляюсь, почему .. – CodingMonkey

+0

Вы действительно должны обновиться. Возможно, что-то изменилось на сервере? – Bruno

+0

Я согласен, но ... Я не тот, кто решает. Как и все крупные компании, мои * немного * вряд ли смогут модернизировать технологии :) – CodingMonkey

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

  • Нет связанных вопросов^_^