«Что я делаю не так?»
Проблема в том, что с одной стороны вы начинаете создавать контейнер сигнатур CMS с использованием PdfPKCS7
экземпляра
PdfPKCS7 sgn = new PdfPKCS7(null, chain, hashAlgorithm, false);
и для рассчитанногодайджест документа hash
извлекает подписанные атрибуты как
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);
для отправки их на подпись.
Пока все хорошо.
Но тогда вы игнорируете контейнер CMSвы начали конструировать, но вместо этого вставьте открытые байты подписи , полученные от службы , в PDF .
Это не может работать, поскольку байты вашей подписи не подписывают документнапрямую, но вместо этого они подписывают эти подписанные атрибуты (и, следовательно, косвенно документ как хэш документа является одним из подписанных атрибутов).Таким образом, игнорируя создаваемый контейнер CMS, вы удаляете фактически подписанные данные ...
Кроме того, используемый вами подфильтр ADBE_PKCS7_DETACHED
обещает, что встроенная подпись является полным контейнером сигнатуры CMS, а не несколькими голыми сигнатурами.в байтах, поэтому формат также неправильный.
Как это сделать вместо этого?
Вместо того, чтобы вставлять в PDF-файл открытые байты подписи, полученные из службы, как есть, их необходимо установить.как внешний дайджест в экземпляре PdfPKCS7
, в котором вы изначально начали создавать контейнер подписи:
sgn.SetExternalDigest(sig, null, ENCRYPTION_ALGO);
(ENCRYPTION_ALGO
должна быть частью шифрования алгоритма подписи, я полагаю в вашем случае "RSA"
.)
и затем вы можете получить сгенерированный контейнер подписи CMS:
byte[] encodedSig = sgn.GetEncodedPKCS7(hash, null, null, null, CryptoStandard.CMS);
Теперь это контейнер подписи, который нужно вставить в документ с помощью MyExternalSignatureContainer
:
IExternalSignatureContainer external = new MyExternalSignatureContainer(encodedSig);
MakeSignature.SignDeferred(reader, "Signature1", os, external);
Остальные проблемы
Исправив ваш код, Adobe Reader по-прежнему предупреждает о вашей подписи:
- "ПодписьИдентификатор NER неизвестен, поскольку он не был включен в список доверенных идентификаторов, и ни один, или его родительские сертификаты не являются доверенными. "
Это предупреждение следует ожидатьи исправьте!
Идентификатор подписавшего неизвестен , поскольку ваша служба подписи использует только демонстрационный сертификат, а не сертификат для производственного использования:
Как видите, сертификат выпущен "GlobalSign Непубличная демонстрация HVCA", и непубличная демонстрация эмитентов по очевидным причинам должнынельзя доверять (если вы не добавите их вручную в хранилище доверенных сертификатов для тестирования).
«Подпись помечена меткой времени, но метка не может быть проверена»
Существует две причины, по которым Adobe не одобряет вашу метку времени:
На однойС другой стороны, как и выше, сертификат временной метки является закрытым демонстрационным сертификатом («DSS Non-Public Demo TSA Responder»).Таким образом, у верификатора нет причин доверять вашей метке времени.
С другой стороны, однако, в коде вашей метки времени есть реальная ошибка, вы применяете алгоритм хеширования дважды!В вашем MyITSAClient
классе у вас есть
public byte[] GetTimeStampToken(byte[] imprint)
{
string hashedImprint = Sha256_hash(imprint);
// hashedImprint sent to signing service
return Convert.FromBase64String("Base64 encoded DER representation of TimeStampToken received from signing service");
}
Параметр imprint
вашей реализации GetTimeStampToken
уже хэширован, поэтому вам необходимо закодировать эти байты в шестнадцатеричном формате и отправить их для отметки времени.Но вы применяете свой метод Sha256_hash
, который сначала хеширует, а затем выполняет шестнадцатеричное кодирование этого нового хэша.
Таким образом, вместо применения Sha256_hash
просто шестнадцатеричное кодирование кодирует imprint
!