问题:我想用 iText 和 PKCS11 提供程序签署 PDF 文档(在 C# 中,Java 也可以)。这可行,但签名的 PDF 缺少几个signed attributes
:
- 发行人
- 序列号
- 签约时间
因此,在@mkl 发表评论后,我实现了一个自定义IExternalSignatureContainer
,但签名看起来无效我当前的代码:
try
{
using (var signature = new Pkcs11Signature(libraryPath, slotId, pin, "SHA256")) // My custom PKCS11 provider
using (var pdfReader = new PdfReader(inputFile))
using (var result = File.Create(outputFile))
{
var stampingProperties = new StampingProperties();
stampingProperties.UseAppendMode();
// Sign the document
var pdfSigner = new PdfSigner(pdfReader, result, stampingProperties);
pdfSigner.SignExternalContainer(new ExternalSignature(signature), 8192);
}
}
catch (Exception exception)
{
throw new Exception("Unable to sign PDF file: " + exception.Message);
}
using iText.Kernel.Pdf;
using iText.Signatures;
using Org.BouncyCastle.Crypto.Digests;
namespace acme;
public class ExternalSignature : IExternalSignatureContainer
{
private Pkcs11Signature pkcs11Signature;
public ExternalSignature(Pkcs11Signature pkcs11Signature)
{
this.pkcs11Signature = pkcs11Signature;
}
public byte[] Sign(Stream data)
{
// Get the certificate chain via PKCS11
var chain = pkcs11Signature.GetChain();
// Create the PKCS7 container
var pdfPkcS7 = new PdfPKCS7(null, chain, pkcs11Signature.GetHashAlgorithm(), false);
var secondDigest = DigestAlgorithms.Digest(data, new Sha256Digest());
var authenticatedAttributeBytes = pdfPkcS7.GetAuthenticatedAttributeBytes(secondDigest, PdfSigner.CryptoStandard.CMS, null, null);
// Dump the authenticated attributes so we can check them via ASN1 parsing
//File.WriteAllBytes("messageex.bin", authenticatedAttributeBytes);
// Sign the message
var digest = pkcs11Signature.Sign(authenticatedAttributeBytes);
// Set the digest
pdfPkcS7.SetExternalDigest(digest, null, pkcs11Signature.GetEncryptionAlgorithm());
var encodedPkcS7 = pdfPkcS7.GetEncodedPKCS7(secondDigest, PdfSigner.CryptoStandard.CMS, null, null, null);
return encodedPkcS7;
}
public void ModifySigningDictionary(PdfDictionary signDic)
{
//throw new NotImplementedException();
}
}