Ключевое слово в защите информации
КЛЮЧЕВОЕ СЛОВО
в защите информации
Получить ГОСТ TLS-сертификат для домена (SSL-сертификат)
Добро пожаловать, Гость! Чтобы использовать все возможности Вход. Новые регистрации запрещены.

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline Анатолий Широков  
#1 Оставлено : 5 июня 2025 г. 11:14:54(UTC)
Анатолий Широков

Статус: Участник

Группы: Участники
Зарегистрирован: 22.01.2019(UTC)
Сообщений: 22
Мужчина
Российская Федерация
Откуда: Санкт-Петербург

Сказал «Спасибо»: 7 раз
Добрый день!

Есть просроченный сертификат expired.cer (до 31 мая 2025), есть сертификат УЦ действующий ca.cer, есть список отзыва ca.crl (c 1 июня по 8 июня 2025). Сертификат expired.cer в списке отозванных отсутствует.

Пытаюсь построить цепочку просроченного сертификата оффлайн на дату, когда еще сертификат дейстовал (в примере 28 мая 2025). Ожидал получил цепочку, но получаю ошибку:

Цитата:

sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at java.base/sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:148)
at java.base/sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:129)
at java.base/java.security.cert.CertPathBuilder.build(CertPathBuilder.java:297)
at ru.CryptoPro.reprov.CPCertPathBuilder.engineBuild(Unknown Source)
at java.base/java.security.cert.CertPathBuilder.build(CertPathBuilder.java:297)
at certpath.CertPathTest.main(CertPathTest.java:84)


Программа получения цепочки:
Код:

package certpath;

import java.security.KeyStore;
import java.security.Security;
import java.security.cert.CertPath;
import java.security.cert.CertPathBuilder;
import java.security.cert.CertPathBuilderResult;
import java.security.cert.CertStore;
import java.security.cert.CertificateFactory;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.PKIXBuilderParameters;
import java.security.cert.TrustAnchor;
import java.security.cert.X509CRL;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
import java.time.LocalDate;
import java.time.ZoneOffset;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

import ru.CryptoPro.Crypto.CryptoProvider;
import ru.CryptoPro.JCP.JCP;
import ru.CryptoPro.JCSP.JCSP;

public class CertPathTest {

  public static void main(String[] args) {
    try {
      System.setProperty("com.sun.security.enableCRLDP", "false");
      System.setProperty("com.sun.security.enableAIAcaIssuers", "false");
      System.setProperty("com.ibm.security.enableCRLDP", "false");
      System.setProperty("ru.CryptoPro.reprov.enableAIAcaIssuers", "false");

      Security.removeProvider(JCSP.PROVIDER_NAME);
      Security.addProvider(new JCSP());
      Security.removeProvider(JCP.PROVIDER_NAME);
      Security.addProvider(new JCP());
      Security.removeProvider(ru.CryptoPro.reprov.RevCheck.PROVIDER_NAME);
      Security.addProvider(new ru.CryptoPro.reprov.RevCheck());
      Security.removeProvider(CryptoProvider.PROVIDER_NAME);
      Security.addProvider(new CryptoProvider());
      
      TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
      trustManagerFactory.init((KeyStore) null);
      List<TrustManager> trustManagers = Arrays.asList(trustManagerFactory.getTrustManagers());
      Set<X509Certificate> cacerts = new HashSet<>(trustManagers.stream().filter(X509TrustManager.class::isInstance)
          .map(X509TrustManager.class::cast).map(trustManager -> Arrays.asList(trustManager.getAcceptedIssuers()))
          .flatMap(Collection::stream).toList());

      CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");

      X509Certificate cert = (X509Certificate) certificateFactory
          .generateCertificate(CertPathTest.class.getResourceAsStream("expired.cer"));
      X509Certificate caCert = (X509Certificate) certificateFactory
          .generateCertificate(CertPathTest.class.getResourceAsStream("ca.cer"));
      X509CRL caCRL = (X509CRL) certificateFactory.generateCRL(CertPathTest.class.getResourceAsStream("ca.crl"));
      
      if( !cacerts.contains(caCert) ) {
        throw new IllegalStateException("ca.cer it not trust ca certificate");
      }
      Set<TrustAnchor> trustAnchors = Collections.singleton(new TrustAnchor(caCert, null)); 
      
      X509CertSelector targetConstraints = new X509CertSelector();
      targetConstraints.setCertificate(cert);

      PKIXBuilderParameters pkixBuilderParams = new PKIXBuilderParameters(trustAnchors, targetConstraints);
      pkixBuilderParams.addCertStore(
          CertStore.getInstance("Collection", new CollectionCertStoreParameters(Collections.singleton(caCRL))));
      pkixBuilderParams.setRevocationEnabled(true);
      pkixBuilderParams.setDate(Date.from(LocalDate.parse("2025-05-28").atStartOfDay(ZoneOffset.UTC).toInstant()));

      CertPathBuilder certPathBuilder = CertPathBuilder.getInstance("CPPKIX");
      
      CertPathBuilderResult certPathBuilderResult = certPathBuilder.build(pkixBuilderParams);
      CertPath certPath = certPathBuilderResult.getCertPath();
      certPath.getCertificates().forEach(c->{
        X509Certificate x509= (X509Certificate) c;
        System.out.println(x509.getSubjectX500Principal());
      });

    } catch (Exception e) {
      System.out.println("Cannot get certificate path");
      e.printStackTrace();
    }
  }
}


Я что-то упустил? Или я должен предоставить CRL на дату проверки отзыва, поскольку при включенном режиме отладки certpath -Djava.security.debug=certpath я вижу:

certpath: X509CRLSelector.match: update out-of-range

А если посмотреть исходники OpenJDK:

Код:

/* match on dateAndTime */
        if (dateAndTime != null) {
            Date crlThisUpdate = xcrl.getThisUpdate();
            Date nextUpdate = xcrl.getNextUpdate();
            if (nextUpdate == null) {
                if (debug != null) {
                    debug.println("X509CRLSelector.match: nextUpdate null");
                }
                return false;
            }
            Date nowPlusSkew = dateAndTime;
            Date nowMinusSkew = dateAndTime;
            if (skew > 0) {
                nowPlusSkew = new Date(dateAndTime.getTime() + skew);
                nowMinusSkew = new Date(dateAndTime.getTime() - skew);
            }
            // Check that the test date is within the validity interval:
            //   [ thisUpdate - MAX_CLOCK_SKEW,
            //     nextUpdate + MAX_CLOCK_SKEW ]
            if (nowMinusSkew.after(nextUpdate)
                || nowPlusSkew.before(crlThisUpdate)) {
                if (debug != null) {
                    debug.println("X509CRLSelector.match: update out-of-range");
                }
                return false;
            }
        }


Получается он отвергает мой CRL. А отвергает он потому что КриптоПро устанавливает дату для X509CRLSelector

crl.JPG (158kb) загружен 5 раз(а).

А надо ли устанавливать дату для X509CRLSelector? Ведь CRL это накопительный список с фиксацией даты отзыва. Зачем требуется CRL именно на дату построения цепочку и проверки отзыва? Ведь если я предоставлю более новый CRL это не изменит информации о дате отзыва того или иного сертификата?

Отредактировано пользователем 5 июня 2025 г. 17:40:45(UTC)  | Причина: Не указана

Offline Анатолий Широков  
#2 Оставлено : 5 июня 2025 г. 12:05:50(UTC)
Анатолий Широков

Статус: Участник

Группы: Участники
Зарегистрирован: 22.01.2019(UTC)
Сообщений: 22
Мужчина
Российская Федерация
Откуда: Санкт-Петербург

Сказал «Спасибо»: 7 раз
Отвергать CRL старее даты проверки - это нормально, но почему отвергать CRL новее даты проверки? Какая здесь логика?

Нашел старое обсуждение https://www.cryptopro.ru...ts&m=79915#post79915

Получается, что я должен хранить все выпуски CRL и на определенную дату подставлять выпуск списка отзыва, который включает дату проверки между датой выпуска и датой следующего выпуска? Я правильно понимаю?

Вообщем, в итоге создал свою реализацию CollectionCertStore, где сбрасываю дату в X509CRLSelector-e перед вызовом match-a, зарегистрировал ее в своем провайдере и теперь получаю цепочку на любую дату с актуальным CRL. Перспектива хранить все выпуску CRL меня особо не греет.

Спасибо за внимание! :)

Отредактировано пользователем 5 июня 2025 г. 17:40:30(UTC)  | Причина: Не указана

RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Guest
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.