source

Java는 Let's Encrypt 인증서를 지원합니까?

lovecheck 2022. 11. 28. 21:14
반응형

Java는 Let's Encrypt 인증서를 지원합니까?

저는 HTTP를 통해 리모트 서버의 REST API를 조회하는 Java 어플리케이션을 개발하고 있습니다.시큐러티상의 이유로, 이 통신은 HTTPS 로 전환할 필요가 있습니다.

이제 Let's Encrypt가 공개 베타 버전을 시작했으므로 Java가 현재 기본 인증서로 동작하는지(또는 향후 동작할 것으로 확인됨) 알고 싶습니다.

Let's Encrypt는 IdenTrust에 의해 중간 상호 서명을 받았습니다.이것은 좋은 소식이 될 것입니다.단, 이 명령어 출력에는 다음 두 가지가 없습니다.

keytool -keystore "..\lib\security\cacerts" -storepass changeit -list

신뢰할 수 있는 CA를 각 머신에 수동으로 추가할 수 있다는 것은 알고 있습니다만, 추가 설정 없이 애플리케이션을 무료로 다운로드하여 실행할 수 있어야 하기 때문에 "즉시 사용 가능한" 솔루션을 찾고 있습니다.나한테 좋은 소식 있어?

[2016-06-08 업데이트: https://bugs.openjdk.java.net/browse/JDK-8154757에 따르면 IdenTrust CA는 Oracle Java 8u101에 포함될 예정입니다]

[업데이트 2016-08-05: Java 8u101이 출시되었으며 IdenTrust CA: 릴리즈 노트도 포함되어 있습니다]


Java는 Let's Encrypt 인증서를 지원합니까?

예. 암호화 인증서는 일반 공용 키 인증서입니다.Java는 이를 지원합니다(Let's Encrypt Certificate Compatibility에 따르면 Java 7 > = 7u1900 및 Java 8 > = 8u101).

Java trust Let's Encrypt certificates는 개봉 즉시 사용할 수 있습니까?

아니요/JVM에 따라 다릅니다.최대 8u66의 Oracle JDK/JRE 신뢰 스토어에는 Let's Encrypt CA도 서명된 IdenTrust CA도 포함되어 있지 않습니다. new URL("https://letsencrypt.org/").openConnection().connect();예를 들어 결과javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException.

그러나 필요한 루트 CA를 포함하는 사용자 지정 키스토어를 직접 제공하거나 정의하거나 인증서를 JVM 신뢰 스토어로 가져올 수 있습니다.

https://community.letsencrypt.org/t/will-the-cross-root-cover-trust-by-the-default-list-in-the-jdk-jre/134/10에서도 주제에 대해 설명합니다.


다음은 실행 시 기본 신뢰 저장소에 인증서를 추가하는 방법을 보여 주는 코드 예입니다.증명서만 추가하면 됩니다(firefox에서 .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

출처 : https://community.letsencrypt.org/t/will-the-cross-root-cover-trust-by-the-default-list-in-the-jdk-jre/134/13

컨피규레이션파일의 백업을 포함한 로컬 설정 변경을 희망하는 유저에 대한 상세한 회답:

1. 변경 전 동작 여부를 테스트합니다.

테스트 프로그램이 아직 없는 경우 TLS 핸드쉐이크를 테스트하는 Java SSLPing ping 프로그램을 사용할 수 있습니다(HTTPS뿐만 아니라 모든 SSL/TLS 포트에서 작동합니다).사전 빌드된 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. 증명서의 Import

JAVA_를 탑재한 Mac OS X를 사용하고 있습니다.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

Import할 서명 증명서를 다운로드합니다.

$ wget https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.der

Import를 수행합니다.

$ 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

Let Encrypt 하지 않는JDK의 를 JDK에 할 수 .cacerts(덕분에) 이 프로세스를 수행합니다.

https://letsencrypt.org/certificates/에 모든 증명서를 다운로드하고(der 형식을 선택), 이러한 종류의 명령어를 사용하여1개씩 추가합니다(용도).letsencryptauthorityx1.der

keytool -import -keystore PATH_TO_JDK\jre\lib\security\cacerts -storepass changeit -noprompt -trustcacerts -alias letsencryptauthorityx1 -file PATH_TO_DOWNLOADS\letsencryptauthorityx1.der

언급URL : https://stackoverflow.com/questions/34110426/does-java-support-lets-encrypt-certificates

반응형