SignerInformationVerifier
, полученный из JcaSimpleSignerInfoVerifierBuilder...build(cert)
(который в основном охватывает ContentVerifierProvider
), управляется SignerInformation.verify
следующим образом:
, так как была использована перегрузка build(cert)
, а не перегрузка build(publickey)
, , если присутствует атрибут аутентификации / подписи (обязательно должен быть) signatureTime, он проверяет, что значение signatureTime равно в течение срока действия сертификата
если присутствуют аутентифицированные / подписанные атрибуты, он проверяет их, включая проверку того, что дайджест (полученного) содержимого соответствует атрибуту дайджеста, и проверяет, что подпись проверяется как подпись подписанных атрибутов под publickey в сертификате (и алгоритмах, указанных в сообщении и SignerInfo)
в противном случае (без подписанных атрибутов) он проверяет, что подпись проверяется как подпись (полученного) контента под открытым ключом в сертификате (и алгоритмы, указанные в сообщении и SignerInfo)
Если вместо этого вы используете перегрузку JcaSimpleSignerInfoVerifierBuilder...build(cert.getPublicKey())
, единственное отличие состоит в том, что он не сравнивает подписывающее время, если оно присутствует, с периодом действия сертификата.
Может проверять атрибуты подписавшего по атрибутам сертификата (только для субъекта? Или также серийный номер, эмитент?)
Это не так. Ваш код должен; см. org.bouncycastle.cms.CMSSignedDataParser
javadoc для минимального примера, который использует Store
сертификатов в сообщении, чтобы найти сертификат, соответствующий 'SID' (SignerIdentification
) в SignerInfo
. Этот «SID» обычно представляет собой пару «Эмитент» и «Последовательный», но в CMS это может быть SubjectKeyIdentifier. Стандартный формат PKCS7 / CMS не определяет имя субъекта для подписавшего (или SubjectAltName, в этом отношении), поэтому любой метод определения этого и использования его для поиска или проверки сертификата будет нестандартным. Однако вполне возможно, что, как только вы найдете сертификат другим способом, вы можете захотеть использовать его тему (или SAN) в качестве полезной информации при обработке подписанного содержимого.
Он вообще не проверяет, является ли сертификат действительным / доверенным. Пример отмечает это как проблему.
Если вы хотите использовать простой подход, вы можете просто проверить, находится ли сертификат в вашем хранилище доверенных сертификатов или иным образом напрямую настроен, и не истек ли он, возможно, пропустив последний, если SignerInformation
содержит подписанный атрибут signatureTime, который было проверено, как указано выше. Это подвергает вас риску, если сертификат подписавшегося был отозван из-за компрометации ключа или сертификат был признан мошенническим; вы будете продолжать принимать подписи от вора или мошенника. Кроме того, вы зависите от себя или кого-то, кто обновляет локальное хранилище доверенных сертификатов или конфигурацию после ручной проверки каждого нового сертификата подписи, и если вы можете обманным путем сделать это, вы снова примете поддельные подписи.
Если вы хотите действительно проверить сертификат, см. Руководство программиста Java PKI (или CertPathProgGuide в некоторых старых версиях) и javadoc для связанных классов, в основном java.security.cert.CertPathValidator
.
В моем понимании подпись - это шифрование с закрытым ключом хеша (дайджеста сообщения) документа pdf. Причина, по-видимому, заключается в том, что такой способ подписи намного быстрее. Затем функция signer.verify (signerInformationVerifier), скорее всего, расшифровывает дайджест подписанного хэшированного сообщения, используя открытый ключ сертификата, и сравнивает его с дайджестом хэшированного сообщения (используя хэш-функцию, определенную в сертификате) - она должна дать тот же результат.
В основном нет.Подписание не является шифрованием.Для алгоритма one , RSA, существует математическая симметрия между операциями в ядре шифрования и подписи, которая первоначально соблазнила людей описывать подпись как «шифрование с помощью частного ключа», но рассматривать ее таким образом было вскорекак оказалось, приводят к уязвимостям, и используемые в настоящее время схемы шифрования и подписи существенно различаются и не могут быть взаимозаменяемыми, хотя многие люди, которые просто копируют найденные в Интернете вещи, являются копиями вещей, найденных 10 лет назад и являющимися копиямивещи, найденные кем-то еще 20 лет назад, постоянно повторяют ошибкуJava crypto не помогает, потому что он был задан еще в 1990-х годах и включал неверное представление о том, что Cipher.init
для RSA принимает аргументы для «шифрования» с помощью privatekey или «дешифрования» с помощью publickey и фактически молча выполняет подпись PKCS1 иливосстановление вместо шифрования и дешифрования.Для других алгоритмов, таких как DSA, ECDSA и (теперь) EdDSA, нет никакого сходства или какой-либо связи между подписанием и шифрованием.Это обсуждается в десятках Qs на crypto.SX и security.SX, если вам интересно.
Это верно , что большинство схем подписи сейчас, и все они поддерживаются PKCS7 / CMS,гибрид: «массивные» данные сначала надежно хэшируются (также называемые «переваренными»), а затем сигнатура вычисляется с использованием (небольшого) хеша / дайджеста вместо массивных данных.Если вы имели в виду скорость подписания и проверки, это зависит от ситуации;для RSA, как это реализовано в современную эпоху (примерно с 1980 года), подписывание намного медленнее, чем проверка;для DSA и ECDSA проверка немного медленнее, чем подписывание.
Для PKCS7 / CMS, как подразумевается в приведенном выше описании, подпись обычно не берется из «содержимого» (вашего PDF-файла).Вместо этого хэш содержимого, а также некоторые другие метаданные, включены в структуру данных, которая называется authenticatedAttributes в PKCS7 и переименована в signatureAttr [ibute] в CMS, а означает, что покрывается подписью publickey (включаяхэш).Но есть опция обратной совместимости, когда подписанные атрибуты не используются, а подпись открытого ключа равна , примененной к хешу содержимого.Точно то, что подписывающее лицо и верификатор делают в обоих случаях, описано в RFC 5652 и в разделах 5.4-5.6 , хотя вам может понадобиться весь раздел 5 для контекста.Также используемый алгоритм хэширования не определен в сертификате, но в сообщении PKCS7 / CMS;однако алгоритм и размер publickey (и, следовательно, сила) определены в сертификате , если используется (что является предпочтительным, но на самом деле не требуется), и хорошей практикой является выбор хеша, который достаточно разумно соответствуетсила publickey.
Для RSA верификатор «восстанавливает» (не дешифрует) хэш из подписи и сравнивает его с вновь вычисленным хешем полученных данных - либо содержимого, либо подписанных атрибутов, как указано выше.,Технически это делается в классе провайдера JCA для RSA, вызываемом (косвенно) классами BouncyCastle, так же как совершенно разные операции проверки для DSA и ECDSA выполняются в их классах провайдера, но результат тот женасколько вы обеспокоены.