c# - 在 C# 和 iText 7 中使用 x509Certificate2 创建 IExternalSignature

标签 c# itext primary-key sign x509certificate2

我正在测试 iText 7.1.2.0 库来签署 pdf 文件,在 C# 项目中使用数字证书或智能卡 (X509Certificate2)。但是当我尝试创建 IExternalSignature 时出现此错误。

enter image description here

根据找到的文档(hereherehere),实现此过程的方法是使用允许从数字证书中提取主键的 BouncyCaSTLe 库,但是,它给了我一个错误,我找不到另一种方法来做到这一点。 在文档 ( here ) 中,它们是从 .pfx 文件创建的,但对于这种情况,我需要直接从读卡器中的证书中获取主 key 。在以前的 iText 版本中,允许使用以下命令创建:

IExternalSignature externalSignature = new X509Certificate2Signature(Certificate, "SHA-1");

但在版本 7 中它不再可用,而且在文档中我也看不到如何操作。

有人使用过 iText 7 并且能够使用知道创建 IExternalSignature 的正确方法的 X509Certificate2 进行签名吗?

这是我正在使用的代码:

public void SignPDF(string source, string target, X509Certificate2 certificate, string reason, string location, bool addVisibleSign, bool addTimeStamp, string strTSA, int qtySigns, int pageNumber)
    {
        try
        {
            Org.BouncyCastle.X509.X509Certificate vert = Org.BouncyCastle.Security.DotNetUtilities.FromX509Certificate(certificate);

            X509CertificateParser objCP = new X509CertificateParser();
            Org.BouncyCastle.X509.X509Certificate[] objChain = new Org.BouncyCastle.X509.X509Certificate[] { objCP.ReadCertificate(certificate.RawData) };

            IList<ICrlClient> crlList = new List<ICrlClient>();
            crlList.Add(new CrlClientOnline(objChain));

            PdfReader objReader = new PdfReader(source);
            PdfSigner objStamper = new PdfSigner(objReader, new FileStream(target, FileMode.Create), false);

            ITSAClient tsaClient = null;
            IOcspClient ocspClient = null;

            if (addTimeStamp)
            {
                OCSPVerifier ocspVerifier = new OCSPVerifier(null, null);
                ocspClient = new OcspClientBouncyCastle(ocspVerifier);
                tsaClient = new TSAClientBouncyCastle(strTSA);
            }

            PdfSignatureAppearance signatureAppearance = objStamper.GetSignatureAppearance();
            signatureAppearance.SetReason(reason);
            signatureAppearance.SetLocation(location);
            signatureAppearance.SetPageNumber(pageNumber);
            signatureAppearance.SetRenderingMode(PdfSignatureAppearance.RenderingMode.NAME_AND_DESCRIPTION);

            if (addVisibleSign && qtySigns == 1)
                signatureAppearance.SetPageRect(new iText.Kernel.Geom.Rectangle(36, 20, 144, 53)).SetPageNumber(pageNumber);
            else if (addVisibleSign && qtySigns == 2)
                signatureAppearance.SetPageRect(new iText.Kernel.Geom.Rectangle(160, 20, 268, 53)).SetPageNumber(pageNumber);
            else if (addVisibleSign && qtySigns == 3)
                signatureAppearance.SetPageRect(new iText.Kernel.Geom.Rectangle(284, 20, 392, 53)).SetPageNumber(pageNumber);
            else if (addVisibleSign && qtySigns == 4)
                signatureAppearance.SetPageRect(new iText.Kernel.Geom.Rectangle(408, 20, 516, 53)).SetPageNumber(pageNumber);

            var pk = Org.BouncyCastle.Security.DotNetUtilities.GetKeyPair(certificate.PrivateKey).Private;

            IExternalSignature externalSignature = new PrivateKeySignature(pk, "SHA-1");
            objStamper.SignDetached(externalSignature, objChain, crlList, ocspClient, tsaClient, 0, PdfSigner.CryptoStandard.CMS);

            if (objReader != null)
            {
                objReader.Close();
            }
        }
        catch (Exception ex)
        {
            result.error = true;
            result.errorMessage += "Error: " + ex.Message;
        }
    }

谢谢!

最佳答案

我不相信该类已移植到 iText 7 - 它只是一个包装类。

您可以在 this example 中查看如何创建自定义 IExternalSignatureContainer

请注意,可以找到 iText 5 X509Certificate2Signature 的来源 here

所以像这样:

public class X509Certificate2Signature: IExternalSignature {
    private String hashAlgorithm;
    private String encryptionAlgorithm;
    private X509Certificate2 certificate;

    public X509Certificate2Signature(X509Certificate2 certificate, String hashAlgorithm) {
        if (!certificate.HasPrivateKey)
            throw new ArgumentException("No private key.");
        this.certificate = certificate;
        this.hashAlgorithm = DigestAlgorithms.GetDigest(DigestAlgorithms.GetAllowedDigest(hashAlgorithm));
        if (certificate.PrivateKey is RSACryptoServiceProvider)
            encryptionAlgorithm = "RSA";
        else if (certificate.PrivateKey is DSACryptoServiceProvider)
            encryptionAlgorithm = "DSA";
        else
            throw new ArgumentException("Unknown encryption algorithm " + certificate.PrivateKey);
    }

    public virtual byte[] Sign(byte[] message) {
        if (certificate.PrivateKey is RSACryptoServiceProvider) {
            RSACryptoServiceProvider rsa = (RSACryptoServiceProvider) certificate.PrivateKey;
            return rsa.SignData(message, hashAlgorithm);
        }
        else {
            DSACryptoServiceProvider dsa = (DSACryptoServiceProvider) certificate.PrivateKey;
            return dsa.SignData(message);
        }
    }

    public virtual String GetHashAlgorithm() {
        return hashAlgorithm;
    }

    public virtual String GetEncryptionAlgorithm() {
        return encryptionAlgorithm;
    }
}

将在 iText 7 中复制该类的功能。显示如何使用该类 here在我的第一个链接中,尽管您很可能会使用 signDetached() 方法而不是 signDeffered() 方法。

关于c# - 在 C# 和 iText 7 中使用 x509Certificate2 创建 IExternalSignature,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50627483/

相关文章:

c# - 动态构建 LINQ 查询 - 强制使用 sp_executesql 而不是原始查询

c# - 关闭文档时抛出“文档没有页面”错误

c# - .net 数据集主键 - 强制唯一性?

oracle11g - 如何使用alter命令为已经有主键的表定义复合主键?

c# - Mvc,外键关系

c# - 相当于Visual Studio的 "Properties Window"的控件?

javascript - 如何创建具有初始 View = Fit 的 PDF 文件

java - Java中用JPA组成的主键

C#4 : Raising and Subscribing Events Between Static CLasses

c# - 使用 ItextSharp 在 PDF 中的图像上绘制线条