Поддерживает ли Java шифрование сертификатов?
Я разрабатываю приложение Java, которое запрашивает REST API на удаленном сервере через HTTP. По соображениям безопасности это сообщение должно быть переключено на HTTPS.
теперь давайте шифровать начал свою публичную бета-версию, я хотел бы знать, работает ли Java в настоящее время (или подтверждается, что работает в будущем) с их сертификатами по умолчанию.
давайте зашифруем их промежуточный перекрестная подпись IdenTrust, что должно быть хорошо новость. Однако я не могу найти ни одного из этих двух в выводе этой команды:
keytool -keystore "..libsecuritycacerts" -storepass changeit -list
Я знаю, что доверенный CAs может быть добавлен вручную на каждой машине, но поскольку мое приложение должно быть свободно загружаться и исполняться без какой-либо дальнейшей конфигурации, я ищу решения, которые работают "из коробки". У тебя есть хорошие новости для меня?
4 ответов:
[обновление 2016-06-08: согласно https://bugs.openjdk.java.net/browse/JDK-8154757 IdenTrust CA будет включен в Oracle Java 8u101.]
[обновление 2016-08-05: Java 8u101 был выпущен и действительно включает в себя IdenTrust CA:заметки]
поддерживает ли Java шифрование сертификатов?
Да. Давайте шифровать сертификат-это просто обычный сертификат открытого ключа. Java поддерживает его (согласно давайте шифровать совместимость сертификатов, для Java 7 >= 7u111 и Java 8 >= 8u101).
доверяет ли Java давайте шифровать сертификаты из коробки?
нет / это зависит от JVM. Хранилище доверия Oracle JDK / JRE до 8u66 не содержит ни Let's Encrypt CA specifically, ни IdenTrust CA, который перекрестно подписал его.
new URL("https://letsencrypt.org/").openConnection().connect();например результаты вjavax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException.однако вы можете предоставить свой собственный валидатор / определить пользовательское хранилище ключей, содержащее требуемый корневой ЦС, или импортировать сертификат в хранилище JVM truststore.
https://community.letsencrypt.org/t/will-the-cross-root-cover-trust-by-the-default-list-in-the-jdk-jre/134/10 обсуждается и эта тема.
вот пример кода, который показывает, как добавить сертификат в хранилище доверенных сертификатов по умолчанию во время выполнения. Вы просто нужно добавить сертификат (экспортированный из firefox as .der и поставить в classpath)
на основе как я могу получить список доверенных корневых сертификатов в Java? и http://developer.android.com/training/articles/security-ssl.html#UnknownCa
import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.security.KeyStore; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.cert.PKIXParameters; import java.security.cert.TrustAnchor; import java.security.cert.X509Certificate; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.TrustManagerFactory; public class SSLExample { // BEGIN ------- ADDME static { try { KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); Path ksPath = Paths.get(System.getProperty("java.home"), "lib", "security", "cacerts"); keyStore.load(Files.newInputStream(ksPath), "changeit".toCharArray()); CertificateFactory cf = CertificateFactory.getInstance("X.509"); try (InputStream caInput = new BufferedInputStream( // this files is shipped with the application SSLExample.class.getResourceAsStream("DSTRootCAX3.der"))) { Certificate crt = cf.generateCertificate(caInput); System.out.println("Added Cert for " + ((X509Certificate) crt) .getSubjectDN()); keyStore.setCertificateEntry("DSTRootCAX3", crt); } if (false) { // enable to see System.out.println("Truststore now trusting: "); PKIXParameters params = new PKIXParameters(keyStore); params.getTrustAnchors().stream() .map(TrustAnchor::getTrustedCert) .map(X509Certificate::getSubjectDN) .forEach(System.out::println); System.out.println(); } TrustManagerFactory tmf = TrustManagerFactory .getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(keyStore); SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, tmf.getTrustManagers(), null); SSLContext.setDefault(sslContext); } catch (Exception e) { throw new RuntimeException(e); } } // END ---------- ADDME public static void main(String[] args) throws IOException { // signed by default trusted CAs. testUrl(new URL("https://google.com")); testUrl(new URL("https://www.thawte.com")); // signed by letsencrypt testUrl(new URL("https://helloworld.letsencrypt.org")); // signed by LE's cross-sign CA testUrl(new URL("https://letsencrypt.org")); // expired testUrl(new URL("https://tv.eurosport.com/")); // self-signed testUrl(new URL("https://www.pcwebshop.co.uk/")); } static void testUrl(URL url) throws IOException { URLConnection connection = url.openConnection(); try { connection.connect(); System.out.println("Headers of " + url + " => " + connection.getHeaderFields()); } catch (SSLHandshakeException e) { System.out.println("Untrusted: " + url); } } }
Я знаю, что OP запросил решение без изменений локальной конфигурации, но в случае, если вы хотите добавить цепочку доверия в хранилище ключей постоянно:
$ keytool -trustcacerts \ -keystore $JAVA_HOME/jre/lib/security/cacerts \ -storepass changeit \ -noprompt \ -importcert \ -file /etc/letsencrypt/live/hostname.com/chain.pem
подробный ответ для тех из нас, кто готов внести локальные изменения конфигурации, которые включают резервное копирование файла конфигурации:
1. Проверьте, работает ли он до изменений
если у вас еще нет тестовой программы, вы можете использовать мою программу Java SSLPing ping, которая проверяет рукопожатие TLS (будет работать с любым портом SSL/TLS, а не только HTTPS). Я буду использовать готовый SSLPing.jar, но чтение кода и создание его самостоятельно-это быстро и легко задача:
$ git clone https://github.com/dimalinux/SSLPing.git Cloning into 'SSLPing'... [... output snipped ...]поскольку моя версия Java является более ранней, чем 1.8.0_101 (не выпущена на момент написания этой статьи), сертификат Let's Encrypt не будет проверяться по умолчанию. Давайте посмотрим, как выглядит сбой перед применением исправления:
$ java -jar SSLPing/dist/SSLPing.jar helloworld.letsencrypt.org 443 About to connect to 'helloworld.letsencrypt.org' on port 443 javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target [... output snipped ...]
2. Импортируйте сертификат
Я на Mac OS X с набором переменных окружения JAVA_HOME. Более поздние команды будут предполагать, что эта переменная установлена для установки java изменение:
$ echo $JAVA_HOME /Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/сделайте резервную копию файла cacerts, который мы будем изменять, чтобы вы могли отменить любые изменения без переустановки JDK:
$ sudo cp -a $JAVA_HOME/jre/lib/security/cacerts $JAVA_HOME/jre/lib/security/cacerts.origзагрузите сертификат подписи, который нам нужно импортировать:
$ wget https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.derвыполнить импорт:
$ sudo keytool -trustcacerts -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit -noprompt -importcert -alias lets-encrypt-x3-cross-signed -file lets-encrypt-x3-cross-signed.der Certificate was added to keystore
3. Убедитесь, что он работает после изменений
убедитесь, что Java теперь счастливо подключается к порту SSL:
$ java -jar SSLPing/dist/SSLPing.jar helloworld.letsencrypt.org 443 About to connect to 'helloworld.letsencrypt.org' on port 443 Successfully connected
для JDK, которые еще не поддерживают давайте шифровать сертификаты, вы можете добавить их в JDK
cacertsпосле этого процесса (благодаря этой).Загрузите все сертификаты на https://letsencrypt.org/certificates/ (выберите der формат) и добавить их один за другим с помощью такого рода команды (пример для
letsencryptauthorityx1.der):keytool -import -keystore PATH_TO_JDK\jre\lib\security\cacerts -storepass changeit -noprompt -trustcacerts -alias letsencryptauthorityx1 -file PATH_TO_DOWNLOADS\letsencryptauthorityx1.der
Comments