Why does SSL handshake give 'Could not generate DH keypair' exception?

前端 未结 21 776
梦如初夏
梦如初夏 2020-11-22 07:46

When I make an SSL connection with some IRC servers (but not others - presumably due to the server\'s preferred encryption method) I get the following exception:

<         


        
相关标签:
21条回答
  • 2020-11-22 08:26

    It is possible that you have incorrect Maven dependencies. You must find these libraries in Maven dependency hierarchy:

    bcprov-jdk14, bcpkix-jdk14, bcmail-jdk14
    

    If you have these dependencies that is the error, and you should do this:

    Add the dependency:

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

    Exclude these dependencies from the artifact that included the wrong dependencies, in my case it is:

    <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>
    
    0 讨论(0)
  • 2020-11-22 08:27

    I have the same problem with Yandex Maps server, JDK 1.6 and Apache HttpClient 4.2.1. The error was

    javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
    

    with enabled debug by -Djavax.net.debug=all there was a message in a log

    Could not generate DH keypair
    

    I have fixed this problem by adding BouncyCastle library bcprov-jdk16-1.46.jar and registering a provider in a map service class

    public class MapService {
    
        static {
            Security.addProvider(new BouncyCastleProvider());
        }
    
        public GeocodeResult geocode() {
    
        }
    
    }
    

    A provider is registered at the first usage of MapService.

    0 讨论(0)
  • 2020-11-22 08:27

    I use coldfusion 8 on JDK 1.6.45 and had problems with giving me just red crosses instead of images, and also with cfhttp not able to connect to the local webserver with ssl.

    my test script to reproduce with coldfusion 8 was

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

    this gave me the quite generic error of " I/O Exception: peer not authenticated." I then tried to add certificates of the server including root and intermediate certificates to the java keystore and also the coldfusion keystore, but nothing helped. then I debugged the problem with

    java SSLPoke www.onlineumfragen.com 443
    

    and got

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

    and

    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
    

    I then had the idea that the webserver (apache in my case) had very modern ciphers for ssl and is quite restrictive (qualys score a+) and uses strong diffie hellmann keys with more than 1024 bits. obviously, coldfusion and java jdk 1.6.45 can not manage this. Next step in the odysee was to think of installing an alternative security provider for java, and I decided for bouncy castle. see also http://www.itcsolutions.eu/2011/08/22/how-to-use-bouncy-castle-cryptographic-api-in-netbeans-or-eclipse-for-java-jse-projects/

    I then downloaded the

    bcprov-ext-jdk15on-156.jar
    

    from http://www.bouncycastle.org/latest_releases.html and installed it under C:\jdk6_45\jre\lib\ext or where ever your jdk is, in original install of coldfusion 8 it would be under C:\JRun4\jre\lib\ext but I use a newer jdk (1.6.45) located outside the coldfusion directory. it is very important to put the bcprov-ext-jdk15on-156.jar in the \ext directory (this cost me about two hours and some hair ;-) then I edited the file C:\jdk6_45\jre\lib\security\java.security (with wordpad not with editor.exe!) and put in one line for the new provider. afterwards the list looked like

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

    (see the new one in position 1)

    then restart coldfusion service completely. you can then

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

    and enjoy the feeling... and of course

    what a night and what a day. Hopefully this will help (partially or fully) to someone out there. if you have questions, just mail me at info ... (domain above).

    0 讨论(0)
  • 2020-11-22 08:28

    If the server supports a cipher that does not include DH, you can force the client to select that cipher and avoid the DH error. Such as:

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

    Keep in mind that specifying an exact cipher is prone to breakage in the long run.

    0 讨论(0)
  • 2020-11-22 08:29

    Here is my solution (java 1.6), also would be interested why I had to do this:

    I noticed from the javax.security.debug=ssl, that sometimes the used cipher suite is TLS_DHE_... and sometime it is TLS_ECDHE_.... The later would happen if I added BouncyCastle. If TLS_ECDHE_ was selected, MOST OF the time it worked, but not ALWAYS, so adding even BouncyCastle provider was unreliable (failed with same error, every other time or so). I guess somewhere in the Sun SSL implementation sometimes it choose DHE, sometimes it choose ECDHE.

    So the solution posted here relies on removing TLS_DHE_ ciphers completely. NOTE: BouncyCastle is NOT required for the solution.

    So create the server certification file by:

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

    Save this as it will be referenced later, than here is the solution for an SSL http get, excluding the 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));
            }
    
        }
    }
    

    Finally here is how it is used (certFilePath if the path of the certificate saved from 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();
            }
    
    0 讨论(0)
  • 2020-11-22 08:29

    I've got this error with Bamboo 5.7 + Gradle project + Apache. Gradle tried to get some dependencies from one of our servers via SSL.

    Solution:

    1. Generate DH Param:

    with OpenSSL:

    openssl dhparam 1024
    

    example output:

    -----BEGIN DH PARAMETERS-----
    MIGHfoGBALxpfMrDpImEuPlhopxYX4L2CFqQov+FomjKyHJrzj/EkTP0T3oAkjnS
    oCGh6p07kwSLS8WCtYJn1GzItiZ05LoAzPs7T3ST2dWrEYFg/dldt+arifj6oWo+
    vctDyDqIjlevUE+vyR9MF6B+Rfm4Zs8VGkxmsgXuz0gp/9lmftY7AgEC
    -----END DH PARAMETERS-----
    
    1. Append output to certificate file (for Apache - SSLCertificateFile param)

    2. Restart apache

    3. Restart Bamboo

    4. Try to build project again

    0 讨论(0)
提交回复
热议问题