iText7 PDF-подписи с сертификатом GlobalSign DSS AATL показывает нарушенную цепочку доверия в Adobe Reader - PullRequest
1 голос
/ 03 апреля 2020

Я подписываю цифровой документ PDF с помощью iText7 и GlobalSign DSS. Я реализовал вызовы GlobalSing DSS API в необходимые классы iText. Я получаю правильные ответы сервера и могу вызвать метод pdfSigner.signDetached () со всеми необходимыми аргументами. Подписание с pdfSigner также успешно, и я получаю подписанный PDF, который выглядит хорошо с первого взгляда. Но когда я открываю подписанный pdf в Adobe Reader, он говорит мне, что цепочка доверия сертификата подписи разорвана и что он не может отследить его до CA root. Что странно, потому что это сертификат AATL и список AATL в Adobe Reader обновлен. И я не понимаю, почему это происходит. Вот что я делаю:

  • вызов DSS для идентификации: возвращает строку идентификатора, сертификат подписи и ответ ocsp

  • вызов DSS для цепочки доверия: возвращает цепочку сертификатов, используемых для
    подписи сертификата подписи, вплоть до GlobalSign root вместе с
    их ответами на осцилляции (за исключением root)

  • Я создаю массив объектов сертификата X509, содержащий подписывающий сертификат
    , 2 промежуточных звена и сертификат GlobalSign root (в указанном порядке)

  • Я реализую IOcspClient, который использует ответ ocsp от вызова DSS для идентификации

  • Я реализую ITsaClient, который вызывает DSS API / timestamp / {digest}

  • и наконец я выполняю: pdfSigner.signDetached (externalDigest, externalSignature, chain.toArray (новый X509Certificate [] {}), null, dssOcspClient, dssTSAClient, 0, PdfSigner.CryptoStandard.CMS * 10 *;

  • * 10 33 * в котором externalSignature (реализация IExternalSignature) будет вызывать идентификатор DSS / {id} / sign / {digest} API

при отладке в методе signDetached и глубже в Код pdfSigner, я четко вижу, что все сертификаты находятся в цепочке в правильном порядке. Я вижу, как они обрабатываются в классе PdfPKCS7 (однако я не знаю / точно не понимаю, что там происходит). Я вижу, что подписание происходит, никаких исключений не выдается, и в конце созданный PDF выглядит так, как будто он подписан правильно. Какой Adobe говорит, что нет.

Что мне здесь не хватает? Ответ TrustCain от de DSS API не только возвращает сертификаты из цепочки доверия сертификата подписи, но также и ответы OCSP для двух промежуточных звеньев между сертификатом подписи и GlobalSign root. Они никогда не используются. И на самом деле я тоже не знаю, что с ними делать. Могут ли это быть недостающие фрагменты для AdobeReader для восстановления цепочки доверия до GlobalSign root? И если так: как мне поместить их в этот PDF? А если нет: то, что я делаю неправильно, что нарушает эту цепочку доверия? Ответ на эти вопросы спас бы мой день :-) Вот ссылка на PDF, который покажет проблему: тестовый pdf с подписью DSS (после принятия ответа я удалил пример pdf по запросу моего клиента) Ниже приведены некоторые фрагменты кода. Центральная часть, которая собирает информацию о DSS и вызывает метод signDetached

    private InputStream sign(byte[] unsignedDocument) throws IOException, DssServiceException, GeneralSecurityException {

    SigningIdentity signingIdentity = signingIdentityService.getValidSigningIdentity();
    DssOcspClient dssOcspClient = new DssOcspClient(signingIdentity);

    TrustChainResponse trustChainResponse = digitalSigningService.getTrustChain();
    List<X509Certificate> chain = new ArrayList<>();
    chain.add(signingIdentity.getCertificate());
    chain.addAll(trustChainResponse.getTrustChain());

    IExternalDigest externalDigest = new ProviderDigest(BC_SECURITY_PROVIDER);
    IExternalSignature externalSignature = new DssExternalSignature(signingIdentity.getIdentity(), digitalSigningService);

    ByteArrayOutputStream signedPdfOut = new ByteArrayOutputStream();
    PdfSigner pdfSigner = createPdfSigner(new ByteArrayInputStream(unsignedDocument), signedPdfOut);
    pdfSigner.signDetached(externalDigest, externalSignature, chain.toArray(new X509Certificate[]{}), null, dssOcspClient, dssTSAClient, 0, PdfSigner.CryptoStandard.CADES);

    return new ByteArrayInputStream(signedPdfOut.toByteArray());
}

Реализация IExternalSignature

    @Override
public byte[] sign(byte[] message) throws GeneralSecurityException {
    MessageDigest messageDigest = new BouncyCastleDigest().getMessageDigest(DEFAULT_DIGEST_ALGORITHM);
    byte[] documentHash = messageDigest.digest(message);
    try {
        return digitalSigningService.getSignature(signingIdentity, documentHash);
    }
    catch (DssServiceException e) {
        LOGGER.error("error getting signature", e);
        throw  new GeneralSecurityException(e);
    }
}

Реализация IOcspClient

    @Override
public byte[] getEncoded(X509Certificate checkCert, X509Certificate issuerCert, String url) {
    try {
        if(Objects.equals(signingIdentity.getCertificate(), checkCert)) {
            OCSPResp response = new OCSPResp(signingIdentity.getOcsp());
            BasicOCSPResp basicResponse = (BasicOCSPResp)response.getResponseObject();
            return basicResponse.getEncoded();
        }
    }
    catch (CertificateException | IOException | OCSPException e) {
        LOGGER.warn("OCSP validatie gefaald!", e.getMessage());
    }
    return null;
}

Реализация ITSAClient

    @Override
public byte[] getTimeStampToken(byte[] imprint) throws Exception {

    String digestAlgorithmOID = DigestAlgorithms.getAllowedDigest(DEFAULT_DIGEST_ALGORITHM);
    ASN1ObjectIdentifier digestAlgOID = new ASN1ObjectIdentifier(digestAlgorithmOID);
    AlgorithmIdentifier algID = new AlgorithmIdentifier(digestAlgOID, DERNull.INSTANCE);
    MessageImprint messageImprint = new MessageImprint(algID, imprint);

    byte[] hash = messageImprint.getHashedMessage();
    return digitalSigningService.getTimeStamp(hash);
}

1 Ответ

1 голос
/ 08 апреля 2020

Короче говоря

Ваш сертификат подписавшего недействителен.

Подробно

Ваш сертификат подписавшего и его цепочка сертификатов (в зависимости от соответствия эмитента / субъекта) встроены в подпись, в частности, ваш сертификат с предметом

cn = Homologat ie Voertuigen, ou = Департамент Mobiliteit en Openbare Werken, ou = Vlaams Huis voor de Verkeersveiligheid, o = Служение Ван де Вламсе, Gemeenschap, l = Brussel, st = Brussel, c = BE

и его заявленный эмитент

cn = GlobalSign CA 5 для AATL, o = GlobalSign nv-sa, c = BE

Таким образом, можно проверить подпись, с которой подписан ваш сертификат. И при этом видно, что часть TBSCertificate вашего сертификата подписавшего (часть для подписи) имеет это значение дайджеста

C8751FDC7F679CB627F61028ACDD0D09613AFA782412ACFC7E189EA5DA625831

, но подпись фактически подписывает это значение дайджеста

16090737B41E6E0466E7EB7A7EBD79F5494E438C11D0FB408BCA663A5923AD03

Таким образом, ваш сертификат подписавшего подписан неправильно.

Что это значит

В комментарии вы спрашиваете

Но я немного запутался в том, что именно это значит. Действительно ли мы что-то делаем неправильно во время подписания, отправляя неправильный документ ha sh на сервер подписи? Или вы имеете в виду, что что-то не так с сертификатом подписи на стороне сервера, выданным GlobalSign, который они используют для подписи этого документа, ha sh?

Вы, по крайней мере, не делаете ничего плохого во время подписания Я так не думаю. Подорванная подпись - это не подпись, подписывающая документ, а подпись, подписывающая ваш сертификат вашим центром сертификации.

Я вижу, по сути, три возможные причины этого:

  • Сертификат подпись просто сломана и нигде не соответствует вашему сертификату.

    Это меня удивило бы.

  • Подпись сертификата была рассчитана не для DER-закодированной формы вашей подписываемой части сертификата, а для какой-либо другой формы.

    Это не неслыханно для , если ваш сертификат изначально был не в форме DER, а сертификат процесс подписания предполагал, что форма не-DER может быть подписана (даже если согласно спецификации форма DER должна быть подписана). Если бы затем какой-нибудь валидатор проверил подпись, которая также не обеспечивает форму DER, но принимает TBSCertificate как есть, этот валидатор даже указал бы, что подпись действительна.

    В сертификате, который встроен в подпись PDF, -be-подписанная часть кодируется с помощью DER, но это могло быть применено на каком-то этапе после первоначальной генерации сертификата.

  • Возможно, с вашим сертификатом после создания произошли незначительные изменения.

    Это также возможно.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...