2012-05-03 15 views
16

Có một số mã trong hệ thống của chúng tôi để tự động tạo chứng chỉ tự ký vào kho khóa mà sau đó được Jetty sử dụng. Nếu một khóa cho một máy chủ đã cho đã tồn tại thì không có gì xảy ra nhưng nếu nó không tồn tại, chúng tôi tạo ra một khóa mới, như thế này:Nếu có nhiều hơn một chứng chỉ trong kho khóa của Jetty, nó sẽ chọn như thế nào?

public void generateKey(String commonName) { 
    X500Name x500Name = new X500Name("CN=" + commonName); 
    CertAndKeyGen keyPair = new CertAndKeyGen("DSA", "SHA1withDSA"); 
    keyPair.generate(1024); 
    PrivateKey privateKey = keyPair.getPrivateKey(); 
    X509Certificate certificate = keyPair.getSelfCertificate(x500Name, 20*365*24*60*60); 
    Certificate[] chain = { certificate }; 
    keyStore.setEntry(commonName, privateKey, "secret".toCharArray(), chain); 
} 

Điều này tất cả hoạt động tốt miễn là chỉ có một khóa và chứng chỉ trong kho khóa. Khi bạn có nhiều phím, những điều kỳ lạ xảy ra khi bạn cố gắng kết nối:

java.io.IOException: HTTPS hostname wrong: should be <127.0.0.1> 

này khá một lỗi bí ẩn nhưng cuối cùng tôi đã được quản lý để theo dõi nó xuống bằng cách viết một bài kiểm tra đơn vị này kết nối với máy chủ và khẳng định rằng CN trên chứng chỉ khớp với tên máy chủ. Những gì tôi thấy khá thú vị - Jetty dường như tự ý chọn chứng chỉ nào để trình bày cho khách hàng, nhưng theo một cách nhất quán.

Ví dụ:

  • Nếu "CN = localhost" và "CN = cheese.mydomain" đang ở trong cửa hàng quan trọng, nó luôn luôn chọn "CN = cheese.mydomain".
  • Nếu "CN = 127.0.0.1" và "CN = cheese.mydomain" nằm trong kho khóa, nó luôn chọn "CN = cheese.mydomain".
  • Nếu "CN = 192.168.222.100" (cheese.mydomain) và "CN = cheese.mydomain" nằm trong kho khóa, nó luôn chọn "CN = 192.168.222.100".

Tôi đã viết một số mã vòng qua chứng chỉ trong cửa hàng để in ra và thấy rằng nó không nhất quán chọn chứng chỉ đầu tiên hoặc bất kỳ điều gì tầm thường như thế.

Vậy chính xác sử dụng tiêu chí nào? Ban đầu tôi nghĩ rằng localhost là đặc biệt nhưng sau đó ví dụ thứ ba đã làm tôi bối rối hoàn toàn.

Tôi lấy nó rằng điều này được quyết định bằng cách nào đó bởi KeyManagerFactory, đó là SunX509 trong trường hợp của tôi.

Trả lời

13

Điều này thực sự cuối cùng được quyết định bởi KeyManager (thường thu được từ một số KeyManagerFactory).

Kho lưu trữ khóa có thể có một số chứng chỉ được lưu trữ dưới các bí danh khác nhau. Nếu không có bí danh nào được cấu hình rõ ràng qua certAlias in the Jetty configuration, triển khai SunX509 sẽ chọn các bí danh đầu tiên mà nó tìm thấy có khóa riêng và khóa đúng loại cho bộ mã hóa đã chọn (thường là RSA, nhưng có thể là DSA trong trường hợp của bạn tại đây) . Có nhiều hơn một chút để nó vào logic lựa chọn, nếu bạn nhìn vào Sun provider implementation, nhưng bạn không nên thực sự dựa vào thứ tự nói chung, chỉ cần tên bí danh.

Tất nhiên, bạn có thể cung cấp cho Jetty SSLContext của riêng bạn với số X509KeyManager của riêng bạn để chọn bí danh. Bạn sẽ phải thực hiện:

chooseServerAlias(String keyType, Principal[] issuers, Socket socket) 

Thật không may, ngoài keyTypeissuers, tất cả các bạn có thể đưa ra quyết định là socket riêng của mình. Tốt nhất, thông tin hữu ích bạn nhận được ở đó là địa chỉ IP cục bộ và địa chỉ từ xa.

Trừ khi máy chủ của bạn đang nghe nhiều địa chỉ IP trên cùng một cổng, bạn sẽ luôn nhận được cùng một địa chỉ IP cục bộ.(Ở đây, rõ ràng, bạn có ít nhất hai: 127.0.0.1192.168.222.100, nhưng tôi nghi ngờ bạn không thực sự quan tâm đến localhost ngoại trừ các thử nghiệm của riêng bạn.) Bạn sẽ cần hỗ trợ Server Name Indication (SNI) ở phía máy chủ để có thể để đưa ra quyết định dựa trên tên máy chủ được yêu cầu (bởi khách hàng hỗ trợ nó). Thật không may, SNI was only introduced in Java 7, but only on the client side.

Một vấn đề khác mà bạn sẽ gặp phải ở đây là Java clients will complain about IP addresses in the Subject DN's CN. Một số trình duyệt sẽ chấp nhận điều này, nhưng điều này không tuân thủ đặc tả HTTPS (RFC 2818). Địa chỉ IP phải là mục nhập Tên thay thế chủ đề của loại địa chỉ IP.

+0

Vâng, chúng tôi đã phát hiện ra điều có địa chỉ IP, điều này dẫn đến việc viết HostnameVerifier riêng của chúng tôi để kiểm tra xem liệu nó có khớp và trả về true không. Ban đầu chúng tôi đã có một HostnameVerifier mà trả về đúng luôn luôn, mà chỉ đơn giản là đã được ném ra vì lý do rõ ràng. Nhiều người dùng hiện có đã định cấu hình địa chỉ IP là "tên máy chủ" của họ và chúng tôi không muốn tấn công mạnh mẽ vào lúc này. – Trejkaz