web-dev-qa-db-ja.com

Java 7およびDHキーペアを生成できませんでした

サーバーが1024ビットを超えるキーを送信したときに発生した「DHキーペアを生成できませんでした」というエラーに関する以前の投稿を読みました。 JCE無制限のjarファイルをダウンロードすると、この問題が修正されます。テスト環境で次の問題が発生しました。同じWebサーバーでJavaを使用すると、httpsクエリの実行時にエラーは発生しませんが、Javaを使用すると7その後、「DHキーペアを生成できませんでした」が表示されます。

JCE unlimitedのjarファイルを置き換えてみましたが、それでも同じエラーが発生します。バグは2007年以降報告されていますが、Java 7ではなくJava 6で実行されるのはなぜですか?ダウンロードするファイルは適切なものではありませんか?以前の投稿からリンクを取得しました Java:SSLハンドシェイクで「DHキーペアを生成できませんでした」例外が発生するのはなぜですか?

現時点では、どうすればよいかわかりません。 BouncyCastleプロバイダーをロードしようとすると、ArrayOutOfIndex例外が発生します。私のサーバーではDHアルゴリズムしか使用できないため、上記の投稿で提案されているような別のアルゴリズムを使用できません。

14
user1408089

いくつかの追加または説明:

(Suncle)Java 7 7u09は7u04でのランダムな順序とは異なり、デフォルトでより適切な一貫性のある暗号スイートの順序を使用します(04と09の間にテストはありません。)この順序ECDHEとプレーンRSA(別名akRSA)をDHEの前に配置することで、サーバーがECDHEまたはRSAをサポートし、クライアント設定に同意する場合にのみ問題を回避します(またはECDHで修正されますが、実際には誰も使用しません)。 (何らかの理由で)DHEを要求し、かつDH> 1024ビットを使用する場合でも、問題が発生します。

質問者(または他の誰か)が整数DH(ECDHやRSAではなく)を本当に必要とするサーバーに接続する場合、8の前にJavaで作業する唯一の方法は、サーバーをDH 1024ビットを使用します。このAFAWKは数年以上技術的に安全ですが、マージンが薄いため、NISTなどの重要な当局によって禁止されています(csa.nist.govのSpecial Pub 800-57を参照)(RSA 1024でも実際にはまだ壊れていませんが、おそらくすぐに壊れるので禁止されています。)

「無制限の強度ポリシー」はこの問題には関係ありません、または少なくとも直接は関係ありません。#6851461への良い答えはそうではありませんでした。これは、SunJCEのDHパラメータの制限を変更しません。これは、(誤って)強度の問題ではなく標準の問題として扱われます。 (具体的には、DSAで適切であった制限を採用し、DHに適用します。)AES-256およびSHA-2(TLSv1.2のみ)スイートを有効にし、十分に奇妙な設定リストを指定すると、選択結果をDHE(失敗)から非DHE(機能)に変更します。

Java 6リストに完全に戻る必要はありません。DHEよりも他のキー交換に優先順位を付ける必要があります。または、難解なサーバーの場合はDHEを完全にドロップします。絶対に戻らないでください。レガシーサーバーに絶対に必要な場合を除いて、EXPORTまたはsingle-DESスイートを有効にします。これらは現在数年間安全ではなく、デフォルトで6で有効になっているはずです。

11

私はSSLScoketsで同じ問題に出くわし、この回帰の理由をJava 7で特定しました。その理由は、クライアントとサーバー間でネゴシエートされる暗号にあります。

デフォルトでは、Java 6は、TLS接続に対してこれらの暗号を有効にします(優先順))。

SSL_RSA_WITH_RC4_128_MD5
SSL_RSA_WITH_RC4_128_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_DSS_WITH_AES_128_CBC_SHA
SSL_RSA_WITH_3DES_EDE_CBC_SHA
SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA
SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA
SSL_RSA_WITH_DES_CBC_SHA
SSL_DHE_RSA_WITH_DES_CBC_SHA
SSL_DHE_DSS_WITH_DES_CBC_SHA
SSL_RSA_EXPORT_WITH_RC4_40_MD5
SSL_RSA_EXPORT_WITH_DES40_CBC_SHA
SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA
SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA
TLS_EMPTY_RENEGOTIATION_INFO_SCSV

そしてJava 7はこれらの暗号を有効にします:

TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA
SSL_RSA_WITH_RC4_128_SHA
TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
TLS_ECDHE_RSA_WITH_RC4_128_SHA
TLS_ECDH_ECDSA_WITH_RC4_128_SHA
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
TLS_ECDH_RSA_WITH_RC4_128_SHA
TLS_EMPTY_RENEGOTIATION_INFO_SCSV
TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
SSL_RSA_WITH_RC4_128_MD5
TLS_DHE_DSS_WITH_AES_128_CBC_SHA
SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA
SSL_RSA_WITH_3DES_EDE_CBC_SHA

Diffie-Hellmanを使用する暗号は、Java 7が優先されますが、強力な暗号化パッケージがインストールされていない限り、1024ビットより長いキーをサポートするようには見えません。

私が使用した回避策は、SSLSocketでJava 6によって有効にされる暗号を指定することでした:

SSLSocketFactory socketFactory = SSLContext.getInstance("TLS").getSocketFactory();
SSLSocket socket = (SSLSocket) socketFactory.createSocket(InetAddress.getByName(hostname), port);
socket.setEnabledCipherSuites(new String[] {
        "SSL_RSA_WITH_RC4_128_MD5",
        "SSL_RSA_WITH_RC4_128_SHA",
        "TLS_RSA_WITH_AES_128_CBC_SHA",
        "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
        "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
        "SSL_RSA_WITH_3DES_EDE_CBC_SHA",
        "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
        "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
        "SSL_RSA_WITH_DES_CBC_SHA",
        "SSL_DHE_RSA_WITH_DES_CBC_SHA",
        "SSL_DHE_DSS_WITH_DES_CBC_SHA",
        "SSL_RSA_EXPORT_WITH_RC4_40_MD5",
        "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
        "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
        "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
        "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"});

socket.startHandshake();
8
Emmanuel Bourg

最新のJavaエディションを使用していてもエラーが発生する場合、C。\ Program Files\Java\jre1.8.0_xx\libフォルダーなどのJava.securityで設定を変更できます。 \セキュリティ

# Example:
#   jdk.tls.disabledAlgorithms=MD5, SSLv3, DSA, RSA keySize < 2048
    jdk.tls.disabledAlgorithms=SSLv3, RC4

Jdk.tls.disabledAlgorithmsの無効なアルゴリズムとしてDHを追加します

    jdk.tls.disabledAlgorithms=SSLv3, RC4, DH

Tomcatを再起動するか、プログラムを再実行します。

6
Tolomir

Java7とJava8でもこの問題が発生していました。また、Emanual Borgの提案と同様の回避策を使用しました。しかし、私たちの目標は、CipherSuiteの固定リストのハードコーディングを回避することでした。そこで、問題の原因となったエントリを(試行錯誤して)削除しようとしました...

String[] enabledCipherSuites = socket.getEnabledCipherSuites();

// avoid hardcoding a new list, we just remove the entries
// which cause the exception
List<String> asList = new ArrayList(Arrays.asList(enabledCipherSuites));

// we identified the following entries causeing the problems
// "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)"
asList.remove("TLS_DHE_RSA_WITH_AES_128_CBC_SHA");
asList.remove("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA");
asList.remove("TLS_DHE_RSA_WITH_AES_256_CBC_SHA");

String[] array = asList.toArray(new String[0]);
socket.setEnabledCipherSuites(array);

質問:このアプローチに問題がある人はいますか?

ところで:Apache HTTPClientを使用している場合は、 https://issues.Apache.org/jira/browse/HTTPCLIENT-1111 が興味深いです。これは、CipherSuitesの設定方法を示しています(HTTPClient v4以降)。 2)メソッド経由

SSLConnectionSocketFactory() {...}.prepareSocket(SSLSocket)

更新2015/10/31:これを使用するコンテキストをよりよく理解するために、ここでは、フックする方法を示す完全な疑似コードの例として、でprepareSocket()メソッドをオーバーライドします。

HttpClientBuilder builder = HttpClients.custom();

SSLContextBuilder sslContextBuilder = SSLContexts.custom();
SSLContext sslContext = sslContextBuilder.build();

SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, hostNameVerfier)
{


    protected void prepareSocket(SSLSocket socket) throws IOException {

    // Workaround to use different order of CipherSuites used by Java6 in order
        // to avoid the the problem of Java7 "Could not generate DH keypair"
        String[] enabledCipherSuites = socket.getEnabledCipherSuites();

        // but to avoid hardcoding a new list, we just remove the entries
        // which cause the exception (via TrialAndError)
        List<String> asList = new ArrayList(Arrays.asList(enabledCipherSuites));

        // we identified the following entries causeing the problems
        // "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)"
        asList.remove("TLS_DHE_RSA_WITH_AES_128_CBC_SHA");
        asList.remove("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA");
        asList.remove("TLS_DHE_RSA_WITH_AES_256_CBC_SHA");

        String[] array = asList.toArray(new String[0]);
        socket.setEnabledCipherSuites(array);

    };
};

Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create().register("https", sslsf).build();

PoolingHttpClientConnectionManager conman = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
builder.setConnectionManager(conman);

CloseableHttpClient httpClient =  builder.build();

注意してくださいこのコードは、ユーザーが明示的に自己署名証明書を信頼できるようにするコンテキストでのみ使用しています(たとえば、テスト環境など)。 )。これを実行したくない場合は、SSLをいじらないでください。

2
Christoph

Jdk1.7.0_04を使用している場合は、jdk1.7.0_21にアップグレードします。このアップデートで問題が修正されました。

1
Lekkie