当前位置: 首页 > 知识库问答 >
问题:

使用GlobalSign DSS的iText 7 PDF签名

田德运
2023-03-14

我正在ASP.NET应用程序中使用iText7对PDF进行数字签名。我用的是vb,但我也能找到一个C#答案。我们使用GlobalSign DSS以使签名不作为未知(AATL)出现。

我从我们公司的SSL证书创建了一个pfx文件,我可以使用该文件对PDF文件进行签名,但我不明白如何使用从GlobalSign获得的东西来完成同样的事情。此服务要求发送一个十六进制编码的SHA256摘要,作为返回,我接收一个十六进制编码的SignatureValue。除此之外,我还接收到一个PEM编码的X509签名证书、中间证书(表示签名证书颁发者的PEM编码的X509证书)、signing_certificate的OCSP响应的Base64编码的DER表示、timestamp令牌的Base64编码的DER表示。它包括SignedData.CertificateSet中的TSA签名证书。

Dim outputFileStream As New FileStream(Server.MapPath(strDest), IO.FileMode.Create, IO.FileAccess.ReadWrite)
Dim signer As New PdfSigner(New PdfReader(Server.MapPath(strTemp)), outputFileStream, True)

signer.SetCertificationLevel(PdfSigner.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS)

Dim appearance As PdfSignatureAppearance = signer.GetSignatureAppearance
Dim rect As New iText.Kernel.Geom.Rectangle(50, 425, 500, 200)
appearance.SetContact("Contact Name - Phone")
appearance.SetSignatureCreator("Company - New Program")
appearance.SetReason(vbCrLf + "eDoc Consent Agreement: " + CType(Session("eDocConsentDateTime"), Date).ToString + vbCrLf _
                     + "Terms and Conditions Agreement: " + objInstall.AgreementSigned.ToString + vbCrLf _
                     + "Identifier: " + Session("Ident"))
appearance.SetLocation(vbCrLf + strInstallationAddress)
appearance.SetReuseAppearance(False)
appearance.SetPageRect(rect)
appearance.SetPageNumber(2)     'Signature will appear on Page 2
appearance.SetRenderingMode(PdfSignatureAppearance.RenderingMode.DESCRIPTION)

signer.SetFieldName(signer.GetNewSigFieldName())

Dim cert As New X509Certificate(Server.MapPath("CompSSL.pfx"), "password")
Dim tsaUrl As String = CertificateUtil.GetTSAURL(DotNetUtilities.FromX509Certificate(cert))
tsaClient = New TSAClientBouncyCastle(tsaUrl)
Dim crlList As IList(Of ICrlClient) = New List(Of ICrlClient)()

Dim fsCertFile As New FileStream(Server.MapPath("CompSSL.pfx"), FileMode.Open, FileAccess.Read)
Dim pk12 As New Pkcs12Store(fsCertFile, "password")
fsCertFile.Dispose()

'then Iterate throught certificate entries to find the private key entry
Dim [alias] As String = Nothing
For Each tAlias As String In pk12.Aliases
  If pk12.IsKeyEntry(tAlias) Then
    [alias] = tAlias
    Exit For
  End If
Next
Dim pk = pk12.GetKey([alias]).Key

Dim myExternalSignature As IExternalSignature = New PrivateKeySignature(pk, DigestAlgorithms.SHA1)

signer.SignDetached(myExternalSignature, New Org.BouncyCastle.X509.X509Certificate() {pk12.GetCertificate([alias]).Certificate}, Nothing, Nothing, Nothing, 0, PdfSigner.CryptoStandard.CMS)
    null

我试着遵循iTextsharp的例子,甚至这个例子(iTextsharp用带签名的哈希签名pdf),这正是我正在尝试做的,但它似乎没有给我完成它所需的信息。谢谢你的帮助。

编辑:
谢谢你的帮助,Dsandoval。我继续对未更改的文件进行散列,这就是我发送给GlobalSign的内容:

Dim s As New SHA256Managed
Dim fileBytes() As Byte = IO.File.ReadAllBytes(Server.MapPath(strSrc))
Dim hash() As Byte = s.ComputeHash(fileBytes)
Dim calculatedHash As String = ByteArrayToString(hash)

还有这个:

Private Function ByteArrayToString(ByVal arrInput() As Byte) As String
  Dim sb As New System.Text.StringBuilder(arrInput.Length * 2)
  For i As Integer = 0 To arrInput.Length - 1
    sb.Append(arrInput(i).ToString("X2"))
  Next
  Return sb.ToString().ToUpper
End Function
Using sw As New StreamWriter(File.Open(strFile2, FileMode.OpenOrCreate))
  sw.WriteLine(strTempCert2)
End Using
Dim fileStream2 = System.IO.File.OpenText(strFile2)
Dim pemReader2 = New Org.BouncyCastle.OpenSsl.PemReader(fileStream2)
Dim myCertificateChain() As Org.BouncyCastle.X509.X509Certificate = New Org.BouncyCastle.X509.X509Certificate() {pemReader.ReadObject, pemReader2.ReadObject}
Private Function StringToByteArray(s As String) As Byte()
  ' remove any spaces from, e.g. "A0 20 34 34"
  s = s.Replace(" "c, "")
  ' make sure we have an even number of digits
  If (s.Length And 1) = 1 Then
    Throw New FormatException("Odd string length when even string length is required.")
  End If

' calculate the length of the byte array and dim an array to that
  Dim nBytes = s.Length \ 2
  Dim a(nBytes - 1) As Byte

  ' pick out every two bytes and convert them from hex representation
  For i = 0 To nBytes - 1
    a(i) = Convert.ToByte(s.Substring(i * 2, 2), 16)
  Next

  Return a
End Function
signer.SignDetached(myExternalSignature, myCertificateChain, Nothing, Nothing, Nothing, 0, PdfSigner.CryptoStandard.CMS)

共有1个答案

利永年
2023-03-14

我使用C#实现。我对VB不太熟悉,但希望这能有所帮助。我所看到的大多数示例都是使用Java的,它们在如何实现这一点上存在一些差异,所以我必须围绕它们进行工作。我必须为这项工作实现的唯一东西是iExternalSignatural、IOcspClient和iSaclient。

>

  • 发送给GlobalSign的摘要是应用于签名之前的文档内容,因此如果应用于签名,可以省略外观。我相信,在使用pdfsigner.signdetached应用签名之前,文档不会被修改。要计算摘要,需要使用SHA256算法对消息进行散列并对其进行hexencode。这是将发送给GS的摘要。
  • 您需要将GlobalSign中的两个证书都放入以创建证书链。首先添加签名证书,然后添加可以从他们的'Certificate_Path'endpoint检索的证书。
  • 我不确定如何转换为该类型,但在C#库中,IExternalSignature的Sign方法返回一个字节[]。使用我自己的接口实现,我只需将从GS接收到的SignatureValue转换为Byte[]。
  • 对于时间戳,我们还实现了自己的ITsaClient,它调用GS来获取时间戳。摘要必须在GetTimeStampToken方法中计算并发送到GS。响应是一个hexencoded字符串,我们将其转换为byte[].
  • 对于OCSP,我们还实现了自己的IOCSPClient。由于我们在获取标识时获得ocsp_response,所以这个客户机只需使用它,而不是再次调用GS。在仅将Base64字符串转换为Byte[]返回响应时,我在启用LTV时遇到了问题。BouncyCastle在阅读这种格式的回应时遇到了困难。我必须将其转换为下面的BouncyCastle对象,才能正常工作。

    public byte[] GetEncoded( X509Certificate checkCert, X509Certificate issuerCert, string url )
    {
        var decoded = Base64.Decode(_ocspResponse); //_ocspResponse is same one that we received when fecthing the identity
        var response = new OcspResp(decoded);
        var basicResponse = (BasicOcspResp)response.GetResponseObject();
    
        return basicResponse.GetEncoded();
    }
    

    让我知道,如果你需要任何更多的代码示例或任何其他问题。

    public class ExternalSignature : IExternalSignature
    {
        private readonly SigningIdentity _identity;
        private readonly GlobalSignClient _client;
        public ExternalSignature( GlobalSignClient client, SigningIdentity identity )
        {
            _client = client;
            _identity = identity;
        }
    
        public string GetEncryptionAlgorithm() => "RSA";
    
        public string GetHashAlgorithm() => DigestAlgorithms.SHA256;
    
        public byte[] Sign( byte[] message )
        {
            // Using the System.Security.Cryptography implementation of SHA256
            using (var sha = SHA256.Create())
            {
                // Hash the message, containing the PDF
                var bytes = sha.ComputeHash(message);
                // HexEconde the hashed message to send to GlobalSign   
                var digest = Helpers.ByteArrayToString(bytes);
                // Send the digest to GlobalSign
                var signature = _client.GetSignatureAsync(_identity.Id, digest).Result;
                // Return the returned signature as a byte[]
                return Helpers.StringToByteArray(signature);
            }
        }
    }
    
    var signature = new ExternalSignature(_client, signingIdentity);
    ...
    ...
    //After creating the PDF signer, adding appearance, creating the OCSP and TSA clients.
    signer.SignDetached(signature, certChain, null, ocsp, tsa, 0, PdfSigner.CryptoStandard.CMS);
    

    我对OCSP和TSA的客户也做了同样的事情。

  •  类似资料:
    • 我正在尝试将支付网关集成到我的nodejs应用程序中。当支付完成时,网关用支付结果将用户重定向到我的站点。结果是RSA签名的,我需要用支付网关提供的公钥来验证它。 下面是支付网关为签名验证提供的示例PHP代码。 有谁知道怎么把这件事搞定吗?

    • 我已经尝试了很多事情,我承认失败了(我在这里读了很多回应,但到目前为止没有一个对我有帮助)。我正在尝试为CloudFont上保存的文件设置签名URL。我可以为S3创建签名的URL,但我不能为CloudFront工作。对于cloudfront,我使用AWS SDK中的以下内容: 我得到一个签名的URL生成,但我得到访问拒绝时,跟随链接,当我读到它建议我设置起源访问标识。因此,我转到我的分发设置和设置

    • 我尝试使用pdfbox向我的pdf添加多个签名,我尝试使用两个签名,第二个签名总是无效。请给出建议,PDF文件可以进行多次数字签名吗?Adobe livecycle论坛表示同意。

    • 一、简介 本章节主要介绍PHPCMS内置模块标签,标签说明及自定义调用数据的方式 二、目录 PC标签使用说明 PC标签保留参数 功能模块 工具箱

    • 标签(Tag),我们需要你!有时 Puppet 的一个类需要知道另一个类,或者至少要知道其是否已存在。 例如,一个管理防火墙的类或许需要知道一个节点是否是 web 服务器。 Puppet 的 tagged 函数会告诉你一个被命名的类或资源是否已经存在于这个节点的目录中。 你还可以对一个节点或类应用任何标签并检查这些标签是否存在。 操作步骤 为了帮你辨别你是否运行在一个指定的节点或一组节点,所有节点

    • 我正在使用iText成功地签署文档。但是,每当我检查Adobe Reader中的“高级签名属性”时,我都会看到“签名是使用Not available创建的。” 我的问题是,如何使用iText更新此信息,然后在Adobe Reader或任何其他PDF阅读器中正确显示? 编辑#1: 建议使用类的setSignatureCreator(String SignatureCreator)(API和Sourc

    • 在密码学中,跟生活一样,在你签名时必须小心慎重。一般地,当你要为 Puppetmaster 介绍一个新的客户端加入时,需要先在客户端上生成一个证书请求(certificate request), 然后到 Puppetmaster 上签署这个证书请求。 然而,你可以使用 自动签名(autosigning) 跳过这一步骤。 操作步骤 在 Puppetmaster 上创建文件 /etc/puppet/a