diff --git a/maven/plugin/pom.xml b/maven/plugin/pom.xml index 18df8ad..935ab07 100644 --- a/maven/plugin/pom.xml +++ b/maven/plugin/pom.xml @@ -29,7 +29,7 @@ org.apache.maven.plugins maven-dependency-plugin - 3.1.2 + 3.2.0 org.ow2.asm @@ -82,6 +82,14 @@ + + org.apache.maven.plugins + maven-compiler-plugin + + 10 + 10 + + diff --git a/maven/plugin/src/main/java/de/fraunhofer/iem/maven/CogniCryptMojo.java b/maven/plugin/src/main/java/de/fraunhofer/iem/maven/CogniCryptMojo.java index 6b24853..21c575a 100644 --- a/maven/plugin/src/main/java/de/fraunhofer/iem/maven/CogniCryptMojo.java +++ b/maven/plugin/src/main/java/de/fraunhofer/iem/maven/CogniCryptMojo.java @@ -1,12 +1,16 @@ package de.fraunhofer.iem.maven; import java.io.File; +import java.nio.file.Path; +import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.regex.Pattern; +import crypto.cryslhandler.CrySLModelReader; +import crypto.cryslhandler.CrySLModelReaderClassPath; import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; @@ -27,10 +31,7 @@ import crypto.reporting.SourceCodeLocater; import crypto.rules.CrySLRule; import crypto.rules.CrySLRuleReader; -import soot.SceneTransformer; -import soot.SootMethod; -import soot.Transformer; -import soot.Unit; +import soot.*; @Mojo(name = "cognicrypt", requiresDependencyResolution = ResolutionScope.COMPILE, defaultPhase = LifecyclePhase.VERIFY, threadSafe = true) public class CogniCryptMojo extends SootMojo { @@ -47,15 +48,64 @@ public class CogniCryptMojo extends SootMojo { @Parameter(property = "cognicrypt.dynamic-cg", defaultValue = "true") private boolean dynamicCg; + private CrySLRuleReader reader; + @Override - protected void doExecute() throws MojoExecutionException, MojoFailureException { + protected void doExecute() throws MojoExecutionException { validateParameters(); - super.doExecute(); + + var targetDir = getProjectTargetDir(); + var classFolder = targetDir.resolve("classes"); + if(!classFolder.toFile().exists()) { + getLog().debug("No class folder for project found at " + classFolder + ""); + getLog().info("CogniCrypt found nothing to analyze!"); + return; + } + + getLog().debug("Resolving project dependencies..."); + var dependencies = resolveDependencies(); + getLog().debug("Resolved " + dependencies.size() + " dependencies"); + + getLog().debug("Initializing Soot..."); + registerDependencies(dependencies); + List rules; + try { + getLog().info("Fetching CogniCrypt Rules."); + rules = getRules(); + } catch (CryptoAnalysisException e) { + getLog().error("Failed fetching rules: " + e.getMessage(), e); + return; + } + getLog().debug("Initialized CogniCrypt."); + + getLog().debug("Initializing Soot..."); + var setupData = createSootSetupData(classFolder, dependencies, rules); + new SootSetup(setupData).run(); + getLog().debug("Initialized Soot."); + + getLog().info("Running CogniCrypt..."); + analyse(rules); + getLog().info("CogniCrypt analysis done!"); + } - @Override - protected Transformer createAnalysisTransformer() { + private void analyse(List rules) { + PackManager.v().getPack("wjap").add(new Transform("wjap.ifds", createAnalysisTransformer(rules))); + PackManager.v().runPacks(); + } + + private void registerDependencies(Collection dependencies){ + CrySLModelReaderClassPath classPath; + if (dependencies.size() == 0) { + classPath = CrySLModelReaderClassPath.JAVA_CLASS_PATH; + } else { + classPath = CrySLModelReaderClassPath.createFromPaths(dependencies); + } + reader = new CrySLRuleReader(new CrySLModelReader(classPath)); + } + + private Transformer createAnalysisTransformer(List rules) { return new SceneTransformer() { @Override @@ -65,29 +115,20 @@ protected void internalTransform(String phaseName, Map options) final CrySLResultsReporter reporter = new CrySLResultsReporter(); ErrorMarkerListener fileReporter; - System.out.println("Fetching CogniCrypt Rules."); - List rules; - try { - rules = getRules(); - } catch (Exception e) { - System.out.println("Failed fetching rules: " + e.getMessage()); - return; - } - if(outputFormat.equalsIgnoreCase("standard")) { - fileReporter = new CommandLineReporter(getReportFolder().getAbsolutePath(), rules); + fileReporter = new CommandLineReporter(getReportFolder().toAbsolutePath().toString(), rules); } else if(outputFormat.equalsIgnoreCase("sarif")) { MavenProject project = getProject(); - fileReporter = new SARIFReporter(getReportFolder().getAbsolutePath(), rules, + fileReporter = new SARIFReporter(getReportFolder().toAbsolutePath().toString(), rules, new SourceCodeLocater(project.hasParent() ? project.getParent().getBasedir() : project.getBasedir())); } else { - throw new RuntimeException("Illegal state"); + throw new IllegalStateException("Illegal output format specified"); } reporter.addReportListener(fileReporter); - System.out.println("Creating ICFG!"); + getLog().debug("Creating ICFG!"); final ObservableICFG icfg; if(!dynamicCg) { icfg = new ObservableStaticICFG(new BoomerangICFG(true)); @@ -106,8 +147,7 @@ public CrySLResultsReporter getAnalysisListener() { return reporter; } }; - - System.out.println("Starting CogniCrypt Analysis!"); + getLog().debug("Starting CogniCrypt Analysis!"); scanner.scan(rules); } }; @@ -128,17 +168,17 @@ private void validateParameters() throws MojoExecutionException { * Receives the set of rules form a given directory. */ private List getRules() throws CryptoAnalysisException { - return CrySLRuleReader.readFromDirectory(new File(rulesDirectory)); + return reader.readFromDirectory(new File(rulesDirectory)); } - - private File getReportFolder() { - File reportsFolder = new File(reportsFolderParameter); + private Path getReportFolder() { + var reportsFolder = Path.of(reportsFolderParameter); if (!reportsFolder.isAbsolute()) { - reportsFolder = new File(getProjectTargetDir(), reportsFolderParameter); + reportsFolder = getProjectTargetDir().resolve(reportsFolderParameter); } - if (!reportsFolder.exists()) { - reportsFolder.mkdirs(); + var asFile = reportsFolder.toFile(); + if (!asFile.exists()) { + asFile.mkdirs(); } return reportsFolder; } diff --git a/maven/plugin/src/main/java/de/fraunhofer/iem/maven/JavaUtils.java b/maven/plugin/src/main/java/de/fraunhofer/iem/maven/JavaUtils.java index c0cb586..d3a0396 100644 --- a/maven/plugin/src/main/java/de/fraunhofer/iem/maven/JavaUtils.java +++ b/maven/plugin/src/main/java/de/fraunhofer/iem/maven/JavaUtils.java @@ -7,10 +7,10 @@ class JavaUtils { - static Optional javaVersion = Optional.empty(); + private static Optional javaVersion = Optional.empty(); public static int getJavaVersion() { - if (!javaVersion.isPresent()){ + if (javaVersion.isEmpty()){ String versionString = System.getProperty("java.version"); if(versionString.startsWith("1.")) { versionString = versionString.substring(2, 3); @@ -21,13 +21,13 @@ public static int getJavaVersion() { } } int version = Integer.parseInt(versionString); - javaVersion = Optional.ofNullable(version); + javaVersion = Optional.of(version); } return javaVersion.get(); } - public static boolean isModularProject(File classPath) { - Path moduleClassPath = Paths.get(classPath.getAbsolutePath(), "module-info.class"); + public static boolean isModularProject(Path classPath) { + Path moduleClassPath = classPath.resolve("module-info.class"); return moduleClassPath.toFile().exists(); } diff --git a/maven/plugin/src/main/java/de/fraunhofer/iem/maven/SootMojo.java b/maven/plugin/src/main/java/de/fraunhofer/iem/maven/SootMojo.java index e069776..d62a7af 100644 --- a/maven/plugin/src/main/java/de/fraunhofer/iem/maven/SootMojo.java +++ b/maven/plugin/src/main/java/de/fraunhofer/iem/maven/SootMojo.java @@ -1,17 +1,9 @@ package de.fraunhofer.iem.maven; -import java.io.File; -import java.util.Collection; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - import com.google.common.base.Joiner; import com.google.common.collect.Lists; +import crypto.rules.CrySLRule; import org.apache.maven.artifact.Artifact; -import org.apache.maven.artifact.resolver.ArtifactResolver; import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; @@ -22,16 +14,16 @@ import org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter; import org.apache.maven.shared.transfer.repository.RepositoryManager; import org.codehaus.plexus.util.StringUtils; - import soot.PackManager; import soot.Transform; import soot.Transformer; -public abstract class SootMojo extends AbstractDependencyFilterMojo { - - private List classFolders = Lists.newLinkedList(); +import java.io.File; +import java.nio.file.Path; +import java.util.*; +import java.util.stream.Collectors; - private Optional targetDir = Optional.empty(); +public abstract class SootMojo extends AbstractDependencyFilterMojo { @Parameter(defaultValue = "${session}", readonly = true) private MavenSession session; @@ -54,17 +46,6 @@ public abstract class SootMojo extends AbstractDependencyFilterMojo { @Component private RepositoryManager repositoryManager; - @Component - private ArtifactResolver artifactResolver; - - public File getProjectTargetDir() { - if (!targetDir.isPresent()){ - File td = new File(project.getBuild().getDirectory()); - targetDir = Optional.of(td); - } - return targetDir.get(); - } - @Override public MavenProject getProject() { return this.project; @@ -75,67 +56,51 @@ protected ArtifactsFilter getMarkedArtifactFilter() { return null; } - @Override - protected void doExecute() throws MojoExecutionException, MojoFailureException { - if (includeDependencies) { - Set artifacts = getResolvedDependencies(false); - for (Artifact a : artifacts) { - String file = a.getFile().getPath(); - // substitute the property for the local repo path to make the classpath file - // portable. - if (StringUtils.isNotEmpty(localRepoProperty)) { - File localBasedir = repositoryManager - .getLocalRepositoryBasedir(session.getProjectBuildingRequest()); - - file = StringUtils.replace(file, localBasedir.getAbsolutePath(), localRepoProperty); - } - classFolders.add(file); + protected Collection resolveDependencies() throws MojoExecutionException { + if (!includeDependencies) + return Collections.emptyList(); + var dependencies = new ArrayList(); + Set artifacts = getResolvedDependencies(false); + for (Artifact artifact : artifacts) { + var filePath = artifact.getFile().getPath(); + if (StringUtils.isNotEmpty(localRepoProperty)) { + // substitute the property for the local repo path to make the classpath file portable. + File localBasedir = repositoryManager.getLocalRepositoryBasedir(session.getProjectBuildingRequest()); + filePath = StringUtils.replace(filePath, localBasedir.getAbsolutePath(), localRepoProperty); } + var dependency = Path.of(filePath); + dependencies.add(dependency); } - run(getProjectTargetDir()); + return dependencies; } - public void run(File targetDir) { - final File classFolder = new File(targetDir.getAbsolutePath() + File.separator + "classes"); - if(!classFolder.exists()) { - getLog().info("No class folder found at " + classFolder + ""); - return; - } - - new SootSetup(CreateSootSetupData()).run(); - analyse(); - getLog().info("Soot analysis done!"); + protected Path getProjectTargetDir() { + return Path.of(project.getBuild().getDirectory()); } - protected abstract Transformer createAnalysisTransformer(); - - private SootSetupData CreateSootSetupData() { - List excludeList = getExcludeList(); - List appCp = buildApplicationClassPath(); - String sootCp = buildSootClassPath(classFolders, appCp); - boolean modular = JavaUtils.isModularProject(new File(getProjectTargetDir(), "classes")); + protected SootSetupData createSootSetupData(Path applicationPath, Collection dependencies, Collection rules) { + List excludeList = getExcludeList(rules); + List appCp = Lists.newArrayList(applicationPath.toAbsolutePath().toString()); + String sootCp = buildSootClassPath(applicationPath, dependencies); + boolean modular = JavaUtils.isModularProject(applicationPath); return new SootSetupData(callGraph, sootCp, appCp, modular, excludeList); } - private void analyse() { - PackManager.v().getPack("wjap").add(new Transform("wjap.ifds", createAnalysisTransformer())); - PackManager.v().runPacks(); - } - - - private List getExcludeList() { - return Lists.newArrayList(excludedPackages.split(",")); - } - private List buildApplicationClassPath() { - final File classFolder = new File(getProjectTargetDir().getAbsolutePath(), "classes"); - return Lists.newArrayList(classFolder.getAbsolutePath()); + private List getExcludeList(Collection rules) { + var excludeList = Lists.newArrayList(excludedPackages.split(",")); + for(var rule : rules) { + excludeList.add(rule.getClassName()); + } + return excludeList; } - private String buildSootClassPath(List dependencies, List applicationCp) { - List sootCp = Stream.of(dependencies, applicationCp) - .flatMap(Collection::stream) - .collect(Collectors.toList()); + private String buildSootClassPath(Path applicationPath, Collection dependencies) { + var sootCp = new ArrayList(); + for (var dep: dependencies) { + sootCp.add(dep.toAbsolutePath().toString()); + } + sootCp.add(applicationPath.toAbsolutePath().toString()); String javaPath = JavaUtils.getJavaRuntimePath().getAbsolutePath(); sootCp.add(0, javaPath); List distinctSootCp = sootCp.stream().distinct().collect(Collectors.toList()); diff --git a/maven/plugin/src/main/java/de/fraunhofer/iem/maven/SootSetup.java b/maven/plugin/src/main/java/de/fraunhofer/iem/maven/SootSetup.java index 40a2127..97f0b20 100644 --- a/maven/plugin/src/main/java/de/fraunhofer/iem/maven/SootSetup.java +++ b/maven/plugin/src/main/java/de/fraunhofer/iem/maven/SootSetup.java @@ -1,7 +1,6 @@ package de.fraunhofer.iem.maven; import java.io.File; -import java.util.Collections; import java.util.LinkedList; import java.util.List; diff --git a/pom.xml b/pom.xml index d20c074..53042e3 100644 --- a/pom.xml +++ b/pom.xml @@ -36,7 +36,7 @@ maven-compiler-plugin 3.10.0 - 8 + 11