Skip to content

Support custom rules like Bouncy Castle #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion maven/plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.2</version>
<version>3.2.0</version>
<exclusions>
<exclusion>
<groupId>org.ow2.asm</groupId>
Expand Down Expand Up @@ -82,6 +82,14 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>10</source>
<target>10</target>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
Expand Down
102 changes: 71 additions & 31 deletions maven/plugin/src/main/java/de/fraunhofer/iem/maven/CogniCryptMojo.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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 {
Expand All @@ -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<CrySLRule> 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<CrySLRule> rules) {
PackManager.v().getPack("wjap").add(new Transform("wjap.ifds", createAnalysisTransformer(rules)));
PackManager.v().runPacks();
}

private void registerDependencies(Collection<Path> 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<CrySLRule> rules) {
return new SceneTransformer() {

@Override
Expand All @@ -65,29 +115,20 @@ protected void internalTransform(String phaseName, Map<String, String> options)
final CrySLResultsReporter reporter = new CrySLResultsReporter();
ErrorMarkerListener fileReporter;

System.out.println("Fetching CogniCrypt Rules.");
List<CrySLRule> 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<Unit, SootMethod> icfg;
if(!dynamicCg) {
icfg = new ObservableStaticICFG(new BoomerangICFG(true));
Expand All @@ -106,8 +147,7 @@ public CrySLResultsReporter getAnalysisListener() {
return reporter;
}
};

System.out.println("Starting CogniCrypt Analysis!");
getLog().debug("Starting CogniCrypt Analysis!");
scanner.scan(rules);
}
};
Expand All @@ -128,17 +168,17 @@ private void validateParameters() throws MojoExecutionException {
* Receives the set of rules form a given directory.
*/
private List<CrySLRule> 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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@

class JavaUtils {

static Optional<Integer> javaVersion = Optional.empty();
private static Optional<Integer> 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);
Expand All @@ -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();
}

Expand Down
113 changes: 39 additions & 74 deletions maven/plugin/src/main/java/de/fraunhofer/iem/maven/SootMojo.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<String> classFolders = Lists.newLinkedList();
import java.io.File;
import java.nio.file.Path;
import java.util.*;
import java.util.stream.Collectors;

private Optional<File> targetDir = Optional.empty();
public abstract class SootMojo extends AbstractDependencyFilterMojo {

@Parameter(defaultValue = "${session}", readonly = true)
private MavenSession session;
Expand All @@ -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;
Expand All @@ -75,67 +56,51 @@ protected ArtifactsFilter getMarkedArtifactFilter() {
return null;
}

@Override
protected void doExecute() throws MojoExecutionException, MojoFailureException {
if (includeDependencies) {
Set<Artifact> 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<Path> resolveDependencies() throws MojoExecutionException {
if (!includeDependencies)
return Collections.emptyList();
var dependencies = new ArrayList<Path>();
Set<Artifact> 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<String> excludeList = getExcludeList();
List<String> appCp = buildApplicationClassPath();
String sootCp = buildSootClassPath(classFolders, appCp);
boolean modular = JavaUtils.isModularProject(new File(getProjectTargetDir(), "classes"));
protected SootSetupData createSootSetupData(Path applicationPath, Collection<Path> dependencies, Collection<CrySLRule> rules) {
List<String> excludeList = getExcludeList(rules);
List<String> 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<String> getExcludeList() {
return Lists.newArrayList(excludedPackages.split(","));
}

private List<String> buildApplicationClassPath() {
final File classFolder = new File(getProjectTargetDir().getAbsolutePath(), "classes");
return Lists.newArrayList(classFolder.getAbsolutePath());
private List<String> getExcludeList(Collection<CrySLRule> rules) {
var excludeList = Lists.newArrayList(excludedPackages.split(","));
for(var rule : rules) {
excludeList.add(rule.getClassName());
}
return excludeList;
}

private String buildSootClassPath(List<String> dependencies, List<String> applicationCp) {
List<String> sootCp = Stream.of(dependencies, applicationCp)
.flatMap(Collection::stream)
.collect(Collectors.toList());
private String buildSootClassPath(Path applicationPath, Collection<Path> dependencies) {
var sootCp = new ArrayList<String>();
for (var dep: dependencies) {
sootCp.add(dep.toAbsolutePath().toString());
}
sootCp.add(applicationPath.toAbsolutePath().toString());
String javaPath = JavaUtils.getJavaRuntimePath().getAbsolutePath();
sootCp.add(0, javaPath);
List<String> distinctSootCp = sootCp.stream().distinct().collect(Collectors.toList());
Expand Down
Original file line number Diff line number Diff line change
@@ -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;

Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.0</version>
<configuration>
<release>8</release>
<release>11</release>
</configuration>
</plugin>
<plugin>
Expand Down