Вопрос по java, pkix, certificate, keystore, x509certificate – Проверка сертификата в Java вызывает исключение - не удается найти действительный путь к сертификату для запрошенной цели

6

У меня есть веб-приложение, которое требует, чтобы клиент отправил свой сертификат, а сервер должен проверить сертификат (т.е. посмотреть, является ли эмитент действительным эмитентом и присутствует в хранилище доверенных сертификатов сервера). Вот код:

<code>FileInputStream fin=new FileInputStream("C:/trustedca");
    KeyStore anchors = KeyStore.getInstance("JKS","SUN");
    anchors.load(fin, "server".toCharArray());
    X509CertSelector target = new X509CertSelector();
    FileInputStream fin1=new FileInputStream("C:/client.crt");
    CertificateFactory cf=CertificateFactory.getInstance("X.509");
    X509Certificate cert=null;
    while (fin1.available() > 0) 
    {
     System.out.println("in while---------");
     cert =(X509Certificate) cf.generateCertificate(fin1);
    }
    target.setCertificate(cert);
    PKIXBuilderParameters params = new PKIXBuilderParameters(anchors, target);

    CertPathBuilder builder = (CertPathBuilder) CertPathBuilder.getInstance("PKIX").build(params);
    PKIXCertPathBuilderResult r = (PKIXCertPathBuilderResult) builder.build((CertPathParameters)params);<br>
</code>

Но я получаю исключение:

<code>sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid
 certification path to requested target<br>
</code>

NOTE :
Здесь сертификат, отправляемый клиентом, является client.crt, а сертификат, используемый для подписи сертификата client.crt, - это ca.crt, который присутствует в хранилище ключей «trustca». Тогда почему он дает это исключение?

Стоит упомянуть, что, взглянув на этот код, невозможно сказать, почему компоновщик PKIX не может построить путь. Но добавление -Djava.security.debug = all к параметрам java предоставит выходные данные отладчика отладчика и может пролить свет на проблему. Pawel Veselov

Ваш Ответ

3   ответа
12

пусть JSSE сделает все это за вас. Если вы хотите использовать свое собственное хранилище доверенных сертификатов для определенного соединения, настройте JSSE для его использования. ПроверитьНастройка JSSE раздел в справочной документации.

Вот краткий пример построенияSSLContext с настраиваемым трастовым магазином. (Другое, более сложноеX509TrustManagerМожно также использовать, но это вам редко нужно)

TrustManagerFactory tmf = TrustManagerFactory
    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream fis = new FileInputStream("/.../example.jks");
ks.load(fis, null);
// or ks.load(fis, "thepassword".toCharArray());
fis.close();

tmf.init(ks);

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);

Если вы используете существующий сервер приложений, то как пройти настройку, все это будет зависеть от сервера и от того, как он будет настроен. Использование JSSE для этого также обеспечит соответствие ключевых атрибутов использования.

Если вы получили сертификат другим способом и хотите его проверить, вам нужно использоватьPKI API, Если вы будете следоватьExample of Validating a Certification Path using the PKIX algorithm, вы должны получить что-то вроде этого:

X509Certificate certToVerify = ...

CertificateFactory cf = CertificateFactory.getInstance("X.509");
CertPath cp = cf.generateCertPath(Arrays
    .asList(new X509Certificate[] { certToVerify }));

TrustAnchor trustAnchor = new TrustAnchor(caCert, null);

CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
PKIXParameters pkixParams = new PKIXParameters(
    Collections.singleton(trustAnchor));
pkixParams.setRevocationEnabled(false);

cpv.validate(cp, pkixParams);

Проверьте результат от validate (и, конечно, он не выдал исключение проверки). Здесь я отключил проверки отзыва для упрощения. Вы также можете установить другие аспектыPKIXParameters для проверки политики. Это может быть довольно сложным (и почему лучше сделать так, чтобы менеджеры JSSE по умолчанию сделали это за вас).

Вы также спрашивали обо всем этом в контексте этого другого вопроса, который вы задали на Security.SE:What is the actual value of a certificate fingerprint?.

Предположим, у вас есть дваX509Certificates:serverCert а такжеcaCertгде вы хотите это проверитьserverCert был подписан (закрытый ключ соответствует открытому ключу)caCert.

Самый простой способ:

serverCert.verify(caCert.getPublicKey());

Если вы хотите сделать это немного больше вручную, используйтеSignature API:

System.out
     .println("Signature algorithm: " + serverCert.getSigAlgName());
Signature sig = Signature.getInstance(serverCert.getSigAlgName());
sig.initVerify(caCert.getPublicKey());
sig.update(serverCert.getTBSCertificate());
System.out
    .println("Verified? " + sig.verify(serverCert.getSignature()));

Предполагая, что алгоритмSHA1withRSAВы также можете вычислить дайджест:

MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.reset();
digest.update(serverCert.getTBSCertificate());
byte[] digestBytes = digest.digest();

Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, caCert.getPublicKey());
byte[] cipherText = cipher.doFinal(serverCert.getSignature());

Сам дайджест будет только частью результата от использованияCipher: что вы получаете отserverCert.getSignature() фактически является более сложной структурой ASN.1, которая включает в себя идентификатор алгоритма дайджеста, в данном случаеdigestBytes должен быть с префиксом что-токак это:

SHA-1:   (0x)30 21 30 09 06 05 2b 0e 03 02 1a 05 00 04 14 || H.

(BouncyCastle может быть полезно, если вы хотите правильно проанализировать структуру ASN.1.)

Обратите внимание, что ничего из этого не проверяет достоверность времени или любые другие атрибуты. Соответствие PKIX - это гораздо больше, чем проверка подписи (см. RFC 3820 и 5820).

Посмотрите на & quot;Example of Building a Certification Path using the PKIX algorithm& quot;: вам нужно добавить CertStore к своим параметрам со всеми задействованными сертификатами.
Что не так с моим кодом? Ashwin
1

s truststore

JSSE уже все это делает. Вы не должны делать ничего из этого, за исключением, может быть, проверки того, что срок действия сертификата однорангового узла не истек.

@suraj Если он подписан авторизованным центром сертификации, вам не нужно добавлять его вообще. Склад доверенных сертификатов, распространяемый с Java, уже доверяет всем распознанным центрам сертификации. Вот и вся идея.
@suraj и Ashwin, вы больше не новичок в SO. Вам нужноknow what you ask, пытатьсяnot to redirect the question completely in commentsи избегайте дубликатовhere а такжеhere.
@suraj Вы не получилиwhat? Когда вы добавляете сертификат в хранилище доверенных сертификатов, вы говорите хранилищу доверенных сертификатов доверять этому сертификату. Если вы не доверяете этому, не добавляйте его.
@suraj Ваше хранилище доверенных сертификатов должно изначально содержать все, что находится в хранилище доверенных сертификатов, распространяемых вместе с JDK, или по крайней мере те сертификаты CA, которым вы готовы доверять. Этот механизмavoids необходимость загружать клиентские сертификаты в хранилище доверенных сертификатов вообще. Это то, что представляет собой механизм хранилища доверенных сертификатов и весь механизм X.509.
@suraj Если вы положите самоподписанный сертификат в свой склад доверенных сертификатов, вы доверяете ему. Вот что означает операция. Если вы не доверяете этому, не добавляйте его. Я уже все это сказал. Вы уже сказали, что ваше хранилище доверенных сертификатов не является хранилищем доверенных сертификатов Java по умолчанию. Мой вопрос почему нет? Мне кажется, что вы все делаете неправильно. Вам вообще не нужно писать код для получения сертификата, поскольку это должен быть автономный процесс с независимой проверкой. В противном случае все, что вы делаете, это нарушаете безопасность, встроенную в SSL.
4

допустимый путь не может быть создан, потому что некоторые промежуточные сертификаты отсутствуют. Ваш цикл загрузки сертификатов сбрасывает все, кроме последнего. Вместо этого сохраните все эти сертификаты и передайте ихCertPathBuilder чтобы помочь в строительстве пути.

Другая распространенная проблема заключается в том, что проверки отзыва выполняются по умолчанию, что хорошо для безопасности. Если вы не понимаете, как получить CRL или используете OCSP, вы можете снизить уровень безопасности и отключить проверки отзыва. Это также показано в примере ниже.

...
CertificateFactory fac = CertificateFactory.getInstance("X.509");
FileInputStream is = new FileInputStream("client.crt");
Collection<? extends Certificate> intermediate;
try {
  intermediate = fac.generateCertificates(is);
} finally {
  is.close();
}
X509Certificate client = null;
for (Certificate c : intermediate)
  client = (X509Certificate) c;
if (client == null)
  throw new IllegalArgumentException("Empty chain.");
X509CertSelector t = new X509CertSelector();
t.setCertificate(client);
PKIXBuilderParameters params = new PKIXBuilderParameters(anchors, t);
CertStoreParameters store = new CollectionCertStoreParameters(intermediate);
params.addCertStore(CertStore.getInstance("Collection", store));
params.setRevocationEnabled(false);
...

Это помогло бы узнать, как вы получаете & quot; client.crt & quot; файл и его содержимое, как ожидается. Как и респонденты, мне интересно, почему вы не можете использовать встроенные средства JSSE для выполнения этой проверки.

@erickson: промежуточных сертификатов нет. Как я уже сказал, client.crt загружается клиентом. В целях тестирования я создал CA и подписал client.csr, используя ca.crt, чтобы передать client.crt. Я добавил файл ca.crt в «доверенный» и с клиентского компьютера загрузил файл client.crt. Итак, вы видите, что нет промежуточных сертификатов. Сертификат CA находится в хранилище ключей «доверенный». Я добавил это и целевой сертификат в PKIXBuilderParameters Ashwin
@Ashwin, это не просто промежуточный сертификат, вам нужно добавить сертификат конечного объекта, который вы тоже хотите проверить.X509CertSelector это просто селектор, вы на самом деле не добавляете его в коллекцию сертификатов, чтобы использовать его при добавлении сертификата в селектор. Читатьthis section или посмотрите, как инициализируется код erickson.intermediate.
На основеthis duplicate Вопрос, сертификат приходит из формы HTML. Непонятно, как это затем связывается с владельцем закрытого ключа, совпадающим с открытым ключом в этом сертификате. Помимо этого, не ясно, какие атрибуты должны быть проверены (например, использование ключа) для их применения.

Похожие вопросы