Во-первых, вы показываете нам код из неизвестного источника и задаете вопросы о нем.Поскольку мы не знаем его контекста, ответы могут быть немного расплывчатыми или не соответствовать реальному контексту.
Вопрос 1:
См. Код рядом:
// the validity of the certificate isn't verified, just the fact that one of the certs matches the given signer
Зачем это проверять?Что здесь может пойти не так?
(Под «кодом рядом ...» вы подразумеваете, какой именно код? Поскольку неясно, я пытаюсь просто поместить комментарий в контекст ...)
На этом этапе все, что произошло, это то, что для текущего объекта SignerInfo
объект SignerIdentifier
в нем использовался для идентификации одного из сертификатов, содержащихся в контейнере для подписи, как заявлено .сертификат подписывающего лица (да, на самом деле существует цикл из нескольких возможных совпадений, но общий случай - найти ровно одно совпадение, все остальное следует считать подозрительным).
Таким образом, код на самом деле еще не подтвердил сертификат, но определил , какой сертификат проверить позже (и проверить подпись с помощью).
Итак ...
- "Зачем это проверять?"- Пока ничего не проверено.
- "Что здесь может пойти не так?"- Возможно, заявленный сертификат подписавшего не может быть найден среди сертификатов в контейнере подписи, или найдено несколько кандидатов.Ваш код не предлагает стратегию для первого случая, даже не выводится предупреждение или ошибка.В последнем случае это проверяет каждого кандидата.Обычно проверка завершается не более чем одним из сертификатов-кандидатов.
Вопрос 2:
См. Код рядом:
Collection certCollection = certStore.getMatches(signer.getSID());
Получает сертификатыиз PDF, которые принадлежат подписавшему.Разве это не дублируется в коде рядом:
SignerInformationVerifier signerInformationVerifier = new JcaSimpleSignerInfoVerifierBuilder().build(cert2);
(Под "кодом рядом ..." вы подразумеваете, какой именно код? Как непонятно, я предполагаю, что вы имеете в виду именностроки кода, которые вы цитировали)
«При этом из pdf-файла получаются сертификаты, принадлежащие подписавшему».- Ну, строго говоря, он извлекает кандидатов для сертификата подписавшего из сертификатов, хранящихся в контейнере подписи, хранящемся в PDF-файле, соответствующего SignerIdentifier
.
"Разве это не дублируется вcode ... "- Нет, код там создает BouncyCastle SignerInformationVerifier
, который эффективно объединяет несколько служебных объектов верификатора для различных аспектов подписи.Этот объект инициализируется сертификатом кандидата на подпись, полученным в предыдущем коде.Таким образом, без дублирования.
Вопрос 3:
Если PDF-файл был изменен после подписи, то код по-прежнему выдает сообщение «Проверка подписи PDF верна». Я бы подумал, что проверкатерпит неудачу!Что такое Java-код, чтобы обнаружить, что PDF был изменен после подписания?
Это зависит от как PDF был изменен !Есть два варианта: либо изменения были применены посредством инкрементного обновления (в этом случае оригинальные подписанные байты PDF копируются без изменений, а изменения добавляются после этого), либо иным образом (в этом случае оригинальные подписанные байты PDF не не представляет собой начало измененного PDF).
В последнем случае изменяются первоначально подписанные байты, и ваш код напечатает «Проверка подписи PDF не удалась».
В первом случаеоднако подписанные байты не изменяются, и в вашем коде будет отображаться «Проверка подписи PDF верна».Чтобы отследить изменения такого типа, вам также необходимо проверить, являются ли байты подписанного PDF целым PDF, за исключением места, зарезервированного для контейнера подписи CMS, или других байтов, не учитываемых.
Длянекоторые подробности читайте этот ответ , а для изменений, которые считаются разрешенными, читайте этот ответ .
Вопрос 4:
См. код:
PKIXCertPathValidatorResult validatorResult = (PKIXCertPathValidatorResult) certPathValidator.validate(certPath, parameters);
Сбой, если путь к сертификату не ведет к доверенному сертификату. Разве это не намного лучшая проверка, чем проверка, указанная в вопросе 1?
Как уже говорилось выше, код, приводящий к вопросу 1, вовсе не является проверкой , а приблизительно определяет сертификат, который в конечном итоге подлежит проверке. Код здесь, на самом деле, принимает этот ранее определенный сертификат и фактически проверяет его.
Квинтэссенция
Вопросы 1, 2 и 4 по существу касаются понимания шагов, которые необходимо предпринять при проверке контейнера подписи CMS. В частности, вы должны
- определяет кандидата на сертификат сертификата подписчика (ваш код делает это на основе значения
SignerIdentifier
; так как он сам по себе не подписан, однако в настоящее время один этот критерий считается недостаточным и дополнительно использует подписанные атрибуты (ESSCertID
или ESSCertIDv2
);
- проверить, можно ли использовать сертификат-кандидат для проверки значения криптографической подписи (в вашем случае во время
signer.verify(signerInformationVerifier)
);
- убедитесь, что хэш диапазонов подписанных документов соответствует значению атрибута со знаком
messageDigest
(в вашем случае также во время signer.verify(signerInformationVerifier)
);
- проверьте, можно ли доверять сертификату подписавшего (в вашем случае во время
certPathValidator.validate
).
Вопрос 3, по сути, касается понимания дополнительных шагов, которые необходимо предпринять при проверке контейнера подписи CMS, встроенного в PDF. В частности, вы должны
- проверьте, охватывают ли подписанные байтовые диапазоны весь PDF, кроме заполнителя, оставленного для контейнера подписи (не выполняется вашим кодом).