Как выбрать нужный доверенный сертификат из хранилища доверенных сертификатов, когда существует несколько сертификатов с одинаковыми trustX500Principals - PullRequest
0 голосов
/ 12 июня 2019

У меня скоро истекает срок действия корневого сертификата сервера с SHA1, и я получил новый корневой сертификат сервера с более длительным сроком службы с SHA256. Мы хотим включить их обоих в наше хранилище доверия клиентов, чтобы обеспечить плавный переход, когда среда prod переключает сертификат.

Мы предоставляем диспетчер доверия в нашем коде, загружая хранилище доверенных сертификатов через javax.net.ssl.TrustManagerFactory, затем мы увидели ошибку при запуске нашего клиентского приложения:

Caused by: java.security.SignatureException: Signature length not correct: got 256 but was expecting 128
    at sun.security.rsa.RSASignature.engineVerify(RSASignature.java:189)
    at java.security.Signature$Delegate.engineVerify(Signature.java:1222)
    at java.security.Signature.verify(Signature.java:655)
    at sun.security.x509.X509CertImpl.verify(X509CertImpl.java:444)
    at sun.security.x509.X509CertImpl.verify(X509CertImpl.java:392)
    at sun.security.validator.SimpleValidator.engineValidate(SimpleValidator.java:213)

Два доверенных сертификата принадлежат одному и тому же эмитенту, но отличаются датой истечения срока действия и алгоритмами подписи.

Я обнаружил, что основной причиной является то, что sun.security.validator.SimpleValidator выбирает только первые доверенные сертификаты в случае, если существует несколько сертификатов с одним и тем же эмитентом

Исходный код SimpleValidator от jdk показывает причину, если для одного и того же эмитента существует несколько доверительных сертификатов, всегда будет использоваться первый:

        // check if we can append a trusted cert
        X509Certificate cert = chain[chain.length - 1];
        X500Principal subject = cert.getSubjectX500Principal();
        X500Principal issuer = cert.getIssuerX500Principal();
        List<X509Certificate> list = trustedX500Principals.get(issuer);
        if (list != null) {
            X509Certificate trustedCert = list.iterator().next();
            c.add(trustedCert);
            return c.toArray(CHAIN0);
        }

Я предполагаю, что существует способ проверки сертификата сервера на основе всех доверенных с одним и тем же эмитентом.

Или способ выбора правильных сертификатов доверия на основе эмитента и алгоритма подписи.

Любая помощь будет оценена.

Ответы [ 2 ]

0 голосов
/ 14 июня 2019

Нечто подобное, как показано ниже - при создании контекста ssl

private TrustManager[] wrapLoggingTrustDelegate(TrustManager[] trustManagers) {
    if (trustManagers == null || trustManagers.length == 0) {
        return trustManagers;
    }
    TrustManager[] result = new TrustManager[trustManagers.length];
    for (int i = 0; i < trustManagers.length; i++) {
        result[i] = (trustManagers[i] == null || !(trustManagers[i] instanceof X509TrustManager)) ? trustManagers[i] : new SigNameMatchingX509TrustManager(new LoggingDelegateX509TrustManager((X509TrustManager)trustManagers[i]), trustManagerKeyStore);
    }
    return result;
}

private SSLContext getSslContext() {
    SSLContext sc;

    try {
        sc = SSLContext.getInstance(sslContextType);
        sc.init(wrapLoggingKeyDelegate(keyManagerFactory.getKeyManagers()), wrapLoggingTrustDelegate(trustManagerFactory.getTrustManagers()), null);
    } catch (Exception e) {
        log.error("Error configuring SSL Context.", e);
        throw new IllegalStateException("Error configuring the SSL Context", e);
    }

    return sc;
}
0 голосов
/ 14 июня 2019

Бьюсь об заклад, сервер, к которому вы подключаетесь, отвечает только листовым сертификатом. Сверхлегким решением было бы попросить Сервер ответить полной цепью (Leaf + Intermediate + Root CA), чтобы java мог извлекать имя / алгоритм подписи непосредственно из представленных сертификатов.

Если это невозможно, то при передаче цепочки сертификатов сервера в валидатор необходимо добавить в цепочку требуемый сертификат доверия на основе эмитента и имени алгоритма подписи. См .: https://github.com/frohoff/jdk8u-jdk/blob/da0da73ab82ed714dc5be94acd2f0d00fbdfe2e9/src/share/classes/sun/security/validator/SimpleValidator.java#L378

...