diff --git a/pom.xml b/pom.xml
index 5076a9f4..7fa8c9cb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -242,6 +242,11 @@
jackson-databind
2.17.0
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-yaml
+ 2.17.0
+
org.jacoco
jacoco-maven-plugin
diff --git a/src/main/java/com/siemens/pki/cmpracomponent/util/FileTracer.java b/src/main/java/com/siemens/pki/cmpracomponent/util/FileTracer.java
index 68d593f3..83f018ed 100644
--- a/src/main/java/com/siemens/pki/cmpracomponent/util/FileTracer.java
+++ b/src/main/java/com/siemens/pki/cmpracomponent/util/FileTracer.java
@@ -59,23 +59,41 @@ public class FileTracer {
private static boolean enableAsn1Dump;
+ private static boolean enableJsonDump;
+
+ private static boolean enableYamlDump;
+
static {
final String dumpDirName = System.getProperty("dumpdir");
- if (dumpDirName != null) {
- msgDumpDirectory = new File(dumpDirName);
- if (!msgDumpDirectory.isDirectory() || !msgDumpDirectory.canWrite()) {
- LOGGER.error(msgDumpDirectory + " is not writable, disable dump");
- msgDumpDirectory = null;
- } else {
- LOGGER.info("dump transactions below " + msgDumpDirectory);
- }
- }
- // "pem+txt+der+asn1"
- final String dumpFormat = System.getProperty("dumpformat", "txt").toLowerCase();
+ // "pem+txt+der+asn1+json+yaml"
+ final String dumpFormat = System.getProperty("dumpformat", "yaml").toLowerCase();
+ init(dumpDirName, dumpFormat);
+ }
+
+ /**
+ *
+ * @param dumpDirName directory to dump to
+ * @param dumpFormat dump format to use, one or more of
+ * "pem,txt,der,asn1,json,yaml" concatinated in one string
+ */
+ public static void init(final String dumpDirName, final String dumpFormat) {
enablePemDump = dumpFormat.contains("pem");
enableTxtDump = dumpFormat.contains("txt");
enableDerDump = dumpFormat.contains("der");
enableAsn1Dump = dumpFormat.contains("asn");
+ enableJsonDump = dumpFormat.contains("json");
+ enableYamlDump = dumpFormat.contains("yaml");
+
+ if (dumpDirName == null) {
+ return;
+ }
+ msgDumpDirectory = new File(dumpDirName);
+ if (!msgDumpDirectory.isDirectory() || !msgDumpDirectory.canWrite()) {
+ LOGGER.error(msgDumpDirectory + " is not writable, disable dump");
+ msgDumpDirectory = null;
+ } else {
+ LOGGER.info("dump transactions below " + msgDumpDirectory);
+ }
}
private static final AtomicLong messagecounter = new AtomicLong(0);
@@ -85,38 +103,34 @@ public class FileTracer {
*
* @param msg message to dump
* @param interfaceName file name prefix to use
+ * @return directory where the log goes in
*/
- public static void logMessage(final PKIMessage msg, final String interfaceName) {
- if (msgDumpDirectory == null
- || msg == null
- || !enablePemDump && !enableTxtDump && !enableDerDump && !enableAsn1Dump) {
- return;
+ public static File logMessage(final PKIMessage msg, final String interfaceName) {
+ if (msgDumpDirectory == null || msg == null) {
+ return null;
+ }
+ if (!isPemOrDerOutEnabled() && !isTxtOutEnabled() && !enableJsonDump && !enableYamlDump) {
+ return null;
}
try {
- final String tidAsString = defaultIfNull(
- ifNotNull(
- msg.getHeader().getTransactionID(),
- tid -> B64_ENCODER_WITHOUT_PADDING.encodeToString(tid.getOctets())),
- "null");
- final String subDirName = "trans_" + tidAsString;
- final File subDir = new File(msgDumpDirectory, subDirName);
- if (!subDir.isDirectory()) {
- subDir.mkdirs();
- }
+ final File subDir = getCreateTransactionDirectory(msg);
final String fileprefix = String.format(
"%03d_%s_%s", messagecounter.incrementAndGet(), interfaceName, MessageDumper.msgTypeAsString(msg));
- final byte[] encodedMessage = enableDerDump || enablePemDump ? msg.getEncoded(ASN1Encoding.DER) : null;
- if (enableDerDump) {
- try (final FileOutputStream binOut = new FileOutputStream(new File(subDir, fileprefix + ".PKI"))) {
- binOut.write(encodedMessage);
+ if (isPemOrDerOutEnabled()) {
+ final byte[] encodedMessage = msg.getEncoded(ASN1Encoding.DER);
+ if (enableDerDump) {
+ try (final FileOutputStream binOut = new FileOutputStream(new File(subDir, fileprefix + ".PKI"))) {
+ binOut.write(encodedMessage);
+ }
}
- }
- if (enablePemDump) {
- try (final PemWriter pemOut = new PemWriter(new FileWriter(new File(subDir, fileprefix + ".pem")))) {
- pemOut.writeObject(new PemObject("PKIXCMP", encodedMessage));
+ if (enablePemDump) {
+ try (final PemWriter pemOut =
+ new PemWriter(new FileWriter(new File(subDir, fileprefix + ".pem")))) {
+ pemOut.writeObject(new PemObject("PKIXCMP", encodedMessage));
+ }
}
}
- if (enableAsn1Dump || enableTxtDump) {
+ if (isTxtOutEnabled()) {
try (final FileWriter txtOut = new FileWriter(new File(subDir, fileprefix + ".txt"))) {
if (enableTxtDump) {
txtOut.write(MessageDumper.dumpPkiMessage(msg));
@@ -126,11 +140,43 @@ public static void logMessage(final PKIMessage msg, final String interfaceName)
}
}
}
+ if (enableJsonDump) {
+ try (final FileWriter txtOut = new FileWriter(new File(subDir, fileprefix + ".json"))) {
+ txtOut.write(JsonYamlMessageDumper.dumpPkiMessageAsJson(msg));
+ }
+ }
+ if (enableYamlDump) {
+ try (final FileWriter txtOut = new FileWriter(new File(subDir, fileprefix + ".yaml"))) {
+ txtOut.write(JsonYamlMessageDumper.dumpPkiMessageAsYaml(msg));
+ }
+ }
+ return subDir;
} catch (final Exception e) {
LOGGER.error("error writing dump", e);
+ return null;
}
}
+ private static File getCreateTransactionDirectory(final PKIMessage msg) {
+ final String transactionId = ifNotNull(
+ msg.getHeader().getTransactionID(), tid -> B64_ENCODER_WITHOUT_PADDING.encodeToString(tid.getOctets()));
+ final String tidAsString = defaultIfNull(transactionId, "null");
+ final String subDirName = "trans_" + tidAsString;
+ final File subDir = new File(msgDumpDirectory, subDirName);
+ if (!subDir.isDirectory()) {
+ subDir.mkdirs();
+ }
+ return subDir;
+ }
+
+ private static boolean isTxtOutEnabled() {
+ return enableAsn1Dump || enableTxtDump;
+ }
+
+ private static boolean isPemOrDerOutEnabled() {
+ return enableDerDump || enablePemDump;
+ }
+
// utility class
private FileTracer() {}
}
diff --git a/src/main/java/com/siemens/pki/cmpracomponent/util/JsonYamlMessageDumper.java b/src/main/java/com/siemens/pki/cmpracomponent/util/JsonYamlMessageDumper.java
new file mode 100644
index 00000000..547b5fd4
--- /dev/null
+++ b/src/main/java/com/siemens/pki/cmpracomponent/util/JsonYamlMessageDumper.java
@@ -0,0 +1,430 @@
+/*
+ * Copyright (c) 2024 Siemens AG
+ *
+ * Licensed 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package com.siemens.pki.cmpracomponent.util;
+
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.Version;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.MapperFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.cfg.MapperBuilder;
+import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
+import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
+import com.fasterxml.jackson.databind.json.JsonMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import org.bouncycastle.asn1.ASN1Enumerated;
+import org.bouncycastle.asn1.ASN1GeneralizedTime;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.cmp.PKIBody;
+import org.bouncycastle.asn1.cmp.PKIFreeText;
+import org.bouncycastle.asn1.cmp.PKIMessage;
+import org.bouncycastle.asn1.cmp.PKIStatusInfo;
+import org.bouncycastle.asn1.cmp.PollRepContent;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.Extensions;
+import org.bouncycastle.asn1.x509.GeneralName;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+
+/**
+ * A utility class providing functions for dumping messages in JSON/YAML format.
+ */
+public class JsonYamlMessageDumper {
+
+ private static ObjectMapper jsonMapper;
+
+ private static ObjectMapper yamlMapper;
+
+ /**
+ * Serializer for {@link ByteArrayInputStream}
+ */
+ public static class ByteArrayInputStreamSerializer extends JsonSerializer {
+ /**
+ */
+ @Override
+ public Class handledType() {
+ return ByteArrayInputStream.class;
+ }
+
+ @Override
+ public void serialize(
+ final ByteArrayInputStream value, final JsonGenerator jsonGenerator, final SerializerProvider provider)
+ throws IOException {
+ if (value == null) {
+ jsonGenerator.writeNull();
+ return;
+ }
+ if ("encoded".equals(jsonGenerator.getOutputContext().getCurrentName())) {
+ jsonGenerator.writeNull();
+ } else {
+ jsonGenerator.writeBinary(value.readAllBytes());
+ }
+ }
+ }
+
+ /**
+ * Serializer for {@link ByteArrayInputStream}
+ */
+ public static class PKIBodySerializer extends JsonSerializer {
+
+ @Override
+ public Class handledType() {
+ return PKIBody.class;
+ }
+
+ @Override
+ public void serialize(final PKIBody value, final JsonGenerator jsonGenerator, final SerializerProvider provider)
+ throws IOException {
+ if (value == null) {
+ jsonGenerator.writeNull();
+ return;
+ }
+ jsonGenerator.writeStartObject();
+ jsonGenerator.writeStringField("type", MessageDumper.msgTypeAsString(value));
+ jsonGenerator.writeStringField(
+ "ContentClass", value.getContent().getClass().getSimpleName());
+ jsonGenerator.writePOJOField("content", value.getContent());
+ jsonGenerator.writeEndObject();
+ }
+ }
+
+ /**
+ * Serializer for {@link PollRepContent}
+ */
+ public static class PollRepContentSeralizer extends JsonSerializer {
+
+ @Override
+ public Class handledType() {
+ return PollRepContent.class;
+ }
+
+ class PollRepContentWrapper {
+ public PollRepContentWrapper(PollRepContent wrapped) {
+ this.wrapped = wrapped;
+ }
+
+ private final PollRepContent wrapped;
+
+ public Entry[] getEntries() {
+ int size = wrapped.size();
+ Entry[] ret = new Entry[size];
+ for (int i = 0; i < size; i++) {
+ ret[i] = new Entry(i);
+ }
+ return ret;
+ }
+
+ class Entry {
+ private final int index;
+
+ public Entry(int index) {
+ super();
+ this.index = index;
+ }
+
+ public ASN1Integer getCertReqId() {
+ return wrapped.getCertReqId(index);
+ }
+
+ public ASN1Integer getCheckAfter() {
+ return wrapped.getCheckAfter(index);
+ }
+
+ public PKIFreeText getReason() {
+ return wrapped.getReason(index);
+ }
+ }
+ }
+
+ @Override
+ public void serialize(
+ final PollRepContent value, final JsonGenerator jsonGenerator, final SerializerProvider provider)
+ throws IOException {
+ if (value == null) {
+ jsonGenerator.writeNull();
+ return;
+ }
+ jsonGenerator.writePOJO(new PollRepContentWrapper(value).getEntries());
+ }
+ }
+
+ /**
+ * Serializer for {@link Extensions}
+ */
+ public static class ExtensionsSeralizer extends JsonSerializer {
+
+ @Override
+ public Class handledType() {
+ return Extensions.class;
+ }
+
+ class ExtensionsWrapper {
+ public ExtensionsWrapper(Extensions wrapped) {
+ this.wrapped = wrapped;
+ }
+
+ private final Extensions wrapped;
+
+ public List getEntries() {
+ return Arrays.stream(wrapped.getExtensionOIDs())
+ .map(wrapped::getExtension)
+ .collect(Collectors.toList());
+ }
+ }
+
+ @Override
+ public void serialize(
+ final Extensions value, final JsonGenerator jsonGenerator, final SerializerProvider provider)
+ throws IOException {
+ if (value == null) {
+ jsonGenerator.writeNull();
+ return;
+ }
+ jsonGenerator.writePOJO(new ExtensionsWrapper(value).getEntries());
+ }
+ }
+
+ public static class ArraySerializer extends JsonSerializer {
+
+ private final Class handledType;
+
+ private final BiFunction getArray;
+
+ private Function sizeSupplier;
+
+ public ArraySerializer(Class handledType, Function size, BiFunction getArray) {
+ this.handledType = handledType;
+ this.getArray = getArray;
+ this.sizeSupplier = size;
+ }
+
+ @Override
+ public Class handledType() {
+ return handledType;
+ }
+
+ @Override
+ public void serialize(final T value, final JsonGenerator jsonGenerator, final SerializerProvider provider)
+ throws IOException {
+
+ int size = sizeSupplier.apply(value);
+ if (size < 1 || value == null) {
+ jsonGenerator.writeNull();
+ return;
+ }
+ jsonGenerator.writeStartArray();
+ for (int i = 0; i < size; i++) {
+ jsonGenerator.writeObject(getArray.apply(i, value));
+ }
+ jsonGenerator.writeEndArray();
+ }
+ }
+
+ /**
+ * generic toString Serializer
+ */
+ public static class GenericSerializer extends JsonSerializer {
+
+ private final Class handledType;
+
+ private final Function mapToString;
+
+ public GenericSerializer(Class handledType) {
+ this.handledType = handledType;
+ mapToString = T::toString;
+ }
+
+ public GenericSerializer(Class handledType, Function mapToString) {
+ super();
+ this.handledType = handledType;
+ this.mapToString = mapToString;
+ }
+
+ @Override
+ public Class handledType() {
+ return handledType;
+ }
+
+ @Override
+ public void serialize(final T value, final JsonGenerator jsonGenerator, final SerializerProvider provider)
+ throws IOException {
+ if (value == null) {
+ jsonGenerator.writeNull();
+ return;
+ }
+ jsonGenerator.writeString(mapToString.apply(value));
+ }
+ }
+
+ /**
+ * Serializer for {@link SubjectPublicKeyInfoSerializer}
+ */
+ public static class SubjectPublicKeyInfoSerializer extends JsonSerializer {
+
+ @Override
+ public Class handledType() {
+ return SubjectPublicKeyInfo.class;
+ }
+
+ @Override
+ public void serialize(
+ final SubjectPublicKeyInfo value, final JsonGenerator jsonGenerator, final SerializerProvider provider)
+ throws IOException {
+ if (value == null) {
+ jsonGenerator.writeNull();
+ return;
+ }
+ jsonGenerator.writeStartObject();
+ jsonGenerator.writeStringField(
+ "Algorithm",
+ MessageDumper.getOidDescriptionForOid(value.getAlgorithm().getAlgorithm())
+ .toString());
+ try {
+ ASN1Primitive parsedKey = value.parsePublicKey();
+ jsonGenerator.writePOJOField("ParsedKey", parsedKey);
+ } catch (IOException ex) {
+ jsonGenerator.writePOJOField("UnparsedKeyData", value.getPublicKeyData());
+ }
+ jsonGenerator.writeEndObject();
+ }
+ }
+
+ /**
+ * Dump PKI message in JSON format.
+ *
+ * @param msg PKI message to be dumped
+ * @return JSON representation of the PKI message
+ */
+ public static final String dumpPkiMessageAsJson(final PKIMessage msg) {
+ if (msg == null) {
+ return "";
+ }
+ try {
+ return getJsonMapper().writeValueAsString(msg);
+ } catch (JsonProcessingException e) {
+ return e.getLocalizedMessage();
+ }
+ }
+
+ /**
+ * Dump PKI message in YAML format.
+ *
+ * @param msg PKI message to be dumped
+ * @return YAML representation of the PKI message
+ */
+ public static final String dumpPkiMessageAsYaml(final PKIMessage msg) {
+ if (msg == null) {
+ return "";
+ }
+ try {
+ return getYamlMapper().writeValueAsString(msg);
+ } catch (JsonProcessingException e) {
+ return e.getLocalizedMessage();
+ }
+ }
+
+ private static ObjectMapper initMapper(MapperBuilder, ?> builder) {
+ ObjectMapper mapper = builder.enable(MapperFeature.AUTO_DETECT_IS_GETTERS)
+ .enable(SerializationFeature.INDENT_OUTPUT)
+ .configure(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL, true)
+ .configure(SerializationFeature.FAIL_ON_SELF_REFERENCES, false)
+ .configure(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS, true)
+ .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
+ .serializationInclusion(Include.NON_NULL)
+ .annotationIntrospector(new JacksonAnnotationIntrospector() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public boolean hasIgnoreMarker(AnnotatedMember m) {
+ return m.getDeclaringClass() == ASN1Object.class || super.hasIgnoreMarker(m);
+ }
+
+ @Override
+ public String findImplicitPropertyName(AnnotatedMember m) {
+ String methodName = m.getName();
+ if (methodName != null && methodName.startsWith("to") && methodName.endsWith("Array")) {
+ return methodName.substring(2, methodName.length() - 5);
+ }
+ return super.findImplicitPropertyName(m);
+ }
+ })
+ .build();
+ final SimpleModule simpleModule = new SimpleModule("Dump", new Version(1, 0, 0, null, null, null));
+ simpleModule.addSerializer(new ByteArrayInputStreamSerializer());
+ simpleModule.addSerializer(new PKIBodySerializer());
+ simpleModule.addSerializer(new SubjectPublicKeyInfoSerializer());
+ simpleModule.addSerializer(new GenericSerializer<>(ASN1Primitive.class));
+ simpleModule.addSerializer(new GenericSerializer<>(GeneralName.class));
+ simpleModule.addSerializer(new GenericSerializer<>(Number.class));
+ simpleModule.addSerializer(new GenericSerializer<>(CharSequence.class));
+ simpleModule.addSerializer(new GenericSerializer<>(X500Name.class));
+ simpleModule.addSerializer(new GenericSerializer<>(Date.class));
+ simpleModule.addSerializer(new GenericSerializer<>(PKIStatusInfo.class, MessageDumper::pkiStatus2String));
+ simpleModule.addSerializer(new GenericSerializer<>(ASN1GeneralizedTime.class, a -> {
+ try {
+ return a.getDate().toString();
+ } catch (ParseException e) {
+ return e.getLocalizedMessage();
+ }
+ }));
+ simpleModule.addSerializer(
+ new GenericSerializer<>(ASN1ObjectIdentifier.class, a -> MessageDumper.getOidDescriptionForOid(a)
+ .toString()));
+ simpleModule.addSerializer(
+ new GenericSerializer<>(ASN1Enumerated.class, a -> a.getValue().toString()));
+ simpleModule.addSerializer(new ArraySerializer<>(
+ PKIFreeText.class, p -> p.size(), (i, p) -> p.getStringAtUTF8(i).toString()));
+ simpleModule.addSerializer(new PollRepContentSeralizer());
+ simpleModule.addSerializer(new ExtensionsSeralizer());
+ mapper.registerModule(simpleModule);
+ return mapper;
+ }
+
+ private static ObjectMapper getJsonMapper() {
+ if (jsonMapper == null) {
+ jsonMapper = initMapper(JsonMapper.builder());
+ }
+ return jsonMapper;
+ }
+
+ private static ObjectMapper getYamlMapper() {
+ if (yamlMapper == null) {
+ yamlMapper = initMapper(YAMLMapper.builder());
+ }
+ return yamlMapper;
+ }
+
+ private JsonYamlMessageDumper() {}
+}
diff --git a/src/test/java/com/siemens/pki/cmpclientcomponent/test/TestRrWithPolling.java b/src/test/java/com/siemens/pki/cmpclientcomponent/test/TestRrWithPolling.java
index ecd3ab19..8cd64177 100644
--- a/src/test/java/com/siemens/pki/cmpclientcomponent/test/TestRrWithPolling.java
+++ b/src/test/java/com/siemens/pki/cmpclientcomponent/test/TestRrWithPolling.java
@@ -32,7 +32,9 @@
import com.siemens.pki.cmpracomponent.configuration.VerificationContext;
import com.siemens.pki.cmpracomponent.test.framework.ConfigurationFactory;
import com.siemens.pki.cmpracomponent.test.framework.SignatureValidationCredentials;
+import com.siemens.pki.cmpracomponent.util.FileTracer;
import java.math.BigInteger;
+import java.nio.file.Files;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
@@ -49,6 +51,12 @@ public void setUp() throws Exception {
launchDelayedCmpCaAndRa(ConfigurationFactory.buildSignatureBasedDownstreamConfiguration());
}
+ @Test
+ public void testRrWithPollingAndDump() throws Exception {
+ FileTracer.init(Files.createTempDirectory("dump").toFile().getAbsolutePath(), "pem,txt,der,asn1,json,yaml");
+ testRrWithPolling();
+ }
+
/**
* Revoking a certificate/Handling Delayed Delivery
*
diff --git a/src/test/java/com/siemens/pki/cmpracomponent/test/TestFileTracer.java b/src/test/java/com/siemens/pki/cmpracomponent/test/TestFileTracer.java
new file mode 100644
index 00000000..172070ab
--- /dev/null
+++ b/src/test/java/com/siemens/pki/cmpracomponent/test/TestFileTracer.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2024 Siemens AG
+ *
+ * Licensed 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package com.siemens.pki.cmpracomponent.test;
+
+import static org.junit.Assert.assertTrue;
+
+import com.siemens.pki.cmpracomponent.msggeneration.PkiMessageGenerator;
+import com.siemens.pki.cmpracomponent.test.framework.HeaderProviderForTest;
+import com.siemens.pki.cmpracomponent.util.FileTracer;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Function;
+import org.bouncycastle.asn1.cmp.PKIMessage;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * test the {@link FileTracer}
+ */
+@RunWith(Parameterized.class)
+public class TestFileTracer {
+
+ @Parameters(name = "{index}: dumpDirName=>{0}, dumpFormat=>{1}")
+ public static List