C# 如何使用 Windows Cert Store 中的证书签署 PDF 文档?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14997118/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 13:42:38  来源:igfitidea点击:

How do I sign a PDF document using a certificate from the Windows Cert Store?

c#pdfcertificateitextsharpsigning

提问by doppelgreener

I need to sign a PDF document using a certificate that exists in the Windows Certificate Store. I have been digging around all day trying to figure it out, and I am so closeyet so far away.

我需要使用 Windows 证书存储中存在的证书对 PDF 文档进行签名。我一整天都在四处寻找,试图弄清楚,我那么近,却又那么远

All that is missing is this: How do I get an IExternalSignature object to sign the PDF file with?

所缺少的就是:如何获取 IExternalSignature 对象来签署 PDF 文件?

Rahul Singlahas written a beautiful example of how to sign a PDF document using the new iText 5.3.0 API - as long asyou can access a .pfx file sitting around on your PC somewhere.

Rahul Singla写了一个很好的例子,说明如何使用新的 iText 5.3.0 API 签署 PDF 文档 -只要您可以访问 PC 上某处的 .pfx 文件。

There is a previous questionon signing using a certificate from the Windows Cert Store, except it was using a version of the API where SetCryptostill exists, and the signature was apparently optional. In iText 5.3.0, the API has changed, and SetCryptois no longer a thing.

之前有一个关于使用来自 Windows Cert Store 的证书签名的问题,除了它使用的 API 版本SetCrypto仍然存在,并且签名显然是可选的。在 iText 5.3.0 中,API 发生了变化,SetCrypto不再是一回事。

Here's what I have so far (comments added for posterity, since this might be the most complete and recent version of how to do this on the 'net):

这是我到目前为止所拥有的(为后代添加的评论,因为这可能是如何在“网上”执行此操作的最完整和最新版本):

using iTextSharp.text.pdf;
using iTextSharp.text.pdf.security;
using BcX509 = Org.BouncyCastle.X509;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Crypto;
using DotNetUtils = Org.BouncyCastle.Security.DotNetUtilities;

...

// Set up the PDF IO
PdfReader reader = new PdfReader(@"some\dir\SomeTemplate.pdf");
PdfStamper stamper = PdfStamper.CreateSignature(reader,
    new FileStream(@"some\dir\SignedPdf.pdf", FileMode.Create), '
X509Certificate cert = certCollection[0]; // Your code
X509Certificate2 signatureCert = new X509Certificate2(cert);

var pk = Org.BouncyCastle.Security.DotNetUtilities.GetKeyPair(signatureCert.PrivateKey).Private;
'); PdfSignatureAppearance sap = stamper.SignatureAppearance; sap.Reason = "For no apparent raisin"; sap.Location = "..."; // Acquire certificate chain var certStore = new X509Store(StoreName.My, StoreLocation.LocalMachine); certStore.Open(OpenFlags.ReadOnly); X509CertificateCollection certCollection = certStore.Certificates.Find(X509FindType.FindBySubjectName, "My.Cert.Subject", true); X509Certificate cert = certCollection[0]; // iTextSharp needs this cert as a BouncyCastle X509 object; this converts it. BcX509.X509Certificate bcCert = DotNetUtils.FromX509Certificate(cert); var chain = new List<BcX509.X509Certificate> { bcCert }; certStore.Close(); // Ok, that's the certificate chain done. Now how do I get the PKS? IExternalSignature signature = null; /* ??? */ // Sign the PDF file and finish up. MakeSignature.SignDetached(sap, signature, chain, // the important stuff null, null, null, 0, CryptoStandard.CMS); stamper.Close();

As you can see: I have everything but the signature, and I'm stumped as to how I should obtain it!

如您所见:我拥有除签名之外的所有内容,但我不知道如何获得它!

采纳答案by Sam Shiles

IExternalSignature es = new PrivateKeySignature(pk, "SHA-256");

If you have the pk, which can get as above, you create an IExternalSignature as follows:

如果您有 pk,如上所示,您可以创建一个 IExternalSignature,如下所示:

X509Store x509Store = new X509Store("My");
x509Store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certificates = x509Store.Certificates;
IList<X509Certificate> chain = new List<X509Certificate>();
X509Certificate2 pk = null;
if (certificates.Count > 0) {
    X509Certificate2Enumerator certificatesEn = certificates.GetEnumerator();
    certificatesEn.MoveNext();
    pk = certificatesEn.Current;
    X509Chain x509chain = new X509Chain();
    x509chain.Build(pk);
    foreach (X509ChainElement x509ChainElement in x509chain.ChainElements) {
        chain.Add(DotNetUtilities.FromX509Certificate(x509ChainElement.Certificate));
    }
}
x509Store.Close();

You may also find the following articles of use:

您还可以找到以下使用文章:

回答by Bruno Lowagie

Please download the book on PDF and digital signatures. You'll find a Java example on how to sign using the Windows Certificate Store in Chapter 3. As you can see, you need the Windows-MY keystore.

请下载有关PDF 和数字签名的书籍。您将在第 3 章中找到有关如何使用 Windows 证书存储进行签名的 Java 示例。如您所见,您需要 Windows-MY 密钥库。

Now go to the repository where we've published the C# port of these examples. Look for C3_11_SignWithToken.cs.

现在转到我们发布这些示例C# 端口的存储库。查找C3_11_SignWithToken.cs

public byte[] SignPdf(byte[] pdf)
{
    using (MemoryStream output = new MemoryStream())
    {
        //get certificate from path
        X509Certificate2 cert1 = new X509Certificate2(@"C:\temp\certtemp.pfx", "12345", X509KeyStorageFlags.Exportable);
        //get private key to sign pdf
        var pk = Org.BouncyCastle.Security.DotNetUtilities.GetKeyPair(cert1.PrivateKey).Private;
        // convert the type to be used at .SetCrypt(); 
        Org.BouncyCastle.X509.X509Certificate bcCert = Org.BouncyCastle.Security.DotNetUtilities.FromX509Certificate(cert1);
        // get the pdf u want to sign
        PdfReader pdfReader = new PdfReader(pdf);

        PdfStamper stamper = PdfStamper.CreateSignature(pdfReader, output, '##代码##');
        PdfSignatureAppearance pdfSignatureAppearance = stamper.SignatureAppearance;
        //.SetCrypt(); sign the pdf
        pdfSignatureAppearance.SetCrypto(pk, new Org.BouncyCastle.X509.X509Certificate[] { bcCert }, null, PdfSignatureAppearance.WINCER_SIGNED);

        pdfSignatureAppearance.Reason = "Este documento está assinado digitalmente pelo Estado Portugues";
        pdfSignatureAppearance.Location = " Lisboa, Portugal";
        pdfSignatureAppearance.SignDate = DateTime.Now;

        stamper.Close();

        return output.ToArray();
    }
} 

If I understand correctly chainand pkare the variable you were looking for;

如果我理解正确chain并且pk是您正在寻找的变量;

回答by Frederico Monteiro

##代码##

I use this code to get byte[]PDF and return again a byte[]PDF already signed.

我使用此代码获取byte[]PDF 并再次返回byte[]已签名的PDF。

It's iTextSharp-LGPL.

它是 iTextSharp-LGPL。