Как отключить проверку ограничений (тип сертификата Netscape) в Java6?

Я пытаюсь создать собственный HTTPS-сервер на Java (6), используя встроенный класс com.sun.net.httpserver.HttpsServer. Он работает нормально, пока мне не потребуется аутентификация клиента. В этот момент происходит сбой со следующим исключением в отладке SSL на сервере.

sun.security.validator.ValidatorException: тип сертификата Netscape не разрешает использование для клиента SSL

Я использую сертификаты, выданные нашим внутренним центром сертификации, который используется для всех внутренних приложений. Я проверил сведения о сертификате и обнаружил, что это тип «SSL-сервер» (подробности приведены ниже). Поскольку наша политика заключается в использовании типа «SSL-сервер» для всех внутренних приложений, изменить сертификат сложно. Поскольку я хочу использовать сертификат сервера для клиента, я не думаю, что это проблема безопасности.

Я ищу способ отключить эту проверку ограничений в Java. Кто-нибудь сталкивался с этим и решил это? Любая помощь высоко ценится.

С уважением, Арун

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#.
]

]

person Arun    schedule 23.09.2012    source источник


Ответы (1)


Вы можете обернуть менеджеры доверия по умолчанию и поймать это конкретное исключение. Это будет что-то в этом роде:

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
}        

Затем используйте этот диспетчер доверия, чтобы создать SSLContext и использовать его на своем сервере.

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

Вы должны инициализировать свои менеджеры ключей из хранилищ ключей вашего сервера (как обычно). После этого вы сможете использовать HttpsConfigurator HttpsServer для настройки SSLContext (см. пример в документации).

Однако эта техника не идеальна.

  • Во-первых, ValidatorException находится в пакете sun.*, который не является частью общедоступного API: этот код будет специфичным для Oracle/OpenJDK JRE.
  • Во-вторых, он основан на факте проверки конечного объекта (который проверяет расширение использования ключа) случается после остальной части проверки доверия (что позволяет игнорировать это исключение, поскольку таким образом вы не игнорируете другие более фундаментальные проверки).

Конечно, вы могли бы повторно реализовать свою собственную проверку вместо этого, используя API Java Certificate Path и игнорируя только использование ключа для этой цели. Это требует немного больше кода.

В более общем случае вы все равно пытаетесь обойти спецификации, если хотите использовать сертификат для SSL/TLS в качестве клиентского сертификата, если у него нет правильного расширения. Лучшее решение для этого — изменить политику ЦС, что в любом случае должно быть осуществимо, если это внутренний ЦС. Для серверных сертификатов довольно часто также устанавливается расширенный ключ использования клиента TLS, даже в крупных центрах сертификации.

person Bruno    schedule 23.09.2012
comment
Большое Вам спасибо. Это сработало очень хорошо. Я согласен с тем, что идеальным решением является обновление политики ЦС, но если я не создам обходное решение, обновление моего программного обеспечения на паре сотен систем потребует немедленного обновления сертификата. - person Arun; 26.09.2012
comment
Это звучит как грязное исправление, которое будет длиться всю вечность и после. - person sjas; 26.03.2015
comment
@sjas Да, я просто надеюсь, что тот, кто прочитает это, прочитает текст, а не просто скопирует и вставит. - person Bruno; 26.03.2015