2012-09-17 41 views
5

Tôi đang làm việc trên xác thực ứng dụng khách-cert giữa máy chủ cầu nối được nhúng và máy khách. Cả hai đều sử dụng kho khóa. Chứng chỉ ứng dụng khách được ký bởi chứng chỉ của máy chủ được ký bởi một CA. Jetty sử dụng 2 phương pháp để xác thực chứng chỉ ứng dụng khách, javax.net.ssl.SSLEngine có vẻ hoạt động và họ cũng sử dụng mã ở trên.Java/Keystore Xác minh chứng chỉ đã ký

List<X509Certificate> certList = Certificate chain sent by the client 
KeyStore truststore = server's truststore 

//No use of CRL/OSCP/CRLDP 
_crls = null; 
_enableOCSP = false; 
_enableCRLDP = false; 

try{ 
X509CertSelector certSelect = new X509CertSelector(); 
certSelect.setCertificate((X509Certificate) certList.get(0)); 

// Configure certification path builder parameters 
PKIXBuilderParameters pbParams = new PKIXBuilderParameters(truststore, certSelect); 
pbParams.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(certList))); 

// Set maximum certification path length 
pbParams.setMaxPathLength(-1); 

// Enable revocation checking 
pbParams.setRevocationEnabled(true); 

// Set static Certificate Revocation List 
if (_crls != null && !_crls.isEmpty()) 
    pbParams.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(_crls))); 

    // Enable On-Line Certificate Status Protocol (OCSP) support 
    if (_enableOCSP) 
     Security.setProperty("ocsp.enable","true"); 

    // Enable Certificate Revocation List Distribution Points (CRLDP) support 
    if (_enableCRLDP) 
     System.setProperty("com.sun.security.enableCRLDP","true"); 

// Build certification path 
CertPathBuilderResult buildResult = CertPathBuilder.getInstance("PKIX").build(pbParams);    

// Validate certification path 
CertPathValidator.getInstance("PKIX").validate(buildResult.getCertPath(),pbParams); 
}catch(GeneralSecurityException gse){ 
... 
} 

Tất nhiên tôi phải sử dụng cách thứ hai này ... Vì vậy, hãy tập trung vào mã này, đây là một cách tốt để xác minh giấy chứng nhận có chữ ký? Đây là một bãi chứa của keystores tôi:

Khách hàng Keystore:

Entry type: PrivateKeyEntry 
Certificate chain length: 2 
Certificate[1]: 
Owner: [email protected], CN=Servlet, OU=dev, O=Imbasoft, ST=Ile-de-France, C=FR 
Issuer: [email protected], CN=Greenpacs, OU=dev, O=Imbasoft, L=Bondy, ST=Ile-de-France, C=FR 
... 

Certificate[2]: 
Owner: [email protected], CN=Greenpacs, OU=dev, O=Imbasoft, L=Bondy, ST=Ile-de-France, C=FR 
Issuer: [email protected], CN=Greenpacs Certificate Authority, OU=dev, O=Imbasoft, ST=Ile-de-France, C=FR 
... 

server truststore:

Entry type: trustedCertEntry 

Owner: [email protected], CN=Greenpacs, OU=dev, O=Imbasoft, L=Bondy, ST=Ile-de-France, C=FR 
Issuer: [email protected], CN=Greenpacs Certificate Authority, OU=dev, O=Imbasoft, ST=Ile-de-France, C=FR 

Tôi không chắc chắn về những keystores nhưng tôi đã cố gắng với một khác nhau (thêm Chứng nhận CA cho chuỗi chứng chỉ của khách hàng, thêm chứng chỉ vào truststore) và xác thực vẫn không thành công. Và với những keystores này, cách xác thực đầu tiên (SSLEngine) dường như hoạt động.

Sản lượng debug là quá lớn để đặt nó ở đây nhưng đây là stacktrace:

java.security.cert.CertPathValidatorException: Could not determine revocation status 
    at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:153) 
    at sun.security.provider.certpath.PKIXCertPathValidator.doValidate(PKIXCertPathValidator.java:325) 
    at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:187) 
    at java.security.cert.CertPathValidator.validate(CertPathValidator.java:267) 
    at MainClass.main(MainClass.java:75) 
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:197) 
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:255) 
    at sun.security.provider.certpath.CrlRevocationChecker.buildToNewKey(CrlRevocationChecker.java:583) 
    at sun.security.provider.certpath.CrlRevocationChecker.verifyWithSeparateSigningKey(CrlRevocationChecker.java:459) 
    at sun.security.provider.certpath.CrlRevocationChecker.verifyRevocationStatus(CrlRevocationChecker.java:339) 
    at sun.security.provider.certpath.CrlRevocationChecker.verifyRevocationStatus(CrlRevocationChecker.java:248) 
    at sun.security.provider.certpath.CrlRevocationChecker.check(CrlRevocationChecker.java:189) 
    at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:131) 
    ... 4 more 

Nếu tôi vô hiệu hóa việc thu hồi hoặc nếu tôi đặt giấy chứng nhận cuối cùng (thay vì là người đầu tiên) như X509CertSelector công việc mã nhưng tôi không chắc chắn về những gì tôi đang làm.

Tôi bắt đầu nghi ngờ về mã cầu nối nhưng tôi không phải là chuyên gia về chứng chỉ và bắt tay SSL vì vậy nó cũng có thể đến từ kho khóa/kho tin xấu. Đó là lý do tại sao tôi đã không tạo ra một vấn đề trên tàu của cầu tàu và hỏi ở đây trước, để chắc chắn rằng mã cần phải được thay đổi.

Cũng có thể hữu ích khi biết cách xác thực chứng chỉ đã ký bằng Java.

+0

Tại sao bạn không để người quản lý tin cậy qua JSSE thực hiện tất cả điều này cho bạn? – Bruno

+0

Bởi vì máy chủ của tôi cũng chấp nhận kết nối không xác thực. Tôi phải để cho nó chấp nhận tất cả các kết nối đầu tiên và sau đó trong một số trường hợp xác nhận chứng chỉ của khách hàng nếu có. – Ghetolay

+4

Không, bạn chỉ cần tạo chứng chỉ ứng dụng khách bằng tùy chọn wantClientAuth (thay vì cần). – Bruno

Trả lời

0

Vui lòng kiểm tra CRL chứng chỉ của bạn hoặc OCSP có thể truy cập, bạn có thể tìm thấy những thông tin đó trong giấy chứng nhận, chẳng hạn như

[1]CRL Distribution Point 
    Distribution Point Name: 
      Full Name: 
       URL=http://crl.verisign.com/pca2-g2.crl 
+0

Tôi không sử dụng bất kỳ CRL, OSCP hoặc CRLDP nào. Không có dòng như vậy trên chứng chỉ của tôi. Ngoài ra mã hiển thị là không hoàn thành có một số "nếu" cho CRL/OSCP/CRLDP nhưng những "nếu" không bao giờ đạt được bởi vì tôi đã không thiết lập các tùy chọn này. Tôi có nên không? là nó hoàn toàn cần thiết? – Ghetolay

0

Thật sự tôi không cần phải làm như xác nhận bản thân mình.

Các SSLEngine đã được làm việc đó và nếu một chứng chỉ hợp lệ được gửi bởi các khách hàng mà bạn có thể nhận được nó bằng cách sử getPeerCertificateChain(), nếu không có chứng chỉ hoặc giấy chứng nhận hợp lệ được gửi bởi client getPeerCertificateChain() trở lại vô ném một ngoại lệ.

Sử dụng cầu nối (hoặc bất kỳ ServletContain Java nào tôi đoán) bạn chỉ cần kiểm tra thuộc tính của HttpServletRequest ["javax.servlet.request.X509Certificate"] để biết liệu chứng chỉ hợp lệ có được gửi bởi máy khách hay không.

Tôi vẫn không biết cách xác thực chứng chỉ bằng Java nhưng giải pháp này đủ cho tôi :) Tôi không cần phải tự làm nữa. Cảm ơn Bruno!

+0

getPeerCertificateChain() không trả về null, nó ném một ngoại lệ. – EJP

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