签署PDF使用ITextSharp和XML签名(Sign Pdf Using ITextSharp and XML Signature)

编程入门 行业动态 更新时间:2024-10-28 04:24:35
签署PDF使用ITextSharp和XML签名(Sign Pdf Using ITextSharp and XML Signature)

我正在尝试使用远程Web服务来演唱pdf,该服务返回包含PKCS#1签名和最终用户证书的XML签名。

我需要使用此签名通过IText deferred签名来签署pdf,因为Web服务是asynchronously 。

所有IText示例都使用PKCS#7消息格式,但我不确定应该如何处理XML签名。

添加空签名字段并获取Pdf的可签名字节的代码

public static string GetBytesToSign(string unsignedPdf, string tempPdf, string signatureFieldName) { if (File.Exists(tempPdf)) File.Delete(tempPdf); using (PdfReader reader = new PdfReader(unsignedPdf)) { using (FileStream os = File.OpenWrite(tempPdf)) { PdfStamper stamper = PdfStamper.CreateSignature(reader, os, '\0'); PdfSignatureAppearance appearance = stamper.SignatureAppearance; appearance.SetVisibleSignature(new Rectangle(36, 748, 250, 400), 1, signatureFieldName); IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED); MakeSignature.SignExternalContainer(appearance, external, 8192); byte[] array = SHA256Managed.Create().ComputeHash(appearance.GetRangeStream()); return Convert.ToBase64String(array); } } }

打开Temp Pdf并嵌入接收签名的代码

public static void EmbedSignature(string tempPdf, string signedPdf, string signatureFieldName, string signature) { byte[] signedBytes = Convert.FromBase64String(signature); using (PdfReader reader = new PdfReader(tempPdf)) { using (FileStream os = File.OpenWrite(signedPdf)) { IExternalSignatureContainer external = new MyExternalSignatureContainer(signedBytes); MakeSignature.SignDeferred(reader, signatureFieldName, os, external); } } }

从Web服务返回的XML签名:

<SignatureValue Id="Signature-xxx-SIG"> RMFbYIigsrjYQEc4PCoHMMg8vwz/hYrCjj0IR+835BZZ/TsTMHZhMVnu2KQZi1UL dWMeuhTxagBmjdBSzGiy1OEdH5r0FM77Of4Zz99o/aAhYqr3qpOETGgNn9GHlphL 5FSPYbNsq2rDHA8FsNdqNdb6qJUZYsfYvuhJaUMstBXeL/dLIT46t7ySCQ7CGjE5 mpD1AG8M+TVWf4ut5tucZuZV9PMQB3tyoarQD5RoUv872RzB5IorcIhLnf+O6E6o EF0HuGitRhN9bbPgdLaUma5MNjKCaeQTpCXp3KXwi8VoQGd5fpUBZbAKtMpKeCts RAOk1O4uk/4poic4IGPhDw== </SignatureValue> <KeyInfo> <KeyValue> <RSAKeyValue> <Modulus> AI5T0zOBBD4i7Cb1v8wDL0+By8i1h2U0HDFQ73/iNBkM9Gd7mUU0i2A9wJTeiktS IeBU/JLzqVp7vK857dZlrlT9qiH2cNQufh+q2MpNk7wtPcDACVedVkBUNkIgoXBy g4cGmAYoWBsD2zDXiZXukStjUWws+/xCU0hADIelFONr141zRHindfq86QrDTC7q bHBtDT7dJckWzaDPHf3Xlej+U/A1x/8kd504VZaFQfAPYBOgGPY918G1HjBtlajR nyrl10LuV708IHZtAmKmEfdZOeq//9OGZZLh2nJ86b5Fa6XPFhxzLx/ugBS/8GHt iVYeJOlfHXRl5w2k2Vv/ssU= </Modulus> <Exponent>AQAB</Exponent> </RSAKeyValue> </KeyValue> <X509Data> <X509Certificate> MIIGpTCCBY2gAwIBAgIRAJvlsG1D+P++OcU8W8D8FnkwDQYJKoZIhvcNAQELBQAw bzELMAkGA1UEBhMCVFIxKDAmBgNVBAoMH0VsZWt0cm9uaWsgQmlsZ2kgR3V2ZW5s aWdpIEEuUy4xNjA0BgNVBAMMLVRFU1QgVHVya2NlbGwgTW9iaWwgTkVTIEhpem1l dCBTYWdsYXlpY2lzaSBTMjAeFw0xNzA4MjUxMjQ3MjFaFw0xODA4MjUxMjQ3MjFa MEoxCzAJBgNVBAYTAlRSMREwDwYDVQQKDAhGaXJlIExMVDEUMBIGA1UEBRMLNzY1 NDM0NTY3NjUxEjAQBgNVBAMMCU1lcnQgSW5hbjCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAI5T0zOBBD4i7Cb1v8wDL0+By8i1h2U0HDFQ73/iNBkM9Gd7 mUU0i2A9wJTeiktSIeBU/JLzqVp7vK857dZlrlT9qiH2cNQufh+q2MpNk7wtPcDA CVedVkBUNkIgoXByg4cGmAYoWBsD2zDXiZXukStjUWws+/xCU0hADIelFONr141z RHindfq86QrDTC7qbHBtDT7dJckWzaDPHf3Xlej+U/A1x/8kd504VZaFQfAPYBOg GPY918G1HjBtlajRnyrl10LuV708IHZtAmKmEfdZOeq//9OGZZLh2nJ86b5Fa6XP FhxzLx/ugBS/8GHtiVYeJOlfHXRl5w2k2Vv/ssUCAwEAAaOCA18wggNbMEIGCCsG AQUFBwEBBDYwNDAyBggrBgEFBQcwAYYmaHR0cDovL3Rlc3RvY3NwMi5lLWd1dmVu LmNvbS9vY3NwLnh1ZGEwHwYDVR0jBBgwFoAUT9gSazAfQrnZruIq9+dJFZ7E9OUw ggFyBgNVHSAEggFpMIIBZTCBsQYGYIYYAwABMIGmMDYGCCsGAQUFBwIBFipodHRw Oi8vd3d3LmUtZ3V2ZW4uY29tL2RvY3VtZW50cy9ORVNVRS5wZGYwbAYIKwYBBQUH AgIwYBpeQnUgc2VydGlmaWthLCA1MDcwIHNhecSxbMSxIEVsZWt0cm9uaWsgxLBt emEgS2FudW51bmEgZ8O2cmUgbml0ZWxpa2xpIGVsZWt0cm9uaWsgc2VydGlmaWth ZMSxcjCBrgYJYIYYAwABAQEDMIGgMDcGCCsGAQUFBwIBFitodHRwOi8vd3d3LmUt Z3V2ZW4uY29tL2RvY3VtZW50cy9NS05FU0kucGRmMGUGCCsGAQUFBwICMFkaV0J1 IHNlcnRpZmlrYSwgTUtORVNJIGthcHNhbcSxbmRhIHlhecSxbmxhbm3EscWfIGJp ciBuaXRlbGlrbGkgZWxla3Ryb25payBzZXJ0aWZpa2FkxLFyLjBdBgNVHR8EVjBU MFKgUKBOhkxodHRwOi8vdGVzdHNpbC5lLWd1dmVuLmNvbS9FbGVrdHJvbmlrQmls Z2lHdXZlbmxpZ2lBU01LTkVTSS1TMi9MYXRlc3RDUkwuY3JsMA4GA1UdDwEB/wQE AwIGwDCBgwYIKwYBBQUHAQMEdzB1MAgGBgQAjkYBATBpBgtghhgBPQABp04BAQxa QnUgc2VydGlmaWthLCA1MDcwIHNheWlsaSBFbGVrdHJvbmlrIEltemEgS2FudW51 bmEgZ8O2cmUgbml0ZWxpa2xpIGVsZWt0cm9uaWsgc2VydGlmaWthZGlyMFAGA1Ud CQRJMEcwFAYIKwYBBQUHCQIxCAQGQW5rYXJhMB0GCCsGAQUFBwkBMREYDzE5Nzgx MjMxMjAwMDAwWjAQBggrBgEFBQcJBDEEBAJUUjAYBgNVHREEETAPgQ1maXJlQGZp cmUuY29tMB0GA1UdDgQWBBTYUEJX62lhEzkZLSrTdSIdE9n8KzANBgkqhkiG9w0B AQsFAAOCAQEAV/MY/Tp7n7eG7/tWJW+XlDgIPQK1nAFgvZHm+DodDJ8Bn7CPWmv8 EBmcNxx5PYMoG7y54E6+KzVyjdPBu5o0YtWyKlLKnH1St+EtptOmt29VFAODjalb Q0An9361DxIDRHbMnQOaJiRTwMlIhED5VDa3OTUhBr7bNlVkp3N5Vs2RuoSdNypR fq4D/cCpakVugsFyPk4zhWkGhTS5DlL7c5KYqCnU4ugpC33IRJGB05PSdjICeX7Y N0oAdhzF+5QZEwePjgrDb+ROVpXYaGVMWICA8N2tOXuqdDYoGAzj1YemnPqrSn8a 2iwqbWnFujwep5w5C/TCFVaQWa4NGncMOw== </X509Certificate> </X509Data> </KeyInfo>

当我使用返回的PKCS#1签名和上面的代码时,签名验证失败, “BER解码时遇到错误”

由于使用BlankSignatureContainer创建了ADBE_PKCS7_DETACHED ,我认为这是正常的。 但是,我不确定我应该为PKCS#1使用哪个filter和subFilter? 或者我应该/可以从PKCS#1和用户证书创建PKCS#7消息并使用此格式吗?

编辑1:

我还可以在请求签名之前检索最终用户证书。

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"> <soap:Body> <ns1:MSS_ProfileQueryResponse xmlns:ns1="/mobilesignature/validation/soap"> <MSS_ProfileResp MinorVersion="1" MajorVersion="1" xmlns:ns2="http://www.w3.org/2000/09/xmldsig#" xmlns:ns3="http://www.w3.org/2001/04/xmlenc#" xmlns:ns4="http://www.w3.org/2003/05/soap-envelope" xmlns:ns5="http://uri.etsi.org/TS102204/v1.1.2#"> <ns5:AP_Info Instant="2017-09-16T04:54:43.260Z" AP_PWD="turkcell123" AP_TransID="_1371012883260" AP_ID="http://turkcell.com.tr"/> <ns5:MSSP_Info Instant="2017-09-16T13:33:36.316+02:00"> <ns5:MSSP_ID/> </ns5:MSSP_Info> <ns5:SignatureProfile> <ns5:mssURI>http://MobileSignature/profile2</ns5:mssURI> <ns5:CertIssuerDN> Mobil NES Hizmet Saglayicisi S2</ns5:CertIssuerDN> <ns5:CertSerialNumber>71408272140747005781907792964830346324</ns5:CertSerialNumber> <ns5:CertHash> <ns5:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ns5:DigestValue>e1yKlaPIU95phxxYvrUsmSQDpKqKU60/b+a8BLw1wNM=</ns5:DigestValue> </ns5:CertHash> <ns5:msspUrl>http://localhost</ns5:msspUrl> <ns5:certIssuerDN-DER>MG8xCzAJBgNVBAYTAlRSMSgwJgYDVQQKDB9FbGVrdHJvbmlrIEJpbGdpIEd1dmVubGlnaSBBLlMuMTYwNAYDVQQDDC1URVNUIFR1cmtjZWxsIE1vYmlsIE5FUyBIaXptZXQgU2FnbGF5aWNpc2kgUzI=</ns5:certIssuerDN-DER> </ns5:SignatureProfile> <ns5:Status> <ns5:StatusCode Value="100"/> <ns5:StatusMessage>REQUEST_OK</ns5:StatusMessage> </ns5:Status> </MSS_ProfileResp> </ns1:MSS_ProfileQueryResponse> </soap:Body> </soap:Envelope>

编辑2:

我已更新我的签名代码以构建CMS。 但是,要签名的结果哈希值是77个字节。 Web服务除了32字节SHA256散列数据。

public static byte[] GetBytesToSign(string unsignedPdf, string tempPdf, string signatureFieldName, byte[] x509Signature) { if (File.Exists(tempPdf)) File.Delete(tempPdf); var chain = new List<Org.BouncyCastle.X509.X509Certificate> { Org.BouncyCastle.Security.DotNetUtilities.FromX509Certificate(new X509Certificate2(x509Signature)) }; Org.BouncyCastle.X509.X509Certificate certificate = chain.ElementAt(0); using (PdfReader reader = new PdfReader(unsignedPdf)) { using (FileStream os = File.OpenWrite(tempPdf)) { PdfStamper stamper = PdfStamper.CreateSignature(reader, os, '\0'); PdfSignatureAppearance appearance = stamper.SignatureAppearance; appearance.SetVisibleSignature(new Rectangle(36, 748, 250, 400), 1, signatureFieldName); appearance.Certificate = chain[0]; IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED); MakeSignature.SignExternalContainer(appearance, external, 8192); Stream data = appearance.GetRangeStream(); byte[] hash = DigestAlgorithms.Digest(data, "SHA256"); var signature = new PdfPKCS7(null, chain, "SHA256", false); byte[] signatureHash = signature.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS); _signature = signature; _apperance = appearance; _hash = hash; _signatureHash = signatureHash; return signatureHash; } } } public static void EmbedSignature(string tempPdf, string signedPdf, string signatureFieldName, byte[] signedBytes) { using (PdfReader reader = new PdfReader(tempPdf)) { using (FileStream os = File.OpenWrite(signedPdf)) { _signature.SetExternalDigest(signedBytes, null, "RSA"); byte[] encodedSignature = _signature.GetEncodedPKCS7(_hash, null, null, null, CryptoStandard.CMS); IExternalSignatureContainer external = new MyExternalSignatureContainer(encodedSignature); MakeSignature.SignDeferred(reader, signatureFieldName, os, external); } } }

I am trying to sing a pdf using a remote web service which returns a XML signature that consists of PKCS#1 signature with end users certificate.

I need to use this signature to sign pdf via IText deferred signing because the web service works asynchronously.

All the IText examples uses PKCS#7 message format but I am not sure what should I do for XML signature.

Code That Adds Empty Signature Field and Gets Signable Bytes of Pdf

public static string GetBytesToSign(string unsignedPdf, string tempPdf, string signatureFieldName) { if (File.Exists(tempPdf)) File.Delete(tempPdf); using (PdfReader reader = new PdfReader(unsignedPdf)) { using (FileStream os = File.OpenWrite(tempPdf)) { PdfStamper stamper = PdfStamper.CreateSignature(reader, os, '\0'); PdfSignatureAppearance appearance = stamper.SignatureAppearance; appearance.SetVisibleSignature(new Rectangle(36, 748, 250, 400), 1, signatureFieldName); IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED); MakeSignature.SignExternalContainer(appearance, external, 8192); byte[] array = SHA256Managed.Create().ComputeHash(appearance.GetRangeStream()); return Convert.ToBase64String(array); } } }

Code That Opens Temp Pdf And Embeds The Received Signature

public static void EmbedSignature(string tempPdf, string signedPdf, string signatureFieldName, string signature) { byte[] signedBytes = Convert.FromBase64String(signature); using (PdfReader reader = new PdfReader(tempPdf)) { using (FileStream os = File.OpenWrite(signedPdf)) { IExternalSignatureContainer external = new MyExternalSignatureContainer(signedBytes); MakeSignature.SignDeferred(reader, signatureFieldName, os, external); } } }

The returned XML Signature from web service:

<SignatureValue Id="Signature-xxx-SIG"> RMFbYIigsrjYQEc4PCoHMMg8vwz/hYrCjj0IR+835BZZ/TsTMHZhMVnu2KQZi1UL dWMeuhTxagBmjdBSzGiy1OEdH5r0FM77Of4Zz99o/aAhYqr3qpOETGgNn9GHlphL 5FSPYbNsq2rDHA8FsNdqNdb6qJUZYsfYvuhJaUMstBXeL/dLIT46t7ySCQ7CGjE5 mpD1AG8M+TVWf4ut5tucZuZV9PMQB3tyoarQD5RoUv872RzB5IorcIhLnf+O6E6o EF0HuGitRhN9bbPgdLaUma5MNjKCaeQTpCXp3KXwi8VoQGd5fpUBZbAKtMpKeCts RAOk1O4uk/4poic4IGPhDw== </SignatureValue> <KeyInfo> <KeyValue> <RSAKeyValue> <Modulus> AI5T0zOBBD4i7Cb1v8wDL0+By8i1h2U0HDFQ73/iNBkM9Gd7mUU0i2A9wJTeiktS IeBU/JLzqVp7vK857dZlrlT9qiH2cNQufh+q2MpNk7wtPcDACVedVkBUNkIgoXBy g4cGmAYoWBsD2zDXiZXukStjUWws+/xCU0hADIelFONr141zRHindfq86QrDTC7q bHBtDT7dJckWzaDPHf3Xlej+U/A1x/8kd504VZaFQfAPYBOgGPY918G1HjBtlajR nyrl10LuV708IHZtAmKmEfdZOeq//9OGZZLh2nJ86b5Fa6XPFhxzLx/ugBS/8GHt iVYeJOlfHXRl5w2k2Vv/ssU= </Modulus> <Exponent>AQAB</Exponent> </RSAKeyValue> </KeyValue> <X509Data> <X509Certificate> MIIGpTCCBY2gAwIBAgIRAJvlsG1D+P++OcU8W8D8FnkwDQYJKoZIhvcNAQELBQAw bzELMAkGA1UEBhMCVFIxKDAmBgNVBAoMH0VsZWt0cm9uaWsgQmlsZ2kgR3V2ZW5s aWdpIEEuUy4xNjA0BgNVBAMMLVRFU1QgVHVya2NlbGwgTW9iaWwgTkVTIEhpem1l dCBTYWdsYXlpY2lzaSBTMjAeFw0xNzA4MjUxMjQ3MjFaFw0xODA4MjUxMjQ3MjFa MEoxCzAJBgNVBAYTAlRSMREwDwYDVQQKDAhGaXJlIExMVDEUMBIGA1UEBRMLNzY1 NDM0NTY3NjUxEjAQBgNVBAMMCU1lcnQgSW5hbjCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAI5T0zOBBD4i7Cb1v8wDL0+By8i1h2U0HDFQ73/iNBkM9Gd7 mUU0i2A9wJTeiktSIeBU/JLzqVp7vK857dZlrlT9qiH2cNQufh+q2MpNk7wtPcDA CVedVkBUNkIgoXByg4cGmAYoWBsD2zDXiZXukStjUWws+/xCU0hADIelFONr141z RHindfq86QrDTC7qbHBtDT7dJckWzaDPHf3Xlej+U/A1x/8kd504VZaFQfAPYBOg GPY918G1HjBtlajRnyrl10LuV708IHZtAmKmEfdZOeq//9OGZZLh2nJ86b5Fa6XP FhxzLx/ugBS/8GHtiVYeJOlfHXRl5w2k2Vv/ssUCAwEAAaOCA18wggNbMEIGCCsG AQUFBwEBBDYwNDAyBggrBgEFBQcwAYYmaHR0cDovL3Rlc3RvY3NwMi5lLWd1dmVu LmNvbS9vY3NwLnh1ZGEwHwYDVR0jBBgwFoAUT9gSazAfQrnZruIq9+dJFZ7E9OUw ggFyBgNVHSAEggFpMIIBZTCBsQYGYIYYAwABMIGmMDYGCCsGAQUFBwIBFipodHRw Oi8vd3d3LmUtZ3V2ZW4uY29tL2RvY3VtZW50cy9ORVNVRS5wZGYwbAYIKwYBBQUH AgIwYBpeQnUgc2VydGlmaWthLCA1MDcwIHNhecSxbMSxIEVsZWt0cm9uaWsgxLBt emEgS2FudW51bmEgZ8O2cmUgbml0ZWxpa2xpIGVsZWt0cm9uaWsgc2VydGlmaWth ZMSxcjCBrgYJYIYYAwABAQEDMIGgMDcGCCsGAQUFBwIBFitodHRwOi8vd3d3LmUt Z3V2ZW4uY29tL2RvY3VtZW50cy9NS05FU0kucGRmMGUGCCsGAQUFBwICMFkaV0J1 IHNlcnRpZmlrYSwgTUtORVNJIGthcHNhbcSxbmRhIHlhecSxbmxhbm3EscWfIGJp ciBuaXRlbGlrbGkgZWxla3Ryb25payBzZXJ0aWZpa2FkxLFyLjBdBgNVHR8EVjBU MFKgUKBOhkxodHRwOi8vdGVzdHNpbC5lLWd1dmVuLmNvbS9FbGVrdHJvbmlrQmls Z2lHdXZlbmxpZ2lBU01LTkVTSS1TMi9MYXRlc3RDUkwuY3JsMA4GA1UdDwEB/wQE AwIGwDCBgwYIKwYBBQUHAQMEdzB1MAgGBgQAjkYBATBpBgtghhgBPQABp04BAQxa QnUgc2VydGlmaWthLCA1MDcwIHNheWlsaSBFbGVrdHJvbmlrIEltemEgS2FudW51 bmEgZ8O2cmUgbml0ZWxpa2xpIGVsZWt0cm9uaWsgc2VydGlmaWthZGlyMFAGA1Ud CQRJMEcwFAYIKwYBBQUHCQIxCAQGQW5rYXJhMB0GCCsGAQUFBwkBMREYDzE5Nzgx MjMxMjAwMDAwWjAQBggrBgEFBQcJBDEEBAJUUjAYBgNVHREEETAPgQ1maXJlQGZp cmUuY29tMB0GA1UdDgQWBBTYUEJX62lhEzkZLSrTdSIdE9n8KzANBgkqhkiG9w0B AQsFAAOCAQEAV/MY/Tp7n7eG7/tWJW+XlDgIPQK1nAFgvZHm+DodDJ8Bn7CPWmv8 EBmcNxx5PYMoG7y54E6+KzVyjdPBu5o0YtWyKlLKnH1St+EtptOmt29VFAODjalb Q0An9361DxIDRHbMnQOaJiRTwMlIhED5VDa3OTUhBr7bNlVkp3N5Vs2RuoSdNypR fq4D/cCpakVugsFyPk4zhWkGhTS5DlL7c5KYqCnU4ugpC33IRJGB05PSdjICeX7Y N0oAdhzF+5QZEwePjgrDb+ROVpXYaGVMWICA8N2tOXuqdDYoGAzj1YemnPqrSn8a 2iwqbWnFujwep5w5C/TCFVaQWa4NGncMOw== </X509Certificate> </X509Data> </KeyInfo>

When I use the returned PKCS#1 signature with above code, the signature verification fails with "Error encountered while BER decoding".

Since the BlankSignatureContainer created with ADBE_PKCS7_DETACHED subFilter, I think this is normal. However, I am not sure what filter and subFilter I should use for PKCS#1? Or Should / Can I create PKCS#7 message from PKCS#1 and user's certificate and use this format instead?

EDIT 1:

I can also retrieve the end users certificate before requesting the signature.

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"> <soap:Body> <ns1:MSS_ProfileQueryResponse xmlns:ns1="/mobilesignature/validation/soap"> <MSS_ProfileResp MinorVersion="1" MajorVersion="1" xmlns:ns2="http://www.w3.org/2000/09/xmldsig#" xmlns:ns3="http://www.w3.org/2001/04/xmlenc#" xmlns:ns4="http://www.w3.org/2003/05/soap-envelope" xmlns:ns5="http://uri.etsi.org/TS102204/v1.1.2#"> <ns5:AP_Info Instant="2017-09-16T04:54:43.260Z" AP_PWD="turkcell123" AP_TransID="_1371012883260" AP_ID="http://turkcell.com.tr"/> <ns5:MSSP_Info Instant="2017-09-16T13:33:36.316+02:00"> <ns5:MSSP_ID/> </ns5:MSSP_Info> <ns5:SignatureProfile> <ns5:mssURI>http://MobileSignature/profile2</ns5:mssURI> <ns5:CertIssuerDN> Mobil NES Hizmet Saglayicisi S2</ns5:CertIssuerDN> <ns5:CertSerialNumber>71408272140747005781907792964830346324</ns5:CertSerialNumber> <ns5:CertHash> <ns5:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ns5:DigestValue>e1yKlaPIU95phxxYvrUsmSQDpKqKU60/b+a8BLw1wNM=</ns5:DigestValue> </ns5:CertHash> <ns5:msspUrl>http://localhost</ns5:msspUrl> <ns5:certIssuerDN-DER>MG8xCzAJBgNVBAYTAlRSMSgwJgYDVQQKDB9FbGVrdHJvbmlrIEJpbGdpIEd1dmVubGlnaSBBLlMuMTYwNAYDVQQDDC1URVNUIFR1cmtjZWxsIE1vYmlsIE5FUyBIaXptZXQgU2FnbGF5aWNpc2kgUzI=</ns5:certIssuerDN-DER> </ns5:SignatureProfile> <ns5:Status> <ns5:StatusCode Value="100"/> <ns5:StatusMessage>REQUEST_OK</ns5:StatusMessage> </ns5:Status> </MSS_ProfileResp> </ns1:MSS_ProfileQueryResponse> </soap:Body> </soap:Envelope>

EDIT 2:

I have updated my signing code to construct a CMS. However, the resulting hash value to be signed is 77 bytes. The web service excepts 32 bytes SHA256 hashed data.

public static byte[] GetBytesToSign(string unsignedPdf, string tempPdf, string signatureFieldName, byte[] x509Signature) { if (File.Exists(tempPdf)) File.Delete(tempPdf); var chain = new List<Org.BouncyCastle.X509.X509Certificate> { Org.BouncyCastle.Security.DotNetUtilities.FromX509Certificate(new X509Certificate2(x509Signature)) }; Org.BouncyCastle.X509.X509Certificate certificate = chain.ElementAt(0); using (PdfReader reader = new PdfReader(unsignedPdf)) { using (FileStream os = File.OpenWrite(tempPdf)) { PdfStamper stamper = PdfStamper.CreateSignature(reader, os, '\0'); PdfSignatureAppearance appearance = stamper.SignatureAppearance; appearance.SetVisibleSignature(new Rectangle(36, 748, 250, 400), 1, signatureFieldName); appearance.Certificate = chain[0]; IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED); MakeSignature.SignExternalContainer(appearance, external, 8192); Stream data = appearance.GetRangeStream(); byte[] hash = DigestAlgorithms.Digest(data, "SHA256"); var signature = new PdfPKCS7(null, chain, "SHA256", false); byte[] signatureHash = signature.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS); _signature = signature; _apperance = appearance; _hash = hash; _signatureHash = signatureHash; return signatureHash; } } } public static void EmbedSignature(string tempPdf, string signedPdf, string signatureFieldName, byte[] signedBytes) { using (PdfReader reader = new PdfReader(tempPdf)) { using (FileStream os = File.OpenWrite(signedPdf)) { _signature.SetExternalDigest(signedBytes, null, "RSA"); byte[] encodedSignature = _signature.GetEncodedPKCS7(_hash, null, null, null, CryptoStandard.CMS); IExternalSignatureContainer external = new MyExternalSignatureContainer(encodedSignature); MakeSignature.SignDeferred(reader, signatureFieldName, os, external); } } }

最满意答案

(这个答案总结了评论过程中工作代码的演变和对问题的编辑。)

PDF支持哪个选项

PDF格式(通常支持的ISO 32000-1:2008)使用裸PKCS#1签名或完整PKCS#7 / CMS签名容器指定嵌入式签名,参见 第12.8.3节“签名互操作性”,特别是

第12.8.3.2节“PKCS#1签名”和 第12.8.3.3节“ISO 32000中使用的PKCS#7签名”。

较新的标准,如ETSI PAdES标准和新的ISO 32000-2:2017,禁止或弃用前一种选择。 因此,对于一个在发布当天不会过时的新解决方案,应该选择后者。

事先知道证书

我正在尝试使用远程Web服务来演唱pdf,该服务返回包含PKCS#1签名和最终用户证书的XML签名。

如果这是Web服务的所有功能,那么就会出现问题:嵌入裸露的PKCS#1签名和构建PKCS#7签名容器时,都需要调用服务之前知道最终实体证书。为哈希创建签名,因为该证书或对其的引用必须嵌入到签名的PDF数据或签名的CMS属性中。

(严格来说,非常基本的CMS签名容器不需要这个,但所有签名配置文件都要认真对待。)

幸运的是,结果是(编辑1)那一个

可以访问另一项服务“此服务使应用程序提供商能够请求最终用户的证书序列号和证书哈希值,这些哈希值可用于构建要签名的数据。”

代码

OP发现了iText / Java代码,用于实现使用基于签名服务的嵌入式PKCS#7 / CMS签名容器签署PDF的功能,如上所述(编辑2)。

但是,要签名的结果哈希值是77个字节。 Web服务除了32字节SHA256散列数据。

事实证明,这77个字节不是签名属性的哈希值:

public static byte[] GetBytesToSign(string unsignedPdf, string tempPdf, string signatureFieldName, byte[] x509Signature) { [...] byte[] signatureHash = signature.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS); [...] return signatureHash; }

它们是签名的属性字节。 因此,仅需要对这些字节进行散列以产生散列以发送到签名服务以创建签名。

(This answer summarizes the evolution of working code in the course of comments and edits to the question.)

Which option does PDF support

The PDF format (the commonly supported ISO 32000-1:2008) specified embedded signatures using either naked PKCS#1 signatures or full PKCS#7/CMS signature containers, cf. section 12.8.3 "Signature Interoperability", in particular

section 12.8.3.2 "PKCS#1 Signatures" and section 12.8.3.3 "PKCS#7 Signatures as used in ISO 32000".

Newer standards, like the ETSI PAdES standards and the new ISO 32000-2:2017, forbid or deprecate the former option. For a new solution that shall not be outdated already on the day it is published, therefore, one should go for the latter choice.

Knowing the certificate beforehand

I am trying to sing a pdf using a remote web service which returns a XML signature that consists of PKCS#1 signature with end users certificate.

If that were all the functionality of the web service, there'd be a problem: Both when embedding a naked PKCS#1 signature and when constructing a PKCS#7 signature container, one needs to know the end entity certificate before calling the service to create a signature for a hash because that certificate or a reference to it must be embedded in the signed PDF data or the signed CMS attributes.

(Strictly speaking very basic CMS signature container do not require this but all signature profiles to take seriously do.)

Fortunately it turned out (edit 1) that one

can access to another service "This service enables Application Providers to request end user’s certificate serial number and certificate hash which can be used in constructing the data to be signed."

The code

The OP found iText/Java code for implementing the functionality to sign a PDF with an embedded PKCS#7/CMS signature container based on a signing service as described above (edit 2).

However, the resulting hash value to be signed is 77 bytes. The web service excepts 32 bytes SHA256 hashed data.

As it turned out, though, those 77 bytes were not the hash of the signed attributes:

public static byte[] GetBytesToSign(string unsignedPdf, string tempPdf, string signatureFieldName, byte[] x509Signature) { [...] byte[] signatureHash = signature.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS); [...] return signatureHash; }

They were the signed attributes bytes. Thus, these bytes merely needed to be hashed to produce the hash to send to the signing service for creating a signature.

更多推荐

本文发布于:2023-07-05 02:42:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1032103.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:XML   ITextSharp   PDF   Signature   Pdf

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!