在http://itextpdf.com/book/digitalsignatures中跟随“使用智能卡和PKCS#11签署文档”主题并创建类似于提供的代码示例之后,签名文件签名在Adobe Reader中无效,签名外观具有不可否认证书的名称(即eID所有者的名称),但在Adobe Reader的签名面板中显示:
验证时发生错误:
我正在使用 Gemalto PinPad 和葡萄牙语eID pteidpkcs11.dll
与位于C:\ Windows \ System32中的eID中间件软件一起安装。< / p>
我试过了:
ks.getCertificateChain("CITIZEN SIGNATURE CERTIFICATE");
返回的证书[]只有签名证书答案 0 :(得分:3)
作为替代方案,您只需使用www.poreid.org上提供的java组件,即可使用葡萄牙语开发卡(CartãodeCidadão)进行签名。它也可以在maven中央存储库中使用artifactid poreid
以下是基于itext documentation
中提供的示例的示例public void createPdf(String filename) throws IOException, DocumentException {
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream(filename));
document.open();
document.add(new Paragraph("Assinado com o Cartão de Cidadão!"));
document.close();
}
public void signPdf(String src, String dest)
throws IOException, DocumentException, GeneralSecurityException {
KeyStore ks = KeyStore.getInstance(POReIDConfig.POREID);
ks.load(null);
PrivateKey pk = (PrivateKey) ks.getKey(POReIDConfig.AUTENTICACAO, null);
Certificate[] chain = ks.getCertificateChain(POReIDConfig.AUTENTICACAO);
// reader and stamper
PdfReader reader = new PdfReader(src);
FileOutputStream os = new FileOutputStream(dest);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
// appearance
PdfSignatureAppearance appearance = stamper .getSignatureAppearance();
appearance.setReason("qualquer motivo");
appearance.setLocation("qualquer localização");
appearance.setVisibleSignature(new Rectangle(72, 732, 144, 780), 1, "primeira assinatura");
// digital signature
ExternalSignature es = new PrivateKeySignature(pk, "SHA-256", POReIDConfig.POREID);
ExternalDigest digest = new ProviderDigest(null); // find provider
MakeSignature.signDetached(appearance, digest, es, chain, null, null, null, 0, CryptoStandard.CMS);
}
public static void main(String[] args) throws DocumentException, IOException, GeneralSecurityException {
Security.addProvider(new POReIDProvider());
App exemplo = new App();
exemplo.createPdf("/home/quim/exemplo.pdf");
exemplo.signPdf("/home/quim/exemplo.pdf","/home/quim/exemplo.assinado.pdf");
}
答案 1 :(得分:2)
提供的代码示例尝试获取签名证书的PrivateKey
,我发现它很奇怪,但认为它只是用作参考。浏览用户取消PinPad中的进程时触发的异常的堆栈跟踪给了我以下想法,幸运的是,这解决了这个问题:
com.itextpdf.text.pdf.security.ExternalSignature
实施sun.security.pkcs11.wrapper.PKCS11
包装器与您的eID pkcs11 dll(在我的情况下, pteidpkcs11.dll )进行交互,并提供一个接收字节的签名方法[ ]消息然后被发送到SmartCard阅读器进行签名,并返回此操作的byte []结果如果您正在为葡萄牙语eID CartãoCidadão进行开发,可以使用一些提示:
PTeID4JPKCS11
类,您只需要调用PTeID4JPKCS11.getInstance().sign(...);
ExternalSignature
接口所需的哈希和加密算法,哈希为 SHA-1 ,加密<强> RSA 强> 答案 2 :(得分:1)
我一直在使用葡萄牙公民卡进行PDF文档的数字签名,这就是我所拥有的:
public void signCAdES(...) {
String pkcs11Config = "name=GemPC" + "\n" + "library=C:\\WINDOWS\\SysWOW64\\pteidpkcs11.dll";
ByteArrayInputStream configStream = new ByteArrayInputStream(pkcs11Config.getBytes());
Provider pkcs11Provider = new sun.security.pkcs11.SunPKCS11(configStream);
//provider_name: SunPKCS11-GemPC
Security.addProvider(pkcs11Provider);
javax.security.auth.callback.CallbackHandler cmdLineHdlr = new DialogCallbackHandler();
KeyStore.Builder builder = KeyStore.Builder.newInstance("PKCS11", pkcs11Provider,
new KeyStore.CallbackHandlerProtection(cmdLineHdlr));
KeyStore ks= builder.getKeyStore();
PdfReader reader = new PdfReader(src);
FileOutputStream os = new FileOutputStream(dest);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0', new File(tempPath), true);
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setReason(reason);
appearance.setLocation(location);
appearance.setCertificationLevel(level);
String alias = "CITIZEN SIGNATURE CERTIFICATE";
//certificates from electronic card and resources folder
Certificate[] certs = getSignatureCertificatesChain(ks);
PrivateKey pk = (PrivateKey) ks.getKey(alias, null);
ExternalSignature es = new PrivateKeySignature(pk, "SHA-1", pkcs11Provider.getName());
ExternalDigest digest = new BouncyCastleDigest();
MakeSignature.signDetached(appearance, digest, es, certs, null, null, null, 0, MakeSignature.CryptoStandard.CADES);
}
我必须建立证书链( getSignatureCertificatesChain(ks)),因为 ks.getCertificateChain(“CITIZEN SIGNATURE CERTIFICATE”)只提供一个证书,然后是卡本身没有所有证书,所以我必须在 pki.cartaodecidadao.pt 网站上找到丢失的证书并将它们放在资源文件夹中。基本上,我使用卡中和资源文件夹中的两个证书来构建我的链,方法是将它们与 certificate.getIssuerX500Principal()。getName()和 certificate.getSubjecX500Principal()中的值相关联。 .getName()(不同的卡可以使用相同类型的不同证书,因为有效性可能会有所不同,因此在同一类型中可以有004或008)。
根据我的理解,对CAdES( MakeSignature.CryptoStandard.CADES )的itext支持是最新的,但您需要使用它,因为使用MakeSignature.CryptoStandard.CMS可能会导致签名不满足CAdES的所有标准(例如,缺少签名证书属性 - 请参阅http://docbox.etsi.org/ESI/Open/Latest_Drafts/prEN-319122-1v003-CAdES-core-STABLE-DRAFT.pdf)。
此代码认为唯一的小问题是可能缺少某些可选属性。我使用了此工具https://github.com/arhs/sd-dss中的验证程序,当生成的签名通过验证时,它仍然会发出缺少 issuer-serial 属性的警告。我已创建帖子,希望有人知道如何在此处添加属性:CAdES Digital Signature
答案 3 :(得分:0)
ks.getCertificateChain("CITIZEN SIGNATURE CERTIFICATE")
应该返回证书链。
我在哪里可以找到有效的在线工具?
建议:致电负责中间件的组织并寻求支持。