2012-03-09 31 views
5

Tôi đang cố gắng viết một ứng dụng khách (thực tế là phần mềm trung gian, là khách hàng cho một thực thể, nhưng cũng hoạt động như một máy chủ cho người khác). Trong khả năng khách hàng của nó, nó được cho là để nói chuyện với một máy chủ (VirtualCenter của VMware), và yêu cầu nó để làm công cụ thay mặt nó.Bắt buộc SSL Client Socket để gửi chứng chỉ

Để cung cấp cho bạn nhiều ngữ cảnh hơn, VirtualCenter cho phép ứng dụng đăng ký dưới dạng tiện ích mở rộng. Đơn đăng ký có thể đăng ký chứng nhận tại thời điểm đăng ký (setCertificate). Sau đó, ứng dụng có thể đăng nhập vào VirtualCenter bằng cách sử dụng chứng chỉ của nó (phương thức loginExtensionByCertificate()) và do đó không cần lưu trữ tên người dùng và mật khẩu. Tuy nhiên, để làm việc này, ứng dụng khách (ứng dụng của tôi) phải gửi chứng chỉ như là một phần của kết nối SSL của nó, mặc dù máy chủ (VirtualCenter) không yêu cầu đặc biệt.

Tôi đang viết ứng dụng của mình bằng Java. Tạo trình quản lý khóa của riêng tôi, nối nó với kho khóa của tôi và chỉ định bí danh để sử dụng. Sau đó, khởi tạo bối cảnh ssl của tôi để sử dụng trình quản lý khóa đó. Trong các ổ cắm được tạo ra, tôi thấy SSLContext của họ có trình quản lý khóa của tôi trong chúng. Tuy nhiên, tôi không thấy người quản lý khóa đó từng được gọi để lấy chứng chỉ. Đối với một số lý do, các ổ cắm không cảm thấy nó cần phải gửi một cert.

Tôi hiểu rằng máy chủ có thể yêu cầu khách hàng trình bày chứng chỉ của nó. Trong trường hợp này, nó không xảy ra. Những gì tôi đang tự hỏi liệu có một cách để buộc các ổ cắm được tạo ra để trình bày một cert bất kể cho dù máy chủ yêu cầu nó.

+0

Tôi khuyên bạn nên gỡ lỗi bắt tay bằng cách sử dụng '-Djavax.net.debug = ssl' hoặc ít nhất là' Djavax.net.debug = ssl: handshake' để xem bạn có nhận được 'CertificateRequest' hay không và kiểm tra danh sách' certificate_authorities' Nó chứa. – Bruno

Trả lời

2

Tuy nhiên, để làm việc này, các khách hàng (ứng dụng của tôi) phải gửi giấy chứng nhận như một phần của kết nối SSL của nó, mặc dù máy chủ (VirtualCenter) không yêu cầu nó đặc biệt là

Để làm việc, máy chủ phải yêu cầu. Đó là cách giao thức SSL được định nghĩa. Nếu bạn có thể sắp xếp cho khách hàng của bạn để gửi nó không được yêu cầu, mà bạn không thể, máy chủ sẽ bị ràng buộc để thả kết nối.

Giải pháp cho điều này là ở cuối máy chủ. Bạn có chắc chắn 100% nó không phải là yêu cầu? Có thể nó đang hỏi nhưng khách hàng của bạn không gửi? ví dụ, bởi vì chứng chỉ không được ký bởi một CA mà máy chủ tin cậy.

+0

Bạn có chắc chắn về việc 'ngắt kết nối' không? AFAIK IIS có thể được đặt để bỏ qua chứng chỉ ứng dụng khách. –

+0

@desaivv RFC 4346 'Thư này chỉ được gửi nếu máy chủ yêu cầu chứng chỉ' có vẻ khá rõ ràng; có thể nó không bắt buộc phải bỏ kết nối, nhưng JSSE chắc chắn sẽ không gửi chứng chỉ trừ khi được yêu cầu. Tôi không biết gì về IIS. – EJP

+1

Phần 7.4 cũng cho biết "* Thông báo giao thức bắt tay được trình bày bên dưới theo thứ tự mà chúng PHẢI gửi đi; gửi thông báo bắt tay theo thứ tự không mong muốn dẫn đến lỗi nghiêm trọng *". Tôi sẽ xem xét việc gửi một thông điệp 'ClientCertificate' không được yêu cầu là" thứ tự không mong muốn "(vì vậy điều này sẽ phá vỡ kết nối). @desaivv, những gì bạn có nghĩa là "IIS có thể được thiết lập để bỏ qua chứng chỉ khách hàng"? (Bất kỳ doc/con trỏ?) Không phải là "bỏ qua" ở đây chỉ là về việc không sử dụng chúng để xác thực/ủy quyền của các ứng dụng ngồi phía sau? – Bruno

4

Chứng chỉ ứng dụng khách chỉ có thể được gửi nếu máy chủ yêu cầu. Xem TLS Spec. - Client Certificate message (RFC 4346, Section 7.4.6):

Đây là thông điệp đầu tiên khách hàng có thể gửi sau khi nhận được tin nhắn chào mừng . Thông báo này chỉ được gửi nếu máy chủ yêu cầu chứng chỉ.

Bạn không thể buộc khách hàng gửi chứng chỉ ứng dụng khách là máy chủ chưa yêu cầu.

EDIT: Tất nhiên, bạn cũng sẽ cần phải đảm bảo rằng keymanager/keystore của bạn được thiết lập đúng cách. Bạn có thể phải đối mặt với vấn đề tương tự như mô tả trong why doesn't java send the client certificate during SSL handshake?

0

VMware VC sẽ luôn yêu cầu chứng chỉ SSL của ứng dụng khách, vì đây là số lượng tiện ích được xác thực đăng nhập vào VC. Vì vậy, bạn đang đi đúng hướng.

Tôi nghi ngờ bạn đang gặp sự cố với tương tác SSL/Java và không phải vấn đề cụ thể của VMware (mặc dù luôn khó nói với SSL ...).

Tôi nghĩ rằng bạn muốn làm theo những gợi ý trên đây: Java client certificates over HTTPS/SSL

0

Cuối cùng, giải quyết vấn đề. Có vẻ như VMware có một con đường rất khác. Câu hỏi đã được hiểu sai.

Trước tiên, tôi truy tìm kết nối bằng WireShark và không cần máy chủ yêu cầu (cần hoặc muốn) chứng chỉ. Tuy nhiên, VirtualCenter (VC) cung cấp cách đăng ký chứng chỉ như là một phần của kết nối và sau đó sử dụng chứng chỉ đó để xác thực. Để làm việc này, chúng cung cấp một cách để kết nối đường hầm.

Chuỗi tôi sử dụng là:

  • Đầu tiên chỉ định URL để kết nối là https: //: (lưu ý giao thức là an toàn, nhưng cổng không phải là).

  • Ổ cắm ban đầu sẽ được mở tới cổng văn bản rõ ràng. Nhưng có https là giao thức sẽ buộc gọi SSLSocketFactory của riêng tôi. Trong nhà máy ổ cắm của tôi, tôi nhận được một cuộc gọi đến phương pháp public Socket createSocket(Socket s, String host, int port, boolean autoClose) của tôi, cho phép tôi chuyển đổi ổ cắm của tôi sang SSLSocket theo sở thích của tôi.

Mã của tôi về cơ bản trông giống như:

@Override 
public Socket createSocket(Socket s, String host, int port, boolean autoClose) 
    throws IOException { 
    s.setKeepAlive(true); 
    String connectReq = "CONNECT /sdkTunnel HTTP/1.1\r\n\r\n"; 
    OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream()); 
    writer.write(connectReq, 0, connectReq.length()); 
    writer.flush(); 
    // In this initial response, all that matters is the http code. If 
    // it is 200, the rest can be ignored. 
    READ_AND_VERIFY_INITIAL_RESPONSE(); 
    SSLSocket sock = (SSLSocket) origSslSockFactory 
     .createSocket(s, s.getInetAddress().getHostName(), s.getPort(), true); 
    // Depending on whether the caller actually does the handshake 
    // or not, you may need to call handshake here. In my case, I 
    // did not need to, since HTTPClient I am using calls the 
    // handshake. Axis does not call, so you may have to in that 
    // case. 

    // sock.startHandshake(); 
    return sock; 
} 

Trong khối trên, origSslSockFactory là SSLSocketFactory đó đã được thay thế bằng thực hiện của bạn. Trong trường hợp của tôi nó là một thể hiện của sun.security.ssl.SSLSocketFactoryImpl.

Sau thủ tục đó, hãy gọi ExtensionManager.setExtensionCertificate() thành công. Và sau đó, tất cả các cuộc gọi đến SessionManager.loginExtensionByCertificate() cũng thành công.

Tôi muốn đăng bài này vì dường như có rất nhiều câu hỏi về vấn đề này.

0

Khi vCenter được cài đặt, nó sử dụng proxy ngược trên cổng 443 để chuyển tiếp các yêu cầu qua HTTP tới dịch vụ thực tế. Proxy không bao giờ yêu cầu chứng chỉ ứng dụng khách sẽ không thể chuyển tiếp nó.

Cố gắng tìm cổng thực tế mà dịch vụ đang chạy và kết nối với dịch vụ đó.

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