Java: sun.security.provider.certpath.SunCertPathBuilderException: tidak dapat menemukan jalur sertifikasi yang valid ke target yang diminta

249

Saya memiliki kelas yang akan mengunduh file dari server https . Ketika saya menjalankannya, ia mengembalikan banyak kesalahan. Tampaknya saya memiliki masalah dengan sertifikat saya. Apakah mungkin untuk mengabaikan otentikasi klien-server? Jika ya, bagaimana caranya?

package com.da;

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.CharBuffer;
import java.util.concurrent.Future;

import org.apache.http.HttpResponse;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.impl.nio.client.DefaultHttpAsyncClient;
import org.apache.http.nio.IOControl;
import org.apache.http.nio.client.HttpAsyncClient;
import org.apache.http.nio.client.methods.AsyncCharConsumer;
import org.apache.http.nio.client.methods.HttpAsyncGet;
import org.apache.http.nio.client.methods.HttpAsyncPost;

public class RSDDownloadFile {
    static FileOutputStream fos;

    public void DownloadFile(String URI, String Request) throws Exception
    {
        java.net.URI uri = URIUtils.createURI("https", "176.66.3.69:6443", -1, "download.aspx",
                "Lang=EN&AuthToken=package", null);
        System.out.println("URI Query: " + uri.toString());

        HttpAsyncClient httpclient = new DefaultHttpAsyncClient();
        httpclient.start();
        try {
            Future<Boolean> future = httpclient.execute(
                    new HttpAsyncGet(uri),
                    new ResponseCallback(), null);

            Boolean result = future.get();
            if (result != null && result.booleanValue()) {
                System.out.println("\nRequest successfully executed");
            } else {
                System.out.println("Request failed");
            }              
        } 
        catch(Exception e){
            System.out.println("[DownloadFile] Exception: " + e.getMessage());
        }
        finally {
            System.out.println("Shutting down");
            httpclient.shutdown();
        }
        System.out.println("Done");  

    }

    static class ResponseCallback extends AsyncCharConsumer<Boolean> {

        @Override
        protected void onResponseReceived(final HttpResponse response) {
             System.out.println("Response: " + response.getStatusLine());
             System.out.println("Header: " + response.toString());
             try {   
                 //if(response.getStatusLine().getStatusCode()==200)
                     fos = new FileOutputStream( "Response.html" );
             }catch(Exception e){
                 System.out.println("[onResponseReceived] Exception: " + e.getMessage());
             }
        }

        @Override
        protected void onCharReceived(final CharBuffer buf, final IOControl ioctrl) throws IOException {
            try
            {
                while (buf.hasRemaining()) 
                {
                    //System.out.print(buf.get());
                    fos.write(buf.get());
                }
            }catch(Exception e)
            {
                System.out.println("[onCharReceived] Exception: " + e.getMessage());
            }
        }

        @Override
        protected void onCleanup() {
            try
            {             
                if(fos!=null)
                    fos.close();
            }catch(Exception e){
                System.out.println("[onCleanup] Exception: " + e.getMessage());         
            }
             System.out.println("onCleanup()");
        }

        @Override
        protected Boolean buildResult() {
            return Boolean.TRUE;
        }

    }
}

Kesalahan:

URI Query: https://176.66.3.69:6443/download.aspx?Lang=EN&AuthToken=package
Aug 2, 2011 3:47:57 PM org.apache.http.impl.nio.client.NHttpClientProtocolHandler exception
SEVERE: I/O error: General SSLEngine problem
javax.net.ssl.SSLHandshakeException: General SSLEngine problem
    at com.sun.net.ssl.internal.ssl.Handshaker.checkThrown(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLEngineImpl.checkTaskThrown(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLEngineImpl.writeAppRecord(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLEngineImpl.wrap(Unknown Source)
    at javax.net.ssl.SSLEngine.wrap(Unknown Source)
    at org.apache.http.impl.nio.reactor.SSLIOSession.doHandshake(SSLIOSession.java:154)
    at org.apache.http.impl.nio.reactor.SSLIOSession.isAppInputReady(SSLIOSession.java:276)
    at org.apache.http.impl.nio.client.InternalClientEventDispatch.inputReady(InternalClientEventDispatch.java:79)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:161)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:335)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:315)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:275)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:104)
    at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:542)
    at java.lang.Thread.run(Unknown Source)
Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLEngineImpl.fatal(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Unknown Source)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.net.ssl.internal.ssl.Handshaker$DelegatedTask.run(Unknown Source)
    at org.apache.http.impl.nio.reactor.SSLIOSession.doHandshake(SSLIOSession.java:180)
    ... 9 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.validator.PKIXValidator.doBuild(Unknown Source)
    at sun.security.validator.PKIXValidator.engineValidate(Unknown Source)
    at sun.security.validator.Validator.validate(Unknown Source)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
    at com.sun.net.ssl.internal.ssl.JsseX509TrustManager.checkServerTrusted(Unknown Source)
    ... 16 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source)
    at java.security.cert.CertPathBuilder.build(Unknown Source)
    ... 21 more
onCleanup()

[DownloadFile] Exception: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
Shutting down
Done
neztreh
sumber
2
Suatu kali saya mendapatkan kesalahan ini dan menghubungi tim keamanan kami, dan ternyata saya harus menambal JAR yang kami gunakan, karena tim kami menggunakan yang lama yang disediakan oleh perusahaan. Hanya FYI untuk siapa pun yang mungkin berada dalam situasi yang sama.
kayleeFrye_onDeck

Jawaban:

215

Masalah muncul ketika server Anda memiliki sertifikat yang ditandatangani sendiri. Untuk mengatasinya, Anda dapat menambahkan sertifikat ini ke daftar sertifikat tepercaya JVM Anda.

Dalam artikel ini penulis menjelaskan cara mengambil sertifikat dari browser Anda dan menambahkannya ke file cacerts JVM Anda. Anda dapat mengedit JAVA_HOME/jre/lib/security/cacertsfile atau menjalankan aplikasi Anda dengan -Djavax.net.ssl.trustStoreparameter. Verifikasi JDK / JRE mana yang Anda gunakan juga karena ini sering menjadi sumber kebingungan.

Lihat juga: Bagaimana nama server sertifikat SSL teratasi / Bisakah saya menambahkan nama alternatif menggunakan keytool? Jika Anda mengalami java.security.cert.CertificateException: No name matching localhost foundpengecualian.

Maxim Mazin
sumber
3
ini tidak berhasil untuk saya. Saya sudah menginstal root dan sertifikat rantai, tetapi Tomcat-7 masih melaporkan validatorException yang disebabkan oleh "tidak dapat menemukan jalur sertifikasi yang valid ke target yang diminta" cara apa pun untuk debug ini?
Cheruvim
Masalahnya juga muncul dengan sertifikat yang ditandatangani oleh orang lain yang tidak dipercaya.
Marquis of Lorne
Bagus! Berhasil! Hanya saja, jangan lupa bahwa Anda dapat memiliki jre dan jdk, dan keduanya cacertsharus diperbarui
Dima Fomin
Dalam kasus saya, root CA ada di sana tetapi tidak CA berikutnya turun. Menambahkan CA turun berikutnya melakukan trik - terima kasih.
java-addict301
1
Dalam kasus saya, saya menggunakan Netbeans + Apache Tomcat (terintegrasi), jadi, menambahkan .cer ke trust store "cacerts" di Jdk / jre (C: \ Program Files \ Java \ jdk1.8.0_152 \ jre \ lib \ keamanan) dan Jre (C: \ Program Files \ Java \ jre1.8.0_91 \ lib \ security) bekerja untuk saya
Jnn
149

Inilah yang andal bekerja untuk saya di macOS. Pastikan untuk mengganti example.com dan 443 dengan nama host dan port aktual yang Anda coba sambungkan, dan berikan alias khusus. Perintah pertama mengunduh sertifikat yang disediakan dari server jarak jauh dan menyimpannya secara lokal dalam format x509. Perintah kedua memuat sertifikat yang disimpan ke toko kepercayaan SSL Java.

openssl x509 -in <(openssl s_client -connect example.com:443 -prexit 2>/dev/null) -out ~/example.crt
sudo keytool -importcert -file ~/example.crt -alias example -keystore $(/usr/libexec/java_home)/jre/lib/security/cacerts -storepass changeit
Gabe Martin-Dempesy
sumber
3
Bekerja untuk saya mengapa? Anda perlu memberikan penjelasan.
Marquis of Lorne
openssl x509 -dalam <(openssl s_client -connect example.com:443 -prexit 2> / dev / null) -out ~ / example.crt - apa itu example.crt pada perintah saya memiliki sertifikat .pem yang harus saya berikan itu disini ??
Wisnu Ranganathan
3
.crt dan .pem adalah ekstensi file yang biasa digunakan untuk format file yang sama. Jika Anda sudah memiliki file tersebut, jalankan saja perintah kedua dan berikan ke argumen -file.
Gabe Martin-Dempesy
1
Hal yang bagus. Satu-satunya hal adalah: Saya harus menggunakan openssl 1.0.Xx terbaru untuk beberapa alasan, 9.X.Xx lama tidak berfungsi.
zbstof
1
Ini tidak bekerja dengan titik akhir SNI. Untuk itu Anda perlu menambahkan: -servername example.com saat mengambil sertifikat
Patrik Beck
46

Saya memiliki masalah yang sama dengan sertifikat wildcard ditandatangani yang valid dari symantec.

Pertama coba jalankan aplikasi java Anda dengan -Djavax.net.debug = SSL untuk melihat apa yang sebenarnya terjadi.

Saya akhirnya mengimpor sertifikat perantara yang menyebabkan rantai sertifikat terputus.

Saya mengunduh sertifikat perantara yang hilang dari symantec (Anda dapat melihat tautan unduhan ke sertifikat yang hilang di log jabat tangan ssl: http://svrintl-g3-aia.verisign.com/SVRIntlG3.cer dalam kasus saya).

Dan saya mengimpor sertifikat di java keystore. Setelah mengimpor sertifikat perantara, sertifikat wildcard ssl saya akhirnya mulai berfungsi:

keytool -import -keystore ../jre/lib/security/cacerts -trustcacerts -alias "VeriSign Class 3 International Server CA - G3" -file /pathto/SVRIntlG3.cer
Stephan Oudmaijer
sumber
Inilah yang terjadi:
Kisna
2
Untuk menghindari kebingungan, jalankan java (atau jcurl) dengan parameter debug untuk melihat "rantai Sertifikat" jarak jauh dalam log, lalu ambil "CN" di truststore yang diteruskan secara eksplisit (bukan default) sebagai berikut, jika tidak ada, Anda perlu menambahkan. ssllabs.com/ssltest/analyze.html akan menunjukkan apakah sertifikat sisi server memiliki rantai tidak lengkap, dan termasuk sertifikat jalur sertifikasi menengah yang perlu ditambahkan. -Djavax.net.debug=ssl,handshake -Djavax.net.ssl.keyStoreType=PKCS12 -Djavax.net.ssl.keyStore=our-client-certs -Djavax.net.ssl.trustStoreType=jks -Djavax.net.ssl.trustStore=their-server-certs
kisna
Saya memiliki masalah yang sama, ini sangat berguna, tetapi dalam kasus saya Anda hanya perlu menambahkan sertifikat server ke file cacerts versi JDK
Pigritia
Harap diingat bahwa ada alat lain yang disebut portecle yang dapat membuka file cacert (toko sertifikat) dan mengimpor sertifikat dengan mudah. Hanya ingat untuk menyimpan file cacert sesudahnya.
will824
41
  1. Ekspor sertifikat SSL menggunakan Firefox. Anda dapat mengekspornya dengan menekan URL di browser dan kemudian memilih opsi untuk mengekspor sertifikat. Mari kita asumsikan nama file cert adalah your.ssl.server.name.crt
  2. Pergi ke JRE_HOME/bin atauJDK/JRE/bin
  3. Ketikkan perintah
  4. keytool -keystore ..\lib\security\cacerts -import -alias your.ssl.server.name -file .\relative-path-to-cert-file\your.ssl.server.name.crt
  5. Mulai ulang proses Java Anda
Robin
sumber
13
Jika diminta kata sandi, gunakan kata sandi cysterts keystore default changeit( stackoverflow.com/a/22782035/1304830 ). Pastikan juga untuk menjalankan cmd sebagai administrator.
Fr4nz
22

@Gabe Martin-Dempesy membantu saya. Dan saya menulis skrip kecil yang terkait dengannya. Penggunaannya sangat sederhana.

Pasang sertifikat dari host:

> sudo ./java-cert-importer.sh example.com

Hapus sertifikat yang sudah diinstal.

> sudo ./java-cert-importer.sh example.com --delete

java-cert-importer.sh

#!/usr/bin/env bash

# Exit on error
set -e

# Ensure script is running as root
if [ "$EUID" -ne 0 ]
  then echo "WARN: Please run as root (sudo)"
  exit 1
fi

# Check required commands
command -v openssl >/dev/null 2>&1 || { echo "Required command 'openssl' not installed. Aborting." >&2; exit 1; }
command -v keytool >/dev/null 2>&1 || { echo "Required command 'keytool' not installed. Aborting." >&2; exit 1; }

# Get command line args
host=$1; port=${2:-443}; deleteCmd=${3:-${2}}

# Check host argument
if [ ! ${host} ]; then
cat << EOF
Please enter required parameter(s)

usage:  ./java-cert-importer.sh <host> [ <port> | default=443 ] [ -d | --delete ]

EOF
exit 1
fi;

if [ "$JAVA_HOME" ]; then
    javahome=${JAVA_HOME}
elif [[ "$OSTYPE" == "linux-gnu" ]]; then # Linux
    javahome=$(readlink -f $(which java) | sed "s:bin/java::")
elif [[ "$OSTYPE" == "darwin"* ]]; then # Mac OS X
    javahome="$(/usr/libexec/java_home)/jre"
fi

if [ ! "$javahome" ]; then
    echo "WARN: Java home cannot be found."
    exit 1
elif [ ! -d "$javahome" ]; then
    echo "WARN: Detected Java home does not exists: $javahome"
    exit 1
fi

echo "Detected Java Home: $javahome"

# Set cacerts file path
cacertspath=${javahome}/lib/security/cacerts
cacertsbackup="${cacertspath}.$$.backup"

if ( [ "$deleteCmd" == "-d" ] || [ "$deleteCmd" == "--delete" ] ); then
    sudo keytool -delete -alias ${host} -keystore ${cacertspath} -storepass changeit
    echo "Certificate is deleted for ${host}"
    exit 0
fi

# Get host info from user
#read -p "Enter server host (E.g. example.com) : " host
#read -p "Enter server port (Default 443) : " port

# create temp file
tmpfile="/tmp/${host}.$$.crt"

# Create java cacerts backup file
cp ${cacertspath} ${cacertsbackup}

echo "Java CaCerts Backup: ${cacertsbackup}"

# Get certificate from speficied host
openssl x509 -in <(openssl s_client -connect ${host}:${port} -prexit 2>/dev/null) -out ${tmpfile}

# Import certificate into java cacerts file
sudo keytool -importcert -file ${tmpfile} -alias ${host} -keystore ${cacertspath} -storepass changeit

# Remove temp certificate file
rm ${tmpfile}

# Check certificate alias name (same with host) that imported successfully
result=$(keytool -list -v -keystore ${cacertspath} -storepass changeit | grep "Alias name: ${host}")

# Show results to user
if [ "$result" ]; then
    echo "Success: Certificate is imported to java cacerts for ${host}";
else
    echo "Error: Something went wrong";
fi;
bhdrk
sumber
Bekerja dengan sempurna. Kerja bagus! . Ini adalah cara kerjanya: mulai layanan SSL Anda (jika tidak berjalan), dan jalankan perintah seperti yang dijelaskan (misalnya ./java-cert-importer.sh example.com 1234). Itu dia.
lepe
1
Bagus sekali. Saya mendapatkan kesalahan pada server Jenkins yang terhubung ke API eksternal yang mengubah sertifikatnya dan gagal builts saya. Ini menyelesaikan masalah saya
user9869932
Oracle seharusnya menyediakan sesuatu seperti ini sejak awal atau tidak pernah setiap orang membuat solusi SSL mereka sendiri yang mengerikan. Penanganan sertifikat SSL harus menjadi pekerjaan sistem operasi.
Wolfgang Fahl
17

Mengutip dari Tidak ada lagi 'tidak dapat menemukan jalur sertifikasi yang valid ke target yang diminta'

ketika mencoba untuk membuka koneksi SSL ke host menggunakan JSSE. Apa ini biasanya berarti bahwa server menggunakan sertifikat uji (mungkin dihasilkan menggunakan keytool) daripada sertifikat dari Otoritas Sertifikasi komersial terkenal seperti Verisign atau GoDaddy. Peramban web menampilkan dialog peringatan dalam kasus ini, tetapi karena JSSE tidak dapat mengasumsikan pengguna interaktif hadir, hanya melemparkan pengecualian secara default.

Validasi sertifikat adalah bagian yang sangat penting dari keamanan SSL, tetapi saya tidak menulis entri ini untuk menjelaskan detailnya. Jika Anda tertarik, Anda bisa mulai dengan membaca uraian Wikipedia. Saya menulis entri ini untuk menunjukkan cara sederhana untuk berbicara dengan tuan rumah dengan sertifikat tes, jika Anda benar-benar mau.

Pada dasarnya, Anda ingin menambahkan sertifikat server ke KeyStore dengan sertifikat tepercaya Anda

Coba kode yang disediakan di sana. Mungkin membantu.

Nishant
sumber
5
Bagian tentang "Validasi sertifikat adalah bagian yang sangat penting dari keamanan SSL" belum tentu benar. SSL memberi Anda dua jaminan: (1) bahwa komunikasi Anda bersifat pribadi, dan (2) bahwa Anda berbicara dengan server yang dikenal oleh NSA. (:-) Terkadang Anda hanya peduli dengan privasi percakapan, dan kemudian sertifikasi yang ditandatangani sendiri baik-baik saja. Lihat social-biz.org/2011/10/16/the-anti-ssl-conspiracy
AgilePro
@AgilePro SSL memberi Anda empat jaminan: otentikasi, privasi, integritas, dan kemungkinan otorisasi. Itu tidak memberi Anda jaminan bahwa Anda berbicara dengan server yang dikenal dengan NSA. Peduli hanya tentang privasi tanpa otentikasi adalah kontradiksi dalam hal.
Marquis of Lorne
@ EJP Setuju bahwa jika Anda menggunakan sertifikat klien Anda bisa mendapatkan otentikasi dan saya kira kemungkinan otorisasi ... tetapi sebagian besar penggunaan tidak dengan sertifikat klien. Apa yang Anda sebut perbedaan antara sertifikat yang ditandatangani sendiri dan sertifikat dari otoritas yang menandatangani? Apakah otoritas penandatanganan memberi "integritas". Lelucon saya tentang NSA adalah bahwa semua otoritas penandatangan tidak dapat secara positif menjamin independensi dari segalanya. Bukan berarti paranoid, tetapi intinya sertifikat Anda HANYA rahasia seperti yang bisa dilakukan oleh otoritas penandatanganan. Ditandatangani sendiri bisa lebih rahasia.
AgilePro
@AgilePro Menggunakan sertifikat server mengotentikasi server, dan diharuskan membuat SSL aman, seperti yang tercantum dalam RFC 2246. Sertifikat sama sekali tidak rahasia: oleh karena itu sisa komentar Anda tidak masuk akal.
Marquis of Lorne
6

Ini memecahkan masalah saya,

Kita perlu mengimpor sertifikat ke java lokal. Jika tidak kita bisa mendapatkan pengecualian di bawah ini.

    javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: Gagal membangun jalur PKIX: sun.security.provider.certpath.SunCertPathBuilderException: tidak dapat menemukan jalur sertifikasi yang valid untuk target yang diminta
        di sun.security.ssl.Alerts.getSSLException (Alerts.java:192)
        di sun.security.ssl.SSLSocketImpl.fatal (SSLSocketImpl.java:1949)
        di sun.security.ssl.Handshaker.fatalSE (Handshaker.java:302)

SSLPOKE adalah alat untuk menguji konektivitas https dari mesin lokal Anda.

Perintah untuk menguji konektivitas:

"%JAVA_HOME%/bin/java" SSLPoke <hostname> 443
    sun.security.validator.ValidatorException: Pembuatan jalur PKIX gagal: 
    sun.security.provider.certpath.SunCertPathBuilderException: tidak dapat menemukan jalur sertifikasi yang valid ke target yang diminta
        di sun.security.validator.PKIXValidator.doBuild (PKIXValidator.java:387)
        di sun.security.validator.PKIXValidator.engineValidate (PKIXValidator.java:92)
        di sun.security.validator.Validator.validate (Validator.java:60)
        di sun.security.ssl.X509TrustManagerImpl.validate (X509TrustManagerImpl.java:324)
        di sun.security.ssl.X509TrustManagerImpl.checkTrusted (X509TrustManagerImpl.java .: 29)
        di sun.security.ssl.X509TrustManagerImpl.checkServerTrusted (X509TrustManagerImpl.java:124)
        di sun.security.ssl.ClientHandshaker.serverCertificate (ClientHandshaker.java:1496)
        di sun.security.ssl.ClientHandshaker.processMessage (ClientHandshaker.java .: 16)
        di sun.security.ssl.Handshaker.processLoop (Handshaker.java:1026)
        di sun.security.ssl.Handshaker.process_record (Handshaker.java:961)
        di sun.security.ssl.SSLSocketImpl.readRecord (SSLSocketImpl.java:1062)
        di sun.security.ssl.SSLSocketImpl.performInitialHandshake (SSLSocketImpl.java:1375)
        di sun.security.ssl.SSLSocketImpl.writeRecord (SSLSocketImpl.java:747)
        di sun.security.ssl.AppOutputStream.write (AppOutputStream.java:123)
        di sun.security.ssl.AppOutputStream.write (AppOutputStream.java:138)
        di SSLPoke.main (SSLPoke.java:31)
    Disebabkan oleh: sun.security.provider.certpath.SunCertPathBuilderException: tidak dapat menemukan jalur sertifikasi yang valid untuk 
    target yang diminta
        di sun.security.provider.certpath.SunCertPathBuilder.build (SunCertPathBuilder.java:141)
        di sun.security.provider.certpath.SunCertPathBuilder.engineBuild (SunCertPathBuilder.java:126)
        di java.security.cert.CertPathBuilder.build (CertPathBuilder.java:80)
        di sun.security.validator.PKIXValidator.doBuild (PKIXValidator.java:382)
        ... 15 lagi
keytool -import -alias <anyname> -keystore "%JAVA_HOME%/jre/lib/security/cacerts" -file <cert path>

ini pertama kali akan meminta "Masukkan kata sandi keystore:" changeitadalah kata sandi default. dan akhirnya prompt "Percayai sertifikat ini? [tidak]:", berikan "ya" untuk menambahkan sertifikat ke keystore.

Verifikasi:

C:\tools>"%JAVA_HOME%/bin/java" SSLPoke <hostname> 443
Successfully connected    
Naveen
sumber
5

Saya bisa membuatnya bekerja hanya dengan kode, yaitu tidak perlu menggunakan keytool:

import com.netflix.config.DynamicBooleanProperty;
import com.netflix.config.DynamicIntProperty;
import com.netflix.config.DynamicPropertyFactory;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.nio.conn.NoopIOSessionStrategy;
import org.apache.http.nio.conn.SchemeIOSessionStrategy;
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class Test
{
    private static final DynamicIntProperty MAX_TOTAL_CONNECTIONS = DynamicPropertyFactory.getInstance().getIntProperty("X.total.connections", 40);
    private static final DynamicIntProperty ROUTE_CONNECTIONS = DynamicPropertyFactory.getInstance().getIntProperty("X.total.connections", 40);
    private static final DynamicIntProperty CONNECT_TIMEOUT = DynamicPropertyFactory.getInstance().getIntProperty("X.connect.timeout", 60000);
    private static final DynamicIntProperty SOCKET_TIMEOUT = DynamicPropertyFactory.getInstance().getIntProperty("X.socket.timeout", -1);
    private static final DynamicIntProperty CONNECTION_REQUEST_TIMEOUT = DynamicPropertyFactory.getInstance().getIntProperty("X.connectionrequest.timeout", 60000);
    private static final DynamicBooleanProperty STALE_CONNECTION_CHECK = DynamicPropertyFactory.getInstance().getBooleanProperty("X.checkconnection", true);

    public static void main(String[] args) throws Exception
    {

        SSLContext sslcontext = SSLContexts.custom()
                .useTLS()
                .loadTrustMaterial(null, new TrustStrategy()
                {
                    @Override
                    public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException
                    {
                        return true;
                    }
                })
                .build();
        SSLIOSessionStrategy sslSessionStrategy = new SSLIOSessionStrategy(sslcontext, new AllowAll());

        Registry<SchemeIOSessionStrategy> sessionStrategyRegistry = RegistryBuilder.<SchemeIOSessionStrategy>create()
                .register("http", NoopIOSessionStrategy.INSTANCE)
                .register("https", sslSessionStrategy)
                .build();

        DefaultConnectingIOReactor ioReactor = new DefaultConnectingIOReactor(IOReactorConfig.DEFAULT);
        PoolingNHttpClientConnectionManager connectionManager = new PoolingNHttpClientConnectionManager(ioReactor, sessionStrategyRegistry);
        connectionManager.setMaxTotal(MAX_TOTAL_CONNECTIONS.get());
        connectionManager.setDefaultMaxPerRoute(ROUTE_CONNECTIONS.get());

        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(SOCKET_TIMEOUT.get())
                .setConnectTimeout(CONNECT_TIMEOUT.get())
                .setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT.get())
                .setStaleConnectionCheckEnabled(STALE_CONNECTION_CHECK.get())
                .build();

        CloseableHttpAsyncClient httpClient = HttpAsyncClients.custom()
                .setSSLStrategy(sslSessionStrategy)
                .setConnectionManager(connectionManager)
                .setDefaultRequestConfig(requestConfig)
                .build();

        httpClient.start();

        // use httpClient...
    }

    private static class AllowAll implements X509HostnameVerifier
    {
        @Override
        public void verify(String s, SSLSocket sslSocket) throws IOException
        {}

        @Override
        public void verify(String s, X509Certificate x509Certificate) throws SSLException {}

        @Override
        public void verify(String s, String[] strings, String[] strings2) throws SSLException
        {}

        @Override
        public boolean verify(String s, SSLSession sslSession)
        {
            return true;
        }
    }
}
Jonas Bergström
sumber
1
Btw, saya menggunakan httpasyncclient: 4.0.1
Jonas Bergström
Saya membutuhkan sesuatu yang serupa, @ JonasBergström, solusi Anda dengan SSLContext sangat membantu.
EnterSB
8
Perhatikan bahwa solusi ini tidak aman.
Marquis of Lorne
Terima kasih Jonas, solusi Anda tidak menyelesaikan masalah. Tapi saya merasa perlu waktu sangat lama (3 - 5s) untuk membuat koneksi pertama, setelah itu setiap koneksi hanya membutuhkan 300-400 ms.
twcai
5

Sumber kesalahan ini pada instance Apache 2.4 saya (menggunakan sertifikat wildcard Comodo) adalah jalur yang tidak lengkap ke sertifikat root bertanda tangan SHA-1. Ada beberapa rantai dalam sertifikat yang diterbitkan, dan rantai yang mengarah ke sertifikat akar SHA-1 tidak memiliki sertifikat perantara . Browser modern tahu cara menangani ini, tetapi Java 7 tidak menanganinya secara default (meskipun ada beberapa cara berbelit-belit untuk mencapai ini dalam kode). Hasilnya adalah pesan kesalahan yang terlihat identik dengan kasus sertifikat yang ditandatangani sendiri:

Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:196)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:268)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380)
    ... 22 more

Dalam kasus ini, pesan "tidak dapat menemukan jalur sertifikasi yang valid ke target yang diminta" sedang diproduksi karena sertifikat perantara yang hilang. Anda dapat memeriksa sertifikat mana yang hilang menggunakan tes Labs SSL terhadap server. Setelah Anda menemukan sertifikat yang sesuai, unduh dan (jika server berada di bawah kendali Anda) tambahkan ke bundel sertifikat. Atau, Anda dapat mengimpor sertifikat yang hilang secara lokal. Mengakomodasi masalah ini di server adalah solusi yang lebih umum untuk masalah tersebut.

vallismortis
sumber
ssllabs.com/ssltest adalah penyelamat, hanya perlu membandingkannya dengan validasi sertifikat kerja.
kisna
5

Untuk Windows saja, ikuti langkah-langkah ini:

  1. Di Chrome pergi ke pengaturan.
  2. Pada Pengaturan klik tampilkan pengaturan lanjut.
  3. Di bawah HTTPS / SSL Klik pada Kelola Sertifikat.
  4. Ekspor Sertifikat Anda.
  5. Dalam pencarian Windows (Menekan tombol windows pada keyboard) ketik java.
  6. Pilih (Konfigurasi Java) Opsi Yang akan membuka Java Control Panel
  7. Pilih tab Security di Java Control Panel
  8. Pilih Kelola Sertifikat
  9. Klik Impor
  10. Di bawah (Pengguna) tab yang dipilih dan jenis sertifikat sebagai (Sertifikat Tepercaya)
  11. Klik tombol impor dan browse ke sertifikat yang diunduh dan impor.
Praveen
sumber
4

Bagi mereka yang menyukai Debian dan Java yang dipaket:

sudo mkdir /usr/share/ca-certificates/test/  # don't mess with other certs
sudo cp ~/tmp/test.loc.crt /usr/share/ca-certificates/test/
sudo dpkg-reconfigure --force ca-certificates  # check your cert in curses GUI!
sudo update-ca-certificates --fresh --verbose

Jangan lupa untuk memeriksa /etc/default/cacerts:

# enable/disable updates of the keystore /etc/ssl/certs/java/cacerts
cacerts_updates=yes

Untuk menghapus cert:

sudo rm /usr/share/ca-certificates/test/test.loc.crt
sudo rm /etc/ssl/certs/java/cacerts
sudo update-ca-certificates --fresh --verbose
gavenkoa
sumber
2

Ini juga dapat disebabkan oleh penggunaan sertifikat GoDaddy dengan Java 7 yang ditandatangani menggunakan SHA2.

Chrome dan semua browser lain mulai mencabut sertifikat SSL yang ditandatangani menggunakan SHA1, karena tidak aman.

Info lebih lanjut tentang masalah ini dapat ditemukan di sini , serta cara mengatasinya di server Anda jika perlu sekarang.

Taman Brad
sumber
2

Saya memiliki masalah yang sama dengan kesalahan sertifikat dan karena SNI, dan klien http yang saya gunakan tidak menerapkan SNI. Jadi pembaruan versi melakukan pekerjaan

   <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.3.6</version>
    </dependency>
Radu Toader
sumber
2

UPDATE: Bahwa reboot membantu adalah kebetulan (saya harap begitu, hore!). Penyebab sebenarnya dari masalahnya adalah ini: Ketika Gradle diarahkan untuk menggunakan keystore tertentu, keystore itu juga harus berisi semua sertifikat root resmi. Kalau tidak, ia tidak dapat mengakses perpustakaan dari repositori reguler. Yang harus saya lakukan adalah ini:

Impor sertifikat yang ditandatangani sendiri:

keytool -import -trustcacerts -alias myselfsignedcert -file /Users/me/Desktop/selfsignedcert.crt -keystore ./privateKeystore.jks

Tambahkan sertifikat root resmi:

keytool -importkeystore -srckeystore <java-home>/lib/security/cacerts -destkeystore ./privateKeystore.jks

Mungkin daemon Gradle juga menghalangi. Mungkin layak untuk membunuh semua daemon berjalan yang ditemukan./gradlew --status jika segala sesuatu mulai tampak suram.

POSTING ASLI:

Tidak ada yang akan percaya ini, saya tahu. Namun, jika semuanya gagal, cobalah: Setelah reboot Mac saya, masalahnya hilang. Grrr.

Latar belakang: ./gradlew jar terus memberi saya "tidak dapat menemukan jalur sertifikasi yang valid ke target yang diminta"

Saya terjebak dengan sertifikat yang ditandatangani sendiri, disimpan dari browser, diimpor di privateKeystore.jks. Kemudian menginstruksikan Gradle untuk bekerja dengan privateKeystore.jks:

org.gradle.jvmargs=-Djavax.net.debug=SSL -Djavax.net.ssl.trustStore="/Users/me/IntelliJ/myproject/privateKeystore.jks"  -Djavax.net.ssl.trustStorePassword=changeit

Seperti yang disebutkan, ini hanya berfungsi setelah reboot.

StaticNoiseLog
sumber
2

AVG versi 18.1.3044 (dengan Windows 10) mengganggu aplikasi Spring lokal saya.

Solusi: masuk ke bagian AVG yang disebut "Web dan email" dan nonaktifkan "perlindungan email". AVG memblokir sertifikat jika situs tidak aman.

Di dalam
sumber
2

Pastikan bahwa https://176.66.3.69:6443/ memiliki sertifikat yang valid. Anda dapat memeriksanya melalui browser terlebih dahuluhttps tidak aman jika berfungsi di browser itu akan berfungsi di java.

itu bekerja untuk saya

Amr Ibrahim
sumber
Dan apa yang harus saya lakukan jika browser juga mengeluh?
The Godfather
coba pasang sertifikat
Amr Ibrahim
2

Ada banyak cara untuk menyelesaikan ini ...

Salah satu caranya adalah mengatur sertifikat TrustStore dalam file keystore dan meletakkannya di jalur aplikasi, dan mengatur properti sistem ini dalam metode utama:

public static void main(String[] args) {
  System.setProperty("javax.net.ssl.trustStore", "trust-store.jks");
  System.setProperty("javax.net.ssl.trustStorePassword", "TrustStore");
  ...
}

Cara lain adalah menempatkan keystore sebagai file sumber daya di dalam file jar proyek dan memuatnya:

public static SSLContext createSSLContext(String resourcePath, String pass) throws NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException, UnrecoverableKeyException, KeyManagementException {
  // initialise the keystore
  final char[] password = pass.toCharArray();
  KeyStore ks = KeyStore.getInstance("JKS");
  ks.load(ThisClass.class.getResourceAsStream(resourcePath
  ), password);

  // Setup the key manager factory.
  KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
  kmf.init(ks, password);

  // Setup the trust manager factory.
  TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
  tmf.init(ks);

  SSLContext sslc = SSLContext.getInstance("TLS");
  sslc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
  return sslc;
}

public static void main(String[] args) {
  SSLContext.setDefault(
    createSSLContext("/trust-store.jks", "TrustStore"));
  ...
}

Di windows Anda dapat mencoba solusi ini juga: https://stackoverflow.com/a/59056537/980442


Saya membuat file keystore dari .crtfile CA otoritas sertifikat dengan cara ini:

keytool -import -alias ca -keystore trust-store.jks -storepass TrustStore -trustcacerts -file ca.crt

FYI: https://docs.oracle.com/javadb/10.8.3.0/adminguide/cadminsslclient.html

Daniel De León
sumber
1

Anda memiliki dua opsi, impor sertifikat yang ditandatangani sendiri ke keystore java untuk setiap jvm yang akan dijalankan oleh perangkat lunak atau coba pabrik ssl yang tidak memvalidasi:

jdbc:postgresql://myserver.com:5432/mydatabasename?ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory
Pradip Das
sumber
1

Punya masalah seperti gambar ini.

masukkan deskripsi gambar di sini

Mencoba beberapa solusi. Tetapi menemukan bahwa bahkan jika itu proyek yang sama, ketika itu di tempat kerja orang lain, itu benar-benar baik-baik saja. Tidak diperlukan pengaturan tambahan. Jadi kami kira ini masalah lingkungan. Kami mencoba mengubah versi JDK, IDE tetapi tidak berhasil. butuh sekitar 4 jam untuk penyelidikan, sampai kami mencoba jawaban teratas. Saya tidak menemukan kesalahan yang disebutkan dalam jawaban itu tetapi saya menemukan melalui browser saya tentang HTTP URL (kunci) bahwa ada sertifikasi Charles. Kemudian saya menyadari bahwa charles saya selalu ada. Selama saya mematikannya, itu berfungsi dengan baik.

Jadi saya meninggalkan pengalaman saya yang bisa membantu untuk kasus Anda.

Lalaphoon
sumber
0

Dalam kasus saya, saya menjalankan MacOs High Sierra dengan Java 1.6. File cacert berada di lokasi yang berbeda dari yang disebutkan di atas dalam jawaban Gabe Martin-Dempesy. File cacert juga sudah ditautkan ke lokasi lain (/ Library / Internet Plug-Ins / JavaAppletPlugin.plugin / Contents / Home / lib / security / cacerts).

Menggunakan FireFox, saya mengekspor sertifikat dari situs web yang dimaksud ke file lokal yang disebut "dieksporCertFile.crt". Dari sana, saya menggunakan keytool untuk memindahkan sertifikat ke file cacert. Ini memperbaiki masalah.

bash-3.2# cd /Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/security/
bash-3.2# keytool -importcert -file ~/exportedCertFile.crt -alias example -keystore cacerts -storepass changeit
Alan Curtis
sumber
0

pertama-tama Unduh sertifikat ssl kemudian Anda dapat pergi ke jalur bin java Anda, jalankan perintah di bawah ini di konsol.

C:\java\JDK1.8.0_66-X64\bin>keytool -printcert -file C:\Users\lova\openapi.cer -keystore openapistore
Lova Chittumuri
sumber
-1

Dalam kasus saya, saya memiliki keystore dan truststore memiliki sertifikat yang sama sehingga menghapus truststore membantu. Terkadang rantai sertifikat dapat menjadi masalah jika Anda memiliki beberapa salinan sertifikat.

Smart Coder
sumber