Как исправить ошибку «java.security.cert.CertificateException: нет альтернативных имен объектов»?

У меня есть клиент веб-службы Java, который использует веб-службу через HTTPS.

import javax.xml.ws.Service; @WebServiceClient(name = "ISomeService", targetNamespace = "http://tempuri.org/", wsdlLocation = "...") public class ISomeService extends Service { public ISomeService() { super(__getWsdlLocation(), ISOMESERVICE_QNAME); } 

Когда я подключаюсь к URL-адресу службы ( https://AAA.BBB.CCC.DDD:9443/ISomeService ), я получаю исключение java.security.cert.CertificateException: No subject alternative names present .

Чтобы исправить это, я сначала запустил openssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txt и получил следующее содержимое в файле certs.txt :

 CONNECTED(00000003) --- Certificate chain 0 s:/CN=someSubdomain.someorganisation.com i:/CN=someSubdomain.someorganisation.com -----BEGIN CERTIFICATE----- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -----END CERTIFICATE----- --- Server certificate subject=/CN=someSubdomain.someorganisation.com issuer=/CN=someSubdomain.someorganisation.com --- No client certificate CA names sent --- SSL handshake has read 489 bytes and written 236 bytes --- New, TLSv1/SSLv3, Cipher is RC4-MD5 Server public key is 512 bit Compression: NONE Expansion: NONE SSL-Session: Protocol : TLSv1 Cipher : RC4-MD5 Session-ID: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Session-ID-ctx: Master-Key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Key-Arg : None Start Time: 1382521838 Timeout : 300 (sec) Verify return code: 21 (unable to verify the first certificate) --- при CONNECTED(00000003) --- Certificate chain 0 s:/CN=someSubdomain.someorganisation.com i:/CN=someSubdomain.someorganisation.com -----BEGIN CERTIFICATE----- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -----END CERTIFICATE----- --- Server certificate subject=/CN=someSubdomain.someorganisation.com issuer=/CN=someSubdomain.someorganisation.com --- No client certificate CA names sent --- SSL handshake has read 489 bytes and written 236 bytes --- New, TLSv1/SSLv3, Cipher is RC4-MD5 Server public key is 512 bit Compression: NONE Expansion: NONE SSL-Session: Protocol : TLSv1 Cipher : RC4-MD5 Session-ID: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Session-ID-ctx: Master-Key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Key-Arg : None Start Time: 1382521838 Timeout : 300 (sec) Verify return code: 21 (unable to verify the first certificate) --- 

AFAIK, теперь мне нужно

  1. извлеките часть certs.txt между -----BEGIN CERTIFICATE----- и -----END CERTIFICATE----- ,
  2. измените его так, чтобы имя сертификата было равно AAA.BBB.CCC.DDD и
  3. затем импортируйте результат с помощью keytool -importcert -file fileWithModifiedCertificate (где fileWithModifiedCertificate является результатом операций 1 и 2).

Это верно?

Если да, то как именно я могу сделать сертификат с шага 1 работать с аддоном на основе IP ( AAA.BBB.CCC.DDD )?

Обновление 1 (23.10.2013 15:37 MSK): В ответе на аналогичный вопрос я прочел следующее:

Если вы не контролируете этот сервер, используйте его имя хоста (при условии, что по крайней мере CN соответствует этому имени хоста в существующем сертификате).

Что именно означает «использование»?

Я исправил проблему, отключив проверку HTTPS, используя представленный здесь подход:

Я поместил следующий код в class ISomeService :

 static { disableSslVerification(); } private static void disableSslVerification() { try { // Create a trust manager that does not validate certificate chains TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(X509Certificate[] certs, String authType) { } public void checkServerTrusted(X509Certificate[] certs, String authType) { } } }; // Install the all-trusting trust manager SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); // Create all-trusting host name verifier HostnameVerifier allHostsValid = new HostnameVerifier() { public boolean verify(String hostname, SSLSession session) { return true; } }; // Install the all-trusting host verifier HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (KeyManagementException e) { e.printStackTrace(); } } 

Поскольку я использую https://AAA.BBB.CCC.DDD:9443/ISomeService для тестирования, это достаточно хорошее решение.

У меня та же проблема и решена с помощью этого кода. Я помещаю этот код перед первым звонком на мои веб-службы.

 javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier( new javax.net.ssl.HostnameVerifier(){ public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) { return hostname.equals("localhost"); } }); 

Это просто и прекрасно работает.

Вот исходный источник.

Проверка идентификатора сертификата выполняется в соответствии с запросом клиента.

Когда ваш клиент использует https://xxx.xxx.xxx.xxx/something (где xxx.xxx.xxx.xxx – IP-адрес), идентификатор сертификата проверяется на этот IP-адрес (теоретически, только с использованием IP SAN расширение).

Если у вашего сертификата нет IP SAN, но DNS SAN (или нет DNS SAN, общего имени в DN темы), вы можете заставить это работать, заставив вместо этого использовать URL-адрес с этим именем хоста (или имя хоста для которого сертификат будет действительным, если имеется несколько возможных значений). Например, если у вашего сертификата есть имя для www.example.com , используйте https://www.example.com/something .

Конечно, для этого IP-адреса вам понадобится имя хоста.

Кроме того, если есть DNS SAN, CN в DN субъекта будет проигнорирован, поэтому используйте имя, которое соответствует одному из DNS SAN в этом случае.

Чтобы импортировать сертификат:

  1. Извлеките сертификат с сервера, например openssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txt Это приведет к извлечению сертификатов в формате PEM.
  2. Преобразуйте сертификат в формат DER, поскольку это то, что ожидает openssl x509 -in certs.txt -out certs.der -outform DER , например openssl x509 -in certs.txt -out certs.der -outform DER
  3. Теперь вы хотите импортировать этот сертификат в файл «cacert» по умолчанию. Найдите файл «cacerts» по умолчанию для вашей установки Java. Посмотрите, как получить местоположение cacerts стандартной java-установки?
  4. Импортируйте сертификаты в файл cacerts: sudo keytool -importcert -file certs.der -keystore По умолчанию пароль cacerts – ‘changeit’.

Если сертификат выдан для полного доменного имени и вы пытаетесь подключиться по IP-адресу в вашем Java-коде, то это, вероятно, должно быть исправлено в вашем коде, а не возиться с самим сертификатом. Измените свой код для подключения по FQDN. Если FQDN не разрешимо на вашем компьютере-разработчике, просто добавьте его в файл hosts или настройте машину с DNS-сервером, который может разрешить это полное доменное имя.

моя проблема с получением этой ошибки была решена с использованием полного URL-адреса «qatest.ourCompany.com/webService» вместо «qatest / webService». Причина заключалась в том, что наш сертификат безопасности имел подстановочный знак, то есть «* .ourCompany.com». Как только я включил полный адрес, исключение исчезло. Надеюсь это поможет.

Вы не можете отключить все ssl Verificatication, и поэтому вы можете просто отключить проверку имени хоста через это, что немного менее страшно, чем альтернатива:

 HttpsURLConnection.setDefaultHostnameVerifier( SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); 

[РЕДАКТИРОВАТЬ]

Как уже упоминалось, conapart3 SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER теперь устарел, поэтому его можно удалить в более поздней версии, поэтому в будущем вы можете заставить его сворачивать самостоятельно, хотя я бы все же сказал, что буду избегать любых решений, выключен.

Я решил проблему следующим образом.

1. Создание classа. Класс имеет несколько пустых реализаций

 class MyTrustManager implements X509TrustManager { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(X509Certificate[] certs, String authType) { } public void checkServerTrusted(X509Certificate[] certs, String authType) { } @Override public void checkClientTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate, String paramString) throws CertificateException { // TODO Auto-generated method stub } @Override public void checkServerTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate, String paramString) throws CertificateException { // TODO Auto-generated method stub } 

2. Создание метода

 private static void disableSSL() { try { TrustManager[] trustAllCerts = new TrustManager[] { new MyTrustManager() }; // Install the all-trusting trust manager SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HostnameVerifier allHostsValid = new HostnameVerifier() { public boolean verify(String hostname, SSLSession session) { return true; } }; HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); } catch (Exception e) { e.printStackTrace(); } } 

  1. Вызвать метод disableSSL (), в котором генерируется исключение. Он работал нормально.

Добавьте свой IP-адрес в файл hosts. Который находится в папке C: \ Windows \ System32 \ drivers \ etc. Также добавьте IP и доменное имя IP-адреса. пример: aaa.bbb.ccc.ddd [email protected]

  • Игнорировать недопустимый самоподписанный сертификат ssl в node.js с https.request?
  • Как восстановить отсутствующий сертификат IIS Express SSL?
  • Сертификат клиента SSL в Maven
  • Как сказать Maven игнорировать ошибки SSL (и доверять всем сертификатам)?
  • Преобразование Java Keystore в формат PEM
  • Не удалось установить пакеты Python
  • Как добавить самозаверяющий сертификат в качестве исключения в Chrome?
  • Как установить разрешение на чтение файла закрытого ключа сертификата X.509 из .NET.
  • Как сообщить `ссылкам` игнорировать истекший SSL-сертификат и продолжить?
  • Подписанный SSL-сертификат третьей стороны для localhost или 127.0.0.1?
  • Как настроить SSL-сертификат для сервера express.js?
  • Давайте будем гением компьютера.