development

Java에서 인증서 암호화를 지원합니까?

big-blog 2020. 7. 20. 07:06
반응형

Java에서 인증서 암호화를 지원합니까?


HTTP를 통해 원격 서버에서 REST API를 쿼리하는 Java 애플리케이션을 개발 중입니다. 보안상의 이유로이 통신은 HTTPS로 전환해야합니다.

지금 하자 암호화가 자신의 공개 베타를 시작, 내가 자바는 현재 작동 (또는 미래에 작동하는 확인) 기본적으로 자신의 인증서를 알고 싶습니다.

암호화하자 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는이를 지원합니다 ( Java 7> = 7u111 및 Java 8> = 8u101의 경우 인증서 호환성 암호화 에 따라 ).

Java는 인증서를 즉시 암호화 할 수 있습니까?

아니오 / 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로 내보내고 클래스 경로에 저장).

을 바탕으로 어떻게 자바에서 신뢰할 수있는 루트 인증서 목록을받을 수 있나요? 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. 변경 전에 작동하는지 테스트

If you don't have a test program already, you can use my java SSLPing ping program which tests the TLS handshake (will work with any SSL/TLS port, not just HTTPS). I'll use the prebuilt SSLPing.jar, but reading the code and building it yourself is a quick and easy task:

$ git clone https://github.com/dimalinux/SSLPing.git
Cloning into 'SSLPing'...
[... output snipped ...]

Since my Java version is earlier than 1.8.0_101 (not released at the time of this writing), a Let's Encrypt certificate will not verify by default. Let's see what failure looks like before applying the fix:

$ 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 the certificate

I'm on Mac OS X with the JAVA_HOME environment variable set. Later commands will assume this variable is set for the java installation you are modifying:

$ echo $JAVA_HOME 
/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/

Make a backup of the cacerts file we will be modifying so you can back out any change without reinstalling the JDK:

$ sudo cp -a $JAVA_HOME/jre/lib/security/cacerts $JAVA_HOME/jre/lib/security/cacerts.orig

Download the signing certificate we need to import:

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

Perform the 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. Verify that it is working after the changes

Verify that Java is now happy connecting to the SSL port:

$ java -jar SSLPing/dist/SSLPing.jar helloworld.letsencrypt.org 443
About to connect to 'helloworld.letsencrypt.org' on port 443
Successfully connected

For JDK which do not support Let's Encrypt certificates yet, you can add those to the JDK cacerts following this process (thanks to this).

Download all the certificates on https://letsencrypt.org/certificates/ (choose the der format) and add them one by one with this kind of command (example for 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

반응형