2012-05-21 54 views
14

Tôi đã đọc một bài đăng trước về lỗi 'Không thể tạo cặp khóa DH' được kích hoạt khi máy chủ lấy khóa dài hơn 1024 bit. Tải xuống JCE không giới hạn lọ nên khắc phục vấn đề này. Trong môi trường thử nghiệm, tôi đã gặp phải những điều sau đây, cho cùng một máy chủ web nếu tôi sử dụng Java 6 Tôi không gặp lỗi nào khi thực hiện truy vấn https nhưng nếu tôi sử dụng Java 7 thì tôi nhận được 'Không thể tạo ra cặp khóa DH'.Java 7 và không thể tạo ra cặp khóa DH

Tôi đã thử thay thế tệp jar cho JCE không giới hạn nhưng vẫn gặp lỗi tương tự. Lỗi này được báo cáo từ năm 2007, nhưng tại sao nó lại chạy cho Java 6 chứ không phải cho Java 7? Các tệp có tải xuống không phải là tệp thích hợp không? Tôi đã nhận được liên kết từ bài đăng trước Java: Why does SSL handshake give 'Could not generate DH keypair' exception?.

Tại thời điểm này tôi không biết phải làm gì. Nếu tôi cố gắng tải các nhà cung cấp BouncyCastle tôi nhận được một ngoại lệ ArrayOutOfIndex. Máy chủ của tôi chỉ cho phép thuật toán DH vì vậy tôi không thể sử dụng một thuật toán khác như được đề xuất trong bài đăng ở trên.

Trả lời

8

Tôi tình cờ gặp vấn đề tương tự với SSLScokets và tôi nghĩ rằng tôi đã xác định lý do cho hồi quy này với Java 7. Lý do dẫn đến mật mã được thương lượng giữa máy khách và máy chủ.

Theo mặc định Java 6 cho phép các thuật toán mã hóa cho một kết nối TLS (theo thứ tự ưu tiên):

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 

Và Java 7 cho phép các thuật toán mã hóa:

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 

mật mã sử dụng Diffie-Hellman đến cao ưu tiên trên Java 7, nhưng chúng dường như không hỗ trợ các khóa dài hơn 1024 bit trừ khi gói mật mã mạnh được cài đặt.

Cách giải quyết tôi sử dụng là để xác định mật mã kích hoạt Java 6 trên SSLSocket:

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(); 
+0

Thanks a lot tôi gặp một kỳ lạ * java.security.ProviderException: mặt trời .security.pkcs11.wrapper.PKCS11Exception: CKR_DOMAIN_PARAMS_INVALID * lỗi khi sử dụng Webscarab (SSL MITM proxy). Xác định rõ ràng các bộ mã hóa này làm cho nó hoạt động trở lại. – Lekensteyn

+1

Tôi mới sử dụng chứng khoán java. Tôi nên viết đoạn mã này ở đâu? – Shashank

0

Nếu bạn đang sử dụng jdk1.7.0_04, nâng cấp lên jdk1.7.0_21. Sự cố đã được khắc phục trong bản cập nhật đó.

+0

Tuyệt. Điều này đã được sửa trong các phiên bản Java mới hơn. Nhưng câu hỏi của tôi là về việc sử dụng phiên bản cũ .. Khi tôi sử dụng phiên bản cũ hơn, đôi khi nó hoạt động và đôi khi nó mang lại ngoại lệ trên..Tại sao hành vi ngẫu nhiên như vậy? Nếu nó là một lỗi trong java, thì tôi đoán nó sẽ không bao giờ hoạt động? –

+2

Rất tiếc, tôi vẫn gặp lỗi này trong '7u21-2.3.9-1ubuntu1'. – expert

+0

Tôi vẫn nhận được lỗi này trong xây dựng 1.7.0_45-b18 – duffymo

10

Một số bổ sung hoặc làm rõ:

(Suncle) Java 7 kể từ 7u09 sử dụng một trật tự phù hợp lý hơn của bộ mật mã mặc định, không giống như thứ tự dường như ngẫu nhiên trong 7u04. (Tôi không có kiểm tra giữa 04 và 09.) Lệnh này đặt ECDHE và plain-RSA (aka akRSA) trước DHE, và do đó tránh được vấn đề nếu VÀ CHỈ NẾU máy chủ hỗ trợ ECDHE hoặc RSA và đồng ý với sở thích của khách hàng. (Hoặc ECDH-cố định, nhưng thực tế không ai sử dụng nó.) Nếu máy chủ nhấn mạnh vào DHE (vì lý do gì) VÀ sử dụng DH> 1024 bit, bạn vẫn có vấn đề. Nếu người hỏi (hoặc bất kỳ ai khác) kết nối với máy chủ thực sự yêu cầu số nguyên-DH (chứ không phải ECDH hoặc RSA), cách duy nhất để làm việc với Java trước 8 là để máy chủ sử dụng DH 1024 bit . AFAWK nào về mặt kỹ thuật an toàn trong vài năm nữa, nhưng với biên độ mỏng, các cơ quan quan trọng như NIST bị cấm (xem Special Pub 800-57 tại csrc.nist.gov). (Ngay cả RSA 1024 vẫn chưa thực sự bị hỏng, nhưng nó có thể sẽ sớm và bị cấm.)

"Chính sách sức mạnh không giới hạn" không liên quan đến vấn đề này, hoặc ít nhất là không trực tiếp. # 6851461 không nói là vậy. Nó không thay đổi hạn chế về các tham số DH trong SunJCE, được (sai) được coi là một vấn đề tiêu chuẩn không phải là vấn đề về sức mạnh. (Cụ thể là phải có các hạn chế được sử dụng đúng cho DSA và áp dụng chúng cho DH.) Nó cho phép các bộ AES-256 và SHA-2 (chỉ dành cho TLSv1.2) và đưa ra danh sách tùy chọn đủ lạ, có thể thay đổi kết quả lựa chọn từ DHE (không thành công) thành không phải DHE (công trình).

Bạn không cần hoàn toàn quay lại danh sách Java 6, bạn chỉ cần ưu tiên các trao đổi khóa khác qua DHE, hoặc cho một máy chủ kiên quyết thả DHE hoàn toàn. Bạn chắc chắn KHÔNG nên quay trở lại để bật bất kỳ bộ công cụ EXPORT hoặc DES đơn, trừ khi hoàn toàn cần thiết cho một máy chủ kế thừa; họ đã KHÔNG CHỨNG KHOÁN trong vài năm nay, và vẫn được kích hoạt theo mặc định trong 6 lâu hơn họ cần phải có.

1

Chúng tôi cũng đang gặp sự cố này với Java7 và Java8. Chúng tôi cũng sử dụng cách giải quyết tương tự như đề xuất của Emanual Borg. Nhưng mục tiêu của chúng tôi là tránh hardcoding một danh sách cố định của CipherSuites. Vì vậy, chúng tôi đã cố gắng xóa các mục nhập đã gây ra sự cố (do dùng thử và lỗi ...).

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

Câu hỏi: Có ai thấy vấn đề với cách tiếp cận này không?

Btw: Trong trường hợp bạn đang sử dụng Apache HttpClient, sau đó https://issues.apache.org/jira/browse/HTTPCLIENT-1111 là thú vị trong đó cho thấy làm thế nào để thiết lập các bộ mật mã (bắt đầu với HttpClient v4.2) thông qua phương pháp

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

Cập nhật 2015/10/31 : để giúp hiểu được bối cảnh nơi để sử dụng này, đây là đầy đủ pseudo-code ví dụ mà bạn thấy làm thế nào để treo-in để ghi đè lên prepareSocket) phương pháp (tốt hơn:

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

Hãy cẩn thận Chúng tôi đang sử dụng đoạn mã này chỉ trong ngữ cảnh mà người dùng cho phép rõ ràng để tin cậy các chứng chỉ tự ký (ví dụ: cho môi trường thử nghiệm, v.v.). Nếu bạn không muốn làm điều này, thì tốt hơn không nên làm phiền với các công cụ SSL.

+0

Tôi đang sử dụng apache httpclient, nhưng không thể hiểu cách sử dụng preparSocket –

6

Với bạn đang sử dụng phiên bản java mới nhất và vẫn nhận được lỗi, bạn có thể thay đổi một thiết lập trong java.security (ví dụ trong thư mục C: \ Program Files \ Java \ jre1.8.0_xx \ lib \ security

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

Thêm DH như thuật toán vô hiệu hóa trong jdk.tls.disabledAlgorithms

jdk.tls.disabledAlgorithms=SSLv3, RC4, DH 

Khởi động lại tomcat hoặc chạy lại chương trình của bạn

Các vấn đề liên quan