Как сделать проверку 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.