Java: sun.security.provider.certpath.SunCertPathBuilderException: không thể tìm thấy đường dẫn chứng nhận hợp lệ cho mục tiêu được yêu cầu


248

Tôi có một lớp sẽ tải xuống một tệp từ máy chủ https . Khi tôi chạy nó, nó trả về rất nhiều lỗi. Có vẻ như tôi có vấn đề với chứng chỉ của mình. Có thể bỏ qua xác thực máy khách-máy chủ? Nếu vậy thì thế nào?

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;
        }

    }
}

Lỗi:

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

2
Một lần tôi gặp lỗi này và liên lạc với nhóm bảo mật của chúng tôi, và hóa ra tôi phải vá JAR mà chúng tôi đang sử dụng, vì nhóm của chúng tôi đang sử dụng một lỗi thời do công ty cung cấp. Chỉ là một FYI cho bất cứ ai khác có thể ở trong một tình huống tương tự.
kayleeFrye_onDeck

Câu trả lời:


215

Vấn đề xuất hiện khi máy chủ của bạn có chứng chỉ tự ký. Để giải quyết nó, bạn có thể thêm chứng chỉ này vào danh sách các chứng chỉ tin cậy của JVM.

Trong bài viết này, tác giả mô tả cách lấy chứng chỉ từ trình duyệt của bạn và thêm nó vào tệp trích dẫn của JVM. Bạn có thể chỉnh sửa JAVA_HOME/jre/lib/security/cacertstập tin hoặc chạy ứng dụng với -Djavax.net.ssl.trustStoretham số. Xác minh JDK / JRE nào bạn đang sử dụng vì đây thường là một nguồn gây nhầm lẫn.

Xem thêm: Làm thế nào để tên máy chủ chứng chỉ SSL được giải quyết / Tôi có thể thêm tên thay thế bằng keytool không? Nếu bạn gặp phải java.security.cert.CertificateException: No name matching localhost foundngoại lệ.


3
điều này đã không làm việc cho tôi. Tôi đã cài đặt chứng chỉ gốc và chuỗi, nhưng Tomcat-7 vẫn báo cáo trình xác thựcException gây ra bởi "không thể tìm thấy đường dẫn chứng nhận hợp lệ cho mục tiêu được yêu cầu" có cách nào để gỡ lỗi này không?
Cheruvim

Vấn đề cũng xuất hiện với một chứng chỉ được ký bởi người khác không đáng tin cậy.
Hầu tước Lorne

Tuyệt quá! Nó hoạt động! Đừng quên rằng bạn có thể có cả jre và jdk, và cả hai đều cacertsphải được cập nhật
Dima Fomin

Trong trường hợp của tôi, CA gốc đã ở đó nhưng không có CA tiếp theo. Thêm CA tiếp theo đã thực hiện thủ thuật - cảm ơn.
java-nghiện602

1
Trong trường hợp của tôi, tôi đang sử dụng Netbeans + Apache Tomcat (tích hợp), vì vậy, thêm .cer vào cửa hàng tin cậy "cacerts" trên Jdk / jre (C: \ Program Files \ Java \ jdk1.8.0_152 \ jre \ lib \ bảo mật) và Jre (C: \ Chương trình tập tin \ Java \ jre1.8.0_91 \ lib \ security) hoạt động với tôi
Jnn

149

Đây là những gì đáng tin cậy làm việc cho tôi trên macOS. Đảm bảo thay thế example.com và 443 bằng tên máy chủ và cổng thực tế mà bạn đang cố gắng kết nối và đặt bí danh tùy chỉnh. Lệnh đầu tiên tải chứng chỉ được cung cấp từ máy chủ từ xa và lưu cục bộ ở định dạng x509. Lệnh thứ hai tải chứng chỉ đã lưu vào kho ủy thác SSL của 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

3
Làm việc cho tôi tại sao? Bạn cần cung cấp một lời giải thích.
Hầu tước Lorne

openssl x509 -in <(openssl s_client -connect example.com:443 -prexit 2> / dev / null) -out ~ / example.crt - example.crt trong lệnh tôi có chứng chỉ .pem tôi cần cung cấp ở đây ??
Vishnu Ranganathan

3
.crt và .pem là các phần mở rộng tệp thường được sử dụng cho cùng định dạng tệp. Nếu bạn đã có tệp, chỉ cần chạy lệnh thứ hai và chuyển nó vào đối số -file.
Gabe Martin-Dempesy

1
Công cụ tuyệt vời. Điều duy nhất là: Tôi đã phải sử dụng openssl 1.0.Xx mới nhất vì một số lý do, 9.X.Xx cũ không hoạt động.
zbstof

1
Điều này không hoạt động với điểm cuối SNI. Trong trường hợp đó, bạn cần thêm: -servername example.com khi tìm nạp chứng chỉ
Patrik Beck

46

Tôi đã có cùng một vấn đề với một chứng chỉ ký tự đại diện hợp lệ từ symantec.

Trước tiên hãy thử chạy ứng dụng java của bạn với -Djavax.net.debug = SSL để xem điều gì đang thực sự xảy ra.

Cuối cùng tôi đã nhập chứng chỉ trung gian khiến chuỗi chứng chỉ bị phá vỡ.

Tôi đã tải xuống chứng chỉ trung gian bị thiếu từ symantec (bạn có thể thấy liên kết tải xuống đến chứng chỉ bị thiếu trong nhật ký bắt tay ssl: http://svrintl-g3-aia.verisign.com/SVRIntlG3.cer trong trường hợp của tôi).

Và tôi đã nhập chứng chỉ trong kho khóa java. Sau khi nhập chứng chỉ trung gian, chứng chỉ ssl ký tự đại diện của tôi cuối cùng đã bắt đầu hoạt động:

keytool -import -keystore ../jre/lib/security/cacerts -trustcacerts -alias "VeriSign Class 3 International Server CA - G3" -file /pathto/SVRIntlG3.cer

Đây là trường hợp:
kisna

2
Để tránh nhầm lẫn, hãy chạy java (hoặc jcurl) với các tham số gỡ lỗi để xem "Chuỗi chứng chỉ" từ xa trong nhật ký, sau đó grep "CN" trong Truststore được truyền rõ ràng (thay vì mặc định) như sau, nếu không có, bạn cần thêm. ssllabs.com/ssltest/analyze.html sẽ hiển thị nếu certs phía máy chủ có chuỗi không hoàn chỉnh và bao gồm chứng chỉ đường dẫn chứng nhận trung gian cần được thêm vào. -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

Và, tất nhiên, bài viết chính thức để gỡ lỗi các vấn đề SSL: docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/... blogs.oracle.com/java-platform-group/entry/...
kisna

Tôi có cùng một vấn đề, điều này rất hữu ích, nhưng trong trường hợp của tôi, bạn chỉ phải thêm chứng chỉ máy chủ vào tệp cacerts của phiên bản JDK
Pigritia

41
  1. Xuất chứng chỉ SSL bằng Firefox. Bạn có thể xuất nó bằng cách nhấn URL trong trình duyệt và sau đó chọn tùy chọn để xuất chứng chỉ. Giả sử tên tệp cert là your.ssl.server.name.crt
  2. Đi đến JRE_HOME/binhoặcJDK/JRE/bin
  3. Gõ lệnh
  4. keytool -keystore ..\lib\security\cacerts -import -alias your.ssl.server.name -file .\relative-path-to-cert-file\your.ssl.server.name.crt
  5. Khởi động lại quy trình Java của bạn

13
Nếu được hỏi mật khẩu, hãy sử dụng mật khẩu kho khóa mặc định changeit( stackoverflow.com/a/22782035/1304830 ). Cũng hãy chắc chắn để chạy cmd như quản trị viên.
Fr4nz

22

@Gabe Martin - Câu trả lời của Dempes dành cho tôi. Và tôi đã viết một kịch bản nhỏ liên quan đến nó. Cách sử dụng rất đơn giản.

Cài đặt chứng chỉ từ máy chủ:

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

Xóa chứng chỉ đã cài đặt.

> 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;

Hoạt động hoàn hảo. Bạn đã làm rất tốt! . Đây là cách nó hoạt động: bắt đầu dịch vụ SSL của bạn (nếu nó không chạy) và thực thi lệnh như được giải thích (ví dụ ./java-cert-importer.sh example.com 1234). Đó là nó.
lepe

1
Công trình tuyệt vời. Tôi đã gặp lỗi trên máy chủ Jenkins kết nối với API bên ngoài làm thay đổi chứng chỉ của anh ấy và không thành công. Điều này giải quyết vấn đề của tôi
user9869932

Oracle nên đã cung cấp một cái gì đó như thế này ngay từ đầu hoặc không bao giờ tạo ra giải pháp SSL khủng khiếp của riêng họ. Xử lý chứng chỉ SSL phải là công việc của hệ điều hành.
Wolfgang Fahl

17

Trích dẫn từ Không còn 'không thể tìm thấy đường dẫn chứng nhận hợp lệ cho mục tiêu được yêu cầu'

khi cố gắng mở kết nối SSL đến máy chủ bằng JSSE. Điều này thường có nghĩa là máy chủ đang sử dụng chứng chỉ kiểm tra (có thể được tạo bằng keytool) chứ không phải chứng chỉ từ Cơ quan chứng nhận thương mại nổi tiếng như Verisign hoặc GoDaddy. Các trình duyệt web hiển thị các hộp thoại cảnh báo trong trường hợp này, nhưng vì JSSE không thể cho rằng người dùng tương tác có mặt nên nó chỉ ném một ngoại lệ theo mặc định.

Xác thực chứng chỉ là một phần rất quan trọng của bảo mật SSL, nhưng tôi không viết mục này để giải thích chi tiết. Nếu bạn quan tâm, bạn có thể bắt đầu bằng cách đọc Wikipedia blurb. Tôi đang viết mục này để chỉ ra một cách đơn giản để nói chuyện với chủ nhà đó với chứng chỉ kiểm tra, nếu bạn thực sự muốn.

Về cơ bản, bạn muốn thêm chứng chỉ của máy chủ vào KeyStore bằng chứng chỉ tin cậy của bạn

Hãy thử mã được cung cấp ở đó. Nó sẽ giúp.


5
Phần về "Xác thực chứng chỉ là một phần rất quan trọng của bảo mật SSL" không nhất thiết phải đúng. SSL cung cấp cho bạn hai đảm bảo: (1) rằng giao tiếp của bạn là riêng tư và (2) rằng bạn đang nói chuyện với một máy chủ được biết đến với NSA. (:-) Đôi khi bạn chỉ quan tâm đến quyền riêng tư của cuộc trò chuyện và sau đó chứng nhận tự ký là ổn. Xem Social-biz.org/2011/10/16/the-anti-ssl-conspiracy
AgilePro

@AgilePro SSL cung cấp cho bạn bốn đảm bảo: xác thực, quyền riêng tư, tính toàn vẹn và khả năng ủy quyền. Nó không cung cấp cho bạn bất kỳ đảm bảo rằng bạn đang nói chuyện với một máy chủ được biết đến với NSA. Chỉ quan tâm đến quyền riêng tư mà không cần xác thực là một mâu thuẫn trong điều khoản.
Hầu tước Lorne

@EJP Đồng ý rằng nếu bạn sử dụng chứng chỉ ứng dụng khách, bạn có thể xác thực và tôi cho rằng khả năng ủy quyền ... nhưng hầu hết việc sử dụng không phải với chứng chỉ ứng dụng khách. Bạn sẽ gọi sự khác biệt giữa chứng chỉ "tự ký" và chứng chỉ từ cơ quan ký kết là gì? Có thẩm quyền ký cho "tính toàn vẹn". Trò đùa của tôi về NSA là tất cả các cơ quan ký kết không thể tích cực bảo đảm sự độc lập khỏi mọi thứ. Thực sự không phải là hoang tưởng, nhưng vấn đề là chứng chỉ của bạn CHỈ là bí mật vì cơ quan ký có thể làm cho nó. Tự ký có thể bí mật hơn.
AgilePro

@AgilePro Sử dụng chứng chỉ máy chủ xác thực máy chủ và được yêu cầu bảo mật SSL, như đã lưu ý trong RFC 2246. Chứng chỉ hoàn toàn không bí mật: do đó, phần còn lại của bình luận của bạn không có ý nghĩa gì.
Hầu tước Lorne

6

Điều này đã giải quyết vấn đề của tôi,

Chúng ta cần nhập chứng chỉ vào java cục bộ. Nếu không chúng ta có thể có được ngoại lệ dưới đây.

    javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: xây dựng đường dẫn PKIX không thành công: sun.security.provider.certpath.SunCertPathBuilderException: không thể tìm thấy đường dẫn chứng nhận hợp lệ cho mục tiêu được yêu cầu
        tại sun.security.ssl.Alerts.getSSLException (Alerts.java:192)
        tại sun.security.ssl.SSLSocketImpl.firth (SSLSocketImpl.java:1949)
        tại sun.security.ssl.Handshaker.firthSE (Handshaker.java:302)

SSLPOKE là một công cụ nơi bạn có thể kiểm tra kết nối https từ máy cục bộ của mình.

Lệnh kiểm tra kết nối:

"%JAVA_HOME%/bin/java" SSLPoke <hostname> 443
    sun.security.validator.ValidatorException: xây dựng đường dẫn PKIX không thành công: 
    sun.security.provider.certpath.SunCertPathBuilderException: không thể tìm thấy đường dẫn chứng nhận hợp lệ đến mục tiêu được yêu cầu
        tại sun.security.validator.PKIXValidator.doBuild (PKIXValidator.java:387)
        tại sun.security.validator.PKIXValidator.engineValidate (PKIXValidator.java:292)
        tại sun.security.validator.Validator.validate (Validator.java:260)
        tại sun.security.ssl.X509TrustManagerImpl.validate (X509TrustManagerImpl.java:324)
        tại sun.security.ssl.X509TrustManagerImpl.checkTrusty (X509TrustManagerImpl.java:229)
        tại sun.security.ssl.X509TrustManagerImpl.checkServerTrusty (X509TrustManagerImpl.java:124)
        tại sun.security.ssl.ClientHandshaker.serverCertert (ClientHandshaker.java:1496)
        tại sun.security.ssl.ClientHandshaker. ProcessMessage (ClientHandshaker.java:216)
        tại sun.security.ssl.Handshaker. ProcessLoop (Handshaker.java:1026)
        tại sun.security.ssl.Handshaker. Process_record (Handshaker.java:961)
        tại sun.security.ssl.SSLSocketImpl.readRecord (SSLSocketImpl.java:1062)
        tại sun.security.ssl.SSLSocketImpl.performInitialHandshake (SSLSocketImpl.java:1375)
        tại sun.security.ssl.SSLSocketImpl.writeRecord (SSLSocketImpl.java:747)
        tại sun.security.ssl.AppOutputStream.write (AppOutputStream.java:123)
        tại sun.security.ssl.AppOutputStream.write (AppOutputStream.java:138)
        tại SSLPoke.main (SSLPoke.java:31)
    Nguyên nhân bởi: sun.security.provider.certpath.SunCertPathBuilderException: không thể tìm thấy đường dẫn chứng nhận hợp lệ để 
    mục tiêu yêu cầu
        tại sun.security.provider.certpath.SunCertPathBuilder.build (SunCertPathBuilder.java:141)
        tại sun.security.provider.certpath.SunCertPathBuilder.engineBuild (SunCertPathBuilder.java:126)
        tại java.security.cert.CertPathBuilder.build (CertPathBuilder.java:280)
        tại sun.security.validator.PKIXValidator.doBuild (PKIXValidator.java:382)
        ... 15 nữa
keytool -import -alias <anyname> -keystore "%JAVA_HOME%/jre/lib/security/cacerts" -file <cert path>

điều này trước tiên sẽ nhắc "Nhập mật khẩu kho khóa:" changeitlà mật khẩu mặc định. và cuối cùng là lời nhắc "Tin tưởng chứng chỉ này? [không]:", cung cấp "có" để thêm chứng chỉ vào kho khóa.

Xác minh:

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

5

Tôi chỉ có thể làm cho nó hoạt động với mã, tức là không cần sử dụng 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;
        }
    }
}

1
Btw, tôi đang sử dụng httpasyncclient: 4.0.1
Jonas Bergström

Tôi cần một cái gì đó tương tự, @ JonasBergström, giải pháp của bạn với SSLContext giúp ích rất nhiều.
EnterSB

8
Lưu ý rằng giải pháp này không an toàn.
Hầu tước Lorne

Cảm ơn bạn Jonas, giải pháp của bạn đã giải quyết vấn đề. Nhưng tôi thấy mất rất nhiều thời gian (3 - 5 giây) để tạo kết nối đầu tiên, sau đó mỗi kết nối chỉ cần 300-400 ms.
twcai

5

Nguồn gốc của lỗi này trên cá thể Apache 2.4 của tôi (sử dụng chứng chỉ ký tự đại diện Comodo) là một đường dẫn không đầy đủ đến chứng chỉ gốc có chữ ký SHA-1. Có nhiều chuỗi trong chứng chỉ được cấp và chuỗi dẫn đến chứng chỉ gốc SHA-1 bị thiếu chứng chỉ trung gian . Các trình duyệt hiện đại biết cách xử lý việc này, nhưng Java 7 không xử lý theo mặc định (mặc dù có một số cách phức tạp để thực hiện việc này trong mã). Kết quả là các thông báo lỗi trông giống hệt với trường hợp chứng chỉ tự ký:

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

Trong trường hợp này, thông báo "không thể tìm thấy đường dẫn chứng nhận hợp lệ đến mục tiêu được yêu cầu" đang được tạo ra do chứng chỉ trung gian bị thiếu. Bạn có thể kiểm tra chứng chỉ nào bị thiếu bằng cách sử dụng kiểm tra SSL Labs đối với máy chủ. Khi bạn tìm thấy chứng chỉ phù hợp, hãy tải xuống và (nếu máy chủ nằm dưới sự kiểm soát của bạn) hãy thêm nó vào gói chứng chỉ. Ngoài ra, bạn có thể nhập chứng chỉ bị thiếu tại địa phương. Giải quyết vấn đề này trên máy chủ là một giải pháp tổng quát hơn cho vấn đề.


ssllabs.com/ssltest là một vị cứu tinh, chỉ cần so sánh nó với xác nhận chứng chỉ làm việc.
kisna

5

Chỉ dành cho Windows, hãy làm theo các bước sau:

  1. Trong Chrome, hãy chuyển đến cài đặt.
  2. Trong Cài đặt, nhấp vào hiển thị cài đặt trước.
  3. Trong HTTPS / SSL Nhấp vào Quản lý chứng chỉ.
  4. Xuất chứng chỉ của bạn.
  5. Trong các tìm kiếm Windows (Nhấn phím windows trên bàn phím) gõ java.
  6. Chọn (Cấu hình Java) Tùy chọn sẽ mở Bảng điều khiển Java
  7. Chọn tab Bảo mật trong Bảng điều khiển Java
  8. Chọn Quản lý chứng chỉ
  9. Nhấp vào Nhập
  10. Trong tab (Người dùng) được chọn và loại chứng chỉ là (Chứng chỉ tin cậy)
  11. Nhấp vào nút nhập và duyệt đến chứng chỉ đã tải xuống và nhập nó.

4

Đối với những người thích Debian và Java đóng gói sẵn:

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

Đừng quên kiểm tra /etc/default/cacerts:

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

Để xóa chứng chỉ:

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

2

Điều này cũng có thể được gây ra bằng cách sử dụng certs GoDaddy với Java 7 được ký bằng SHA2.

Chrome và tất cả các trình duyệt khác đang bắt đầu phản đối các chứng chỉ SSL được ký bằng SHA1, vì nó không an toàn.

Thông tin thêm về vấn đề có thể được tìm thấy ở đây , cũng như cách giải quyết nó trên máy chủ của bạn nếu bạn cần ngay bây giờ.


2

Tôi gặp vấn đề tương tự với lỗi chứng chỉ và là do SNI và ứng dụng khách http mà tôi đã sử dụng không được SNI triển khai. Vì vậy, một bản cập nhật đã làm công việc

   <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.3.6</version>
    </dependency>

2

CẬP NHẬT: Đó là một khởi động lại giúp là trùng hợp ngẫu nhiên (tôi hy vọng như vậy, hoan hô!). Nguyên nhân thực sự của vấn đề là do: Khi Gradle được hướng dẫn sử dụng một kho khóa cụ thể, kho khóa đó cũng phải chứa tất cả các chứng chỉ gốc chính thức. Nếu không, nó không thể truy cập các thư viện từ kho thông thường. Những gì tôi phải làm là đây:

Nhập chứng chỉ tự ký:

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

Thêm chứng chỉ gốc chính thức:

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

Có lẽ daemon Gradle cũng cản trở. Có thể đáng để giết tất cả các daemon đang chạy ./gradlew --statusnếu mọi thứ bắt đầu ảm đạm.

BÀI VIẾT GỐC:

Không ai sẽ tin điều này, tôi biết. Tuy nhiên, nếu vẫn thất bại, hãy thử lại: Sau khi khởi động lại máy Mac của tôi, vấn đề đã biến mất. Grrr.

Bối cảnh: ./gradlew jar tiếp tục cho tôi "không thể tìm thấy đường dẫn chứng nhận hợp lệ cho mục tiêu được yêu cầu"

Tôi bị kẹt với chứng chỉ tự ký, được lưu từ trình duyệt, được nhập trong privateKeystore.jks. Sau đó, hướng dẫn Gradle làm việc với privateKeystore.jks:

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

Như đã đề cập, điều này chỉ hoạt động sau khi khởi động lại.


2

AVG phiên bản 18.1.3044 (với Windows 10) can thiệp vào ứng dụng Spring cục bộ của tôi.

Giải pháp: nhập vào phần AVG có tên "Web và email" và vô hiệu hóa "bảo vệ email". AVG chặn chứng chỉ nếu trang web không an toàn.


2

Đảm bảo rằng https://176.66.3,69:6443/ có chứng chỉ hợp lệ. trước tiên bạn có thể kiểm tra nó qua trình duyệt https không an toànnếu nó hoạt động trong trình duyệt thì nó sẽ hoạt động trong java.

đó là làm việc cho tôi


Và tôi nên làm gì nếu trình duyệt cũng phàn nàn?
Bố già

thử cài đặt chứng chỉ
Amr Ibrahim

2

Có rất nhiều cách để giải quyết điều này ...

Một cách là đặt chứng chỉ TrustStore trong tệp kho khóa và đặt nó vào đường dẫn của ứng dụng và đặt các thuộc tính hệ thống này theo phương thức chính:

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

Một cách khác là đặt kho khóa dưới dạng tệp tài nguyên bên trong tệp jar của dự án và tải nó:

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"));
  ...
}

Trong cửa sổ, bạn cũng có thể thử giải pháp này: https://stackoverflow.com/a/59056537/980442


Tôi đã tạo tệp kho khóa từ .crttệp CA ủy quyền theo cách này:

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


1

Bạn có hai tùy chọn, nhập chứng chỉ tự ký vào kho khóa của java cho mỗi jvm, phần mềm sẽ chạy hoặc thử nhà máy ssl không xác thực:

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

1

Có vấn đề như hình ảnh này.

nhập mô tả hình ảnh ở đây

Đã thử một vài giải pháp. Nhưng thấy rằng ngay cả khi đó là cùng một dự án, khi nó ở nơi làm việc của người khác, nó hoàn toàn ổn. Không cần cài đặt thêm. Vì vậy, chúng tôi đoán đó là một vấn đề môi trường. Chúng tôi đã thử thay đổi phiên bản JDK, IDE nhưng không hoạt động. mất khoảng 4 giờ để điều tra, cho đến khi chúng tôi thử câu trả lời được đánh giá cao nhất. Tôi không tìm thấy lỗi được đề cập trong câu trả lời đó nhưng tôi đã tìm thấy qua trình duyệt của mình về URL HTTP (khóa) rằng có chứng nhận của Charles. Sau đó, tôi nhận ra charles của tôi là tất cả các thời gian. Miễn là tôi tắt nó đi, nó sẽ hoạt động tốt.

Vì vậy, tôi để lại kinh nghiệm của tôi có thể hữu ích cho trường hợp của bạn.


0

Trong trường hợp của tôi, tôi đang chạy MacOs High Sierra với Java 1.6. Tệp cacert ở một vị trí khác với tham chiếu ở trên trong câu trả lời của Gabe Martin-Dempesy. Tệp cacert cũng đã được liên kết đến một vị trí khác (/ Library / Internet Plug-Ins / JavaAppletPlugin.plugin / Nội dung / Trang chủ / lib / security / cacerts).

Sử dụng FireFox, tôi đã xuất chứng chỉ từ trang web đang đề cập đến một tệp cục bộ có tên là "exportCertFile.crt". Từ đó, tôi đã sử dụng keytool để di chuyển chứng chỉ vào tệp cacert. Điều này đã khắc phục vấn đề.

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

0

đầu tiên Tải xuống chứng chỉ ssl sau đó bạn có thể đi đến đường dẫn java bin của mình thực hiện lệnh bên dưới trong bảng điều khiển.

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

-1

Trong trường hợp của tôi, tôi đã có cả kho khóa và cửa hàng ủy thác có cùng một chứng chỉ vì vậy loại bỏ Truststore đã giúp. Đôi khi, chuỗi chứng chỉ có thể là một vấn đề nếu bạn có nhiều bản sao chứng chỉ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.