2012-09-23 15 views
5

Próbuję zbudować niestandardowy serwer HTTPS w Javie (6) przy użyciu wbudowanego klasy com.sun.net.httpserver.HttpsServer. Działa dobrze, dopóki nie wymagam uwierzytelnienia klienta. W tym momencie kończy się niepowodzeniem z następującym wyjątkiem w debugowaniu SSL na serwerze.Jak wyłączyć sprawdzanie więzów (typ certyfikatu Netscape) w Java6?

sun.security.validator.ValidatorException: Netscape typ cert nie zezwala na stosowanie do klienta SSL

Używam certyfikaty wydane przez nasz wewnętrzny CA, który jest używany do wszystkich zastosowań wewnętrznych do nas. Sprawdziłem szczegóły certyfikatu i stwierdziłem, że typem był "serwer SSL" (szczegóły cytowane poniżej). Ponieważ naszą polityką jest używanie typu "SSL Server" dla wszystkich wewnętrznych aplikacji, trudno jest zmienić certyfikat. Ponieważ chcę używać certyfikatu serwera dla klienta, nie uważam, że jest to problem związany z bezpieczeństwem.

To, czego szukam, to sposób na wyłączenie tego sprawdzania ograniczeń w Javie. Czy ktoś to napotkał i rozwiązał to? Każda pomoc jest wysoko ceniona.

Pozdrawiam, Arun

Owner: CN=myapp, OU=mygroup, O=mycompany 

Issuer: O=MYCA 

Serial number: 4cc8c1da 

Valid from: Mon Jan 10 13:46:34 EST 2011 until: Thu Jan 10 14:16:34 EST 2013 

Certificate fingerprints: 
     MD5: 8C:84:7F:7A:40:23:F1:B5:81:CD:F9:0C:27:16:69:5E 
     SHA1: 9B:39:0B:2F:61:83:52:93:D5:58:E5:43:13:7A:8F:E1:FD:AC:98:A4 
     Signature algorithm name: SHA1withRSA 
     Version: 3 

Extensions: 

[1]: ObjectId: 2.5.29.16 Criticality=false 
PrivateKeyUsage: [ 
From: Mon Jan 10 13:46:34 EST 2011, To: Wed Jul 11 21:16:34 EDT 2012] 

[2]: ObjectId: 2.5.29.15 Criticality=false 
KeyUsage [ 
    DigitalSignature 
    Key_Encipherment 
] 

[3]: ObjectId: 2.5.29.14 Criticality=false 
SubjectKeyIdentifier [ 
KeyIdentifier [ 
0000: D3 47 35 9B B4 B7 03 18 C6 53 2C B0 FE FD 49 D8 .G5......S,...I. 
0010: D0 FB EE 15          .... 
] 
] 

[4]: ObjectId: 1.2.840.113533.7.65.0 Criticality=false 

[5]: ObjectId: 2.5.29.31 Criticality=false 
CRLDistributionPoints [ 
    [DistributionPoint: 
    [CN=CRL413, O=SWIFT] 
]] 

[6]: ObjectId: 2.5.29.19 Criticality=false 
BasicConstraints:[ 
    CA:false 
    PathLen: undefined 
] 

****[7]: ObjectId: 2.16.840.1.113730.1.1 Criticality=false 
NetscapeCertType [ 
    SSL server 
]**** 

[8]: ObjectId: 2.5.29.35 Criticality=false 
AuthorityKeyIdentifier [ 
KeyIdentifier [ 
0000: 8F AF 56 BC 80 77 A3 FD 9E D2 89 83 98 FE 98 C7 ..V..w.......... 
0010: 20 65 23 CC           e#. 
] 

] 

Odpowiedz

1

Można owinąć menedżerów Zaufanie domyślne i złapać ten szczególny wyjątek. To byłoby coś wzdłuż tych linii:

class IgnoreClientUsageTrustManager extends X509TrustManager { 
    private final X509TrustManager origTrustManager; 
    public class IgnoreClientUsageTrustManager(X509TrustManager origTrustManager) { 
     this.origTrustManager = origTrustManager; 
    } 

    public checkClientTrusted(X509Certificate[] chain, String authType 
     throws IllegalArgumentException, CertificateException { 
     try { 
      this.origTrustManager.checkClientTrusted(chain, authType); 
     } catch (ValidatorException e) { 
      // Check it's that very exception, otherwise, re-throw. 
     } 
    } 

    // delegate the other methods to the origTrustManager 
}   

Następnie użyć tego menedżera zaufania do tworzenia SSLContext i używać go z serwera.

TrustManagerFactory tmf = TrustManagerFactory.getInstance(
    TrustManagerFactory.getDefaultAlgorithm()); 
tmf.init((KeyStore)null); 
TrustManager[] trustManagers = tmf.getTrustManagers(); 

for (int i = 0; i < trustManagers.length; i++) { 
    if (trustManagers[i] instanceof X509TrustManager) { 
     trustManagers[i] = IgnoreClientUsageTrustManager(trustManagers[i]); 
    } 
} 

SSLContext sslContext = SSLContext.getInstance("TLS"); 
sslContext.init(... you keymanagers ..., trustManagers, null); 

Powinieneś zainicjować swoich keymanagers ze swoich magazynów kluczy serwera (jak zwykle). Powinieneś wtedy móc użyć HttpsServer 's HttpsConfigurator, aby skonfigurować SSLContext (patrz przykład w dokumentacji).

Ta technika nie jest jednak idealna.

  • Po pierwsze, ValidatorException jest w sun.* pakietu, który nie jest częścią publicznych API: Ten kod będzie specyficzne dla Oracle/OpenJDK JRE.
  • Po drugie, polega na tym, że jednostka końcowa sprawdziła (weryfikuje rozszerzenie użycia klucza) happens after the rest of the trust validation (co powoduje, że można zignorować ten wyjątek, ponieważ w ten sposób nie ignoruje się innych bardziej fundamentalnych kontroli).

Można oczywiście ponownie wprowadzić własną weryfikację za pomocą interfejsu API ścieżki certyfikatu Java i ignorując tylko użycie klucza do tego celu. To wymaga nieco więcej kodu.

Co więcej, próbujesz omijać specyfikacje, jeśli chcesz użyć certyfikatu SSL/TLS jako certyfikatu klienta, gdy nie ma właściwego rozszerzenia. Najlepszym rozwiązaniem jest zmiana zasad urzędu certyfikacji, co powinno być wykonalne, jeśli mimo to jest wewnętrznym urzędem certyfikacji. Często zdarza się, że certyfikaty serwera mają również ustawiony zestaw kluczy rozszerzonych klienta TLS, nawet w przypadku dużych urzędów certyfikacji.

+0

Dziękuję bardzo. To działało bardzo dobrze. Zgadzam się, że idealnym rozwiązaniem jest zaktualizowanie zasad urzędu certyfikacji, ale jeśli nie zbuduję rozwiązania obejściowego, aktualizacja mojego oprogramowania na kilkuset systemach będzie wymagać natychmiastowego odnowienia certyfikatu. – Arun

+2

To brzmi jak brudna naprawa, która przetrwa całą wieczność i później. – sjas

+0

@sjas Tak, mam tylko nadzieję, że ktokolwiek przeczytał ten tekst, nie po prostu go skopiował i wkleił. – Bruno

Powiązane problemy