Ich werde das externe und späte Signieren mit PDFBox 3.0.x implementieren, aber das ausgegebene signierte PDF verursacht „Signatur ist ungültig“. Das Folgende ist mein Code:
File inputFile = new File(inPdfPath1);
File outputFile = new File(inPdfPath2);
CreateSignature2 sig2 = new CreateSignature2(externalSignService);
CreateSignature2.LateSigningSession session = sig2.prepareSigning(inputFile, outputFile);
byte[] dataToSign = session.getDataToSign();
System.out.println(">>>>SIZE: " + dataToSign.length);
// Send to external signing service
List dataList = Arrays.asList(dataToSign);
List signatures = externalSignService.sign(dataList);
byte[] signature = signatures.get(0);
// Complete the signing stage
sig2.completeSigning(session, signature);
Hängt von der oben genannten CreateSignature2-Klasse ab. Bitte helfen Sie mir und geben Sie mir einen Rat, wie ich das externe und späte Signieren mit PDFBox implementieren kann. Danke.
Ich werde das externe und späte Signieren mit PDFBox 3.0.x implementieren, aber das ausgegebene signierte PDF verursacht „Signatur ist ungültig“. Das Folgende ist mein Code: [code]public class CreateSignature2 {
final DataSigner signer; private Certificate cert; private Certificate[] certificateChain;
public CreateSignature2(DataSigner signer) { this.signer = signer;
/** * Prepares the document for signing and returns the data that needs to be signed */ public LateSigningSession prepareSigning(File inFile, File outFile) throws IOException, NoSuchAlgorithmException, CertificateEncodingException, OperatorCreationException, CMSException { FileOutputStream output = new FileOutputStream(outFile); PDDocument document = Loader.loadPDF(inFile);
// Build CMS structure ESSCertIDv2 certid = new ESSCertIDv2( new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256), MessageDigest.getInstance("SHA-256").digest(cert.getEncoded()) ); SigningCertificateV2 sigcert = new SigningCertificateV2(certid); Attribute attr = new Attribute(PKCSObjectIdentifiers.id_aa_signingCertificateV2, new DERSet(sigcert));
ASN1EncodableVector v = new ASN1EncodableVector(); v.add(attr); AttributeTable atttributeTable = new AttributeTable(v); CMSAttributeTableGenerator attrGen = new DefaultSignedAttributeTableGenerator(atttributeTable);
org.bouncycastle.asn1.x509.Certificate cert2 = org.bouncycastle.asn1.x509.Certificate.getInstance( ASN1Primitive.fromByteArray(cert.getEncoded()) ); JcaSignerInfoGeneratorBuilder sigb = new JcaSignerInfoGeneratorBuilder( new JcaDigestCalculatorProviderBuilder().build() ); sigb.setSignedAttributeGenerator(attrGen);
// Create a ContentSigner that captures the data HashCapturingContentSigner contentSigner = new HashCapturingContentSigner();
CMSSignedDataGenerator gen = new CMSSignedDataGenerator(); gen.addCertificates(new JcaCertStore(Arrays.asList(certificateChain))); gen.addSignerInfoGenerator(sigb.build(contentSigner, new X509CertificateHolder(cert2)));
// Process the document content to populate the ContentSigner's OutputStream CMSTypedData msg = new CMSProcessableInputStream(externalSigning.getContent());
// This will write the data to be signed to the ContentSigner's OutputStream // We catch the expected exception when getSignature() is called prematurely try { CMSSignedData signedData = gen.generate(msg, false); } catch (RuntimeException e) { if (e.getMessage() != null && e.getMessage().contains("Signature not set")) { // Expected - we're capturing the data for late signing } else { throw e; } }
// Get the captured data from the ContentSigner byte[] dataToSign = contentSigner.getCapturedData();
return new LateSigningSession(document, output, externalSigning, contentSigner, gen, msg, dataToSign);
} catch (Exception e) { // Clean up resources if anything fails document.close(); output.close(); throw e; } }
/** * Completes the signing process with the externally generated signature */ public void completeSigning(LateSigningSession session, byte[] externalSignature) throws IOException, CMSException { try { // Set the external signature on the ContentSigner session.getContentSigner().setSignature(externalSignature);
// Now generate the final CMS signature CMSSignedData signedData = session.getGenerator().generate(session.getMessage(), false); byte[] cmsSignature = signedData.getEncoded();
// Set the signature on the document session.getExternalSigningSupport().setSignature(cmsSignature); } finally { // Always close resources session.close(); } }
/** * ContentSigner that captures data for late signing */ private static class HashCapturingContentSigner implements ContentSigner { private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); private byte[] signature; private boolean signatureSet = false;
@Override public byte[] getSignature() { if (!signatureSet) { throw new RuntimeException("Signature not set. Use setSignature() for late signing."); } return signature; }
@Override public OutputStream getOutputStream() { return outputStream; }
@Override public AlgorithmIdentifier getAlgorithmIdentifier() { return new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.2.840.113549.1.1.11")); }
public byte[] getCapturedData() { return outputStream.toByteArray(); } }
/** * Session class to hold signing state between preparation and completion */ public static class LateSigningSession implements AutoCloseable { private final PDDocument document; private final FileOutputStream output; private final ExternalSigningSupport externalSigningSupport; private final HashCapturingContentSigner contentSigner; private final CMSSignedDataGenerator generator; private final CMSTypedData message; private final byte[] dataToSign;
public byte[] getDataToSign() { return dataToSign; }
public ExternalSigningSupport getExternalSigningSupport() { return externalSigningSupport; }
public HashCapturingContentSigner getContentSigner() { return contentSigner; }
public CMSSignedDataGenerator getGenerator() { return generator; }
public CMSTypedData getMessage() { return message; }
@Override public void close() throws IOException { if (document != null) { document.close(); } if (output != null) { output.close(); } } }
/** * Alternative approach that recreates the CMS structure for completion * This is more robust if the first approach has issues */ public LateSigningSession prepareSigningAlternative(File inFile, File outFile) throws IOException, NoSuchAlgorithmException, CertificateEncodingException { FileOutputStream output = new FileOutputStream(outFile); PDDocument document = Loader.loadPDF(inFile);
// Read the document content that will be processed InputStream contentStream = externalSigning.getContent(); ByteArrayOutputStream contentBaos = new ByteArrayOutputStream(); byte[] buffer = new byte[8192]; int bytesRead; while ((bytesRead = contentStream.read(buffer)) != -1) { contentBaos.write(buffer, 0, bytesRead); } byte[] documentContent = contentBaos.toByteArray();
return new LateSigningSession(document, output, externalSigning, null, null, null, documentContent);
/** * Alternative completion that recreates the CMS structure */ public void completeSigningAlternative(LateSigningSession session, byte[] externalSignature) throws IOException, NoSuchAlgorithmException, CertificateEncodingException, OperatorCreationException, CMSException { try { // Recreate the CMS structure with the external signature ESSCertIDv2 certid = new ESSCertIDv2( new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256), MessageDigest.getInstance("SHA-256").digest(cert.getEncoded()) ); SigningCertificateV2 sigcert = new SigningCertificateV2(certid); Attribute attr = new Attribute(PKCSObjectIdentifiers.id_aa_signingCertificateV2, new DERSet(sigcert));
ASN1EncodableVector v = new ASN1EncodableVector(); v.add(attr); AttributeTable atttributeTable = new AttributeTable(v); CMSAttributeTableGenerator attrGen = new DefaultSignedAttributeTableGenerator(atttributeTable);
// Create ContentSigner with the pre-computed signature ContentSigner contentSigner = new PrecomputedContentSigner(externalSignature);
JcaSignerInfoGeneratorBuilder sigb = new JcaSignerInfoGeneratorBuilder( new JcaDigestCalculatorProviderBuilder().build() ); sigb.setSignedAttributeGenerator(attrGen);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator(); gen.addCertificates(new JcaCertStore(Arrays.asList(certificateChain))); gen.addSignerInfoGenerator(sigb.build(contentSigner, new X509CertificateHolder(cert2)));
// Use the captured document content CMSTypedData msg = new CMSProcessableByteArray(session.getDataToSign()); CMSSignedData signedData = gen.generate(msg, false);
/** * ContentSigner that uses a pre-computed signature */ private static class PrecomputedContentSigner implements ContentSigner { private final byte[] signature; private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
public PrecomputedContentSigner(byte[] signature) { this.signature = signature; }
@Override public byte[] getSignature() { return signature; }
@Override public OutputStream getOutputStream() { return outputStream; }
@Override public AlgorithmIdentifier getAlgorithmIdentifier() { return new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.2.840.113549.1.1.11")); } } } [/code] Und das Folgende ist, die obige Klasse aufzurufen: [code] File inputFile = new File(inPdfPath1); File outputFile = new File(inPdfPath2);
CreateSignature2 sig2 = new CreateSignature2(externalSignService);
// Send to external signing service List dataList = Arrays.asList(dataToSign); List signatures = externalSignService.sign(dataList); byte[] signature = signatures.get(0);
// Complete the signing stage sig2.completeSigning(session, signature); [/code] Hängt von der oben genannten CreateSignature2-Klasse ab. Bitte helfen Sie mir und geben Sie mir einen Rat, wie ich das externe und späte Signieren mit PDFBox implementieren kann. Danke.
Ich werde die externe und späte Signatur mit PDFBox 3.0.x implementieren, aber das ausgegebene signierte PDF verursacht „Signatur ist ungültig“. Bitte helfen Sie mir, das Problem zu beheben. Vielen...
Ich habe versucht, viele Lösungen im Internet zu finden, aber es hat nicht funktioniert. Ich muss ein PDF signieren, indem ich den Hash aus dem PDF extrahiere und ihn an einen anderen Serverdienst...
Ich habe versucht, viele Lösungen im Internet zu finden, aber es hat nicht funktioniert. Ich muss ein PDF signieren, indem ich den Hash aus dem PDF extrahiere und ihn an einen anderen Serverdienst...
Ich verwende die Apache PDFBox-Bibliothek zum Verarbeiten von PDF-Dateien und stoße aufgrund von Zirkelverweisen in der PDF-Struktur auf einen StackOverflowError. Der Fehler tritt auf, wenn PDFBox...
Ich verwende das Paket .NET azure.storage.Blobs in einer Azure -Funktion, um Blobs zu schreiben. Der Pfad ist dynamisch, daher verwende ich die Binder -Funktionalität. Ich biete auch Metadaten mit...