ทำไม SSL handshake ให้ข้อยกเว้น 'ไม่สามารถสร้าง DH keypair' ได้


142

เมื่อฉันทำการเชื่อมต่อ SSL กับเซิร์ฟเวอร์ IRC บางตัว (แต่ไม่ใช่อื่น ๆ - น่าจะเป็นเพราะวิธีการเข้ารหัสที่เซิร์ฟเวอร์ต้องการ) ฉันได้รับข้อยกเว้นต่อไปนี้:

Caused by: java.lang.RuntimeException: Could not generate DH keypair
    at com.sun.net.ssl.internal.ssl.DHCrypt.<init>(DHCrypt.java:106)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverKeyExchange(ClientHandshaker.java:556)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:183)
    at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:593)
    at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:529)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:893)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1165)
    ... 3 more

สาเหตุสุดท้าย:

Caused by: java.security.InvalidAlgorithmParameterException: Prime size must be multiple of 64, and can only range from 512 to 1024 (inclusive)
    at com.sun.crypto.provider.DHKeyPairGenerator.initialize(DashoA13*..)
    at java.security.KeyPairGenerator$Delegate.initialize(KeyPairGenerator.java:627)
    at com.sun.net.ssl.internal.ssl.DHCrypt.<init>(DHCrypt.java:100)
    ... 10 more

ตัวอย่างของเซิร์ฟเวอร์ที่แสดงให้เห็นถึงปัญหานี้คือ shutter.esper.net:6697 (นี่คือเซิร์ฟเวอร์ IRC) ตัวอย่างของเซิร์ฟเวอร์ที่ไม่แสดงให้เห็นถึงปัญหาคือ kornbluth.freenode.net:6697 [ไม่น่าแปลกใจเลยที่เซิร์ฟเวอร์ทั้งหมดในแต่ละเครือข่ายมีพฤติกรรมการใช้งานเหมือนกัน]

รหัสของฉัน (ซึ่งดังที่บันทึกไว้จะทำงานเมื่อเชื่อมต่อกับเซิร์ฟเวอร์ SSL บางตัว) คือ:

    SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(null, trustAllCerts, new SecureRandom());
    s = (SSLSocket)sslContext.getSocketFactory().createSocket();
    s.connect(new InetSocketAddress(host, port), timeout);
    s.setSoTimeout(0);
    ((SSLSocket)s).startHandshake();

มันเป็นจุดเริ่มต้นครั้งล่าสุดจับมือกันที่ทำให้เกิดข้อยกเว้น และใช่มีเวทมนตร์ที่เกิดขึ้นกับ 'trustAllCerts'; รหัสนั้นบังคับให้ระบบ SSL ไม่ตรวจสอบใบรับรอง (ดังนั้น ... ไม่ใช่ปัญหาใบรับรอง)

เห็นได้ชัดว่ามีความเป็นไปได้อย่างหนึ่งคือเซิร์ฟเวอร์ของ esper นั้นได้รับการกำหนดค่าผิดพลาด แต่ฉันค้นหาและไม่พบการอ้างอิงอื่น ๆ กับผู้ที่มีปัญหากับพอร์ต SSL ของ esper และ 'openssl' เชื่อมต่อกับมัน (ดูด้านล่าง) ดังนั้นฉันสงสัยว่านี่เป็นข้อ จำกัด ของการสนับสนุน SSL เริ่มต้นของ Java หรือบางอย่าง ข้อเสนอแนะใด ๆ

นี่คือสิ่งที่เกิดขึ้นเมื่อฉันเชื่อมต่อกับช่องรับแสง esper.net 6697 โดยใช้ 'openssl' จาก commandline:

~ $ openssl s_client -connect aperture.esper.net:6697
CONNECTED(00000003)
depth=0 /C=GB/ST=England/L=London/O=EsperNet/OU=aperture.esper.net/CN=*.esper.net/emailAddress=support@esper.net
verify error:num=18:self signed certificate
verify return:1
depth=0 /C=GB/ST=England/L=London/O=EsperNet/OU=aperture.esper.net/CN=*.esper.net/emailAddress=support@esper.net
verify return:1
---
Certificate chain
 0 s:/C=GB/ST=England/L=London/O=EsperNet/OU=aperture.esper.net/CN=*.esper.net/emailAddress=support@esper.net
   i:/C=GB/ST=England/L=London/O=EsperNet/OU=aperture.esper.net/CN=*.esper.net/emailAddress=support@esper.net
---
Server certificate
-----BEGIN CERTIFICATE-----
[There was a certificate here, but I deleted it to save space]
-----END CERTIFICATE-----
subject=/C=GB/ST=England/L=London/O=EsperNet/OU=aperture.esper.net/CN=*.esper.net/emailAddress=support@esper.net
issuer=/C=GB/ST=England/L=London/O=EsperNet/OU=aperture.esper.net/CN=*.esper.net/emailAddress=support@esper.net
---
No client certificate CA names sent
---
SSL handshake has read 2178 bytes and written 468 bytes
---
New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1
    Cipher    : DHE-RSA-AES256-SHA
    Session-ID: 51F1D40A1B044700365D3BD1C61ABC745FB0C347A334E1410946DCB5EFE37AFD
    Session-ID-ctx: 
    Master-Key: DF8194F6A60B073E049C87284856B5561476315145B55E35811028C4D97F77696F676DB019BB6E271E9965F289A99083
    Key-Arg   : None
    Start Time: 1311801833
    Timeout   : 300 (sec)
    Verify return code: 18 (self signed certificate)
---

ดังที่ได้กล่าวมาแล้วมันเชื่อมต่อได้สำเร็จซึ่งมากกว่าที่คุณสามารถพูดได้สำหรับแอป Java ของฉัน

มันควรจะเกี่ยวข้องหรือไม่ฉันใช้ OS X 10.6.8, Java เวอร์ชัน 1.6.0_26


2
เหตุผลน่าจะเป็นเช่นนี้: Prime size must be multiple of 64, and can only range from 512 to 1024 (inclusive). ไม่ทราบว่าเซิร์ฟเวอร์ขนาดนี้ถูกส่งไปที่ใดและสเปคบอกอะไรเกี่ยวกับเรื่องนี้
— Paŭlo Ebermann

@ PaŭloEbermann: จริงๆแล้วคุณสามารถเห็นขนาดของเซิร์ฟเวอร์ที่ใช้ในopensslผลลัพธ์ในคำถาม: "Cipher is DHE-RSA-AES256-SHA, พับลิกคีย์เซิร์ฟเวอร์คือ 2048 บิต" และในปี 2048> 1024 :-)
— sleske

@sleske: ไม่แน่นอน Server public key (size)เคยเป็นและเป็นกุญแจสำคัญในใบรับรอง s_clientในปี 2011 ไม่ได้แสดงกุญแจชั่วคราวเลย 1.0.2 ในปี 2558 และสูงกว่าทำServer Temp Keyหลายบรรทัด แม้ว่าเซิร์ฟเวอร์ที่ดีมักจะทำให้ขนาด DHE เหมือนกับขนาด RSA-auth
— dave_thompson_085

คำตอบ:


117

ปัญหาคือขนาดที่สำคัญ ขนาดที่ยอมรับได้สูงสุดที่ Java ยอมรับคือ 1024 บิต นี่เป็นปัญหาที่ทราบแล้ว (ดูJDK-6521495 )

รายงานข้อผิดพลาดที่ฉันเชื่อมโยงเพื่อระบุวิธีแก้ปัญหาโดยใช้การดำเนินการ JCE ของ BouncyCastle หวังว่าจะได้ผลกับคุณ

UPDATE

สิ่งนี้ถูกรายงานว่าเป็นข้อผิดพลาดJDK-7044060และได้รับการแก้ไขเมื่อเร็ว ๆ นี้

อย่างไรก็ตามโปรดทราบว่าขีด จำกัด นั้นเพิ่มขึ้นเป็น 2048 บิตเท่านั้น สำหรับขนาด> 2048 บิตมีJDK-8072452 - ลบขนาดสำคัญสูงสุดของคีย์ DH ; การแก้ไขดูเหมือนจะเป็น 9


14
+1 ทุกคนที่มีบัญชีเครือข่ายผู้พัฒนา Sun โปรดลงคะแนนให้ข้อผิดพลาดนี้
— Paŭlo Ebermann

1
ขอบคุณ ดูเหมือนว่าจะเป็นปัญหาร้ายแรงเนื่องจากเซิร์ฟเวอร์มีขนาดที่ใหญ่ขึ้น! :( ฉันลองใช้ BouncyCastle หากคุณตั้งค่าเป็นผู้ให้บริการที่ต้องการระบบขัดข้องด้วยข้อยกเว้นที่แตกต่างกัน (ถอนหายใจ) และฉันไม่เห็นวิธีการใช้ที่ชัดเจนสำหรับ DH เพียงอย่างเดียวอย่างไรก็ตามฉันพบวิธีแก้ปัญหาอื่นซึ่งฉัน จะเพิ่มเป็นคำตอบใหม่ (ไม่สวย)
— sam

3
เย็น. สิ่งนี้ได้รับการแก้ไขใน Java เวอร์ชันใหม่กว่า แต่คำถามของฉันเกี่ยวกับการใช้รุ่นที่เก่ากว่า .. เมื่อฉันใช้รุ่นที่เก่ากว่าบางครั้งก็ใช้งานได้และบางครั้งก็มีข้อยกเว้นข้างต้น .. ทำไมพฤติกรรมแบบสุ่มเหรอ? หากมีข้อบกพร่องใน java แล้วฉันเดาว่ามันจะไม่ทำงานหรือไม่
— N ..

2
การแก้ไขในปี 2048 นั้นถูกส่งกลับไปที่ IcedTea 2.5.3 รุ่นที่ใหม่กว่าของ IcedTea เพิ่มเป็น 4096
— fuzzyTew

1
ปัญหาคือ DH prime size ขนาดที่ยอมรับได้สูงสุดที่ Java ยอมรับคือ 2048 บิต ในขณะที่เรารอให้ Oracle ขยายขีด จำกัด คุณสามารถรวบรวมกับ Excelsior Jet ซึ่งมีขีด จำกัด ที่ขยายได้
— user1332994

67

คำตอบ "ไฟล์คำสั่งนโยบายความแข็งแกร่งของไฟล์ จำกัด ขอบเขตการเข้ารหัสของ Java Cryptography (JCE) ไม่ทำงานสำหรับฉัน แต่คำแนะนำของผู้ให้บริการ JCE ของ BouncyCastle นั้น

นี่คือขั้นตอนที่ฉันทำโดยใช้ Java 1.6.0_65-b14-462 บน Mac OSC 10.7.5

1) ดาวน์โหลดไหเหล่านี้:

2) ย้ายไหเหล่านี้ไปที่ $ JAVA_HOME / lib / ext

3) แก้ไข $ JAVA_HOME / lib / security / java.security ดังนี้: security.provider.1 = org.bouncycastle.jce.provider.BouncyCastleProvider

รีสตาร์ทแอปโดยใช้ JRE และลองใหม่


5
ทำงานได้สำหรับฉัน! แม้ว่าจะไม่แน่ใจว่าฉันกำลังทำอะไรอยู่
— DiveIn ถึง

11
security.provider.2 = org.bouncycastle.jce.provider.BouncyCastleProvider ทำงานได้ดีขึ้นโดยวางไว้ที่ 1 ทำให้เกิดข้อผิดพลาดในซอฟต์แวร์เริ่มต้น
— TinusSky

1
สิ่งนี้ใช้ได้กับฉันเช่นกัน แต่ฉันได้เพิ่มผู้ให้บริการแบบไดนามิก ขอ คำตอบที่นี่อีกครั้งเพื่อรับรายละเอียด
— v.ladynev

ขอบคุณตันสิ่งนี้ใช้ได้สำหรับฉันและจำเป็นเพื่อสร้างแหล่ง Tomcat 7.0.78 สำเร็จ
— phillipuniverse

@ mjj1409 ใน Java 1.5 เราไม่มี $ JAVA_HOME / เส้นทาง / ความปลอดภัย
— Mostafa

15

นี่เป็นวิธีแก้ปัญหาของฉัน (java 1.6) ก็จะสนใจว่าทำไมฉันต้องทำเช่นนี้:

ฉันสังเกตเห็นจาก javax.security.debug = ssl ซึ่งบางครั้งชุดรหัสที่ใช้คือ TLS_DHE _... และบางครั้งมันเป็น TLS_ECDHE _.... ในภายหลังจะเกิดขึ้นหากฉันเพิ่ม BouncyCastle หากเลือก TLS_ECDHE_ เวลาส่วนใหญ่ที่ใช้งานได้ แต่ไม่ใช่ ALWAYS ดังนั้นการเพิ่มผู้ให้บริการ BouncyCastle จึงไม่น่าเชื่อถือ (ล้มเหลวด้วยข้อผิดพลาดเดียวกันทุกครั้งหรือมากกว่านั้น) ผมคิดว่าหนึ่งในการดำเนินงานที่ดวงอาทิตย์ SSL บางครั้งก็เลือกDHEบางครั้งก็เลือกECDHE

ดังนั้นวิธีการแก้ปัญหาที่โพสต์ที่นี่อาศัยการลบ TLS_DHE_ ciphers อย่างสมบูรณ์ หมายเหตุ: BouncyCastle ไม่จำเป็นสำหรับการแก้ปัญหา

ดังนั้นสร้างไฟล์การรับรองเซิร์ฟเวอร์โดย:

echo |openssl s_client -connect example.org:443 2>&1 |sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'

บันทึกสิ่งนี้เนื่องจากจะมีการอ้างอิงในภายหลังกว่าที่นี่คือโซลูชันสำหรับ SSL http get ไม่รวม TLS_DHE_ cipher suites

package org.example.security;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;

import org.apache.log4j.Logger;

public class SSLExcludeCipherConnectionHelper {

    private Logger logger = Logger.getLogger(SSLExcludeCipherConnectionHelper.class);

    private String[] exludedCipherSuites = {"_DHE_","_DH_"};

    private String trustCert = null;

    private TrustManagerFactory tmf;

    public void setExludedCipherSuites(String[] exludedCipherSuites) {
        this.exludedCipherSuites = exludedCipherSuites;
    }

    public SSLExcludeCipherConnectionHelper(String trustCert) {
        super();
        this.trustCert = trustCert;
        //Security.addProvider(new BouncyCastleProvider());
        try {
            this.initTrustManager();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void initTrustManager() throws Exception {
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        InputStream caInput = new BufferedInputStream(new FileInputStream(trustCert));
        Certificate ca = null;
        try {
            ca = cf.generateCertificate(caInput);
            logger.debug("ca=" + ((X509Certificate) ca).getSubjectDN());
        } finally {
            caInput.close();
        }

        // Create a KeyStore containing our trusted CAs
        KeyStore keyStore = KeyStore.getInstance("jks");
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", ca);

        // Create a TrustManager that trusts the CAs in our KeyStore
        String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);
    }

    public String get(URL url) throws Exception {
        // Create an SSLContext that uses our TrustManager
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, tmf.getTrustManagers(), null);
        SSLParameters params = context.getSupportedSSLParameters();
        List<String> enabledCiphers = new ArrayList<String>();
        for (String cipher : params.getCipherSuites()) {
            boolean exclude = false;
            if (exludedCipherSuites != null) {
                for (int i=0; i<exludedCipherSuites.length && !exclude; i++) {
                    exclude = cipher.indexOf(exludedCipherSuites[i]) >= 0;
                }
            }
            if (!exclude) {
                enabledCiphers.add(cipher);
            }
        }
        String[] cArray = new String[enabledCiphers.size()];
        enabledCiphers.toArray(cArray);

        // Tell the URLConnection to use a SocketFactory from our SSLContext
        HttpsURLConnection urlConnection =
            (HttpsURLConnection)url.openConnection();
        SSLSocketFactory sf = context.getSocketFactory();
        sf = new DOSSLSocketFactory(sf, cArray);
        urlConnection.setSSLSocketFactory(sf);
        BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
        String inputLine;
        StringBuffer buffer = new StringBuffer();
        while ((inputLine = in.readLine()) != null) 
            buffer.append(inputLine);
        in.close();

        return buffer.toString();
    }

    private class DOSSLSocketFactory extends javax.net.ssl.SSLSocketFactory {

        private SSLSocketFactory sf = null;
        private String[] enabledCiphers = null;

        private DOSSLSocketFactory(SSLSocketFactory sf, String[] enabledCiphers) {
            super();
            this.sf = sf;
            this.enabledCiphers = enabledCiphers;
        }

        private Socket getSocketWithEnabledCiphers(Socket socket) {
            if (enabledCiphers != null && socket != null && socket instanceof SSLSocket)
                ((SSLSocket)socket).setEnabledCipherSuites(enabledCiphers);

            return socket;
        }

        @Override
        public Socket createSocket(Socket s, String host, int port,
                boolean autoClose) throws IOException {
            return getSocketWithEnabledCiphers(sf.createSocket(s, host, port, autoClose));
        }

        @Override
        public String[] getDefaultCipherSuites() {
            return sf.getDefaultCipherSuites();
        }

        @Override
        public String[] getSupportedCipherSuites() {
            if (enabledCiphers == null)
                return sf.getSupportedCipherSuites();
            else
                return enabledCiphers;
        }

        @Override
        public Socket createSocket(String host, int port) throws IOException,
                UnknownHostException {
            return getSocketWithEnabledCiphers(sf.createSocket(host, port));
        }

        @Override
        public Socket createSocket(InetAddress address, int port)
                throws IOException {
            return getSocketWithEnabledCiphers(sf.createSocket(address, port));
        }

        @Override
        public Socket createSocket(String host, int port, InetAddress localAddress,
                int localPort) throws IOException, UnknownHostException {
            return getSocketWithEnabledCiphers(sf.createSocket(host, port, localAddress, localPort));
        }

        @Override
        public Socket createSocket(InetAddress address, int port,
                InetAddress localaddress, int localport) throws IOException {
            return getSocketWithEnabledCiphers(sf.createSocket(address, port, localaddress, localport));
        }

    }
}

สุดท้ายนี่คือวิธีการใช้ (certFilePath หากเส้นทางของใบรับรองที่บันทึกจาก openssl):

try {
            URL url = new URL("https://www.example.org?q=somedata");            
            SSLExcludeCipherConnectionHelper sslExclHelper = new SSLExcludeCipherConnectionHelper(certFilePath);
            logger.debug(
                    sslExclHelper.get(url)
            );
        } catch (Exception ex) {
            ex.printStackTrace();
        }

9
เพิ่งทดสอบวิธีการแก้ปัญหาของคุณ มันทำงานได้ตามที่ตั้งใจไว้ ขอบคุณ จริงๆแล้วเพียงแค่เพิ่มjdk.tls.disabledAlgorithms=DHE, ECDHEเข้าไปJDK_HOME/jre/lib/security/java.securityยังใช้งานได้และหลีกเลี่ยงรหัสนี้ทั้งหมด
— Ludovic Guillaume

3
เพียงแค่ปิดใช้งาน DHE ได้ผลสำหรับฉัน: jdk.tls.disabledAlgorithms=DHE. ใช้ 1.7.0_85-b15
— ฟานฉ

1
เพิ่ม jdk.tls.disabledAlgorithms = DHE, ECDHE ใน JDK_HOME / jre / lib / security / java.security และทำงานได้ดี! ขอบคุณ! ใช้ 1.7.0_79
— Eric Na

1
อย่าปิดการใช้งาน ECDHE มันแตกต่างจาก DHE และไม่ได้ใช้หมายเลขเฉพาะ
— kubanczyk

1
ใครช่วยบอกฉันหน่อยได้ไหมว่าฉันจะได้รับ 'certFilePath' ได้อย่างไร ฉันติดอยู่กับเรื่องนี้เป็นเวลาหนึ่งสัปดาห์ @Zsozso
— user1172490

13

คำตอบข้างต้นถูกต้อง แต่ในแง่ของการแก้ปัญหาฉันมีปัญหากับการใช้งาน BouncyCastle เมื่อฉันตั้งเป็นผู้ให้บริการที่ต้องการ:

java.lang.ArrayIndexOutOfBoundsException: 64
    at com.sun.crypto.provider.TlsPrfGenerator.expand(DashoA13*..)

สิ่งนี้ถูกกล่าวถึงในฟอรัมเดียวที่ฉันพบซึ่งไม่ได้กล่าวถึงวิธีแก้ไขปัญหา http://www.javakb.com/Uwe/Forum.aspx/java-programmer/47512/TLS-problems

ฉันพบโซลูชันอื่นซึ่งใช้งานได้กับกรณีของฉันแม้ว่าฉันจะไม่พอใจเลย วิธีแก้ไขคือตั้งค่าเพื่อไม่ให้อัลกอริทึม Diffie-Hellman เลย จากนั้นสมมติว่าเซิร์ฟเวอร์รองรับอัลกอริธึมสำรองมันจะถูกเลือกระหว่างการเจรจาปกติ เห็นได้ชัดว่าข้อเสียของเรื่องนี้ก็คือถ้าใครบางคนจัดการหาเซิร์ฟเวอร์ที่รองรับ Diffie-Hellman ที่ 1024 บิตหรือน้อยกว่านั้นจริง ๆ แล้วมันจะไม่ทำงานในที่ที่มันเคยทำงานมาก่อน

นี่คือรหัสที่ใช้งานได้กับ SSLSocket (ก่อนที่คุณจะเชื่อมต่อ)

List<String> limited = new LinkedList<String>();
for(String suite : ((SSLSocket)s).getEnabledCipherSuites())
{
    if(!suite.contains("_DHE_"))
    {
        limited.add(suite);
    }
}
((SSLSocket)s).setEnabledCipherSuites(limited.toArray(
    new String[limited.size()]));

น่ารังเกียจ


1
น่าเศร้าที่นี่เป็นวิธีเดียว :( ตั๋วใบนั้นเปิดให้บริการตั้งแต่ '07 แปลก ๆ ที่ไม่ได้ทำอะไรเลยใน 4 ปี
— Vivin Paliath

ฉันยังใหม่กับหลักทรัพย์ของจาวา โปรดช่วยฉันควรเขียนรหัสชิ้นนี้ที่ไหน
— Shashank

ฉันลองทุกวิธีในหัวข้อนี้และนี่เป็นทางเดียวที่ทำงานกับ ibm jvm ของฉัน (ibm-java-s390x-60)
— Gianluca Greco

@Sam ตัวแปรอะไรใน (SSLSocket) s?
— Mostafa

13

คุณสามารถปิดใช้งาน DHE ได้อย่างสมบูรณ์ใน jdk ของคุณแก้ไข jre / lib / security / java.security และตรวจสอบว่า DHE ถูกปิดใช้งานเช่น ชอบ

jdk.tls.disabledAlgorithms=SSLv3, DHE.


4
ที่มีเฉพาะใน JDK 1.7 และใหม่กว่า ลิงก์
— hoangthienan

แก้ไขปัญหาให้ฉัน JDK 1.8.0_144-b01
— MrSmith42

12

คุณสามารถติดตั้งผู้ให้บริการแบบไดนามิก:

1) ดาวน์โหลดไหเหล่านี้:

  • bcprov-jdk15on-152.jar
  • bcprov-ext-jdk15on-152.jar

2) คัดลอกไหไปที่WEB-INF/lib(หรือ classpath ของคุณ)

3) เพิ่มผู้ให้บริการแบบไดนามิก:

import org.bouncycastle.jce.provider.BouncyCastleProvider;

...

Security.addProvider(new BouncyCastleProvider());


โซลูชันนี้ใช้งานได้ดีและเหมาะกับกรณีของฉันเนื่องจากฉันต้องการเปลี่ยนแปลงในระดับโครงการเท่านั้นไม่ใช่ระดับเซิร์ฟเวอร์ / สภาพแวดล้อม ขอบคุณ
— ishanbakshi

ขอบคุณ! สิ่งนี้ใช้ได้สำหรับฉัน ในกรณีของฉันมันเป็นการนำเข้า bcp 1.4 ทำให้อีเมลไปยัง google ล้มเหลว
— Japheth Ongeri - inkalimeva

ฉันได้รับ javax.net.ssl.SSLHandshakeException: ไม่รองรับเส้นโค้ง: 29 กับรุ่นจาวา 1.6.0_27
— อีก


6

หากคุณใช้ jdk1.7.0_04 ให้อัพเกรดเป็น jdk1.7.0_21 ปัญหาได้รับการแก้ไขในการอัปเดตนั้น


2
ฉันเพิ่งดาวน์โหลด Java SE Development Kit 7u25 และตามโปรแกรมเล็ก ๆ ฉันเขียนเพื่อกำหนดขนาด DH สูงสุดที่รองรับก็ยังคง 1024
— user2666524

1
ปัญหายังคงมีอยู่กับ JDK 1.7.0_25
— Sébastien Vanmechelen

การอัปเดต jre ใช้งานได้สำหรับฉันแล้ว 6.22 ได้รับการอัปเดตเป็น 7.59 แก้ไขปัญหา.
— Elazaron

1
@Shashank - การอัพเกรดเป็น JDK 1.8.0_73 ได้ผลสำหรับฉัน
— dgoverde

DHKeyPairs ที่มีความยาวบิตมากกว่า 1024 แนะนำจากJDK 1.7.0_91แต่ไม่มีให้บริการในที่สาธารณะ
— coder อีก

6

เป็นไปได้ว่าคุณมีการพึ่งพา Maven ไม่ถูกต้อง คุณต้องค้นหาไลบรารีเหล่านี้ในลำดับชั้นการพึ่งพา Maven:

bcprov-jdk14, bcpkix-jdk14, bcmail-jdk14

หากคุณมีการพึ่งพาเหล่านี้ซึ่งเป็นข้อผิดพลาดและคุณควรทำสิ่งนี้:

เพิ่มการพึ่งพา:

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcmail-jdk15on</artifactId>
    <version>1.59</version>
</dependency>

ยกเว้นการพึ่งพาเหล่านี้จากสิ่งประดิษฐ์ที่มีการขึ้นต่อกันที่ไม่ถูกต้องในกรณีของฉันคือ:

<dependency>
    <groupId>com.lowagie</groupId>
    <artifactId>itext</artifactId>
    <version>2.1.7</version>
    <exclusions>
        <exclusion>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bctsp-jdk14</artifactId>                
        </exclusion>
        <exclusion>
            <groupId>bouncycastle</groupId>
            <artifactId>bcprov-jdk14</artifactId>               
        </exclusion>
        <exclusion>
            <groupId>bouncycastle</groupId>
            <artifactId>bcmail-jdk14</artifactId>               
        </exclusion>
    </exclusions>       
</dependency>

คำถามได้รับคำตอบมากมายและมีคำตอบที่ถูกต้อง ยิ่งกว่านั้นคำถามได้ถูกถามมากว่า 6 ปีแล้ว ฉันไม่แน่ใจว่ายังเกี่ยวข้องอยู่หรือไม่
— David Guyon

5

ลองดาวน์โหลด "ไฟล์ Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy" จากไซต์ดาวน์โหลด Javaและแทนที่ไฟล์ใน JRE ของคุณ

สิ่งนี้ใช้ได้สำหรับฉันและฉันไม่จำเป็นต้องใช้ BouncyCastle - Sun JCE มาตรฐานสามารถเชื่อมต่อกับเซิร์ฟเวอร์ได้

PS ฉันได้รับข้อผิดพลาดเดียวกัน (ArrayIndexOutOfBoundsException: 64) เมื่อฉันลองใช้ BouncyCastle ก่อนเปลี่ยนไฟล์นโยบายดังนั้นดูเหมือนว่าสถานการณ์ของเราจะคล้ายกันมาก


คุณทำอะไรอีกแล้วหรือยัง? หรือเพียงแค่คัดลอก 2 ไฟล์ลงในโฟลเดอร์?
— Joergi

มันผ่านมานานแล้ว แต่เท่าที่ฉันจำได้นั่นคือทั้งหมดที่ฉันต้องทำ นอกเหนือจากการรีสตาร์ทกระบวนการ Java ที่รันอยู่หลังจากนั้น
— mjomble

5

หากคุณยังคงถูกกัดโดยปัญหานี้และคุณกำลังใช้ Apache httpd v> 2.4.7 ลองทำสิ่งนี้: http://httpd.apache.org/docs/current/ssl/ssl_faq.html#javadh

คัดลอกมาจาก url :

เริ่มต้นด้วยรุ่น 2.4.7, mod_ssl จะใช้พารามิเตอร์ DH ซึ่งรวมถึงช่วงเวลาที่มีความยาวมากกว่า 1024 บิต Java 7 และก่อนหน้านี้ จำกัด การสนับสนุน DH prime size เป็นสูงสุด 1024 บิตอย่างไรก็ตาม

หากไคลเอ็นต์ที่ใช้ Java ของคุณยกเลิกด้วยข้อยกเว้นเช่น java.lang.RuntimeException: ไม่สามารถสร้าง DH keypair และ java.security.InvalidAlgorithmParameterException: ขนาดที่สำคัญจะต้องมีค่าเท่ากับ 64 และสามารถมีช่วงจาก 512 ถึง 1024 (รวม) และ httpd บันทึกข้อผิดพลาดภายในการแจ้งเตือน tlsv1 (หมายเลขการแจ้งเตือน SSL 80) (ที่ข้อมูล LogLevel หรือสูงกว่า) คุณสามารถจัดเรียงรายการการเข้ารหัสของ mod_ssl ใหม่ด้วย SSLCipherSuite (อาจใช้ร่วมกับ SSLHonorCipherOrder) หรือคุณสามารถใช้พารามิเตอร์ DH แบบกำหนดเองได้ ซึ่งจะมีความสำคัญเหนือกว่าพารามิเตอร์ DH ในตัวใด ๆ

ในการสร้างพารามิเตอร์ DH ที่กำหนดเองให้ใช้

openssl dhparam 1024

คำสั่ง หรือคุณสามารถใช้พารามิเตอร์ DHA 1024- บิตมาตรฐานต่อไปนี้จาก RFC 2409, ส่วนที่ 6.2:

-----BEGIN DH PARAMETERS-----
MIGHAoGBAP//////////yQ/aoiFowjTExmKLgNwc0SkCTgiKZ8x0Agu+pjsTmyJR
Sgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVtbVHCReSFtXZiXn7G9ExC6aY37WsL
/1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR7OZTgf//////////AgEC
-----END DH PARAMETERS-----

เพิ่มพารามิเตอร์ที่กำหนดเองรวมถึงบรรทัด "BEGIN DH พารามิเตอร์" และ "END DH พารามิเตอร์" ไปยังจุดสิ้นสุดของไฟล์ใบรับรองแรกที่คุณกำหนดค่าโดยใช้คำสั่ง SSLCertificateFile


ฉันใช้ java 1.6 บนฝั่งไคลเอ็นต์และแก้ไขปัญหาของฉันได้ ฉันไม่ได้ลดชุดรหัสหรือชอบ แต่เพิ่ม DH param ที่สร้างขึ้นเองลงในไฟล์ใบรับรอง ..


โปรดทราบว่าตอนนี้เชื่อว่า 1024 บิต DH เป็นไปได้ที่คำนวณได้ (แม้ว่าจะมีราคาแพงมาก) เพื่อทำลาย
— plugwash

2

ฉันมีปัญหาเดียวกันกับเซิร์ฟเวอร์ Yandex Maps, JDK 1.6 และ Apache HttpClient 4.2.1 ข้อผิดพลาดคือ

javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated

ด้วยการแก้ปัญหาที่เปิดใช้งานโดย-Djavax.net.debug=all มีข้อความในบันทึก

Could not generate DH keypair

ฉันได้แก้ไขปัญหานี้โดยเพิ่มห้องสมุด BouncyCastle bcprov-jdk16-1.46.jarและลงทะเบียนผู้ให้บริการในคลาสบริการแผนที่

public class MapService {

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    public GeocodeResult geocode() {

    }

}

MapServiceผู้ให้บริการที่มีการลงทะเบียนที่ใช้งานครั้งแรกของ


2

ฉันพบข้อผิดพลาด SSL บนเซิร์ฟเวอร์ CentOS ที่ใช้ JDK 6

แผนของฉันคือการติดตั้ง JDK เวอร์ชันที่สูงขึ้น (JDK 7) ให้อยู่ร่วมกับ JDK 6 แต่ปรากฎว่าเพียงแค่ติดตั้ง JDK ที่ใหม่กว่าด้วยrpm -iไม่เพียงพอ

การติดตั้ง JDK 7 จะทำได้สำเร็จด้วยrpm -Uตัวเลือกการอัปเกรดเท่านั้นดังที่แสดงด้านล่าง

1. ดาวน์โหลด JDK 7

wget -O /root/jdk-7u79-linux-x64.rpm --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; o raclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/7u79-b15/jdk-7u79-linux-x64.rpm"

2. การติดตั้ง RPM ล้มเหลว

rpm -ivh jdk-7u79-linux-x64.rpm
Preparing...                ########################################### [100%]
        file /etc/init.d/jexec from install of jdk-2000:1.7.0_79-fcs.x86_64 conflicts with file from package jdk-2000:1.6.0_43-fcs.x86_64

3. การอัพเกรด RPM สำเร็จ

rpm -Uvh jdk-7u79-linux-x64.rpm
Preparing...                ########################################### [100%]
   1:jdk                    ########################################### [100%]
Unpacking JAR files...
        rt.jar...
        jsse.jar...
        charsets.jar...
        tools.jar...
        localedata.jar...
        jfxrt.jar...

4. ยืนยันเวอร์ชันใหม่

java -version
java version "1.7.0_79"
Java(TM) SE Runtime Environment (build 1.7.0_79-b15)
Java HotSpot(TM) 64-Bit Server VM (build 24.79-b02, mixed mode)


1

ฉันใช้ coldfusion 8 บน JDK 1.6.45 และมีปัญหากับการให้ฉันเพียงแค่กากบาทสีแดงแทนภาพและ cfhttp ก็ไม่สามารถเชื่อมต่อกับเว็บเซิร์ฟเวอร์ท้องถิ่นด้วย ssl

สคริปต์ทดสอบของฉันที่จะทำซ้ำกับ coldfusion 8 คือ

<CFHTTP URL="https://www.onlineumfragen.com" METHOD="get" ></CFHTTP>
<CFDUMP VAR="#CFHTTP#">

สิ่งนี้ทำให้ฉันมีข้อผิดพลาดทั่วไปของ "I / O Exception: peer not authenticated" ฉันพยายามเพิ่มใบรับรองของเซิร์ฟเวอร์รวมถึงใบรับรองหลักและใบรับรองกลางไปยังที่เก็บคีย์ java และที่เก็บคีย์ Coldfusion แต่ไม่มีสิ่งใดช่วย จากนั้นฉันก็แก้ไขปัญหาด้วย

java SSLPoke www.onlineumfragen.com 443

และได้รับ

javax.net.ssl.SSLException: java.lang.RuntimeException: Could not generate DH keypair

และ

Caused by: java.security.InvalidAlgorithmParameterException: Prime size must be
multiple of 64, and can only range from 512 to 1024 (inclusive)
    at com.sun.crypto.provider.DHKeyPairGenerator.initialize(DashoA13*..)
    at java.security.KeyPairGenerator$Delegate.initialize(KeyPairGenerator.java:627)
    at com.sun.net.ssl.internal.ssl.DHCrypt.<init>(DHCrypt.java:107)
    ... 10 more

ฉันมีความคิดว่าเว็บเซิร์ฟเวอร์ (apache ในกรณีของฉัน) มี ciphers ที่ทันสมัยมากสำหรับ ssl และค่อนข้างเข้มงวด (qualys ให้คะแนน a +) และใช้คีย์ diffie hellmann ที่แข็งแกร่งที่มีมากกว่า 1024 บิต เห็นได้ชัดว่า coldfusion และ java jdk 1.6.45 ไม่สามารถจัดการสิ่งนี้ได้ ขั้นตอนต่อไปใน odysee คือคิดว่าจะติดตั้งผู้ให้บริการความปลอดภัยทางเลือกสำหรับ java และฉันตัดสินใจที่จะปราสาทเด้ง ดูเพิ่มเติมที่http://www.itcsolutions.eu/2011/08/22/how-to-use-bouncy-castle-cryptographic-api-in-netbeans-or-eclipse-for-java-jse-projects/

ฉันดาวน์โหลดแล้ว

bcprov-ext-jdk15on-156.jar

จากhttp://www.bouncycastle.org/latest_releases.htmlและติดตั้งภายใต้ C: \ jdk6_45 \ jre \ lib \ ext หรือในกรณีที่ jdk ของคุณติดตั้ง Coldfusion ดั้งเดิม 8 มันจะอยู่ภายใต้ C: \ JRun4 \ jre \ lib \ ext แต่ฉันใช้ jdk ใหม่ (1.6.45) ที่อยู่นอกไดเรกทอรี coldfusion มันสำคัญมากที่จะวาง bcprov-ext-jdk15on-156.jar ในไดเรกทอรี \ ext (ค่าใช้จ่ายฉันประมาณสองชั่วโมงและผม ;-) จากนั้นฉันก็แก้ไขไฟล์ C: \ jdk6_45 \ jre \ lib \ security \ java.security (โดยไม่ใช้ wordpad กับ editor.exe!) และใส่หนึ่งบรรทัดสำหรับผู้ให้บริการใหม่ หลังจากนั้นรายการดูเหมือน

#
# List of providers and their preference orders (see above):
#
security.provider.1=org.bouncycastle.jce.provider.BouncyCastleProvider
security.provider.2=sun.security.provider.Sun
security.provider.3=sun.security.rsa.SunRsaSign
security.provider.4=com.sun.net.ssl.internal.ssl.Provider
security.provider.5=com.sun.crypto.provider.SunJCE
security.provider.6=sun.security.jgss.SunProvider
security.provider.7=com.sun.security.sasl.Provider
security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.9=sun.security.smartcardio.SunPCSC
security.provider.10=sun.security.mscapi.SunMSCAPI

(ดูใหม่ในตำแหน่ง 1)

จากนั้นเริ่มบริการ Coldfusion อย่างสมบูรณ์ จากนั้นคุณสามารถ

java SSLPoke www.onlineumfragen.com 443 (or of course your url!)

และเพลิดเพลินไปกับความรู้สึก ... และแน่นอน

คืนอะไรและวันไหน หวังว่านี่จะช่วย (บางส่วนหรือทั้งหมด) กับใครบางคนที่นั่น หากคุณมีข้อสงสัยเพียงส่งเมล์มาที่ info ... (โดเมนด้านบน)


0

หากเซิร์ฟเวอร์รองรับการเข้ารหัสที่ไม่รวม DH คุณสามารถบังคับให้ไคลเอนต์เลือกการเข้ารหัสนั้นและหลีกเลี่ยงข้อผิดพลาด DH เช่น:

String pickedCipher[] ={"TLS_RSA_WITH_AES_256_CBC_SHA"};
sslsocket.setEnabledCipherSuites(pickedCipher);

โปรดทราบว่าการระบุตัวเลขที่แน่นอนมีแนวโน้มที่จะแตกในระยะยาว


0

เราได้รับข้อผิดพลาดข้อยกเว้นที่แน่นอนกลับมาเพื่อแก้ไขได้ง่ายหลังจากชั่วโมงท่องอินเทอร์เน็ต

เราดาวน์โหลด jdk เวอร์ชันสูงสุดที่เราพบได้ใน oracle.com ติดตั้งและชี้เซิร์ฟเวอร์แอปพลิเคชั่น Jboss ไปยังไดเรกทอรีของ jdk ใหม่ที่ติดตั้ง

รีสตาร์ท Jboss, ประมวลผลใหม่, มีปัญหาได้รับการแก้ไข !!!


0

ฉันมีข้อผิดพลาดนี้กับ Bamboo 5.7 + Gradle project + Apache Gradle พยายามรับการอ้างอิงจากเซิร์ฟเวอร์ของเราผ่าน SSL

สารละลาย:

  1. สร้าง DH Param:

ด้วย OpenSSL:

openssl dhparam 1024

เอาท์พุทตัวอย่าง:

-----BEGIN DH PARAMETERS-----
MIGHfoGBALxpfMrDpImEuPlhopxYX4L2CFqQov+FomjKyHJrzj/EkTP0T3oAkjnS
oCGh6p07kwSLS8WCtYJn1GzItiZ05LoAzPs7T3ST2dWrEYFg/dldt+arifj6oWo+
vctDyDqIjlevUE+vyR9MF6B+Rfm4Zs8VGkxmsgXuz0gp/9lmftY7AgEC
-----END DH PARAMETERS-----
  1. ผนวกเอาต์พุตไปยังไฟล์ใบรับรอง (สำหรับ Apache - SSLCertificateFileparam)

  2. รีสตาร์ท apache

  3. รีสตาร์ท Bamboo

  4. ลองสร้างโครงการอีกครั้ง


0

ฉันเคยได้รับข้อผิดพลาดที่คล้ายกันในการเข้าถึง svn.apache.org กับไคลเอนต์ java SVN โดยใช้ IBM JDK ขณะนี้ svn.apache.org ผู้ใช้กำหนดค่ากำหนดรหัสลูกค้า

หลังจากทำงานเพียงครั้งเดียวด้วยการจับแพ็คเก็ต / javax.net.debug = ทั้งหมดฉันสามารถขึ้นบัญชีดำเพียง DHE cipher เดียวและทุกอย่างทำงานได้สำหรับฉัน (ECDHE ถูกเจรจาแทน)

.../java/jre/lib/security/java.security:
    jdk.tls.disabledAlgorithms=SSL_DHE_RSA_WITH_AES_256_CBC_SHA

การแก้ไขด่วนที่ดีเมื่อไม่สามารถเปลี่ยนไคลเอนต์ได้ง่าย


0

เมื่อเร็ว ๆ นี้ฉันมีปัญหาเดียวกันและหลังจากการอัพเกรดรุ่น jdk จาก1.6.0_45เป็นjdk1.7.0_191ซึ่งแก้ไขปัญหาได้


-1

สำหรับฉันบรรทัดคำสั่งต่อไปนี้แก้ไขปัญหา:

java -jar -Dhttps.protocols=TLSv1.2 -Ddeployment.security.TLSv1.2=true -Djavax.net.debug=ssl:handshake XXXXX.jar

ฉันใช้ JDK 1.7.0_79


1
ฉันต้องเผชิญกับสถานการณ์เดียวกันโดยใช้ JDK 1.7.0_xx โดยปัญหาเริ่มต้นจะได้รับการแก้ไขหลังจากใช้ jdk 1.8 แต่บางครั้งเราไม่สามารถอัพเกรด jdk ได้อย่างรวดเร็ว ดังนั้นปัญหาของฉันแก้ไขได้หลังจากเพิ่มการกำหนดค่าระบบ: System.setProperty ("https.protocols", "TLSv1.2"); System.setProperty ("deployment.security.TLSv1.2", "true");
— Ramgau
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.