From b9ae3802e2c96f14420a8008e847d79a75504ffe Mon Sep 17 00:00:00 2001 From: Frank Intorp Date: Tue, 15 Sep 2026 10:39:09 +0200 Subject: [PATCH] chore(deps): update bouncycastle to 1.86, extra-enforcer-rules to 1.12.1 Trims trailing zero-padding from the PDF /Contents byte string before handing it to CMSSignedData, since BouncyCastle 1.86 rejects any bytes after the top-level DER structure ("Extra data detected in stream"), which broke signature validation for signed PDFs. junit-jupiter stays on 5.11.4 (6.x is a major bump, deferred). Co-Authored-By: Claude Sonnet 5 --- .../filetype/pdfutil/SignatureUtil.java | 42 ++++++++++++++++++- pom.xml | 4 +- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/analyzer/src/main/java/org/jadice/filetype/pdfutil/SignatureUtil.java b/analyzer/src/main/java/org/jadice/filetype/pdfutil/SignatureUtil.java index 6eca1be..58d7365 100644 --- a/analyzer/src/main/java/org/jadice/filetype/pdfutil/SignatureUtil.java +++ b/analyzer/src/main/java/org/jadice/filetype/pdfutil/SignatureUtil.java @@ -162,7 +162,7 @@ public static String verifySignature(final byte[] contents, final InputStream si */ public static String verifyPKCS7(final byte[] contents, final InputStream signedContent, final Calendar signDate) { try { - final CMSSignedData cms = new CMSSignedData(new CMSProcessableInputStream(signedContent), contents); + final CMSSignedData cms = new CMSSignedData(new CMSProcessableInputStream(signedContent), trimToDerLength(contents)); final SignerInformation signerInfo = cms.getSignerInfos().getSigners().iterator().next(); X509CertificateHolder certHolder = (X509CertificateHolder) cms.getCertificates().getMatches(signerInfo.getSID()) .iterator().next(); @@ -175,6 +175,44 @@ public static String verifyPKCS7(final byte[] contents, final InputStream signed } } + /** + * The PDF's /Contents byte string is a fixed-size placeholder that is typically + * zero-padded beyond the actual DER-encoded CMS structure (the signature is + * embedded before the exact byte count is known). BouncyCastle rejects any + * trailing bytes after the top-level ASN.1 structure ("Extra data detected in + * stream"), so the array needs to be trimmed to the structure's real length + * before it is handed to {@link CMSSignedData}. + * + * @param contents raw /Contents bytes, possibly zero-padded + * @return contents trimmed to the length of the top-level DER structure it encodes, + * or the original array if that length cannot be determined + */ + private static byte[] trimToDerLength(final byte[] contents) { + if (contents.length < 2 || (contents[1] & 0xFF) == 0x80) { + // too short to hold a header, or indefinite-length (BER) encoding: leave as is + return contents; + } + final int lengthOctet = contents[1] & 0xFF; + final int lengthFieldSize; + final int contentLength; + if (lengthOctet < 0x80) { + lengthFieldSize = 1; + contentLength = lengthOctet; + } else { + lengthFieldSize = 1 + (lengthOctet & 0x7F); + if (contents.length < 1 + lengthFieldSize) { + return contents; + } + int len = 0; + for (int i = 0; i < lengthFieldSize - 1; i++) { + len = (len << 8) | (contents[2 + i] & 0xFF); + } + contentLength = len; + } + final int totalLength = 1 + lengthFieldSize + contentLength; + return totalLength > 0 && totalLength <= contents.length ? Arrays.copyOf(contents, totalLength) : contents; + } + /** * Verify ETSI.RFC3161 TimeStampToken * Copied from: ... @@ -185,7 +223,7 @@ public static String verifyPKCS7(final byte[] contents, final InputStream signed */ public static String verifyETSIdotRFC3161(InputStream signedContent, byte[] contents) throws CMSException, NoSuchAlgorithmException, IOException, TSPException { - final TimeStampToken timeStampToken = new TimeStampToken(new CMSSignedData(contents)); + final TimeStampToken timeStampToken = new TimeStampToken(new CMSSignedData(trimToDerLength(contents))); final TimeStampTokenInfo timeStampInfo = timeStampToken.getTimeStampInfo(); final String hashAlgorithm = timeStampInfo.getMessageImprintAlgOID().getId(); diff --git a/pom.xml b/pom.xml index 2513de7..4173a4a 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 17 - 1.84 + 1.86 1.28.0 4.0.5 4.0.9 @@ -79,7 +79,7 @@ 0.8.15 3.6.0 3.6.3 - 1.12.0 + 1.12.1 3.3.1 3.5.1 3.5.0