微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何使用 itext7 将外部生成的签名应用于 PDF?

如何解决如何使用 itext7 将外部生成的签名应用于 PDF?

我正在尝试将第三方 AATL 服务生成的签名应用于 PDF。

我觉得我在调用所有内容几乎正确,但不出所料,当我查看签名文档时,我被告知签名无效。在这个过程中有很多步骤可能会出错,正如我正在学习的那样,这种绊脚石是意料之中的。 ?

无论如何,我正在寻找一些指导并填补我的知识空白。在编写代码之前,我会列出我认为需要回答的问题,您也可以在代码的注释中看到它们:

  1. 看起来我的摘要使用了正确的来源吗?即data
  2. 如果来源正确,我是否使用正确的技术来生成摘要?即,DigestAlgorithms.digest(...)
  3. 调用的第三方服务返回的签名是 base64 编码的。在将表示作为 ByteArray 返回之前,我是否需要将其从 base64 转换为其他内容
  4. 我知道我必须以某种方式使用他们提供给我的证书,我只是不确定在哪里或如何使用?
  5. 签名人 fieldName 是什么?
  6. 如何确定用于 8192estimatedSize 参数的 signer.signExternalContainer 的正确值?
  7. 如何将 CRL/OCSP 信息添加到 PDF?使用第三方 AATL 签名服务时,它通常来自哪里?

请随时指出不在上面列表中的任何其他建议或错误??

data class ThirdPartyCertificateResponse(val certs: List<String>)
data class ThirdPartySigningResponse(val sig: String,val nonce: String)

class ThirdPartySignatureContainer : IExternalSignatureContainer {

    private lateinit var data: ByteArray

    override fun sign(data: InputStream): ByteArray {

        // note: I've omitted any validation of the nonce from this sample.
        val nonce = UUID.randomUUID()
        val digest = DigestAlgorithms.digest(data,BouncyCastleDigest().getMessageDigest("sha256"))

        // note: The service I'm calling expects requests to look like this.
        //       I'm including this on the offchance that I'm accidentally 
        //       corrupting any of the data that I'm preparing for them.
        val bodyJson = JWSObject(
            JWSHeader(JWSAlgorithm.HS256),Payload(
                mapOf<String,Any>(
                    // note: `digestInfo` is an extension method that returns an `org.bouncycastle.asn1.x509.DigestInfo` instance from a `ByteArray`
                    // note: Would love a tool that generates digests for me to check mine against! Hard to kNow if I'm doing the right thing here by basing it off of `data`??
                    "digestInfo" to digest.digestInfo().toBase64String(),"nonce" to nonce.toString(),"version" to 1,)
            )
        )

        bodyJson.sign(MACSigner("SHARED_SECRET"))

        val (_,_,signatureResult) = "https://thidpartyservice.notreal/api/v1/signatures"
            .httpPost()
            .body(bodyJson.serialize())
            .responSEObject<ThirdPartySigningResponse>()

        val signatureText = when (signatureResult) {
            is Result.Failure -> throw signatureResult.getException()
            is Result.Success -> signatureResult.value.sig
        }

        return signatureText.decodeBase64()
            ?: throw Exception("Unable to decode response from third party service")
    }

    override fun modifySigningDictionary(dictionary: PdfDictionary) {

        val (_,certificateResult) = "https://thidpartyservice.notreal/api/v1/certs"
            .httpGet()
            .responSEObject<ThirdPartyCertificateResponse>()

        val certificateFactory = CertificateFactory.getInstance("x.509")

        // note: I have no idea what to do with these,but I've got them!
        val certificateChain = when (certificateResult) {
            is Result.Failure -> throw certificateResult.getException()
            is Result.Success -> certificateResult.value.certs.map {
                certificateFactory.generateCertificate(it.decodeBase64()?.inputStream())
            }
        }

        // note: What are these doing?
        dictionary.put(PdfName.Filter,PdfName.Adobe_PPKLite)
        dictionary.put(PdfName.SubFilter,PdfName.Adbe_pkcs7_detached)

        // note: I feel like I should be adding the certificate(s) to `dictionary` here...?
    }
}

上面的类被实例化并从代码调用如下:

val stampingProperties = StampingProperties()
val signer = PdfSigner(thisPdfReader,thisSigned.outputStream(),stampingProperties)
// note: What's this?
signer.fieldName = null

signer.signatureAppearance
    .setPageRect(Rectangle(0.0f,0.0f,0.0f))
    .setPageNumber(1)

val container: IExternalSignatureContainer = ThirdPartySignatureContainer()

// note: I don't kNow how to determine a correct value for it,so I've left 8192 in here from examples I've seen.
signer.signExternalContainer(container,8192)

This is a sample of a PDF 我目前正在生成

解决方法

您的 class ThirdPartySignatureContainer 实现了 IExternalSignatureContainer;因此,它的 sign 方法应该返回一个 CMS 签名容器以原样嵌入到 PDF 中。但是,检查 your example file,很明显您的远程签名服务 - 以及您的 sign 方法 - 返回裸签名字节

因此,您应该改为实现 IExternalSignaturesign 方法,该方法预期返回裸签名字节。要签名,您将使用 signer.signDetached 重载而不是 signer.signExternalContainer

这也意味着您的问题的答案如何将 CRL/OCSP 信息添加到 PDF - signDetached 重载具有 ICrlClientIOcspClient 参数,也可以提供 CRL 和 OCSP 响应以进行嵌入。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。