我关注以下帖子:iTextSharp - How to get PDF content for signing and then sign at a later time作为从PDF文档获取数据的基础,创建带有空白签名的临时文件,然后返回该临时文件的哈希值。哈希将发送到具有令牌的客户端,该令牌在本地进行签名并返回到已签名的Web应用程序。到那时,我将其转换为字节并生成最终的签名文档。
但是,已签名的文档没有有效的签名,显示消息:解码BER时出错。
1)生成临时文件,添加空白签名并返回Base64编码哈希的代码:
Public Shared Function GetBytesToSign(ByVal unsignedPdf As String, ByVal tempPdf As String, ByVal signatureFieldName As String) As String
Using reader As PdfReader = New PdfReader(unsignedPdf)
Using os As FileStream = File.OpenWrite(tempPdf)
Dim stamper As PdfStamper = PdfStamper.CreateSignature(reader, os, vbNullChar)
Dim appearance As PdfSignatureAppearance = stamper.SignatureAppearance
appearance.SetVisibleSignature(New Rectangle(36, 748, 144, 780), 1, signatureFieldName)
Dim external As IExternalSignatureContainer = New ExternalBlankSignatureContainer(PdfName.ADBE_PKCS7_DETACHED, PdfName.ADBE_PKCS7_SHA1)
MakeSignature.SignExternalContainer(appearance, external, 8192)
Dim Hash As Byte() = SHA256.Create().ComputeHash(appearance.GetRangeStream())
Dim Base64 As String = Convert.ToBase64String(Hash)
Return Base64
End Using
End Using
End Function
2)客户获得本地的Hash na suamáquina(证书)和密码哈希assinado
3)我收到签名的哈希并将其转换为字节,并生成最终的签名文件:
Public Shared Sub EmbedSignature(ByVal tempPdf As String, ByVal signedPdf As String, ByVal signatureFieldName As String, ByVal signedBytes As Byte())
Using reader As PdfReader = New PdfReader(tempPdf)
Using os As FileStream = File.Create(signedPdf)
Dim external As IExternalSignatureContainer = New MyExternalSignatureContainer(signedBytes)
MakeSignature.SignDeferred(reader, signatureFieldName, os, external)
End Using
End Using
End Sub
Partial Class MyExternalSignatureContainer
Implements IExternalSignatureContainer
Private ReadOnly signedBytes As Byte()
Public Sub New(ByVal signedBytes As Byte())
Me.signedBytes = signedBytes
End Sub
Public Function Sign(data As Stream) As Byte() Implements IExternalSignatureContainer.Sign
Return signedBytes
'Throw New NotImplementedException()
End Function
Public Sub ModifySigningDictionary(signDic As PdfDictionary) Implements IExternalSignatureContainer.ModifySigningDictionary
Throw New NotImplementedException()
End Sub
End Class
mkl,感谢您的回复
我正在做几次测试,因为我真的不知道在这种情况下使用什么正确的方法,因为材料非常宽而且也很旧。所以我想我走得更远,因为现在显示了证书数据,但显示了:无效签名。应用签名后,文档被更改或损坏。
新代码:
Public Function GetBytesToSignNew(ByVal unsignedPdf As String, ByVal tempPdf As String, ByVal signatureFieldName As String, ByVal certificateChain As Org.BouncyCastle.X509.X509Certificate()) As Byte()
' we create a reader and a stamper
Dim reader As PdfReader = New PdfReader(unsignedPdf)
Dim baos As FileStream = File.OpenWrite(tempPdf)
Dim chain = certificateChain
Dim pdfStamper As PdfStamper = PdfStamper.CreateSignature(reader, baos, Microsoft.VisualBasic.ChrW(92), Nothing, True)
Dim sap As PdfSignatureAppearance = pdfStamper.SignatureAppearance
sap.Certificate = certificateChain(0)
sap.SetVisibleSignature(New iTextSharp.text.Rectangle(36, 720, 160, 780), 1, signatureFieldName)
'sap.SetVisibleSignature(signatureFieldName);
sap.SignDate = DateTime.Now
Dim dic As PdfSignature = New PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED)
dic.Date = New PdfDate(sap.SignDate)
dic.Name = CertificateInfo.GetSubjectFields(chain(0)).GetField("CN")
sap.CryptoDictionary = dic
sap.Certificate = certificateChain(0)
sap.Acro6Layers = True
sap.Reason = "test"
sap.Location = "test"
Dim external As IExternalSignatureContainer = New ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED)
MakeSignature.SignExternalContainer(sap, external, 8192)
Dim signatureContainer As PdfPKCS7 = New PdfPKCS7(Nothing, chain, "SHA256", False)
Dim hash() As Byte = DigestAlgorithms.Digest(sap.GetRangeStream, "SHA256")
PDFHash.Text = Convert.ToBase64String(hash)
Session("signatureContainer") = signatureContainer
Return hash
End Function
Private Sub Sign21032020(signatureContainer As PdfPKCS7, ByVal certificateChain As Org.BouncyCastle.X509.X509Certificate(), signedBytes As Byte(), tmpPdf As String, signedPdf As String, signatureFieldName As String) As Byte
Try
Using reader As PdfReader = New PdfReader(tmpPdf)
Using outputStream As FileStream = File.OpenWrite(signedPdf)
Dim external As IExternalSignatureContainer = New MyExternalSignatureContainer(signedBytes, certificateChain, signatureContainer)
MakeSignature.SignDeferred(reader, signatureFieldName, outputStream, external)
End Using
End Using
' Return New Byte()
Catch ex As Exception
File.Delete(tmpPdf)
Console.WriteLine("Error signing file: " + ex.Message)
End Try
End Sub
生成的Code64哈希到客户端签名:
FB / lxYEGgc4xBSM + JlDx02sw / xtHF8jMT13tS9ZLf3A =
从客户端返回的签名哈希:
DU7koJKqS8 / 7 + O00Te7F / IyZCZrIWlTxaOwAAdJWK2SsZyNAr1fxb4AnoImlQe3xKR680egdG5orJgD4iiU4GdcM0LgIrTO / + + yFwz rAlL6PUsW8ZKi3UkTcnGxGAi3uudGghMv / KnFxknNOVD5JuAvSsL3h6cLjqv8 / knb2vfcpm7r5K4ZiyxM7LtvkJ98OwS7D7sErVp6FJTCmijftq6iveF6v5MjPfrzzx43ETKoU1iGrYNiwvR4dgem9gKYibAoQqgpI + Xb6hvDMv0loFYfYhMDgzmIDgSN171ZIdt8FzjIU3vWt5coyhPYYmI23CAX75dED5zQrXZ + IaPD4CQ ==
TempPDF:
SignedPDF:
我在客户端使用此插件签名哈希:
再次感谢,抱歉。我用Google翻译。
罗伯托·皮雷斯
这里的主要问题是,您只是简单地获取了客户端返回的签名字节,并将其嵌入到PDF中,而无需多加费力。
但是,由于您在其子过滤器中的签名声称是adbe.pkcs7.sha1签名,因此您需要嵌入一个PKCS#7 / CMS签名容器,而这不是您的客户端返回的。
这里切换到在签名子过滤器中声明adbe.pkcs7.detached”。这也需要您嵌入PKCS#7 / CMS签名容器,并且最好使用adbe.pkcs7.sha1,该方法利用SHA1(一种摘要算法,在以前的环境中不够安全) PDF甚至被证明是不安全的。
此外,您现在确实嵌入了PKCS#7 / CMS签名容器。因此,Adobe Reader现在可以解码嵌入的签名(不再[解码BER时出错)。
但是您错误地构建了该签名容器:
因此,如果使用iText PdfPKCS7
类创建CMS容器,则必须:
使用此PdfPKCS7
方法将带符号的属性检索为字节数组:
virtual public byte[] getAuthenticatedAttributeBytes(byte[] secondDigest, byte[] ocsp, ICollection<byte[]> crlBytes, CryptoStandard sigtype)
((secondDigest
参数必须包含PDF范围流的哈希。)
消化该字节数组,
使用此方法在PdfPKCS7
对象中设置客户端的签名字节:
virtual public void SetExternalDigest(byte[] digest, byte[] RSAdata, String digestEncryptionAlgorithm)
((digest
包含客户端的签名字节,RSAdata
参数必须为null
,并且digestEncryptionAlgorithm
必须为“ RSA”,“ DSA”或“ ECDSA”。
使用此PdfPKCS7
对象的方法完成CMS签名容器:
virtual public byte[] GetEncodedPKCS7(byte[] secondDigest, ITSAClient tsaClient, byte[] ocsp, ICollection<byte[]> crlBytes, CryptoStandard sigtype)
(这里secondDigest
,ocsp
,crlBytes
和sigtype
的值必须与getAuthenticatedAttributeBytes
调用中的值相同。)
MakeSignature.SignDeferred
实现,使用IExternalSignatureContainer
将这些字节嵌入到PDF中。