Как разрешаются имена серверов сертификатов SSL / Могу ли я добавить альтернативные имена, используя keytool?
Для ясности они могут быть сформулированы как отдельные вопросы, но все они связаны с одной и той же проблемой.
Как разрешаются имена серверов сертификатов SSL?
Почему браузеры, кажется, используют поле сертификата CN, а механизм Java, похоже, рассматривает только "альтернативные имена субъектов"?
Можно ли добавить альтернативные имена в сертификат SSL с помощью keytool? Если нет, то лучше ли использовать openSSL?
Немного предыстории: мне нужно получить главный сервер для связи с несколькими серверами, используя HTTPS. Очевидно, что мы не хотим покупать SSL-сертификаты для каждого сервера (их может быть много), поэтому я хочу использовать самозаверяющие сертификаты (я использовал keytool для их генерации). После того, как я добавил сертификаты как доверенные в ОС, браузеры (IE и Chrome) с радостью принимают соединение как доверенное. Однако даже после добавления сертификатов в серверы Java Java все равно не примет соединение как доверенное и выдает следующее исключение:
Вызывается: java.security.cert.CertificateException: альтернативные имена субъектов отсутствуют в sun.security.util.HostnameChecker.matchIP(HostnameChecker.java:142) в sun.security.util.HostnameChecker.match(HostnameChecker.java:75) в com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkIdentity(X509T rustManagerImpl.java:264) в com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted( X509Trust.ava2:.mp2 sun.net.ssl.internal.ssl.ClientHandshaker.server Сертификат (клиент tHandshaker.java:1185) ... еще 14
Я обнаружил, что могу заставить Java доверять сертификату, реализующему мой собственный HostNameVerifier, который я скопировал отсюда: com.sun.jbi.internal.security.https.DefaultHostnameVerifier просто для проверки (кстати, имя хоста передается в качестве аргумента в HostnameVerifier правильно, так что я думаю, что это должно быть принято).
Я использовал поле сертификата CN в качестве имени хоста (обычно это IP-адрес).
Кто-нибудь может сказать мне, если я делаю что-то не так, и указать мне правильное направление?
1 ответ
Как следует выполнять проверку имени хоста, определено в RFC 6125, который является довольно недавним и обобщает практику для всех протоколов, и заменяет RFC 2818, который был специфичен для HTTPS. (Я даже не уверен, что Java 7 использует RFC 6125, который может быть слишком новым для этого.)
Если присутствует расширение subjectAltName типа dNSName, оно ДОЛЖНО использоваться в качестве идентификатора. В противном случае (наиболее определенное) поле общего имени в поле "Тема" сертификата ДОЛЖНО использоваться. Хотя использование общего имени является существующей практикой, оно устарело, и вместо этого сертификационным органам рекомендуется использовать dNSName.
[...]
В некоторых случаях URI указывается в виде IP-адреса, а не имени хоста. В этом случае iPAddress subjectAltName должно присутствовать в сертификате и должно точно соответствовать IP в URI.
По сути, конкретная проблема возникает из-за того, что вы используете IP-адреса в вашем CN, а не имя хоста. Некоторые браузеры могут работать, потому что не все инструменты строго следуют этой спецификации, в частности, потому что "наиболее специфичный" в RFC 2818 не определен четко (см. Обсуждения в RFC 6215).
Если вы используете keytool
Начиная с Java 7,keytool
имеет возможность включить альтернативное имя субъекта (см. таблицу в документации для -ext
): вы могли бы использовать -ext san=dns:www.example.com
или же -ext san=ip:10.0.0.1
,
РЕДАКТИРОВАТЬ:
Вы можете запросить SAN в OpenSSL, изменив openssl.cnf
(насколько я помню, он выберет копию в текущем каталоге, если вы не хотите редактировать глобальную конфигурацию, или вы можете выбрать явное местоположение, используя OPENSSL_CONF
переменная окружения).
Установите следующие параметры (сначала найдите соответствующие разделы в скобках):
[req]
req_extensions = v3_req
[ v3_req ]
subjectAltName=IP:10.0.0.1
# or subjectAltName=DNS:www.example.com
Есть также хороший прием, чтобы использовать для этого переменную окружения (а не исправлять ее в файле конфигурации) здесь: http://www.crsr.net/Notes/SSL.html