PAdES 签名级别 - Adobe Acrobat
PAdES Signature Level - Adobe Acrobat
我正在使用 pdfbox 3.0.0 RC 创建 PADES 签名,我的代码使用示例创建数字签名。但是,当我使用此工具打开文档时,我无法在 Adobe Acrobat 中看到签名级别,尽管它能够验证我的签名。
我不是在创建 VRI,所以我猜这可能是个问题,但如果这是验证我的签名所必需的,我不明白为什么签名显示为有效?
Adobe Acrobat 签名:
/**
* Service for automatically signing a document as part of a workflow. In this instance no user information is
* gathered
*
* @param taskID
* @param processName which will be added to the document
* @param keyID the ID for the key used to sign the PDF document
* @return the signed PDF document as a base 64 Encoded String
*/
@Transactional
public String signPDFService(String processID,
String processName,
String keyID,
ObjectData signatureImage,
String creator)
{
try {
ByteArrayOutputStream ostream = new ByteArrayOutputStream();
//Optional<ObjectData> pdfDocumentProcessInstance = userDataRepository.findById(documents.get(0).getProcessID());
/*List<Task> tasks = taskService.createTaskQuery()
.taskId(taskID)
.list();
// Optional<ObjectData> pdfDocumentProcessInstance = userDataRepository.findById(documents.get(0).getProcessID());
List<PDFDocument> documents = tasks.stream()
.map(task -> {
String processID = task.getProcessInstanceId();
Map<String, Object> variables = taskService.getVariables(task.getId());
PDFDocument document;
try {
document = new PDFDocument(
(ArrayList) variables.get("assigneeList"),
(String) variables.get("unsignedPDFDocument"),
task.getProcessInstanceId(),
task.getId(),
(String) variables.get("name"),
(String) variables.get("description")
);
document.setHistory((ArrayList) variables.get("history"));
return document;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
} catch (CMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
})
.collect(Collectors.toList());*/
//Optional<ObjectData> pdfDocumentProcessInstance = userDataRepository.findById(documents.get(0).getProcessID());
Optional<ObjectData> pdfDocumentProcessInstance = userDataRepository.findById(processID);
if(pdfDocumentProcessInstance.isEmpty())
throw new IOException("No process found");
String pdfDocumentBase64String = pdfDocumentProcessInstance.get().getAttributes().get("PDFDocument");
String extractedPDFString = pdfDocumentBase64String.replaceAll("data:application/pdf;base64,", "").replaceAll("data:;base64,", "").replaceAll("data:application/octet-stream", "");
//String extractedPDFString = base64PDF.replaceAll("data:application/pdf;base64,", "").replaceAll("data:;base64,", "");
InputStream stream = new ByteArrayInputStream(Base64.getDecoder().decode(extractedPDFString.getBytes()));
//Create the date object to sign the document
Date date = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
//Retrieve certificate chain for the PDF Signer
String certChainPEM = kmsService.getCertChainPEM(keyID);
X509Certificate pdfSignerCertificate = X509Utils.readCertificateChain(certChainPEM).get(0).getCertificate();
//Create the CMS Signing Object
ExternalSignatureCMSSignedDataGenerator cmsGenerator = new ExternalSignatureCMSSignedDataGenerator();
ExternalSignatureSignerInfoGenerator signerGenerator = new ExternalSignatureSignerInfoGenerator(CMSSignedDataGenerator.DIGEST_SHA256, "1.2.840.10045.4.3.2");
signerGenerator.setCertificate(pdfSignerCertificate);
ExternalSigningSupport externalSigningSupport;
PDDocument pdDocument = Loader.loadPDF(stream);
//Create the PDFBox Signature Object
PDSignature pdSignature = new PDSignature();
pdSignature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
pdSignature.setSubFilter(PDSignature.SUBFILTER_ETSI_CADES_DETACHED);
pdSignature.setLocation("Remote IS Blocks Signer");
pdSignature.setName("IS Blocks Signer");
pdSignature.setReason(processName);
pdDocument.setDocumentId(calendar.getTimeInMillis());
pdSignature.setSignDate(calendar);
// Optional: Certify the first time signature
// can be done only if version is at least 1.5 and if not already set
// doing this on a PDF/A-1b file fails validation by Adobe preflight (PDFBOX-3821)
// PDF/A-1b requires PDF version 1.4 max, so don't increase the version on such files.
int accessPermissions = SigUtils.getMDPPermission(pdDocument);
if (pdDocument.getVersion() >= 1.5f && accessPermissions == 0 && processName.contains("Document Certifying Key"))
{
logger.debug("Certifying Document");
SigUtils.setMDPPermission(pdDocument, pdSignature, 3);
}
if(signatureImage != null) {
String data = signatureImage.getAttributes().get("data").replaceAll("data:application/pdf;base64,", "").replaceAll("data:;base64,", "").replaceAll("data:image/png;base64,", "");
int pageNumber = Integer.parseInt(signatureImage.getAttributes().get("page"));
float x = Float.parseFloat(signatureImage.getAttributes().get("x"));
float y = Float.parseFloat(signatureImage.getAttributes().get("y"));
float width = Float.parseFloat(signatureImage.getAttributes().get("width"));
float height = Float.parseFloat(signatureImage.getAttributes().get("height"));
SignatureOptions signatureOptions;
// register signature dictionary and sign interface
signatureOptions = new SignatureOptions();
PDFVisibleSignature pdfVisibleSignature = new PDFVisibleSignature();
signatureOptions.setVisualSignature(pdfVisibleSignature.createVisualSignatureTemplate(
x,
y,
width,
height,
pdDocument,
pageNumber,
pdSignature,
Base64.getDecoder().decode(data.getBytes("UTF-8"))));
signatureOptions.setPage(pageNumber);
pdDocument.addSignature(pdSignature, null, signatureOptions);
} else {
pdDocument.addSignature(pdSignature);
}
externalSigningSupport = pdDocument.saveIncrementalForExternalSigning(ostream);
//Create the message digest of the pre-signed PDF
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] bytes = org.apache.commons.io.IOUtils.toByteArray(externalSigningSupport.getContent());
byte[] hashBytes = digest.digest(bytes);
//CMS Signature
InputStream isBytes = new ByteArrayInputStream(bytes);
CMSProcessable input = new CMSProcessableInputStream(isBytes);
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
MessageDigest messageDigest1 = MessageDigest.getInstance("SHA-256");
byte[] hash = messageDigest1.digest(bytes);
byte[] bytesToSign = signerGenerator.getBytesToSign(PKCSObjectIdentifiers.data, hash, new Date(),
"BC");
String encodedData = Base64.getEncoder().encodeToString(bytesToSign);
logger.debug("Bytes to Sign:" + (Base64.getEncoder().encodeToString(bytesToSign)));
logger.debug("Hash:" + Base64.getEncoder().encodeToString(hash));
//Create the signature using the keyID
//At this time only ECDSAWithSHA256 is supported
Map<String, String> signature = kmsService.sign(keyID, encodedData);
byte[] signedBytes = Base64.getDecoder().decode(signature.get("signature"));
X509Certificate[] chain;
signerGenerator.setCertificate(pdfSignerCertificate);
signerGenerator.setSignedBytes(signedBytes);
cmsGenerator.addSignerInf(signerGenerator);
cmsGenerator.addCertificatesAndCRLs(X509Utils.getCertStore(signature.get("certificateChain")));
CMSSignedData signedData = cmsGenerator.generate(new CMSProcessableByteArray(hash), false);
//Add a RFC3161 Time Stamp
ValidationTimeStamp validation = new ValidationTimeStamp("https://freetsa.org/tsr");
signedData = validation.addSignedTimeStamp(signedData);
ContentSigner nonSigner = new ContentSigner() {
@Override
public byte[] getSignature() {
return signedBytes;
}
@Override
public OutputStream getOutputStream() {
return new ByteArrayOutputStream();
}
@Override
public AlgorithmIdentifier getAlgorithmIdentifier() {
return new DefaultSignatureAlgorithmIdentifierFinder().find( "SHA256WithECDSA" );
}
};
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
JcaSignerInfoGeneratorBuilder sigb = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build());
gen.addCertificate(new X509CertificateHolder(pdfSignerCertificate.getEncoded()));
sigb.setDirectSignature( true );
gen.addSignerInfoGenerator(sigb.build(nonSigner, new X509CertificateHolder(pdfSignerCertificate.getEncoded())));
CMSTypedData msg = new CMSProcessableInputStream( new ByteArrayInputStream( "not used".getBytes() ) );
CMSSignedData signedData1 = gen.generate((CMSTypedData)msg, false);
signedData1.getEncoded();
externalSigningSupport.setSignature(signedData.getEncoded());
//documents.get(0).addHistoricEvent("Signed " + processName);
//ArrayList<String> history = documents.get(0).getHistory();
//Post Signature
String signedPDFDocument = Base64.getEncoder().encodeToString(ostream.toByteArray());
PDDocument newPdf1;
newPdf1 = Loader.loadPDF(ostream.toByteArray());
byte[] fileContent = ostream.toByteArray();
List<PDSignature> pdfSignatures;
pdfSignatures = newPdf1.getSignatureDictionaries();
byte[] signatureAsBytes;
signatureAsBytes = newPdf1.getLastSignatureDictionary().getContents( fileContent );
byte[] signedContentAsBytes;
signedContentAsBytes = newPdf1.getLastSignatureDictionary().getSignedContent( fileContent );
// Now we construct a PKCS #7 or CMS.
CMSProcessable cmsProcessableInputStream = new CMSProcessableByteArray(signedContentAsBytes);
CMSSignedData cmsSignedData;
cmsSignedData = new CMSSignedData(cmsProcessableInputStream, signatureAsBytes);
Store certificatesStore = cmsSignedData.getCertificates();
Collection<SignerInformation> signers = cmsSignedData.getSignerInfos().getSigners();
SignerInformation signerInformation = signers.iterator().next();
Collection matches = certificatesStore.getMatches(signerInformation.getSID());
X509CertificateHolder certificateHolder = (X509CertificateHolder) matches.iterator().next();
ObjectMapper mapper = new ObjectMapper();
ArrayList<String> signatures = null;
//signatures = documents.get(0).getSignatures();
for(int iCount = 0; iCount < pdfSignatures.size(); iCount++) {
PDFSignature pdfSignature = new PDFSignature(
pdfSignatures.get(iCount).getName(),
pdfSignatures.get(iCount).getLocation(),
pdfSignatures.get(iCount).getSignDate().getDisplayName(Calendar.LONG_FORMAT, java.util.Calendar.LONG, Locale.UK),
pdfSignatures.get(iCount).getReason(),
certificateHolder.getSubject().toString(),
certificateHolder.getIssuer().toString(),
Base64.getEncoder().encodeToString(certificateHolder.getEncoded()));
//signatures.add(mapper.writeValueAsString(pdfSignature));
logger.info("Signature" + mapper.writeValueAsString(pdfSignature));
}
Map<String, Object> variables = new HashMap<String, Object>();
// variables.put("history", history);
//variables.put("unsignedPDFDocument", signedPDFDocument);
//variables.put("signatures", signatures);
//variables.put("status", value)
Map<String, String> pdfDocumentProcessInstanceAttributes = pdfDocumentProcessInstance.get().getAttributes();
pdfDocumentProcessInstanceAttributes.put("PDFDocument", signedPDFDocument);
ObjectData newpdfProcessInstance = pdfDocumentProcessInstance.get();
newpdfProcessInstance.setAttributes(pdfDocumentProcessInstanceAttributes);
userDataRepository.save(newpdfProcessInstance);
newpdfProcessInstance.getHistory().add(new Date() + "Signed by:" + creator);
System.out.println(newpdfProcessInstance.getId() + " " + newpdfProcessInstance.toString());
newPdf1.close();
ostream.close();
} catch (Exception e){
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
在分析文件 document-with signingTime.pdf you provided in a comment, I recognized an issue in it. Being aware of that issue I re-checked your original document-17 21.08.14.pdf 时也发现了其中的问题,所以这个问题可能会导致您在这里要解决的验证问题。因此,...
您的两个示例文件 (document-17 21.08.14.pdf and document-with signingTime.pdf) 实际上都包含 两个串联的副本 相同的多修订版 PDF,具有单个签名 Signature1 ,只是第二个副本的ID条目发生了变化。添加到它们的是带有签名 Signature2.
的增量更新
%PDF-1.4
...
15 0 obj
<<
/FT /Sig
...
/T (Signature1)
...
>>
endobj
...
/ID [<1952AB9C134E46B58251246E985D5C15> <7F887303DDC0ED7C37AE77403E30DFB0>]
...
%%EOF
%PDF-1.4
...
15 0 obj
<<
/FT /Sig
...
/T (Signature1)
...
>>
endobj
...
/ID [<1952AB9C134E46B58251246E985D5C15> <A57CD5B87222756EC4A096125C7E8A42>]
...
%%EOF
...
35 0 obj
<<
/FT /Sig
...
/T (Signature2)
...
>>
...
%%EOF
这个结构被破坏了,即使它没有引起错误的交叉引用(因为第一个副本和第二个副本除了 ID、交叉引用和 startxref 偏移量指向第一个副本中的相应位置)。 Adobe Reader 签名验证对此类问题反应非常敏感。
因此,您应该删除此处的第二个副本才能取得成功。
此外,正如评论中已经提到的,您的 CMS 签名容器的 SignerInfo
包含一个 1.2.840.113549.1.9.5 signingTime
签名属性。 PAdES BASELINE 配置文件禁止这样做。
我正在使用 pdfbox 3.0.0 RC 创建 PADES 签名,我的代码使用示例创建数字签名。但是,当我使用此工具打开文档时,我无法在 Adobe Acrobat 中看到签名级别,尽管它能够验证我的签名。
我不是在创建 VRI,所以我猜这可能是个问题,但如果这是验证我的签名所必需的,我不明白为什么签名显示为有效?
Adobe Acrobat 签名:
/**
* Service for automatically signing a document as part of a workflow. In this instance no user information is
* gathered
*
* @param taskID
* @param processName which will be added to the document
* @param keyID the ID for the key used to sign the PDF document
* @return the signed PDF document as a base 64 Encoded String
*/
@Transactional
public String signPDFService(String processID,
String processName,
String keyID,
ObjectData signatureImage,
String creator)
{
try {
ByteArrayOutputStream ostream = new ByteArrayOutputStream();
//Optional<ObjectData> pdfDocumentProcessInstance = userDataRepository.findById(documents.get(0).getProcessID());
/*List<Task> tasks = taskService.createTaskQuery()
.taskId(taskID)
.list();
// Optional<ObjectData> pdfDocumentProcessInstance = userDataRepository.findById(documents.get(0).getProcessID());
List<PDFDocument> documents = tasks.stream()
.map(task -> {
String processID = task.getProcessInstanceId();
Map<String, Object> variables = taskService.getVariables(task.getId());
PDFDocument document;
try {
document = new PDFDocument(
(ArrayList) variables.get("assigneeList"),
(String) variables.get("unsignedPDFDocument"),
task.getProcessInstanceId(),
task.getId(),
(String) variables.get("name"),
(String) variables.get("description")
);
document.setHistory((ArrayList) variables.get("history"));
return document;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
} catch (CMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
})
.collect(Collectors.toList());*/
//Optional<ObjectData> pdfDocumentProcessInstance = userDataRepository.findById(documents.get(0).getProcessID());
Optional<ObjectData> pdfDocumentProcessInstance = userDataRepository.findById(processID);
if(pdfDocumentProcessInstance.isEmpty())
throw new IOException("No process found");
String pdfDocumentBase64String = pdfDocumentProcessInstance.get().getAttributes().get("PDFDocument");
String extractedPDFString = pdfDocumentBase64String.replaceAll("data:application/pdf;base64,", "").replaceAll("data:;base64,", "").replaceAll("data:application/octet-stream", "");
//String extractedPDFString = base64PDF.replaceAll("data:application/pdf;base64,", "").replaceAll("data:;base64,", "");
InputStream stream = new ByteArrayInputStream(Base64.getDecoder().decode(extractedPDFString.getBytes()));
//Create the date object to sign the document
Date date = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
//Retrieve certificate chain for the PDF Signer
String certChainPEM = kmsService.getCertChainPEM(keyID);
X509Certificate pdfSignerCertificate = X509Utils.readCertificateChain(certChainPEM).get(0).getCertificate();
//Create the CMS Signing Object
ExternalSignatureCMSSignedDataGenerator cmsGenerator = new ExternalSignatureCMSSignedDataGenerator();
ExternalSignatureSignerInfoGenerator signerGenerator = new ExternalSignatureSignerInfoGenerator(CMSSignedDataGenerator.DIGEST_SHA256, "1.2.840.10045.4.3.2");
signerGenerator.setCertificate(pdfSignerCertificate);
ExternalSigningSupport externalSigningSupport;
PDDocument pdDocument = Loader.loadPDF(stream);
//Create the PDFBox Signature Object
PDSignature pdSignature = new PDSignature();
pdSignature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
pdSignature.setSubFilter(PDSignature.SUBFILTER_ETSI_CADES_DETACHED);
pdSignature.setLocation("Remote IS Blocks Signer");
pdSignature.setName("IS Blocks Signer");
pdSignature.setReason(processName);
pdDocument.setDocumentId(calendar.getTimeInMillis());
pdSignature.setSignDate(calendar);
// Optional: Certify the first time signature
// can be done only if version is at least 1.5 and if not already set
// doing this on a PDF/A-1b file fails validation by Adobe preflight (PDFBOX-3821)
// PDF/A-1b requires PDF version 1.4 max, so don't increase the version on such files.
int accessPermissions = SigUtils.getMDPPermission(pdDocument);
if (pdDocument.getVersion() >= 1.5f && accessPermissions == 0 && processName.contains("Document Certifying Key"))
{
logger.debug("Certifying Document");
SigUtils.setMDPPermission(pdDocument, pdSignature, 3);
}
if(signatureImage != null) {
String data = signatureImage.getAttributes().get("data").replaceAll("data:application/pdf;base64,", "").replaceAll("data:;base64,", "").replaceAll("data:image/png;base64,", "");
int pageNumber = Integer.parseInt(signatureImage.getAttributes().get("page"));
float x = Float.parseFloat(signatureImage.getAttributes().get("x"));
float y = Float.parseFloat(signatureImage.getAttributes().get("y"));
float width = Float.parseFloat(signatureImage.getAttributes().get("width"));
float height = Float.parseFloat(signatureImage.getAttributes().get("height"));
SignatureOptions signatureOptions;
// register signature dictionary and sign interface
signatureOptions = new SignatureOptions();
PDFVisibleSignature pdfVisibleSignature = new PDFVisibleSignature();
signatureOptions.setVisualSignature(pdfVisibleSignature.createVisualSignatureTemplate(
x,
y,
width,
height,
pdDocument,
pageNumber,
pdSignature,
Base64.getDecoder().decode(data.getBytes("UTF-8"))));
signatureOptions.setPage(pageNumber);
pdDocument.addSignature(pdSignature, null, signatureOptions);
} else {
pdDocument.addSignature(pdSignature);
}
externalSigningSupport = pdDocument.saveIncrementalForExternalSigning(ostream);
//Create the message digest of the pre-signed PDF
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] bytes = org.apache.commons.io.IOUtils.toByteArray(externalSigningSupport.getContent());
byte[] hashBytes = digest.digest(bytes);
//CMS Signature
InputStream isBytes = new ByteArrayInputStream(bytes);
CMSProcessable input = new CMSProcessableInputStream(isBytes);
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
MessageDigest messageDigest1 = MessageDigest.getInstance("SHA-256");
byte[] hash = messageDigest1.digest(bytes);
byte[] bytesToSign = signerGenerator.getBytesToSign(PKCSObjectIdentifiers.data, hash, new Date(),
"BC");
String encodedData = Base64.getEncoder().encodeToString(bytesToSign);
logger.debug("Bytes to Sign:" + (Base64.getEncoder().encodeToString(bytesToSign)));
logger.debug("Hash:" + Base64.getEncoder().encodeToString(hash));
//Create the signature using the keyID
//At this time only ECDSAWithSHA256 is supported
Map<String, String> signature = kmsService.sign(keyID, encodedData);
byte[] signedBytes = Base64.getDecoder().decode(signature.get("signature"));
X509Certificate[] chain;
signerGenerator.setCertificate(pdfSignerCertificate);
signerGenerator.setSignedBytes(signedBytes);
cmsGenerator.addSignerInf(signerGenerator);
cmsGenerator.addCertificatesAndCRLs(X509Utils.getCertStore(signature.get("certificateChain")));
CMSSignedData signedData = cmsGenerator.generate(new CMSProcessableByteArray(hash), false);
//Add a RFC3161 Time Stamp
ValidationTimeStamp validation = new ValidationTimeStamp("https://freetsa.org/tsr");
signedData = validation.addSignedTimeStamp(signedData);
ContentSigner nonSigner = new ContentSigner() {
@Override
public byte[] getSignature() {
return signedBytes;
}
@Override
public OutputStream getOutputStream() {
return new ByteArrayOutputStream();
}
@Override
public AlgorithmIdentifier getAlgorithmIdentifier() {
return new DefaultSignatureAlgorithmIdentifierFinder().find( "SHA256WithECDSA" );
}
};
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
JcaSignerInfoGeneratorBuilder sigb = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build());
gen.addCertificate(new X509CertificateHolder(pdfSignerCertificate.getEncoded()));
sigb.setDirectSignature( true );
gen.addSignerInfoGenerator(sigb.build(nonSigner, new X509CertificateHolder(pdfSignerCertificate.getEncoded())));
CMSTypedData msg = new CMSProcessableInputStream( new ByteArrayInputStream( "not used".getBytes() ) );
CMSSignedData signedData1 = gen.generate((CMSTypedData)msg, false);
signedData1.getEncoded();
externalSigningSupport.setSignature(signedData.getEncoded());
//documents.get(0).addHistoricEvent("Signed " + processName);
//ArrayList<String> history = documents.get(0).getHistory();
//Post Signature
String signedPDFDocument = Base64.getEncoder().encodeToString(ostream.toByteArray());
PDDocument newPdf1;
newPdf1 = Loader.loadPDF(ostream.toByteArray());
byte[] fileContent = ostream.toByteArray();
List<PDSignature> pdfSignatures;
pdfSignatures = newPdf1.getSignatureDictionaries();
byte[] signatureAsBytes;
signatureAsBytes = newPdf1.getLastSignatureDictionary().getContents( fileContent );
byte[] signedContentAsBytes;
signedContentAsBytes = newPdf1.getLastSignatureDictionary().getSignedContent( fileContent );
// Now we construct a PKCS #7 or CMS.
CMSProcessable cmsProcessableInputStream = new CMSProcessableByteArray(signedContentAsBytes);
CMSSignedData cmsSignedData;
cmsSignedData = new CMSSignedData(cmsProcessableInputStream, signatureAsBytes);
Store certificatesStore = cmsSignedData.getCertificates();
Collection<SignerInformation> signers = cmsSignedData.getSignerInfos().getSigners();
SignerInformation signerInformation = signers.iterator().next();
Collection matches = certificatesStore.getMatches(signerInformation.getSID());
X509CertificateHolder certificateHolder = (X509CertificateHolder) matches.iterator().next();
ObjectMapper mapper = new ObjectMapper();
ArrayList<String> signatures = null;
//signatures = documents.get(0).getSignatures();
for(int iCount = 0; iCount < pdfSignatures.size(); iCount++) {
PDFSignature pdfSignature = new PDFSignature(
pdfSignatures.get(iCount).getName(),
pdfSignatures.get(iCount).getLocation(),
pdfSignatures.get(iCount).getSignDate().getDisplayName(Calendar.LONG_FORMAT, java.util.Calendar.LONG, Locale.UK),
pdfSignatures.get(iCount).getReason(),
certificateHolder.getSubject().toString(),
certificateHolder.getIssuer().toString(),
Base64.getEncoder().encodeToString(certificateHolder.getEncoded()));
//signatures.add(mapper.writeValueAsString(pdfSignature));
logger.info("Signature" + mapper.writeValueAsString(pdfSignature));
}
Map<String, Object> variables = new HashMap<String, Object>();
// variables.put("history", history);
//variables.put("unsignedPDFDocument", signedPDFDocument);
//variables.put("signatures", signatures);
//variables.put("status", value)
Map<String, String> pdfDocumentProcessInstanceAttributes = pdfDocumentProcessInstance.get().getAttributes();
pdfDocumentProcessInstanceAttributes.put("PDFDocument", signedPDFDocument);
ObjectData newpdfProcessInstance = pdfDocumentProcessInstance.get();
newpdfProcessInstance.setAttributes(pdfDocumentProcessInstanceAttributes);
userDataRepository.save(newpdfProcessInstance);
newpdfProcessInstance.getHistory().add(new Date() + "Signed by:" + creator);
System.out.println(newpdfProcessInstance.getId() + " " + newpdfProcessInstance.toString());
newPdf1.close();
ostream.close();
} catch (Exception e){
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
在分析文件 document-with signingTime.pdf you provided in a comment, I recognized an issue in it. Being aware of that issue I re-checked your original document-17 21.08.14.pdf 时也发现了其中的问题,所以这个问题可能会导致您在这里要解决的验证问题。因此,...
您的两个示例文件 (document-17 21.08.14.pdf and document-with signingTime.pdf) 实际上都包含 两个串联的副本 相同的多修订版 PDF,具有单个签名 Signature1 ,只是第二个副本的ID条目发生了变化。添加到它们的是带有签名 Signature2.
的增量更新%PDF-1.4
...
15 0 obj
<<
/FT /Sig
...
/T (Signature1)
...
>>
endobj
...
/ID [<1952AB9C134E46B58251246E985D5C15> <7F887303DDC0ED7C37AE77403E30DFB0>]
...
%%EOF
%PDF-1.4
...
15 0 obj
<<
/FT /Sig
...
/T (Signature1)
...
>>
endobj
...
/ID [<1952AB9C134E46B58251246E985D5C15> <A57CD5B87222756EC4A096125C7E8A42>]
...
%%EOF
...
35 0 obj
<<
/FT /Sig
...
/T (Signature2)
...
>>
...
%%EOF
这个结构被破坏了,即使它没有引起错误的交叉引用(因为第一个副本和第二个副本除了 ID、交叉引用和 startxref 偏移量指向第一个副本中的相应位置)。 Adobe Reader 签名验证对此类问题反应非常敏感。
因此,您应该删除此处的第二个副本才能取得成功。
此外,正如评论中已经提到的,您的 CMS 签名容器的 SignerInfo
包含一个 1.2.840.113549.1.9.5 signingTime
签名属性。 PAdES BASELINE 配置文件禁止这样做。