ทำไม 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.