2017-10-10 96 views
0

我创建了一个证书使用keytool:签名与密钥库的Java

keytool -genkeypair -alias sara -keyalg RSA -keysize 2048 -keypass 
password -keystore "\Sviluppo\JavaKeyStore\keystore.jks" -storepass 
12345678 -validity 360 -dname "cn=Sara, ou=***, o=***, l=Padova, 
s=Italia, c=IT" 

然后我想签署此证书的PDF版本,我使用Itextpdf签署一份PDF格式。 首先,我加载私钥和证书密钥库从:

KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); 
File fileKeyStore = new File(pathKeyStore); 
FileInputStream fis = new FileInputStream(fileKeyStore); 
keyStore.load(fis, "12345678".toCharArray()); 
final PrivateKey privateKey = (PrivateKey) keyStore.getKey("sara", "password".toCharArray()); 
final Certificate certificate = keyStore.getCertificate(certID); 

然后我打开文件的哈希计算签名:

PdfReader reader = new PdfReader(new RandomAccessFileOrArray(pdfInputPath), null); 
OutputStream pdfOutputStream = new FileOutputStream(pdfOutputPath); 

PdfStamper stp = PdfStamper.createSignature(reader, pdfOutputStream, '\0', tempPathFile, true) 
PdfSignatureAppearance sap = stp.getSignatureAppearance(); 
PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED); 
dic.setDate(dateNow); 
sap.setCryptoDictionary(dic); 
sap.setCrypto(privateKey, keyStore.getCertificateChain("sara"), null, PdfSignatureAppearance.SELF_SIGNED); 

HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer>(); 
exc.put(PdfName.CONTENTS, (int) (6144 * 2 + 2)); 
sap.preClose(exc); 

然后计算sap.getRangeStream(),从密钥库加载证书的哈希值:

BufferedInputStream bis = new BufferedInputStream(sap.getRangeStream()); 
MessageDigest digest = MessageDigest.getInstance("SHA-256"); 
DigestInputStream dis = new DigestInputStream(bis, digest); 
byte[] buff = new byte[512]; 
while (dis.read(buff) != -1) { 
    ; 
} 
dis.close(); 
dis = null; 
byte[] hashToSign= digest.digest(); 
bis.close(); 

我从证书密钥库登录:

java.security.Signature signature = Signature.getInstance("SHA256withRSA"); 
signature.initSign(privateKey); 
signature.update(hashToSign); 
byte[] hashSigned = signature.sign(); 

末关闭PDF:

byte[] paddedSig = new byte[6144]; 
System.arraycopy(hashSigned, 0, paddedSig, 0, hashSigned.length); 
PdfDictionary pdfDictionary = new PdfDictionary(); 
pdfDictionary.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true)); 
sap.close(pdfDictionary); 

但签署的PDF是无效的:“有包含在此签名的格式或信息错误

有什么问题,证书或签名? 感谢您的帮助 萨拉

+0

为什么直接构建哈希以签名和嵌入数字签名而不是使用itext支持?有很多可能的失败点。例如,你不包括认证链到pdf – pedrofb

+0

如果我打电话给一个外部服务器(例如阿鲁巴CA),我只发送散列,签署pdf的代码工作正常。但是,如果我使用keytool生成证书,pdf是不正确的。我还添加了证书链: sap.setCrypto((PrivateKey)keyStore.getKey(“sara”,“password”.toCharArray()),keyStore.getCertificate(“sara”)。getCertificateChain(),null,PdfSignatureAppearance.SELF_SIGNED ); 但存在同样的问题。 – Sara

+0

不要在评论中包含代码,它很难阅读。只需编辑你自己的问题。你应该包括所有相关的代码,包括你如何计算'hashToSign'。但是,如果您的代码与外部CA一起使用,而不是使用自签名证书,那么问题可能就在那里。检查您的证书是否正确生成 – pedrofb

回答

0

的事业“有包含在该签名的格式或信息错误,”验证失败消息是你的代码放在一个裸体PKCS1签名值,其中一个成熟的CMS签名容器预计:

你,一方面利用SELF_SIGNEDsap.setCrypto这表明你想创建一个adbe.x509.rsa_sha1辅助过滤签名,而在另一方面,子过滤设置为adbe.pkcs7.detached在您的PdfSignature构造函数中。

这不符合所有,adbe.x509.rsa_sha1使用裸PKCS1签名值,而adbe.pkcs7.detached使用CMS签名的容器。

这应该回答你的问题“有什么问题,certificare或签名?” ......


根据你同时发现在行动一iText的副本,第2版解决方案的注释。

请注意,虽然iText签名API已经大幅扩展。如果您正在使用iText 5.5.x,则应该下载并阅读由Bruno Lowagie(iText Software)撰写的白皮书Digital Signatures for PDF Documents。2008年(SOTA在其发布而不是的时间了),数字签名的PDF文档重点:

虽然从的iText在行动代码,第二版,根据ISO 32000-1仍集中在签名根据PAdES签名,同时也包含在ISO 32000-2:2017中。