Как сделать проверку OCSP X509Certificate на Java?

Нашел вот такую строчку для проверки в старых примерах:

Security.addProvider(new KalkanProvider());
try {
URL url;
HttpURLConnection con;
OutputStream os;
cert = generateCert(CERT_FILE);
cacert = generateCert(CA_CERT_FILE);
// указываем алгоритм хэширования
//CertificateID.HASH_GOST34311GT
//CertificateID.HASH_GOST34311
//CertificateID.HASH_SHA256
//CertificateID.HASH_SHA1
//принципиальной разницы для сервера нет
//и не зависит от алгоритма подписи сертификата
byte[] ocspReq = getOcspPackage(cert.getSerialNumber(), cacert,
CertificateID.HASH_SHA1);
String b64Req = new String(Base64.encode(ocspReq));
String getUrl = OCSP_URL + “/” + b64Req;
// сервис понимает и POST и GET, можно выбрать что-то одно
if (getUrl.length() <= 2) {
url = new URL(getUrl);
con = (HttpURLConnection) url.openConnection();
} else {
url = new URL(OCSP_URL);
con = (HttpURLConnection) url.openConnection();
con.setDoOutput(true);
con.setRequestMethod(“POST”);
con.setRequestProperty(“Content-Type”,
“application/ocsp-request”);
os = con.getOutputStream();
os.write(ocspReq);
os.close();
}

  	makeOcspResponse(con);
  	con.disconnect();
  } catch (Exception e) {
  	e.printStackTrace();
  }

}

Не могу понять это две переменные, тип данных у них X509Certificate:
cert = generateCert(CERT_FILE);
cacert = generateCert(CA_CERT_FILE);

Вот для проверки у меня есть сертификат X509 который я получил после парсинга XML. Я так понимаю что я его записываю в переменную cert, а откуда брат сертификат для cacert?

CA cert это корневой сертификат, который выпустил проверямый вами сертификат. СА - certificate authority.

Все корневые есть у нас на сайте https://pki.gov.kz/cert/

Там много разных, какой именно для проверки использовать?

Тот который выпустил проверямый вами сертификат.

Сверяйте расширение authority key identifier в проверяемом сертификате и subject key identifier в корневом.

Можете так же логику немного объяснить? Эти списки заготовлены заранее, как он проверяет те сертификаты которые были отозваны после выпуска этого списка? Просто я воспринимаю вот этот корневой сертификат как заготовленный заранее список на определенный момент времени, и как тогда быть?

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

Ну смотрите, я вот пытаюсь для себя прояснить этот момент.

Мы же проверяем на отозванность сертификат. Когда человек отзывает свой сертификат, данные про этот сертификат уходит в какой-то реестр или что-то в этом роде. И я себе это представляю как что на каком-то удаленном сервере сохраняются данные по всем отозванным сертификатам, а я представляю себе это как какой-то список, и он постоянно пополняется новыми сертификатами. Соответственно, мне представляется что это надо постоянно обращаться на отдаленный сервер где все данные постоянно обновляются. А вы мне говорите про вот эти корневые сертификаты, а они не на удаленном сервере, а в виде файла, который дескретный и он сформирован, то есть он не может пополняться новыми данными по отозванным сертификатам. Вот такие у меня представления.

Также вот вы говорите что там для каждого сертификата, свой корневой сертификат. И я понимаю что их 2 типа RSA и GOST (новый стандарт). И это получается нужно иметь эти два корневых сертификата внутри проекта и когда я хочу проверить сертификат на отозванность, я проверяю его тип RSA или GOST и делаю проверку соответствующим корневым сертификатом. Правильно понял этот момент?

Еще один вопрос. В той ссылке корневых сертификатов не 2 как я себе представлял, а они еще как то по датам делятся и имеют срок годности до 25 или 45 года и как понять какой мне нужен корневой, до 45 или до 25 года.

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

Да, в общих чертах так и есть

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

Да, корневой сертификат не хранит данные об отозванных сертификатах. https://en.wikipedia.org/wiki/Root_certificate

Также вот вы говорите что там для каждого сертификата, свой корневой сертификат. И я понимаю что их 2 типа RSA и GOST (новый стандарт). И это получается нужно иметь эти два корневых сертификата внутри проекта и когда я хочу проверить сертификат на отозванность, я проверяю его тип RSA или GOST и делаю проверку соответствующим корневым сертификатом. Правильно понял этот момент?

У нас 4 корневых сертификата, 2 из которых истекают в 2025 году, поэтому нужно иметь 4 корневых сертификата пока у этих двоих не истечет срок.

какой мне нужен корневой

Как я уже писал ранее нужно сверить расширение authority key identifier в проверяемом сертификате и subject key identifier в корневом.

Такой вопрос, я пишу на джаве и пытаюсь использовать KNCAOCSPChecker() и передаю ему мапу из сертификатов

private static final String GOST_OLD_CERT_FILE = "src/main/resources/certs/nca_gost.cer";
	private static final String RSA_OLD_CERT_FILE = "src/main/resources/certs/nca_rsa.cer";
	private static final String GOST_NEW_CERT_FILE = "src/main/resources/certs/nca_gost_2022.cer";
	private static final String RSA_NEW_CERT_FILE = "src/main/resources/certs/nca_rsa_2022.cer";

caCerts = new HashMap<>();
		caCerts.put(newGost.getIssuerX500Principal(), newGost);
		caCerts.put(newRsa.getIssuerX500Principal(), newRsa);
		caCerts.put(oldGost.getIssuerX500Principal(), oldGost);
		caCerts.put(oldRsa.getIssuerX500Principal(), oldRsa);

Потом для проверки решил вывести на консоль среды разработки и проверяю на совпадение, не совпадает. Первый это сертификат пользователя, второй это один из файлов с сайта который вы до этого указали, то есть pki.gov.kz/cert/:

C=KZ, CN=ҰЛТТЫҚ КУӘЛАНДЫРУШЫ ОРТАЛЫҚ (GOST) 2022
C=KZ,CN=НЕГІЗГІ КУӘЛАНДЫРУШЫ ОРТАЛЫҚ (GOST) 2022
false

Пробовал и КУЦ и НУЦ, но почему то они всегда выходят как НЕГІЗГІ КУӘЛАНДЫРУШЫ ОРТАЛЫҚ, даже НУЦ сертификаты

В чем проблема?

Вы проверяете issuer? Они не могут быть одинаковыми. Ваш сертификат выдан НУЦ РК, а сертификат НУЦ-а выдан КУЦ РК.

А как мне тогда понять каким корневым сертификатом мне проверять проверяемый сертификат?

Вы ранее писали про Authority key identifier и subject key identifier, но в Java не могу достать таких данных, Есть только IssuerDn и SubjectDN.

Эти значения в расширениях, а не в DN имени.

Расширения можно вытащить по OID-ам:
https://docs.oracle.com/javase/8/docs/api/java/security/cert/X509Extension.html#getExtensionValue-java.lang.String-

Значения OID-ов можно найти в классе X509Extensions провайдера.

Как альтернатива, в SDK есть вспомогательная библиотека knca_provider_util, где есть множество готовых методов для работы с сертификатами, в том числе методы для извлечения данных типа authority key identifier.

import kz.gov.pki.provider.utils.X509Util;

....

byte [] cacertAuthorityKeyIdentifierBytes = X509Util.getAuthorityKeyIdentifier(cert);
 X509Certificate cacert = X509Util.getX509Certificate(cacertAuthorityKeyIdentifierBytes, provider);
// index out of bounds -2

....

                    File[] files = new File(cacertPath).listFiles();
                    Collection<X509Certificate> caCertList = new ArrayList<>();
                    for (File file : files) {
                        if (file.isFile()) {
                            System.out.println("file.getName()");
                            System.out.println(file.getName());

                            X509Certificate cacert = OCSPUtils.generateCert(cacertPath+"/"+file.getName());
                            caCertList.add(cacert);
                        }
                    }

                    PKIXUtil pkixUtil = new PKIXUtil(cert, caCertList).withOCSP();
                    pkixUtil.validate();

как достать ocspResponse от pkixUtil?

                    File[] files = new File(cacertPath).listFiles();
                    Map<X500Principal, X509Certificate> caCertsMap = new HashMap<>();
                    for (File file : files) {
                        if (file.isFile()) {
                            System.out.println("file.getName()");
                            System.out.println(file.getName());

                            X509Certificate cacert = OCSPUtils.generateCert(cacertPath+"/"+file.getName());
                            caCertsMap.put(cert.getSubjectX500Principal(), cacert);
                        }
                    }

                    KNCAOCSPChecker ocspChecker = new KNCAOCSPChecker(caCertsMap);
                    ocspChecker.check(cert, null);
                    BasicOCSPResp resp = ocspChecker.getBasicOCSPResponse();

к раннему вопросу, да, конечно же можно достать oscp response вот так, но мне бы хотелось внутри pkixUtil то что ocsp используется оттуда достать.

Добрый день, есть какой то пример помимо того что в SDK2.0, как делать проверку OCSP/CRL? https://ocsp.pki.gov.kz закладываю урл и отправляю запросы, как ни круто ответа не приходит. И где можно про проверку CRL посмотреть? Может быть есть какой пример как эту проверку реализовали в других проектах?

Других примеров нет.

Можете тогда объяснить почему ответ от ocsp pki gov не приходит?

Не может быть чтобы не было никакого ответа. Вы отправляете на http://ocsp.pki.gov.kz? По http?