旧iText 2.1.7使用GOST-3411-2015-512等算法签名PDF无效求助
旧版iText 2.1.7搭配KalkanProvider实现GOST算法PDF签名无效问题排查
我在遗留项目中使用旧版iText 2.1.7,搭配KalkanProvider和BouncyCastle执行加密操作,需要使用GOST-3411-2015-512和ECGOST3411-2015-512算法签名PDF,但签名始终显示无效。
核心签名处理代码
def postProcessPdf(pdf: Array[Byte], os: OutputStream): Unit = { val reader = new PdfReader(pdf) val stamper = PdfStamper.createSignature(reader, os, '\u0000') val appearance = stamper.getSignatureAppearance val signDate = Calendar.getInstance val pdfSignature = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED) pdfSignature.setDate(new PdfDate(signDate)) pdfSignature.setCert(CryptUtils.cert.getEncoded) appearance.setCryptoDictionary(pdfSignature) appearance.setCrypto(null, CryptUtils.chain, null, PdfSignatureAppearance.WINCER_SIGNED) appearance.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED) val estimatedSize = 8192 val exc = new HashMap[PdfName, Int]() exc.put(PdfName.CONTENTS, estimatedSize * 2 + 2) appearance.preClose(exc) val data = appearance.getRangeStream() val digest = MessageDigest.getInstance("GOST-3411-2015-512","KALKAN") val dataBytes = IOUtils.toByteArray(data) digest.update(dataBytes) val appeareanceHash = digest.digest() val signature = Signature.getInstance("GOST3411-2015withECGOST3410-2015-512","KALKAN") signature.initSign(CryptUtils.privateKey) signature.update(appeareanceHash) val signedHash = signature.sign() val encodedPKCS7 = createCMS(signedHash, CryptUtils.cert,CryptUtils.privateKey) val paddedSig = new Array[Byte](estimatedSize) System.arraycopy(encodedPKCS7, 0, paddedSig, 0, encodedPKCS7.length) val dic = new PdfDictionary() dic.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true)) appearance.close(dic) }
已尝试的解决动作
- 已知旧版iText不支持目标算法,尝试修改
PdfPKCS7.class,但问题未解决。 - 自定义CMS生成方法,通过Kalkan类实现签名封装,但签名依旧无效:
def createCMS(data: Array[Byte], cert: X509Certificate, key: PrivateKey): Array[Byte] = { val generator = new CMSSignedDataGenerator generator.addSigner(key, cert,"1.2.398.3.10.1.3.3") val chainStore = CertStore.getInstance("Collection", new CollectionCertStoreParameters(CryptUtils.chain.toSeq.asJava), KalkanProvider.PROVIDER_NAME) generator.addCertificatesAndCRLs(chainStore) val content = new CMSProcessableByteArray(data) val signedData = generator.generate(content, false, KalkanProvider.PROVIDER_NAME) signedData.getEncoded }
问题分析与解决思路
1. 重复摘要导致哈希不匹配
你在签名流程中先对PDF签名范围数据做了GOST-3411-2015-512摘要,再将该摘要传给createCMS生成签名。但CMSSignedDataGenerator在生成签名时会自动对传入内容做摘要处理,相当于做了两次哈希运算,导致验证时哈希值不匹配。
修正方案:直接将原始签名范围数据传给createCMS,去掉手动摘要步骤:
// 替换原摘要+签名逻辑 val dataBytes = IOUtils.toByteArray(data) val encodedPKCS7 = createCMS(dataBytes, CryptUtils.cert,CryptUtils.privateKey)
2. 签名算法OID不匹配
createCMS中指定的算法OID1.2.398.3.10.1.3.3需确认是否与GOST3411-2015withECGOST3410-2015-512对应。OID错误会导致验证工具无法识别签名算法,判定无效。
修正方案:直接使用算法名称而非OID,或确认KalkanProvider对应的正确OID:
generator.addSigner(key, cert, "GOST3411-2015withECGOST3410-2015-512")
3. iText签名字典参数缺失
旧版iText可能未自动填充GOST算法对应的签名字典属性,需手动补充关键参数:
// 确保SubFilter正确,添加摘要算法OID pdfSignature.put(PdfName.SUBFILTER, PdfName.ADBE_PKCS7_DETACHED) pdfSignature.put(new PdfName("DigestAlgorithm"), new PdfName("1.2.398.3.10.1.3.2")) // GOST-3411-2015-512的标准OID
4. 加密提供者兼容性问题
确保KalkanProvider与BouncyCastle版本兼容,并在代码中显式注册提供者:
Security.addProvider(new KalkanProvider())
内容的提问来源于stack exchange,提问作者superkuzet
相关产品推荐
相关产品推荐

