使用 PDFBox ETSI 验证填充签名 [英] Pades Signature using PDFBox ETSI validation

查看:103
本文介绍了使用 PDFBox ETSI 验证填充签名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 PDFBOX 创建了一个 PDF PAdES 签名,并且我正在使用 ETSI 在线验证器

这是我用来签名的代码:

@Overridepublic byte[] sign(InputStream content) 抛出 IOException {尝试 {CMSSignedDataGenerator signGenerator = new CMSSignedDataGenerator();X509Certificate userCert = (X509Certificate) this.certificateChain[0];ContentSigner mySigner = new CustomSigner(this.signerKeyHandle);//TODO 检查以使用 cavium 作为摘要提供程序MessageDigest md = MessageDigest.getInstance("SHA-256", "Cavium");md.update(userCert.getEncoded());byte[] userCertHash = md.digest();X509CertificateHolder issuerCert = new X509CertificateHolder(this.certificateChain[1].getEncoded());//IssuerSerial is = new IssuerSerial(issuerCert.get,//issuerCert.getSerialNumber());ESSCertIDv2 certid = new ESSCertIDv2(new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256),userCertHash);ESSCertIDv2[] essCert1Arr = { certid };SigningCertificateV2 sigcert = new SigningCertificateV2(certid);最终 DERSet attrValues = 新 DERSet(sigcert);属性 attr = 新属性(PKCSObjectIdentifiers.id_aa_signingCertificateV2, attrValues);ASN1EncodableVector v = new ASN1EncodableVector();v.add(attr);AttributeTable atttributeTable = new AttributeTable(v);//根据传入的参数创建一个标准的属性表——certhashCMSAttributeTableGenerator attrGen = 新的 DefaultSignedAttributeTableGenerator(attributeTable){protected Hashtable createStandardAttributeTable(Map 参数){哈希表结果 = super.createStandardAttributeTable(parameters);result.remove(CMSAttributes.signingTime);返回结果;}};JcaSignerInfoGeneratorBuilder signerBuilder = new JcaSignerInfoGeneratorBuilder( new JcaDigestCalculatorProviderBuilder().build());signerBuilder.setSignedAttributeGenerator(attrGen);SignerInfoGenerator signerInfoGenerator = signerBuilder.build(mySigner, userCert);signGenerator.addSignerInfoGenerator(signerInfoGenerator);signGenerator.addCertificates(new JcaCertStore(Arrays.asList(certificateChain)));CMSProcessableInputStream msg = new CMSProcessableInputStream(content);CMSSignedData signedData = signGenerator.generate(msg, false);返回signedData.getEncoded();} catch (GeneralSecurityException | CMSException | OperatorCreationException e) {System.err.println(e.getMessage());throw new RuntimeException(无法签署pdf!");}}

我不太确定这些问题可能出在哪里或为什么会产生这些问题,一开始我有 5 个,现在我只剩下这两个,所以任何输入都将不胜感激

解决方案

原始问题

您使用DefaultSignedAttributeTableGenerator:

signerBuilder.setSignedAttributeGenerator(new DefaultSignedAttributeTableGenerator(new AttributeTable(v)));

根据它的 JavaDocs 它会

/* 从传入的参数创建一个标准属性表 - 这将* 通常包括 contentType、signingTime、messageDigest 和 CMS 算法保护.* 如果使用了使用 AttributeTable 的构造函数,则其中的 contentType、signingTime 和* messageDigest 将覆盖生成的.

特别是它会创建一个 signingTime 签名属性.

但对于(非传统)PAdES 签名,嵌入式 CMS 容器不得包含 signingTime 属性,请参阅 ETSI EN 319 142-1 第 6.3 节了解基线签名

<块引用>

SPO:CMS 签名中的签名时间属性......不得存在

对于 PAdES-BES 和 PAdES-EPES 签名的原始 ETSI TS 102 778-3 第 4.5.3 节已经要求

<块引用>

不应使用签名时间属性.

(严格来说,当前的 ETSI EN 319 142-2 PAdES-E-BES 和 PAdES-E-EPES 配置文件似乎不再禁止使用,他们只是推荐使用M 签名字典条目.但 BES/EPES 的软件检查通常仍然基于旧的 TS 禁止,见上文.现在无论如何都应该去使用基线签名......)

因此,您应该使用不包含签名时间属性的 CMSAttributeTableGenerator 实现,例如通过复制 DefaultSignedAttributeTableGenerator 代码并从其 createStandardAttributeTable 方法中删除签名时间.

更新的问题

在评论中,您说在解决上述问题后仍然存在一个错误:

<块引用>

现在它只有一个错误,它的数字 63 表示 Location-{CodeTest}:Contents/CAdESSSignature/content/signedData/signerInfos/signerInfo1/signedAttrs/attribute[4]/attrValues/NotKnownComponent1-{ForAllTheChildrenDo} 已到达未知组件.因此,TLCC 不知道它的子代及其处理过程.不会对这个组件做进一步的检查

SignerInfo 中的最后一个(第四个)签名属性是 算法标识符保护属性,根据 RFC 6211 从 2011 年 4 月开始.考虑到 ETSI 签名一致性检查器的年龄,它可能确实不知道这个属性.

如果您希望一致性检查器不显示该错误,只需从 DefaultSignedAttributeTableGenerator 的标准属性表中删除该属性,就像删除签名时间属性一样.

I created a PDF PAdES signature using PDFBOX and I am using the ETSI online validator 1 (it requires registration) and right now I am getting only two errors on the report but im kind of lost about what they are or how can I fix them.

This is the etsi online validator report:

And this is the code I am using to sign:

@Override
    public byte[] sign(InputStream content) throws IOException {
        try {
            CMSSignedDataGenerator signGenerator = new CMSSignedDataGenerator();
            X509Certificate userCert = (X509Certificate) this.certificateChain[0];
            ContentSigner mySigner = new CustomSigner(this.signerKeyHandle);
            // TODO check to use cavium as digest provider
            MessageDigest md = MessageDigest.getInstance("SHA-256", "Cavium");
            md.update(userCert.getEncoded());
            byte[] userCertHash = md.digest();
            X509CertificateHolder issuerCert = new X509CertificateHolder(this.certificateChain[1].getEncoded());
            // IssuerSerial is = new IssuerSerial(issuerCert.get,
            // issuerCert.getSerialNumber());
            ESSCertIDv2 certid = new ESSCertIDv2(new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256),
                    userCertHash);
            ESSCertIDv2[] essCert1Arr = { certid };
            SigningCertificateV2 sigcert = new SigningCertificateV2(certid);
            final DERSet attrValues = new DERSet(sigcert);
            Attribute attr = new Attribute(PKCSObjectIdentifiers.id_aa_signingCertificateV2, attrValues);
            ASN1EncodableVector v = new ASN1EncodableVector();
            v.add(attr);
            AttributeTable atttributeTable = new AttributeTable(v);
             //Create a standard attribute table from the passed in parameters - certhash
             CMSAttributeTableGenerator attrGen = new DefaultSignedAttributeTableGenerator(atttributeTable){
                protected Hashtable createStandardAttributeTable(Map parameters)
                {
                    Hashtable result = super.createStandardAttributeTable(parameters);
                    result.remove(CMSAttributes.signingTime);
                    return result;
                }
            };
            JcaSignerInfoGeneratorBuilder signerBuilder = new JcaSignerInfoGeneratorBuilder( new JcaDigestCalculatorProviderBuilder().build());
            signerBuilder.setSignedAttributeGenerator(attrGen);
            SignerInfoGenerator signerInfoGenerator = signerBuilder.build(mySigner, userCert);
            signGenerator.addSignerInfoGenerator(signerInfoGenerator);
            signGenerator.addCertificates(new JcaCertStore(Arrays.asList(certificateChain)));
            CMSProcessableInputStream msg = new CMSProcessableInputStream(content);
            CMSSignedData signedData = signGenerator.generate(msg, false);
            return signedData.getEncoded();
        } catch (GeneralSecurityException | CMSException | OperatorCreationException e) {
            System.err.println(e.getMessage());
            throw new RuntimeException("unable to sign pdf!");
        }
    }

Im not quite sure where those problems could be or why are they generated, at the beginning I had 5 and right now im only down to these two, so any input will be greatly appreciated

解决方案

The Original Question

You use the DefaultSignedAttributeTableGenerator:

signerBuilder.setSignedAttributeGenerator(new DefaultSignedAttributeTableGenerator(new AttributeTable(v)));

According to its JavaDocs it will

/* Create a standard attribute table from the passed in parameters - this will
 * normally include contentType, signingTime, messageDigest, and CMS algorithm protection.
 * If the constructor using an AttributeTable was used, entries in it for contentType, signingTime, and
 * messageDigest will override the generated ones.

In particular it will create a signingTime signed attribute.

But for (non-legacy) PAdES signatures the embedded CMS containers must not contain a signingTime attribute, see ETSI EN 319 142-1 section 6.3 for Baseline signatures

SPO: signing-time attribute in CMS signature ... shall not be present

and already the original ETSI TS 102 778-3 section 4.5.3 for PAdES-BES and PAdES-EPES signatures requires that

the signing-time attribute shall not be used.

(Strictly speaking the current ETSI EN 319 142-2 PAdES-E-BES and PAdES-E-EPES profiles do not appear to forbid the use anymore, they merely recommend using the M signature dictionary entry instead. But software checking for BES/EPES usually still are based on the old TS which does forbid, see above. And nowadays one should go for Baseline signatures anyways...)

Thus, you should use a CMSAttributeTableGenerator implementation instead that does not include the signing time attribute, e.g. by copying the DefaultSignedAttributeTableGenerator code and removing the signing time from its createStandardAttributeTable method.

The Updated Question

In a comment you say that after fixing the issue above one error remains:

Right now its only an error and its the number 63 that says Location-{CodeTest}:Contents/CAdESSignature/content/signedData/signerInfos/signerInfo1/signedAttrs/attribute[4]/attrValues/NotKnownComponent1-{ForAllTheChildrenDo} An unknown component has been reached. Consequently, its children and their processing are unknown to the TLCC. No further checks will be done to this component

The last (fourth) signed attribute in your SignerInfo is an Algorithm Identifier Protection Attribute according to RFC 6211 from April 2011. Considering the age of the ETSI signature conformance checker it may indeed not know this attribute.

If you want the conformance checker to not display that error, simply remove that attribute from the DefaultSignedAttributeTableGenerator's standard attribute table just like you removed the signing time attribute.

这篇关于使用 PDFBox ETSI 验证填充签名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆