Як вирішуються імена серверів сертифікатів SSL / Чи можу я додати альтернативні імена за допомогою інструменту ключів?


78

Вони можуть бути сформульовані як окремі питання для ясності, але всі вони пов’язані з однією проблемою.

Як вирішуються імена серверів сертифікатів SSL?

Чому браузери, здається, використовують поле CN сертифіката, але механізм Java, здається, розглядає лише "альтернативні імена предметів"?

Чи можна додати альтернативні імена до сертифіката SSL, використовуючи інструмент ключів? Якщо ні, то використання натомість openSSL хороший варіант ??

Тільки невелика довідка: мені потрібно отримати основний сервер для спілкування з кількома серверами за допомогою HTTPS. Очевидно, що ми не хочемо купувати сертифікати SSL для кожного сервера (їх може бути багато), тому я хочу використовувати самопідписані сертифікати (я використовував інструмент ключів для їх створення). Після того, як я додаю сертифікати як надійні в ОС, браузери (IE та Chrome) із задоволенням приймають з'єднання як надійне. Однак навіть після додавання сертифікатів до Java-кацертів Java все одно не приймає з'єднання як надійне і видає такий виняток:

Викликано: java.security.cert.CertificateException: Альтернативні імена теми відсутні в sun.security.util.HostnameChecker.matchIP (HostnameChecker.java:142) at 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 (X509TrustManagerImpl. sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate (Clien tHandshaker.java:1185) ... ще 14

Я виявив, що можу змусити Java довіряти сертифікату, що реалізує мій власний HostNameVerifier, який я скопіював звідси: com.sun.jbi.internal.security.https.DefaultHostnameVerifier просто для тестування (до речі, ім'я хосту передається як аргумент до HostnameVerifier правильний, тому я думаю, що його слід було прийняти).

Я використовую поле сертифіката CN як ім'я хосту (зазвичай це IP-адреса).

Хто-небудь може сказати мені, якщо я роблю щось не так, і вказати мені в правильному напрямку?


1
Виберіть свою альтернативу: grepcode.com/search?query=DefaultHostnameVerifier&n=
Ренато

Відповіді:


101

Як слід проводити перевірку імені хоста, визначено у RFC 6125 , який є зовсім недавнім і взагальнює практику для всіх протоколів, і замінює RFC 2818 , який був характерний для HTTPS. (Я навіть не впевнений, що Java 7 використовує RFC 6125, який для цього може бути занадто недавнім.)

З RFC 2818 (Розділ 3.1) :

Якщо присутнє розширення 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


Це саме те, що мені потрібно було знати ... однак, схоже, Java 6 не має цієї опції -ext. Я спробую змінити свою віртуальну машину на Java 7 і перевірити це.
Ренато

2
Зверніть увагу, що ви можете використовувати інструмент клавіш з Java 7 на іншій машині та скопіювати сховище ключів пізніше (вам не обов’язково запускати Java 7). Крім того, я відредагував свою відповідь за те, що робив це за допомогою OpenSSL. Зважаючи на це, можливо, ви виявите більш гнучким використання імен хостів замість IP-адрес у довгостроковій перспективі (використання SAN - це, як би там не було).
Бруно

Параметр -ext не працює в Java6! Я перейду на Java 7 і подивлюсь, чи можу я це зробити, просто використовуючи інструмент клавіш ... Дуже дякую за відповідь .. (PS. Прийме відповідь, як тільки я її перевірив)
Ренато

5
Той факт, що ви використовуєте IP-адреси у своїх сертифікатах, у цьому випадку буде ще більшою проблемою. Для DNS потрібна потенційно змінна IP-адреса. У вас є більше шансів вирішити вашу проблему, використовуючи динамічну службу DNS і використовуючи сертифікати з цим іменем (або будь-яким CNAME, який вирішить цю динамічну назву).
Бруно

1
Просто для того, щоб внести певну плутанину, багато браузери прийматимуть SAN, такі як DNS: 10.0.0.1, але не IP: 10.0.0.1, але хороша новина полягає в тому, що ви можете мати обидва
KCD
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.