Add some code to either transform everything or skip signed jars
diff --git a/tomee-patch-core/pom.xml b/tomee-patch-core/pom.xml
index 0045487..e8f7082 100644
--- a/tomee-patch-core/pom.xml
+++ b/tomee-patch-core/pom.xml
@@ -92,6 +92,12 @@
       <version>4.10</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.bouncycastle</groupId>
+      <artifactId>bcprov-jdk15on</artifactId>
+      <version>1.69</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 </project>
 
diff --git a/tomee-patch-core/src/main/java/org/apache/tomee/patch/core/Jars.java b/tomee-patch-core/src/main/java/org/apache/tomee/patch/core/Jars.java
new file mode 100644
index 0000000..73f31c9
--- /dev/null
+++ b/tomee-patch-core/src/main/java/org/apache/tomee/patch/core/Jars.java
@@ -0,0 +1,120 @@
+/*
+ * 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.tomee.patch.core;
+
+import org.tomitribe.util.IO;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipInputStream;
+
+public class Jars {
+
+    public static boolean isSigned(final File jarFile) throws IOException {
+        // first approach is to look for signature files
+        if (!listJarContent(jarFile, "^META-INF/[^.]+.(SF|DSA|RSA)$").isEmpty()) {
+            return true;
+        }
+
+        // parse the digest and see if we can find entries with a Digest suffix
+        if (hasDigest(jarFileContent(jarFile, "META-INF/MANIFEST.MF"))) {
+            return true;
+        }
+
+        // we can also look for Digest entries in the manifest as a String if we can't parse it
+        return IO.slurp(jarFileContent(jarFile, "META-INF/MANIFEST.MF")).contains("-Digest");
+    }
+
+    public static List<String> listJarContent(final File jarFile) throws IOException {
+        return listJarContent(jarFile, null);
+    }
+
+    public static List<String> listJarContent(final ZipInputStream zipInputStream) throws IOException {
+        return listJarContent(zipInputStream, null);
+    }
+
+    public static List<String> listJarContent(final File jarFile, final String matchPattern) throws IOException {
+        return new ZipFile(jarFile).stream()
+                                   .filter(zipEntry -> matchPattern == null || zipEntry.getName().matches(matchPattern))
+                                   .filter(Objects::nonNull)
+                                   .map(ZipEntry::getName)
+                                   .collect(Collectors.toList());
+    }
+
+    public static List<String> listJarContent(final ZipInputStream zipInputStream, final String matchPattern) throws IOException {
+        final List<String> result = new ArrayList<>();
+        ZipEntry entry;
+        while ((entry = zipInputStream.getNextEntry()) != null) {
+            final String name = entry.getName();
+            if (matchPattern != null && !name.matches(matchPattern)) {
+                continue;
+            }
+            result.add(name);
+        }
+        return result;
+    }
+
+    public static InputStream jarFileContent(final ZipInputStream zipInputStream, final String name) throws IOException {
+        ZipEntry entry;
+        while ((entry = zipInputStream.getNextEntry()) != null) {
+            final String entryName = entry.getName();
+            if (entryName.contains(name)) {
+                return zipInputStream;
+            }
+
+        }
+        return null;
+    }
+
+    public static InputStream jarFileContent(final File jarFile, final String name) throws IOException {
+        return new ZipFile(jarFile).stream()
+                                   .filter(zipEntry -> zipEntry.getName().contains(name))
+                                   .findFirst()
+                                   .map(zipEntry -> {
+                                       try {
+                                           return new ZipFile(jarFile).getInputStream(zipEntry);
+
+                                       } catch (final IOException e) {
+                                           throw new RuntimeException(e);
+                                       }
+                                   }).orElse(null);
+    }
+
+    public static boolean hasDigest(final InputStream inputStream) throws IOException {
+        if (inputStream == null) {
+            return false;
+        }
+        final Manifest man = new Manifest(inputStream);
+        for(Map.Entry<String, Attributes> entry: man.getEntries().entrySet()) {
+            for(Object attrkey: entry.getValue().keySet()) {
+                if (attrkey instanceof Attributes.Name && attrkey.toString().contains("-Digest"))
+                    return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/tomee-patch-core/src/main/java/org/apache/tomee/patch/core/Transformation.java b/tomee-patch-core/src/main/java/org/apache/tomee/patch/core/Transformation.java
index 3cc2a39..ca22a9f 100644
--- a/tomee-patch-core/src/main/java/org/apache/tomee/patch/core/Transformation.java
+++ b/tomee-patch-core/src/main/java/org/apache/tomee/patch/core/Transformation.java
@@ -24,11 +24,19 @@
 import org.tomitribe.util.Mvn;
 import org.tomitribe.util.dir.Dir;
 
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.zip.ZipEntry;
@@ -46,6 +54,7 @@
     private final Additions additions;
     private final Boolean skipTransform;
     private final File patchResources;
+    private final Boolean skipSigned;
 
     public Transformation() {
         this.log = new NullLog();
@@ -53,11 +62,15 @@
         this.skips = new Skips();
         this.additions = new Additions();
         this.skipTransform = false;
+        this.skipSigned = false;
         this.patchResources = new File("does not exist");
     }
 
 
-    public Transformation(final List<Clazz> classes, final File patchResources, final Replacements replacements, final Skips skips, final Additions additions, final Log log, final Boolean skipTransform) {
+    public Transformation(final List<Clazz> classes, final File patchResources, final Replacements replacements,
+                          final Skips skips, final Additions additions, final Log log, final Boolean skipTransform,
+                          final Boolean skipSigned) {
+
         this.classes.addAll(classes);
         this.log = log;
         this.replacements = replacements == null ? new Replacements() : replacements;
@@ -65,6 +78,7 @@
         this.additions = additions == null ? new Additions() : additions;
         this.patchResources = patchResources;
         this.skipTransform = skipTransform;
+        this.skipSigned = skipSigned;
     }
 
     public static File transform(final File jar) throws IOException {
@@ -84,6 +98,7 @@
     }
 
     private void scanJar(final String name, final InputStream inputStream, final OutputStream outputStream) throws IOException {
+
         {
             final String jar = new File(name).getName();
             final String replacement = replacements.getJars().get(jar);
@@ -112,7 +127,8 @@
                 // TODO: the name may be changed in transformation
                 final String path = updatePath(oldEntry.getName());
 
-                if (skip(path)) {
+                // skip all signature files .RSA, .DSA, .SF
+                if (!skipSigned && isSigned(path)) {
                     IO.copy(zipInputStream, skipped);
                     continue;
                 }
@@ -138,9 +154,9 @@
                     if (path.endsWith(".class")) {
                         scanClass(zipInputStream, zipOutputStream);
                     } else if (isZip(path)) {
-                        if(isExcludedJar(path)){
+                        if(isExcludedJar(path)) {
                             IO.copy(zipInputStream, zipOutputStream);
-                        }else{
+                        } else {
                             scanJar(path, zipInputStream, zipOutputStream);
                         }
                     } else if (copyUnmodified(path)) {
@@ -243,7 +259,7 @@
      * Skip signed jar public key files.  We most definitely
      * have tampered with the jar.
      */
-    private boolean skip(final String name) {
+    private boolean isSigned(final String name) {
         if (name.startsWith("META-INF/")) {
             if (name.endsWith(".SF")) return true;
             if (name.endsWith(".DSA")) return true;
@@ -429,6 +445,30 @@
 
                 .get();
 
+        // we remove signatures (.DSA, .RSA, .SF) but we also need to remove all digest entries
+        if (!skipSigned && path.endsWith("MANIFEST.MF")) {
+            final Manifest manifest = new Manifest(inputStream);
+            final Manifest transformedManifest = new Manifest();
+            transformedManifest.getMainAttributes().putAll(manifest.getMainAttributes());
+
+            for (final Map.Entry<String, Attributes> e : manifest.getEntries().entrySet()) {
+                final Attributes attributes = e.getValue();
+                final Attributes transformedAttributes = new Attributes();
+                for (final Map.Entry<Object, Object> entry : attributes.entrySet()) {
+                    if (!String.valueOf(entry.getKey()).contains("-Digest")) {
+                        transformedAttributes.put(entry.getKey(), entry.getValue());
+                    }
+                }
+                if (!transformedAttributes.isEmpty()) {
+                    transformedManifest.getEntries().put(e.getKey(), transformedAttributes);
+                }
+            }
+
+            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            transformedManifest.write(baos);
+            inputStream = IO.read(baos.toByteArray());
+        }
+
         IO.copy(inputStream, outputStream);
     }
 
diff --git a/tomee-patch-core/src/test/java/org/apache/tomee/patch/core/ExcludeJarsTest.java b/tomee-patch-core/src/test/java/org/apache/tomee/patch/core/ExcludeJarsTest.java
index 719ba97..7807cb7 100644
--- a/tomee-patch-core/src/test/java/org/apache/tomee/patch/core/ExcludeJarsTest.java
+++ b/tomee-patch-core/src/test/java/org/apache/tomee/patch/core/ExcludeJarsTest.java
@@ -3,17 +3,26 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.tomitribe.util.Archive;
+import org.tomitribe.util.IO;
+import org.tomitribe.util.Mvn;
 
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.*;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
+import java.util.jar.Manifest;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
+import static org.apache.tomee.patch.core.Jars.hasDigest;
+import static org.apache.tomee.patch.core.Jars.jarFileContent;
+import static org.apache.tomee.patch.core.Jars.listJarContent;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
@@ -28,19 +37,133 @@
     }
 
     @Test
+    public void checkJarIsSigned() throws IOException {
+        final String coordinates = "org.bouncycastle:bcprov-jdk15on:jar:1.69";
+        final File jarFile = Mvn.mvn(coordinates);
+
+        assertTrue(listJarContent(jarFile).size() > 10); // BC Prov has much more
+
+        assertTrue(listJarContent(jarFile, "^META-INF/[^.]+.(SF|DSA|RSA)$").size() > 1);
+
+        System.out.println(IO.slurp(jarFileContent(jarFile, "META-INF/MANIFEST.MF")));
+
+        assertTrue(IO.slurp(jarFileContent(jarFile, "META-INF/MANIFEST.MF")).contains("-Digest"));
+
+        // This call will throw a java.lang.SecurityException if someone has tampered
+        // with the signature of _any_ element of the JAR file.
+        // Alas, it will proceed without a problem if the JAR file is not signed at all
+        final JarFile jar = new JarFile(jarFile);
+        try (final InputStream is = jar.getInputStream(jar.getEntry("META-INF/MANIFEST.MF"))) {
+            assertTrue(hasDigest(is));
+        }
+
+        assertTrue(Jars.isSigned(jarFile));
+    }
+
+    @Test
+    public void isTransformedNotSkippedForSignedJars() throws IOException {
+        final String coordinates = "org.bouncycastle:bcprov-jdk15on:jar:1.69";
+        final String jarName = "bcprov-jdk15on-1.69.jar";
+        final File realRepoJar = Mvn.mvn(coordinates);
+        final File tempFile = Files.createTempFile("bc", "temp").toFile();
+        IO.copy(realRepoJar, tempFile);
+
+        final File zipFile = Archive.archive()
+                                    .add("README.txt", "hi")
+                                    .add(jarName, tempFile).toJar();
+
+        assertTrue(listJarContent(tempFile).size() > 10); // BC Prov has much more
+
+        assertTrue(listJarContent(tempFile, "^META-INF/[^.]+.(SF|DSA|RSA)$").size() > 1);
+
+        // System.out.println(IO.slurp(jarFileContent(jarFile, "META-INF/MANIFEST.MF")));
+
+        assertTrue(IO.slurp(jarFileContent(tempFile, "META-INF/MANIFEST.MF")).contains("-Digest"));
+
+        // This call will throw a java.lang.SecurityException if someone has tampered
+        // with the signature of _any_ element of the JAR file.
+        // Alas, it will proceed without a problem if the JAR file is not signed at all
+        final JarFile jar = new JarFile(tempFile);
+        try (final InputStream is = jar.getInputStream(jar.getEntry("META-INF/MANIFEST.MF"))) {
+            assertTrue(hasDigest(is));
+        }
+
+        assertTrue(Jars.isSigned(tempFile));
+
+        Transformation transformation = new Transformation(new ArrayList<Clazz>(), new File("does not exist"),
+                                                           null, null, null, new NullLog(),
+                                                           false, true);
+        final File transformedZip = transformation.transformArchive(zipFile);
+
+        // With skipSigned to true, we'll skip signed jars so they remain valid
+        assertTrue(obtainJarContent(transformedZip).contains("META-INF/BC1024KE.SF"));
+        assertTrue(obtainJarContent(transformedZip).contains("META-INF/BC1024KE.DSA"));
+
+        assertValidSignedJar(jarName, transformedZip);
+    }
+
+    private void assertValidSignedJar(final String jarName, final File transformedZip) throws IOException {
+        final ZipFile zip = new ZipFile(transformedZip);
+        final InputStream inputStream = zip.getInputStream(new ZipEntry(jarName));
+        final File tempTransformedJar = Files.createTempFile("bc", "temp").toFile();
+        IO.copy(inputStream, tempTransformedJar);
+        final JarFile jarFile = new JarFile(tempTransformedJar);
+
+        final Manifest manifest = jarFile.getManifest();
+        System.out.println(manifest.toString());
+
+        // This call will throw a java.lang.SecurityException if someone has tampered
+        // with the signature of _any_ element of the JAR file.
+        // Alas, it will proceed without a problem if the JAR file is not signed at all
+        try (final InputStream is = jarFile.getInputStream(jarFile.getEntry("META-INF/MANIFEST.MF"))) {
+            System.out.println(IO.slurp(is));
+        }
+    }
+
+    @Test
+    public void isTransformedSkippedForSignedJars() throws IOException {
+        final String coordinates = "org.bouncycastle:bcprov-jdk15on:jar:1.69";
+        final String jarName = "bcprov-jdk15on-1.69.jar";
+        final File realRepoJar = Mvn.mvn(coordinates);
+        final File tempFile = Files.createTempFile("bc", "temp").toFile();
+        IO.copy(realRepoJar, tempFile);
+
+        final File zipFile = Archive.archive()
+                                    .add("README.txt", "hi")
+                                    .add(jarName, tempFile).toJar();
+
+        assertTrue(Jars.isSigned(tempFile));
+
+        Transformation transformation = new Transformation(new ArrayList<Clazz>(), new File("does not exist"),
+                                                           null, null, null, new NullLog(),
+                                                           false, false);
+        final File transformedZip = transformation.transformArchive(zipFile);
+
+        // when skipSigned is false, we'll try to transform them, BUT ...
+        // we need to remove the signature jars, we need to also filter the manifest to remove Digest entries
+        assertFalse(obtainJarContent(transformedZip).contains("META-INF/BC1024KE.SF"));
+        assertFalse(obtainJarContent(transformedZip).contains("META-INF/BC1024KE.DSA"));
+
+        assertValidSignedJar(jarName, transformedZip);
+    }
+
+    @Test
     public void transformWithJarExclusions() throws Exception {
         final String jarSignatureFileName = "META-INF/sigTest.DSA";
         final String jarName = "bcprov-jdk15on-1.69.jar";
+
         final File testJar = Archive.archive()
-                .add(jarSignatureFileName, "DC143C")
-                .add("index.txt", "red,green,blue")
-                .toJar();
+                                    .add(jarSignatureFileName, "DC143C")
+                                    .add("index.txt", "red,green,blue")
+                                    .toJar();
 
         final File zipFile = Archive.archive()
-                .add("README.txt", "hi")
-                .add(jarName, testJar).toJar();
+                                    .add("README.txt", "hi")
+                                    .add(jarName, testJar).toJar();
 
-        Transformation transformation = new Transformation(new ArrayList<Clazz>(), new File("does not exist"),null, customSkips, null, new NullLog(), false);
+        Transformation transformation = new Transformation(new ArrayList<Clazz>(), new File("does not exist"),
+                                                           null, customSkips, null, new NullLog(),
+                                                           false, false);
         File transformedJar = transformation.transformArchive(zipFile);
         assertTrue(obtainJarContent(transformedJar).contains(jarSignatureFileName));
     }
@@ -51,15 +174,17 @@
         final String jarName = "jdbc.jar";
 
         final File testJar = Archive.archive()
-                .add(jarSignatureFileName, "DC143C")
-                .add("index.txt", "red,green,blue")
-                .toJar();
+                                    .add(jarSignatureFileName, "DC143C")
+                                    .add("index.txt", "red,green,blue")
+                                    .toJar();
 
         final File zipFile = Archive.archive()
-                .add("README.txt", "hi")
-                .add(jarName, testJar).toJar();
+                      .add("README.txt", "hi")
+                      .add(jarName, testJar).toJar();
 
-        Transformation transformation = new Transformation(new ArrayList<Clazz>(), new File("does not exist"),null, customSkips, null, new NullLog(), false);
+        Transformation transformation = new Transformation(new ArrayList<Clazz>(), new File("does not exist"),
+                                                           null, customSkips, null, new NullLog(),
+                                                           false, false);
         File transformedJar = transformation.transformArchive(zipFile);
         assertFalse(obtainJarContent(transformedJar).contains(jarSignatureFileName));
     }
diff --git a/tomee-patch-plugin/src/main/java/org/apache/tomee/patch/plugin/PatchMojo.java b/tomee-patch-plugin/src/main/java/org/apache/tomee/patch/plugin/PatchMojo.java
index 192e54a..3fcb85a 100644
--- a/tomee-patch-plugin/src/main/java/org/apache/tomee/patch/plugin/PatchMojo.java
+++ b/tomee-patch-plugin/src/main/java/org/apache/tomee/patch/plugin/PatchMojo.java
@@ -187,6 +187,9 @@
     private Boolean skipTransform;
 
     @Parameter(defaultValue = "false")
+    private Boolean skipSigned;
+
+    @Parameter(defaultValue = "false")
     private Boolean transformSources;
 
     /**
@@ -283,7 +286,7 @@
 
             final List<Clazz> clazzes = classes();
 
-            final Transformation transformation = new Transformation(clazzes, patchResourceDirectory, replace, skips, add, new MavenLog(getLog()), skipTransform);
+            final Transformation transformation = new Transformation(clazzes, patchResourceDirectory, replace, skips, add, new MavenLog(getLog()), skipTransform, skipSigned);
             for (final Artifact artifact : artifacts) {
                 final File file = artifact.getFile();
                 getLog().debug("Patching " + file.getAbsolutePath());