我想使用pdfbox使用hsm服务插入数字签名。
我在这里使用示例作为起点https://github.com/apache/pdfbox/tree/2.0.7/examples/src/main/java/org/apache/pdfbox/examples/signature。这些例子假设我拥有私钥和密码。
在我的情况下,我将生成pdf的相应位的散列并将它们传递给服务以进行签名。在这个帖子的作者的一些指导下:PDF Signing, generated PDF Document certification is invalid? (using external signing, web-eid, HSM)我拼凑了以下对CreateSignatureBase.sign的更改,以便附上证书:
@Override
public byte[] sign(InputStream content) throws IOException
{
try
{
List<Certificate> certList = new ArrayList<Certificate>();
certList.addAll(Arrays.asList(certificateChain));
certList.add(certificate);
Store certs = new JcaCertStore(certList);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
byte[] sh = MessageDigest.getInstance("SHA-256").digest(IOUtils.toByteArray(content));
String hexencodedDigest = new BigInteger(1, sh).toString(16);
hexencodedDigest = hexencodedDigest.toUpperCase();
// Send digest to signing service
final String signedHash = certProvider.signPdfDigest(hexencodedDigest);
ContentSigner nonSigner = new ContentSigner() {
@Override
public byte[] getSignature() {
try {
return Hex.decodeHex(signedHash.toCharArray());
} catch (DecoderException e) {
e.printStackTrace();
}
return null;
}
@Override
public OutputStream getOutputStream() {
return new ByteArrayOutputStream();
}
@Override
public AlgorithmIdentifier getAlgorithmIdentifier() {
return new DefaultSignatureAlgorithmIdentifierFinder().find("SHA256WithRSAEncryption");
}
};
org.bouncycastle.asn1.x509.Certificate cert = org.bouncycastle.asn1.x509.Certificate.getInstance(certificateChain[0].getEncoded());
JcaSignerInfoGeneratorBuilder sigb = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build());
//ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA256WithRSA").build(privateKey);
gen.addSignerInfoGenerator(sigb.build(nonSigner, new X509CertificateHolder(cert)));
gen.addCertificates(certs);
CMSTypedDataInputStream msg = new CMSTypedDataInputStream(new ByteArrayInputStream("useless_data".getBytes())); // this is never used.
//CMSProcessableInputStream msg = new CMSProcessableInputStream(content);
CMSSignedData signedData = gen.generate(msg, false);
if (tsaClient != null)
{
signedData = signTimeStamps(signedData);
}
byte[] pkcs7 = signedData.getEncoded();
content.close();
return pkcs7;
}
catch (GeneralSecurityException | CMSException | TSPException | OperatorCreationException e)
{
throw new IOException(e);
} catch (SessionExpiredException | TokenExpiredException | CertProviderException e) {
throw new IOException(e);
}
}
文档出现更改或损坏,Show签名返回以下错误:
org.bouncycastle.cms.CMSSignerDigestMismatchException:message-digest 属性值与计算值不匹配。