This is an automated email from the ASF dual-hosted git repository. tballison pushed a commit to branch TIKA-1997-pkcs-detection-pr in repository https://gitbox.apache.org/repos/asf/tika.git
commit 4e7a80ba0ed2497eb56936ab6fc6f6b9a976477c Author: tallison <[email protected]> AuthorDate: Tue Jul 14 12:26:52 2026 -0400 TIKA-1997 -- pkcs detection --- CHANGES.txt | 9 ++ docs/modules/ROOT/examples/detector-pkcs7.json | 6 + .../ROOT/pages/configuration/detectors.adoc | 57 ++++++++ docs/modules/ROOT/pages/configuration/index.adoc | 1 + .../org/apache/tika/mime/tika-mimetypes.xml | 25 +++- .../org/apache/tika/config/ConfigExamplesTest.java | 30 +++++ .../java/org/apache/tika/mime/TestMimeTypes.java | 7 +- .../tika/parser/crypto/Pkcs7EndToEndTest.java | 65 ++++++++++ .../resources/config-examples/detector-pkcs7.json | 6 + .../src/test/resources/test-documents/test.xml.p7m | Bin 0 -> 2504 bytes .../testPKCS7_compressed_def_long.p7z | Bin 0 -> 331 bytes .../test-documents/testPKCS7_signed_data_def.p7m | Bin 0 -> 1574 bytes .../apache/tika/detect/crypto/Pkcs7Detector.java | 50 +++++++ .../apache/tika/parser/crypto/CmsClassifier.java | 143 +++++++++++++++++++++ .../org/apache/tika/parser/crypto/Pkcs7Parser.java | 77 ++++++++--- .../tika/detect/crypto/Pkcs7DetectorTest.java | 59 +++++++++ .../tika/parser/crypto/CmsClassifierTest.java | 62 +++++++++ .../tika/parser/crypto/Pkcs7DetectionTest.java | 54 ++++++++ .../apache/tika/parser/crypto/Pkcs7ParserTest.java | 58 ++++++--- .../src/test/resources/test-documents/test.xml.p7m | Bin 0 -> 2504 bytes .../test-documents/testPKCS7_certs_only_def.p7c | Bin 0 -> 2972 bytes .../test-documents/testPKCS7_certs_only_ind.p7c | Bin 0 -> 2976 bytes .../testPKCS7_compressed_def_long.p7z | Bin 0 -> 331 bytes .../testPKCS7_compressed_def_short.p7z | Bin 0 -> 125 bytes .../test-documents/testPKCS7_compressed_ind.p7z | Bin 0 -> 141 bytes .../test-documents/testPKCS7_enveloped_def.p7m | Bin 0 -> 350 bytes .../test-documents/testPKCS7_enveloped_ind.p7m | Bin 0 -> 356 bytes .../test-documents/testPKCS7_signature_def.p7s | Bin 0 -> 1566 bytes .../test-documents/testPKCS7_signature_ind.p7s | Bin 0 -> 1568 bytes .../test-documents/testPKCS7_signed_data_def.p7m | Bin 0 -> 1574 bytes .../test-documents/testPKCS7_signed_data_def.pem | 35 +++++ .../test-documents/testPKCS7_signed_data_ind.p7m | Bin 0 -> 1582 bytes .../resources/test-documents/testRSAKEYandCERT.p12 | Bin 0 -> 1717 bytes 33 files changed, 706 insertions(+), 38 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 92606e27fd..7fe618fb7e 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,12 @@ +Release 4.0.0 - ??? + + NEW FEATURES + + * Content-based detection of ASN.1/DER crypto containers at parse time. An + opt-in Pkcs7Detector surfaces the subtype at detect() time, + but must be enabled via configuration (TIKA-1997). + + Release 4.0.0-beta-1 - 6/29/2026 BREAKING CHANGES diff --git a/docs/modules/ROOT/examples/detector-pkcs7.json b/docs/modules/ROOT/examples/detector-pkcs7.json new file mode 100644 index 0000000000..c4d7c5c9b8 --- /dev/null +++ b/docs/modules/ROOT/examples/detector-pkcs7.json @@ -0,0 +1,6 @@ +{ + "detectors": [ + { "pkcs-7-detector": {} }, + { "default-detector": {} } + ] +} diff --git a/docs/modules/ROOT/pages/configuration/detectors.adoc b/docs/modules/ROOT/pages/configuration/detectors.adoc new file mode 100644 index 0000000000..1ef2e1c058 --- /dev/null +++ b/docs/modules/ROOT/pages/configuration/detectors.adoc @@ -0,0 +1,57 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + += Detector Configuration + +A `detectors` list loads *only* the detectors it names — every other detector is dropped. +To add a detector while keeping the default detection chain, include a `default-detector` +entry (the same pattern as `default-parser`; see xref:configuration/index.adoc[Configuration]). + +== Enabling the PKCS7/CMS detector + +Content detection of ASN.1/DER cryptographic containers is *coarse by default*: a CMS/PKCS7 +message is detected as `application/pkcs7-signature`, and the exact CMS subtype +(signed vs. enveloped vs. certs-only) is refined by `Pkcs7Parser` at *parse* time — it is set +on the output content type, the same way `PDFParser` refines a PDF to `application/illustrator`. + +If you need that subtype from `Tika.detect()` *without* parsing, enable the opt-in +`pkcs-7-detector`. It is not loaded by default (so the common detect path stays cheap and does +no ASN.1 work on every stream); add it ahead of `default-detector`: + +[source,json] +---- +include::example$detector-pkcs7.json[] +---- +icon:github[] https://github.com/apache/tika/blob/main/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/resources/config-examples/detector-pkcs7.json[View source on GitHub] + +[IMPORTANT] +==== +List `pkcs-7-detector` *before* `default-detector`. It returns a parameterized +`application/pkcs7-mime; smime-type=...`, which is a *sibling* of the magic detector's +`application/pkcs7-signature` (neither is a specialization of the other). A `CompositeDetector` +replaces the running type only with a strict specialization, so of two sibling results it keeps +the first — the opt-in detector must run first to win. +==== + +With this configuration, `Tika.detect()` on a signed CMS message returns +`application/pkcs7-mime; smime-type=signed-data` instead of the coarse +`application/pkcs7-signature`. This is verified end-to-end in +link:https://github.com/apache/tika/blob/main/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/java/org/apache/tika/config/ConfigExamplesTest.java[`ConfigExamplesTest`]. + +NOTE: The default (magic-only) path already detects the crypto *families* — PKCS7/CMS, +RFC 5544 timestamped-data, and PKCS12 — so most users do not need this detector. Enable it only +when a routing or downstream decision depends on the CMS subtype before parsing. diff --git a/docs/modules/ROOT/pages/configuration/index.adoc b/docs/modules/ROOT/pages/configuration/index.adoc index 19bcbe165f..afd6f35fd7 100644 --- a/docs/modules/ROOT/pages/configuration/index.adoc +++ b/docs/modules/ROOT/pages/configuration/index.adoc @@ -131,6 +131,7 @@ JSON uses the backslash as an escape character, so path options (e.g. `tesseract === Other Configuration +* xref:configuration/detectors.adoc[Detectors] — Configuring content (MIME) detection, incl. the opt-in PKCS7/CMS detector * xref:configuration/digesters.adoc[Digesters] — Computing cryptographic hashes of documents * xref:configuration/encoding-detectors.adoc[Encoding Detectors] — Configuring charset/encoding detection diff --git a/tika-core/src/main/resources/org/apache/tika/mime/tika-mimetypes.xml b/tika-core/src/main/resources/org/apache/tika/mime/tika-mimetypes.xml index 34b9d27943..a992928769 100644 --- a/tika-core/src/main/resources/org/apache/tika/mime/tika-mimetypes.xml +++ b/tika-core/src/main/resources/org/apache/tika/mime/tika-mimetypes.xml @@ -893,6 +893,15 @@ <mime-type type="application/pkcs7-mime"> <glob pattern="*.p7m"/> <glob pattern="*.p7c"/> + <!-- CMS content types in the 1.2.840.113549.1.9.16.1.* arc (compressedData .9, authData .2, + authEnvelopedData .23, ...) with the final OID byte masked. timestamped-data (.31) has the + same shape but its own higher-priority magic below. The .7 arc (signed/enveloped/...) is + matched by the pkcs7-signature block. Pkcs7Parser refines all of these to the smime-type. --> + <magic priority="50"> + <match value="0x30" offset="0"> + <match value="0x060B2A864886F70D0109100100" mask="0xFFFFFFFFFFFFFFFFFFFFFFFF00" type="string" offset="2:6"/> + </match> + </magic> </mime-type> <mime-type type="application/pkcs7-signature"> @@ -926,8 +935,13 @@ <mime-type type="application/timestamped-data"> <glob pattern="*.tsd"/> - <magic priority="50"> - <match value="0x3080060B2A864886F7" type="string" offset="0"/> + <!-- CMS ContentInfo whose contentType is id-ct-timestampedData (1.2.840.113549.1.9.16.1.31), + matching the full OID across the DER SEQUENCE length forms (short + 1..4-byte long). + Higher priority than the masked pkcs7-mime .9.16.1.* magic so this exact OID wins. --> + <magic priority="60"> + <match value="0x30" offset="0"> + <match value="0x060B2A864886F70D010910011F" type="string" offset="2:6"/> + </match> </magic> </mime-type> @@ -4867,6 +4881,13 @@ <mime-type type="application/x-pkcs12"> <glob pattern="*.p12"/> <glob pattern="*.pfx"/> + <!-- PFX ::= SEQUENCE { version INTEGER (v3), authSafe ContentInfo SEQUENCE, ... }: the + INTEGER 3 then a SEQUENCE (02 01 03 30) tells it apart from CMS (OID next) and keys. --> + <magic priority="50"> + <match value="0x30" offset="0"> + <match value="0x02010330" offset="2:6"/> + </match> + </magic> </mime-type> <mime-type type="application/x-pkcs7-certificates"> <glob pattern="*.p7b"/> diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/java/org/apache/tika/config/ConfigExamplesTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/java/org/apache/tika/config/ConfigExamplesTest.java index 1429984cbf..b16a94b408 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/java/org/apache/tika/config/ConfigExamplesTest.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/java/org/apache/tika/config/ConfigExamplesTest.java @@ -16,6 +16,7 @@ */ package org.apache.tika.config; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import java.io.InputStream; @@ -27,6 +28,10 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import org.apache.tika.config.loader.TikaLoader; +import org.apache.tika.detect.Detector; +import org.apache.tika.io.TikaInputStream; +import org.apache.tika.metadata.Metadata; +import org.apache.tika.parser.ParseContext; import org.apache.tika.parser.Parser; /** @@ -94,4 +99,29 @@ public class ConfigExamplesTest { public void testFullMigrationExample() throws Exception { loadAndValidate("migration-full-example.json"); } + + /** The detectors.adoc example: enabling the opt-in pkcs-7-detector yields the CMS smime-type. */ + @Test + public void testPkcs7DetectorConfig() throws Exception { + Detector detector = loadDetectors("detector-pkcs7.json"); + assertEquals("application/pkcs7-mime; smime-type=signed-data", + detect(detector, "testPKCS7_signed_data_def.p7m")); + } + + private Detector loadDetectors(String resourceName) throws Exception { + try (InputStream is = getClass().getResourceAsStream(EXAMPLES_DIR + resourceName)) { + assertNotNull(is, "Resource not found: " + resourceName); + Path configFile = tempDir.resolve("tika-config.json"); + Files.writeString(configFile, new String(is.readAllBytes(), StandardCharsets.UTF_8), + StandardCharsets.UTF_8); + return TikaLoader.load(configFile).loadDetectors(); + } + } + + private String detect(Detector detector, String resource) throws Exception { + try (TikaInputStream tis = TikaInputStream.get( + getClass().getResourceAsStream("/test-documents/" + resource))) { + return detector.detect(tis, new Metadata(), new ParseContext()).toString(); + } + } } diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/java/org/apache/tika/mime/TestMimeTypes.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/java/org/apache/tika/mime/TestMimeTypes.java index ae731d9f30..b3e220235a 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/java/org/apache/tika/mime/TestMimeTypes.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/java/org/apache/tika/mime/TestMimeTypes.java @@ -1242,10 +1242,9 @@ public class TestMimeTypes { // Parameters only have PEM form, always need data assertTypeByData("application/x-x509-dsa-parameters", "testDSAPARAMS.pem"); assertTypeByData("application/x-x509-ec-parameters", "testECPARAMS.pem"); - // PKCS12 wrappers of Certs+Keys cannot currently be identified - // Once solved, see TIKA-3784, ought to work for name or data - //assertType("application/x-pkcs12", "testRSAKEYandCERT.p12"); - //assertTypeByData("application/x-pkcs12", "testRSAKEYandCERT.p12"); // pass=tika + // PKCS12 is now identified by content via the PFX version-3 anchor (TIKA-1997/TIKA-3784) + assertType("application/x-pkcs12", "testRSAKEYandCERT.p12"); + assertTypeByData("application/x-pkcs12", "testRSAKEYandCERT.p12"); assertTypeByData("application/x-java-keystore", "KeyStore.jks"); } diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/java/org/apache/tika/parser/crypto/Pkcs7EndToEndTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/java/org/apache/tika/parser/crypto/Pkcs7EndToEndTest.java new file mode 100644 index 0000000000..2dcdc8788a --- /dev/null +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/java/org/apache/tika/parser/crypto/Pkcs7EndToEndTest.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tika.parser.crypto; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; + +import org.junit.jupiter.api.Test; + +import org.apache.tika.TikaTest; +import org.apache.tika.metadata.Metadata; +import org.apache.tika.metadata.TikaCoreProperties; + +public class Pkcs7EndToEndTest extends TikaTest { + + /** + * TIKA-1997: a CMS-signed XML is detected as PKCS7, routed to Pkcs7Parser, refined to + * signed-data, and its inner XML payload is unwrapped and its content extracted. + */ + @Test + public void testSignedXmlIsExtracted() throws Exception { + List<Metadata> metadataList = getRecursiveMetadata("test.xml.p7m"); + // the container is refined from the coarse detected type to the CMS subtype + assertEquals("application/pkcs7-mime; smime-type=signed-data", + metadataList.get(0).get(Metadata.CONTENT_TYPE)); + // the signed XML payload is unwrapped and extracted + StringBuilder content = new StringBuilder(); + for (Metadata m : metadataList) { + String c = m.get(TikaCoreProperties.TIKA_CONTENT); + if (c != null) { + content.append(c); + } + } + assertContains("TEST_APP", content.toString()); + assertContains("ESTRAZIONE", content.toString()); + } + + /** CMS compressedData (RFC 3274) is inflated and its inner payload extracted (here a PDF). */ + @Test + public void testCompressedContentIsExtracted() throws Exception { + List<Metadata> metadataList = getRecursiveMetadata("testPKCS7_compressed_def_long.p7z"); + assertEquals("application/pkcs7-mime; smime-type=compressed-data", + metadataList.get(0).get(Metadata.CONTENT_TYPE)); + boolean pdf = metadataList.stream() + .map(m -> m.get(Metadata.CONTENT_TYPE)) + .anyMatch(ct -> ct != null && ct.startsWith("application/pdf")); + assertTrue(pdf, "expected an embedded application/pdf inflated from the compressed payload"); + } +} diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/resources/config-examples/detector-pkcs7.json b/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/resources/config-examples/detector-pkcs7.json new file mode 100644 index 0000000000..c4d7c5c9b8 --- /dev/null +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/resources/config-examples/detector-pkcs7.json @@ -0,0 +1,6 @@ +{ + "detectors": [ + { "pkcs-7-detector": {} }, + { "default-detector": {} } + ] +} diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/resources/test-documents/test.xml.p7m b/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/resources/test-documents/test.xml.p7m new file mode 100644 index 0000000000..ce21cc961f Binary files /dev/null and b/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/resources/test-documents/test.xml.p7m differ diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/resources/test-documents/testPKCS7_compressed_def_long.p7z b/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/resources/test-documents/testPKCS7_compressed_def_long.p7z new file mode 100644 index 0000000000..74474876ed Binary files /dev/null and b/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/resources/test-documents/testPKCS7_compressed_def_long.p7z differ diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/resources/test-documents/testPKCS7_signed_data_def.p7m b/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/resources/test-documents/testPKCS7_signed_data_def.p7m new file mode 100644 index 0000000000..1f0adb7499 Binary files /dev/null and b/tika-parsers/tika-parsers-standard/tika-parsers-standard-integration-tests/src/test/resources/test-documents/testPKCS7_signed_data_def.p7m differ diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/main/java/org/apache/tika/detect/crypto/Pkcs7Detector.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/main/java/org/apache/tika/detect/crypto/Pkcs7Detector.java new file mode 100644 index 0000000000..bda01baa6f --- /dev/null +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/main/java/org/apache/tika/detect/crypto/Pkcs7Detector.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tika.detect.crypto; + +import java.io.IOException; + +import org.apache.tika.annotation.TikaComponent; +import org.apache.tika.detect.Detector; +import org.apache.tika.io.TikaInputStream; +import org.apache.tika.metadata.Metadata; +import org.apache.tika.mime.MediaType; +import org.apache.tika.parser.ParseContext; +import org.apache.tika.parser.crypto.CmsClassifier; + +/** + * Optional detector that surfaces the CMS/PKCS7 {@code smime-type} at detection time, using the + * same {@link CmsClassifier} as {@code Pkcs7Parser}. Marked {@code spi = false} so it is NOT + * auto-loaded (the default detect path stays cheap — magic gives the coarse family and the parser + * refines the subtype); enable it by name in a tika-config when you need the subtype from + * {@code detect()} without parsing. + */ +@TikaComponent(spi = false) +public class Pkcs7Detector implements Detector { + + private static final long serialVersionUID = 6879398011936510897L; + + @Override + public MediaType detect(TikaInputStream tis, Metadata metadata, ParseContext parseContext) + throws IOException { + if (tis == null) { + return MediaType.OCTET_STREAM; + } + MediaType type = CmsClassifier.classify(tis); + return type != null ? type : MediaType.OCTET_STREAM; + } +} diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/main/java/org/apache/tika/parser/crypto/CmsClassifier.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/main/java/org/apache/tika/parser/crypto/CmsClassifier.java new file mode 100644 index 0000000000..2e3777ac1f --- /dev/null +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/main/java/org/apache/tika/parser/crypto/CmsClassifier.java @@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tika.parser.crypto; + +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1SequenceParser; +import org.bouncycastle.asn1.ASN1StreamParser; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.cms.CMSSignedDataParser; +import org.bouncycastle.cms.CMSTypedStream; +import org.bouncycastle.operator.DigestCalculatorProvider; +import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; + +import org.apache.tika.io.TikaInputStream; +import org.apache.tika.mime.MediaType; + +/** + * Classifies a CMS/PKCS7 stream by its {@code ContentInfo} content-type OID (and, for signedData, + * its sub-shape) into a refined Tika {@link MediaType}. Shared by {@link Pkcs7Parser} (parse-time + * labelling) and the optional detector. Reads via the spooled file and returns {@code null} if the + * stream is not recognizable CMS, so a caller can fall back to the coarse type. + */ +public final class CmsClassifier { + + // cap the first primitive read when peeking the content-type OID (an OID is a few bytes) + private static final int OID_PEEK_LIMIT = 1 << 16; + + static final MediaType PKCS7_MIME = MediaType.application("pkcs7-mime"); + static final MediaType PKCS7_SIGNATURE = MediaType.application("pkcs7-signature"); + static final MediaType SIGNED = smime("signed-data"); + static final MediaType CERTS_ONLY = smime("certs-only"); + static final MediaType ENVELOPED = smime("enveloped-data"); + static final MediaType COMPRESSED = smime("compressed-data"); + static final MediaType DIGESTED = smime("digested-data"); + static final MediaType ENCRYPTED = smime("encrypted-data"); + + private CmsClassifier() { + } + + private static MediaType smime(String smimeType) { + return new MediaType("application", "pkcs7-mime", Map.of("smime-type", smimeType)); + } + + /** @return the refined media type, or {@code null} if not recognizable CMS. */ + public static MediaType classify(TikaInputStream tis) { + if (tis == null) { + return null; + } + Path path; + try { + path = tis.getPath(); // spool to a file so we can read it more than once + } catch (Exception e) { + return null; + } + if (path == null) { + return null; + } + ASN1ObjectIdentifier oid = contentType(path); + if (oid == null) { + return null; + } + if (PKCSObjectIdentifiers.signedData.equals(oid)) { + return refineSigned(path); + } else if (PKCSObjectIdentifiers.envelopedData.equals(oid)) { + return ENVELOPED; + } else if (PKCSObjectIdentifiers.id_ct_compressedData.equals(oid)) { + return COMPRESSED; + } else if (PKCSObjectIdentifiers.digestedData.equals(oid)) { + return DIGESTED; + } else if (PKCSObjectIdentifiers.encryptedData.equals(oid)) { + return ENCRYPTED; + } + return null; // plain data or a non-CMS OID: let the coarse type stand + } + + /** Lazily read only the outer {@code SEQUENCE}'s first element (the ContentInfo OID). */ + private static ASN1ObjectIdentifier contentType(Path path) { + try (InputStream is = Files.newInputStream(path)) { + ASN1StreamParser sp = new ASN1StreamParser(is, OID_PEEK_LIMIT); + ASN1Encodable top = sp.readObject(); + if (!(top instanceof ASN1SequenceParser)) { + return null; + } + ASN1Encodable first = ((ASN1SequenceParser) top).readObject(); + if (first == null) { + return null; + } + ASN1Primitive prim = first.toASN1Primitive(); + return prim instanceof ASN1ObjectIdentifier ? (ASN1ObjectIdentifier) prim : null; + } catch (Exception e) { + return null; + } + } + + /** + * Distinguish a signedData's sub-shape via BouncyCastle's streaming parser: content present -> + * signed-data (no drain); otherwise certs + no signers -> certs-only, else a detached signature. + */ + private static MediaType refineSigned(Path path) { + try (InputStream is = Files.newInputStream(path)) { + DigestCalculatorProvider dcp = + new JcaDigestCalculatorProviderBuilder().setProvider("BC").build(); + CMSSignedDataParser parser = new CMSSignedDataParser(dcp, is); + try { + CMSTypedStream content = parser.getSignedContent(); + if (content != null) { + return SIGNED; // has an embedded payload; no need to drain it to classify + } + boolean hasSigners = !parser.getSignerInfos().getSigners().isEmpty(); + boolean hasCerts = !parser.getCertificates().getMatches(null).isEmpty(); + if (hasCerts && !hasSigners) { + return CERTS_ONLY; + } + return PKCS7_SIGNATURE; + } finally { + parser.close(); + } + } catch (Exception e) { + return PKCS7_MIME; // it is signedData but we could not refine the sub-shape + } + } +} diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/main/java/org/apache/tika/parser/crypto/Pkcs7Parser.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/main/java/org/apache/tika/parser/crypto/Pkcs7Parser.java index a7a4dd7ec9..75b7c570ec 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/main/java/org/apache/tika/parser/crypto/Pkcs7Parser.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/main/java/org/apache/tika/parser/crypto/Pkcs7Parser.java @@ -17,11 +17,15 @@ package org.apache.tika.parser.crypto; import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; import java.util.Set; +import org.bouncycastle.cms.CMSCompressedDataParser; import org.bouncycastle.cms.CMSException; import org.bouncycastle.cms.CMSSignedDataParser; import org.bouncycastle.cms.CMSTypedStream; +import org.bouncycastle.cms.jcajce.ZlibExpanderProvider; import org.bouncycastle.operator.DigestCalculatorProvider; import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; @@ -30,31 +34,35 @@ import org.xml.sax.SAXException; import org.apache.tika.annotation.TikaComponent; import org.apache.tika.exception.TikaException; +import org.apache.tika.io.BoundedInputStream; import org.apache.tika.io.TikaInputStream; import org.apache.tika.metadata.Metadata; import org.apache.tika.mime.MediaType; import org.apache.tika.parser.EmptyParser; import org.apache.tika.parser.ParseContext; import org.apache.tika.parser.Parser; +import org.apache.tika.sax.XHTMLContentHandler; /** - * Basic parser for PKCS7 data. + * Parser for PKCS7/CMS data. Refines the content type to the CMS subtype (illustrator-style: + * coarse magic routes here, this parser sets the {@code smime-type}) and extracts the embedded + * content of a signed-data message. Non-signed or detached messages are labelled but not + * extracted (their payload is absent, encrypted, or unsupported) and never throw. */ @TikaComponent public class Pkcs7Parser implements Parser { - /** - * Serial version UID - */ private static final long serialVersionUID = -7310531559075115044L; private static final MediaType PKCS7_MIME = MediaType.application("pkcs7-mime"); - private static final MediaType PKCS7_SIGNATURE = MediaType.application("pkcs7-signature"); - private static final Set<MediaType> SUPPORTED_TYPES = MediaType.set(PKCS7_MIME, PKCS7_SIGNATURE); + // cap the inflated output of a CMS compressedData so a zlib bomb (tiny compressed -> huge + // output) can't blow up the parse; content beyond this is dropped + private static final long MAX_DECOMPRESSED = 100L * 1024 * 1024; + public Set<MediaType> getSupportedTypes(ParseContext context) { return SUPPORTED_TYPES; } @@ -63,18 +71,40 @@ public class Pkcs7Parser implements Parser { ParseContext context) throws IOException, SAXException, TikaException { tis.setCloseShield(); try { + MediaType type = CmsClassifier.classify(tis); + if (type != null) { + metadata.set(Metadata.CONTENT_TYPE, type.toString()); + } + if (CmsClassifier.SIGNED.equals(type)) { + extractSignedContent(tis, handler, metadata, context); + } else if (CmsClassifier.COMPRESSED.equals(type)) { + extractCompressedContent(tis, handler, metadata, context); + } else { + // detached signature / certs-only / enveloped / encrypted / unknown: no embedded + // plaintext to extract (absent, encrypted, or unsupported) -> empty doc, no throw + XHTMLContentHandler xhtml = new XHTMLContentHandler(handler, metadata); + xhtml.startDocument(); + xhtml.endDocument(); + } + } finally { + tis.removeCloseShield(); + } + } + + private void extractSignedContent(TikaInputStream tis, ContentHandler handler, Metadata metadata, + ParseContext context) + throws IOException, SAXException, TikaException { + try (InputStream is = Files.newInputStream(tis.getPath())) { DigestCalculatorProvider digestCalculatorProvider = new JcaDigestCalculatorProviderBuilder().setProvider("BC").build(); - CMSSignedDataParser parser = new CMSSignedDataParser(digestCalculatorProvider, tis); + CMSSignedDataParser parser = new CMSSignedDataParser(digestCalculatorProvider, is); try { CMSTypedStream content = parser.getSignedContent(); - if (content == null) { - throw new TikaException( - "cannot parse detached pkcs7 signature (no signed data to parse)"); - } - try (TikaInputStream contentTis = TikaInputStream.get(content.getContentStream())) { - Parser delegate = context.get(Parser.class, EmptyParser.INSTANCE); - delegate.parse(contentTis, handler, Metadata.newInstance(context), context); + if (content != null) { + try (TikaInputStream contentTis = TikaInputStream.get(content.getContentStream())) { + Parser delegate = context.get(Parser.class, EmptyParser.INSTANCE); + delegate.parse(contentTis, handler, Metadata.newInstance(context), context); + } } } finally { parser.close(); @@ -83,8 +113,23 @@ public class Pkcs7Parser implements Parser { throw new TikaException("Unable to create DigestCalculatorProvider", e); } catch (CMSException e) { throw new TikaException("Unable to parse pkcs7 signed data", e); - } finally { - tis.removeCloseShield(); + } + } + + /** Inflate CMS compressedData (RFC 3274, zlib) and delegate-parse the inner payload. */ + private void extractCompressedContent(TikaInputStream tis, ContentHandler handler, + Metadata metadata, ParseContext context) + throws IOException, SAXException, TikaException { + try (InputStream is = Files.newInputStream(tis.getPath())) { + CMSCompressedDataParser parser = new CMSCompressedDataParser(is); + CMSTypedStream content = parser.getContent(new ZlibExpanderProvider()); + InputStream inflated = new BoundedInputStream(MAX_DECOMPRESSED, content.getContentStream()); + try (TikaInputStream contentTis = TikaInputStream.get(inflated)) { + Parser delegate = context.get(Parser.class, EmptyParser.INSTANCE); + delegate.parse(contentTis, handler, Metadata.newInstance(context), context); + } + } catch (CMSException e) { + throw new TikaException("Unable to parse pkcs7 compressed data", e); } } diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/java/org/apache/tika/detect/crypto/Pkcs7DetectorTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/java/org/apache/tika/detect/crypto/Pkcs7DetectorTest.java new file mode 100644 index 0000000000..220e73410b --- /dev/null +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/java/org/apache/tika/detect/crypto/Pkcs7DetectorTest.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tika.detect.crypto; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +import org.apache.tika.io.TikaInputStream; +import org.apache.tika.metadata.Metadata; +import org.apache.tika.mime.MediaType; +import org.apache.tika.parser.ParseContext; + +/** The opt-in detector surfaces the CMS smime-type at detect time (instantiated directly, not SPI). */ +public class Pkcs7DetectorTest { + + private final Pkcs7Detector detector = new Pkcs7Detector(); + + private MediaType detect(String resource) throws Exception { + try (TikaInputStream tis = TikaInputStream.get( + Pkcs7DetectorTest.class.getResourceAsStream("/test-documents/" + resource))) { + return detector.detect(tis, new Metadata(), new ParseContext()); + } + } + + @Test + public void testSubtypeAtDetectTime() throws Exception { + assertEquals(MediaType.parse("application/pkcs7-mime; smime-type=signed-data"), + detect("testPKCS7_signed_data_def.p7m")); + assertEquals(MediaType.parse("application/pkcs7-mime; smime-type=enveloped-data"), + detect("testPKCS7_enveloped_def.p7m")); + assertEquals(MediaType.parse("application/pkcs7-mime; smime-type=certs-only"), + detect("testPKCS7_certs_only_def.p7c")); + assertEquals(MediaType.application("pkcs7-signature"), + detect("testPKCS7_signature_def.p7s")); + } + + @Test + public void testNonCmsAndNull() throws Exception { + assertEquals(MediaType.OCTET_STREAM, detector.detect(null, new Metadata(), new ParseContext())); + try (TikaInputStream tis = TikaInputStream.get(new byte[]{0x30, 0x03, 0x02, 0x01, 0x00})) { + assertEquals(MediaType.OCTET_STREAM, detector.detect(tis, new Metadata(), new ParseContext())); + } + } +} diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/java/org/apache/tika/parser/crypto/CmsClassifierTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/java/org/apache/tika/parser/crypto/CmsClassifierTest.java new file mode 100644 index 0000000000..f50619ec67 --- /dev/null +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/java/org/apache/tika/parser/crypto/CmsClassifierTest.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tika.parser.crypto; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.cms.ContentInfo; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.junit.jupiter.api.Test; + +import org.apache.tika.io.TikaInputStream; +import org.apache.tika.mime.MediaType; + +/** + * Verifies the ContentInfo content-type OID -> smime-type mapping directly, including the + * digested/encrypted branches for which real fixtures are impractical. A minimal + * {@code ContentInfo{ contentType, content }} is enough: the classifier keys off the OID (the + * signedData sub-shape, which needs a full message, is exercised by the fixtures in + * {@link Pkcs7ParserTest}). + */ +public class CmsClassifierTest { + + private String classify(ASN1ObjectIdentifier contentType) throws Exception { + byte[] der = new ContentInfo(contentType, new DEROctetString(new byte[]{1, 2, 3})) + .getEncoded(); + try (TikaInputStream tis = TikaInputStream.get(der)) { + MediaType type = CmsClassifier.classify(tis); + return type == null ? null : type.toString(); + } + } + + @Test + public void testContentTypeMapping() throws Exception { + assertEquals("application/pkcs7-mime; smime-type=enveloped-data", + classify(PKCSObjectIdentifiers.envelopedData)); + assertEquals("application/pkcs7-mime; smime-type=digested-data", + classify(PKCSObjectIdentifiers.digestedData)); + assertEquals("application/pkcs7-mime; smime-type=encrypted-data", + classify(PKCSObjectIdentifiers.encryptedData)); + assertEquals("application/pkcs7-mime; smime-type=compressed-data", + classify(PKCSObjectIdentifiers.id_ct_compressedData)); + // plain data (and any unrecognized OID) is not a routed CMS container + assertNull(classify(PKCSObjectIdentifiers.data)); + } +} diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/java/org/apache/tika/parser/crypto/Pkcs7DetectionTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/java/org/apache/tika/parser/crypto/Pkcs7DetectionTest.java new file mode 100644 index 0000000000..36905eeb41 --- /dev/null +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/java/org/apache/tika/parser/crypto/Pkcs7DetectionTest.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tika.parser.crypto; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.InputStream; + +import org.junit.jupiter.api.Test; + +import org.apache.tika.Tika; + +/** + * Content-only (magic) detection of the ASN.1/DER crypto families. Magic is coarse — the CMS + * subtype (signed vs enveloped) is refined by {@link Pkcs7Parser}, not magic — so signed/enveloped + * both detect as pkcs7-signature here. + */ +public class Pkcs7DetectionTest { + + private final Tika tika = new Tika(); + + private String detect(String resource) throws Exception { + try (InputStream is = Pkcs7DetectionTest.class.getResourceAsStream( + "/test-documents/" + resource)) { + return tika.detect(is); + } + } + + @Test + public void testContentOnlyDetection() throws Exception { + // new/fixed magic + assertEquals("application/x-pkcs12", detect("testRSAKEYandCERT.p12")); + assertEquals("application/timestamped-data", detect("Test4.pdf.tsd")); + assertEquals("application/pkcs7-mime", detect("testPKCS7_compressed_def_long.p7z")); + assertEquals("application/pkcs7-mime", detect("testPKCS7_compressed_ind.p7z")); + // existing masked CMS magic detects signed/enveloped coarsely as pkcs7-signature by content + assertEquals("application/pkcs7-signature", detect("testPKCS7_signed_data_def.p7m")); + assertEquals("application/pkcs7-signature", detect("testPKCS7_enveloped_def.p7m")); + } +} diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/java/org/apache/tika/parser/crypto/Pkcs7ParserTest.java b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/java/org/apache/tika/parser/crypto/Pkcs7ParserTest.java index dbd2c7f167..36dffdc80e 100644 --- a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/java/org/apache/tika/parser/crypto/Pkcs7ParserTest.java +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/java/org/apache/tika/parser/crypto/Pkcs7ParserTest.java @@ -16,28 +16,54 @@ */ package org.apache.tika.parser.crypto; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; -import org.xml.sax.ContentHandler; +import org.junit.jupiter.api.Test; +import org.xml.sax.helpers.DefaultHandler; -import org.apache.tika.TikaTest; -import org.apache.tika.exception.TikaException; import org.apache.tika.io.TikaInputStream; import org.apache.tika.metadata.Metadata; import org.apache.tika.parser.ParseContext; -import org.apache.tika.sax.BodyContentHandler; -public class Pkcs7ParserTest extends TikaTest { - public void testDetachedSignature() throws Exception { - try (TikaInputStream tis = getResourceAsStream("/test-documents/testDetached.p7s")) { - ContentHandler handler = new BodyContentHandler(); - Metadata metadata = new Metadata(); - new Pkcs7Parser().parse(tis, handler, metadata, new ParseContext()); - } catch (NullPointerException npe) { - fail("should not get NPE"); - } catch (TikaException te) { - assertTrue(te.toString().contains("cannot parse detached pkcs7 signature")); +public class Pkcs7ParserTest { + + /** Parse a fixture and return the content type the parser refined it to. */ + private String parsedType(String resource) throws Exception { + Metadata metadata = new Metadata(); + try (TikaInputStream tis = TikaInputStream.get( + Pkcs7ParserTest.class.getResourceAsStream("/test-documents/" + resource))) { + new Pkcs7Parser().parse(tis, new DefaultHandler(), metadata, new ParseContext()); } + return metadata.get(Metadata.CONTENT_TYPE); + } + + @Test + public void testSubtypeRefinement() throws Exception { + assertEquals("application/pkcs7-mime; smime-type=signed-data", + parsedType("testPKCS7_signed_data_def.p7m")); + assertEquals("application/pkcs7-mime; smime-type=signed-data", + parsedType("testPKCS7_signed_data_ind.p7m")); + assertEquals("application/pkcs7-mime; smime-type=signed-data", + parsedType("test.xml.p7m")); + assertEquals("application/pkcs7-mime; smime-type=enveloped-data", + parsedType("testPKCS7_enveloped_def.p7m")); + assertEquals("application/pkcs7-mime; smime-type=enveloped-data", + parsedType("testPKCS7_enveloped_ind.p7m")); + assertEquals("application/pkcs7-mime; smime-type=certs-only", + parsedType("testPKCS7_certs_only_def.p7c")); + assertEquals("application/pkcs7-mime; smime-type=certs-only", + parsedType("testPKCS7_certs_only_ind.p7c")); + assertEquals("application/pkcs7-mime; smime-type=compressed-data", + parsedType("testPKCS7_compressed_def_long.p7z")); + assertEquals("application/pkcs7-mime; smime-type=compressed-data", + parsedType("testPKCS7_compressed_ind.p7z")); + } + + /** Detached signatures are labelled pkcs7-signature and no longer throw. */ + @Test + public void testDetachedSignatures() throws Exception { + assertEquals("application/pkcs7-signature", parsedType("testPKCS7_signature_def.p7s")); + assertEquals("application/pkcs7-signature", parsedType("testPKCS7_signature_ind.p7s")); + assertEquals("application/pkcs7-signature", parsedType("testDetached.p7s")); } } diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/test.xml.p7m b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/test.xml.p7m new file mode 100644 index 0000000000..ce21cc961f Binary files /dev/null and b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/test.xml.p7m differ diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_certs_only_def.p7c b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_certs_only_def.p7c new file mode 100644 index 0000000000..5f25350c48 Binary files /dev/null and b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_certs_only_def.p7c differ diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_certs_only_ind.p7c b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_certs_only_ind.p7c new file mode 100644 index 0000000000..c0bc161e84 Binary files /dev/null and b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_certs_only_ind.p7c differ diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_compressed_def_long.p7z b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_compressed_def_long.p7z new file mode 100644 index 0000000000..74474876ed Binary files /dev/null and b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_compressed_def_long.p7z differ diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_compressed_def_short.p7z b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_compressed_def_short.p7z new file mode 100644 index 0000000000..da9fbfaf1b Binary files /dev/null and b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_compressed_def_short.p7z differ diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_compressed_ind.p7z b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_compressed_ind.p7z new file mode 100644 index 0000000000..6ec9716b65 Binary files /dev/null and b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_compressed_ind.p7z differ diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_enveloped_def.p7m b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_enveloped_def.p7m new file mode 100644 index 0000000000..dad330064d Binary files /dev/null and b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_enveloped_def.p7m differ diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_enveloped_ind.p7m b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_enveloped_ind.p7m new file mode 100644 index 0000000000..eb182562c8 Binary files /dev/null and b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_enveloped_ind.p7m differ diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_signature_def.p7s b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_signature_def.p7s new file mode 100644 index 0000000000..b90e41ea17 Binary files /dev/null and b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_signature_def.p7s differ diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_signature_ind.p7s b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_signature_ind.p7s new file mode 100644 index 0000000000..dd9400a9b4 Binary files /dev/null and b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_signature_ind.p7s differ diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_signed_data_def.p7m b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_signed_data_def.p7m new file mode 100644 index 0000000000..1f0adb7499 Binary files /dev/null and b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_signed_data_def.p7m differ diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_signed_data_def.pem b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_signed_data_def.pem new file mode 100644 index 0000000000..34ef17fd53 --- /dev/null +++ b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_signed_data_def.pem @@ -0,0 +1,35 @@ +-----BEGIN PKCS7----- +MIIGIgYJKoZIhvcNAQcCoIIGEzCCBg8CAQExDTALBglghkgBZQMEAgEwEwYJKoZI +hvcNAQcBoAYEBHRleHSgggPDMIIDvzCCAyigAwIBAgICAKEwDQYJKoZIhvcNAQEF +BQAwcjELMAkGA1UEBhMCRVMxDzANBgNVBAgTBk1hZHJpZDEPMA0GA1UEBxMGTWFk +cmlkMQ4wDAYDVQQKEwVNSVR5QzEbMBkGA1UECxMSTUlUeUMgRE5JZSBQcnVlYmFz +MRQwEgYDVQQDEwtDQSB1c3VhcmlvczAeFw0xMDA0MDgxMjM4MjJaFw0yMDA0MDUx +MjM4MjJaMHwxCzAJBgNVBAYTAkVTMQ8wDQYDVQQIEwZNYWRyaWQxDzANBgNVBAcT +Bk1hZHJpZDEOMAwGA1UEChMFTUlUeUMxGzAZBgNVBAsTEk1JVHlDIEROSWUgUHJ1 +ZWJhczEeMBwGA1UEAxMVVXN1YXJpbyBkZSBwcnVlYmFzIDYxMIGfMA0GCSqGSIb3 +DQEBAQUAA4GNADCBiQKBgQC2ehoLcO6lXWmKzJfdz2m+vRZmGeDo5OF+Q8MNdVtL +8AKbMykP6G9JOzBT3WLhzQKszMg43DQjViN6mTQsPLYCfe/n6LmTWZkRvsIzrffM +aL7goy47VCX1CeUQ80cuUAHJpRq7UMObNvgV/8rn+zPfYmErqZVhAckleP4/RgeC +9QIDAQABo4IBWDCCAVQwCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwHQYDVR0OBBYE +FNhww+tqmd7gvdedMv0Gk1mEolYdMIGYBgNVHSMEgZAwgY2AFPWhaqh3T1uxBIyn +fkjxDp/Fdo8boXKkcDBuMQ8wDQYDVQQIEwZNYWRyaWQxDzANBgNVBAcTBk1hZHJp +ZDEOMAwGA1UEChMFTUlUeUMxGzAZBgNVBAsTEk1JVHlDIEROSWUgUHJ1ZWJhczEQ +MA4GA1UEAxMHUm9vdCBDQTELMAkGA1UEBhMCRVOCAQMwCQYDVR0RBAIwADA2BgNV +HRIELzAthitodHRwOi8vbWluaXN0ZXItOGpneHk5Lm1pdHljLmFnZS9QS0kvQ0Eu +Y3J0MD0GA1UdHwQ2MDQwMqAwoC6GLGh0dHA6Ly9taW5pc3Rlci04amd4eTkubWl0 +eWMuYWdlL1BLSS9jcmwuY3JsMA0GCSqGSIb3DQEBBQUAA4GBADn3vfsgfhyreHhn +4VCG4WuG+g5qTRKpu72ZScMbyY+e3d2m6fOSMkoEC+NwaXgl4Y/vKlXGKgdhYjLD +WjobRDVQOQRQ4Q/Wv/aPPno1CjBkYdY5rnCM/oiy8QXNjdboXRiE40kCyqj7jiop +B20uO2a0yacC5ooWQz1pqZEhSWRDMYICHTCCAhkCAQEweDByMQswCQYDVQQGEwJF +UzEPMA0GA1UECBMGTWFkcmlkMQ8wDQYDVQQHEwZNYWRyaWQxDjAMBgNVBAoTBU1J +VHlDMRswGQYDVQQLExJNSVR5QyBETkllIFBydWViYXMxFDASBgNVBAMTC0NBIHVz +dWFyaW9zAgIAoTALBglghkgBZQMEAgGggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3 +DQEHATAcBgkqhkiG9w0BCQUxDxcNMTkwMTI0MTM0MjI1WjAvBgkqhkiG9w0BCQQx +IgQgmC2ePrmW9VnmM/TRlN7zdh2Qn1o7ZH0ahR/q1nwyydEwgY4GCSqGSIb3DQEJ +DzGBgDB+MAsGCWCGSAFlAwQBKjAIBgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFl +AwQBFjALBglghkgBZQMEAQIwCgYIKoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0G +CCqGSIb3DQMCAgFAMAcGBSsOAwIHMA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEB +AQUABIGAFR6+Q41Ak8HXUNnbkEQDWN3JBacSYi5mAPtHyJNHGLewKTwxOrf/nGhk +Qq5zqvMLhci0NBU3wvW+lAKX3ytavfkRkRFlTruuH151Stkr2TRW6h132ggA2AAJ +3gGxGqN2bYAYB6O8QY4NhmJdSi+j4bK0ayo15HhpagRfp2181lU= +-----END PKCS7----- diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_signed_data_ind.p7m b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_signed_data_ind.p7m new file mode 100644 index 0000000000..cf54083951 Binary files /dev/null and b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testPKCS7_signed_data_ind.p7m differ diff --git a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testRSAKEYandCERT.p12 b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testRSAKEYandCERT.p12 new file mode 100644 index 0000000000..1c536e8fbe Binary files /dev/null and b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-crypto-module/src/test/resources/test-documents/testRSAKEYandCERT.p12 differ
