diff --git a/CryptoAnalysis/pom.xml b/CryptoAnalysis/pom.xml
index 8cdf9c33e..18bb9d4ae 100644
--- a/CryptoAnalysis/pom.xml
+++ b/CryptoAnalysis/pom.xml
@@ -39,7 +39,7 @@
2.5.1
- 4.2.1
+ 4.4.1
@@ -308,7 +308,6 @@
org.bouncycastle
bcprov-jdk18on
1.77
- test
diff --git a/CryptoAnalysis/src/main/java/crypto/HeadlessCryptoScanner.java b/CryptoAnalysis/src/main/java/crypto/HeadlessCryptoScanner.java
index 695bad2e8..748b99f98 100644
--- a/CryptoAnalysis/src/main/java/crypto/HeadlessCryptoScanner.java
+++ b/CryptoAnalysis/src/main/java/crypto/HeadlessCryptoScanner.java
@@ -4,7 +4,6 @@
import boomerang.callgraph.ObservableICFG;
import boomerang.debugger.Debugger;
import boomerang.debugger.IDEVizDebugger;
-import boomerang.preanalysis.BoomerangPretransformer;
import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists;
import crypto.analysis.CrySLAnalysisListener;
@@ -16,8 +15,8 @@
import crypto.analysis.IAnalysisSeed;
import crypto.exceptions.CryptoAnalysisException;
import crypto.exceptions.CryptoAnalysisParserException;
-import crypto.preanalysis.ExceptionAwareTransformer;
import crypto.preanalysis.SeedFactory;
+import crypto.preanalysis.TransformerSetup;
import crypto.providerdetection.ProviderDetection;
import crypto.reporting.CSVReporter;
import crypto.reporting.CSVSummaryReporter;
@@ -138,7 +137,7 @@ public void exec() {
} catch (CryptoAnalysisException e) {
LOGGER.error("Error happened when executing HeadlessCryptoScanner.", e);
}
- ExceptionAwareTransformer.setup(rules);
+
LOGGER.info("Analysis soot setup done in {} ", stopwatch);
analyse();
LOGGER.info("Analysis finished in {}", stopwatch);
@@ -189,8 +188,8 @@ private Transformer createAnalysisTransformer() {
@Override
protected void internalTransform(String phaseName, Map options) {
- BoomerangPretransformer.v().reset();
- BoomerangPretransformer.v().apply();
+ TransformerSetup.v().setupPreTransformer(rules);
+
ObservableDynamicICFG observableDynamicICFG = new ObservableDynamicICFG(false);
List rules = HeadlessCryptoScanner.rules;
@@ -336,6 +335,14 @@ private void initializeSootWithEntryPointAllReachable(boolean wholeProgram) thro
Options.v().set_no_bodies_for_excluded(true);
Options.v().set_allow_phantom_refs(true);
Options.v().set_keep_line_number(true);
+
+ /* This phase is new in soot 4.3.0 and manipulates the jimple code in a
+ * way that CryptoAnalysis is not able to find seeds in some cases (see
+ * https://github.com/CROSSINGTUD/CryptoAnalysis/issues/293). Therefore,
+ * it is disabled.
+ */
+ Options.v().setPhaseOption("jb.sils", "enabled:false");
+
// JAVA 8
if(getJavaVersion() < 9)
{
@@ -380,13 +387,14 @@ private List getIncludeList() {
includeList.add("java.lang.String");
includeList.add("java.lang.StringCoding");
includeList.add("java.lang.StringIndexOutOfBoundsException");
- return includeList;
+ return new LinkedList<>();
}
private List getExcludeList() {
List exList = new LinkedList();
List rules = getRules();
- for(CrySLRule r : rules) {
+
+ for (CrySLRule r : rules) {
exList.add(r.getClassName());
}
return exList;
diff --git a/CryptoAnalysis/src/main/java/crypto/preanalysis/CastTransformer.java b/CryptoAnalysis/src/main/java/crypto/preanalysis/CastTransformer.java
new file mode 100644
index 000000000..383322d10
--- /dev/null
+++ b/CryptoAnalysis/src/main/java/crypto/preanalysis/CastTransformer.java
@@ -0,0 +1,68 @@
+package crypto.preanalysis;
+
+import soot.Body;
+import soot.UnitPatchingChain;
+import soot.Value;
+import soot.jimple.AssignStmt;
+import soot.jimple.CastExpr;
+import soot.jimple.Constant;
+
+import java.util.Map;
+
+/**
+ * This transformer removes explicit cast expressions from the jimple code.
+ * Since Soot 4.3.0, it transforms the expression 'int a = 65000' into the jimple
+ * statement '$v = (int) 65000'. However, Boomerang is not able to extract the
+ * value 65000 from the statement because of the explicit cast operation (int).
+ * For the analysis, this operation is irrelevant because the variables always
+ * have the correct type (i.e. $v is of type int), so we can remove the cast
+ * operation.
+ */
+public class CastTransformer extends PreTransformer {
+
+ private static CastTransformer instance;
+
+ public CastTransformer() {
+ super();
+ }
+
+ @Override
+ protected void internalTransform(Body body, String phaseName, Map options) {
+ if (!body.getMethod().getDeclaringClass().isApplicationClass()) {
+ return;
+ }
+
+ final UnitPatchingChain units = body.getUnits();
+ units.snapshotIterator().forEachRemaining(unit -> {
+ if (!(unit instanceof AssignStmt)) {
+ return;
+ }
+ AssignStmt assignStmt = (AssignStmt) unit;
+
+ Value rightSide = assignStmt.getRightOp();
+ if (!(rightSide instanceof CastExpr)) {
+ return;
+ }
+
+ CastExpr castExpr = (CastExpr) rightSide;
+ if (!(castExpr.getOp() instanceof Constant)) {
+ return;
+ }
+ Constant constant = (Constant) castExpr.getOp();
+
+ assignStmt.setRightOp(constant);
+ });
+ }
+
+ public static CastTransformer v() {
+ if (instance == null) {
+ instance = new CastTransformer();
+ }
+ return instance;
+ }
+
+ public void reset() {
+ instance = null;
+ }
+
+}
diff --git a/CryptoAnalysis/src/main/java/crypto/preanalysis/ExceptionAwareTransformer.java b/CryptoAnalysis/src/main/java/crypto/preanalysis/ExceptionAwareTransformer.java
index bf1552c1e..9f20a650d 100644
--- a/CryptoAnalysis/src/main/java/crypto/preanalysis/ExceptionAwareTransformer.java
+++ b/CryptoAnalysis/src/main/java/crypto/preanalysis/ExceptionAwareTransformer.java
@@ -1,26 +1,16 @@
package crypto.preanalysis;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
-
import crypto.constraints.ExceptionConstraint;
import crypto.rules.CrySLExceptionConstraint;
import crypto.rules.CrySLRule;
import crypto.typestate.CrySLMethodToSootMethod;
import crypto.typestate.LabeledMatcherTransition;
import soot.Body;
-import soot.BodyTransformer;
-import soot.PackManager;
-import soot.PhaseOptions;
import soot.Scene;
import soot.SootClass;
import soot.SootMethod;
-import soot.Transform;
import soot.Unit;
import soot.UnitPatchingChain;
import soot.jimple.NullConstant;
@@ -28,21 +18,16 @@
import soot.jimple.internal.JEqExpr;
import soot.jimple.internal.JIfStmt;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
/**
* This transformer adds a branch after each statement, that may throw an
* Exception, to the handler of that Exception.
* The exceptions that a statement may throw are declared in the CrySLRule.
*/
-public class ExceptionAwareTransformer extends BodyTransformer {
-
- public static void setup(final List rules) {
- for (final CrySLRule rule : rules) {
- final String phaseName = "jap.etr-" + rule.getClassName();
- PackManager.v().getPack("jap").remove(phaseName);
- PackManager.v().getPack("jap").add(new Transform(phaseName, new ExceptionAwareTransformer(rule)));
- PhaseOptions.v().setPhaseOption(phaseName, "on");
- }
- }
+public class ExceptionAwareTransformer extends PreTransformer {
private final SootClass spec;
diff --git a/CryptoAnalysis/src/main/java/crypto/preanalysis/PreTransformer.java b/CryptoAnalysis/src/main/java/crypto/preanalysis/PreTransformer.java
new file mode 100644
index 000000000..9422db3a2
--- /dev/null
+++ b/CryptoAnalysis/src/main/java/crypto/preanalysis/PreTransformer.java
@@ -0,0 +1,43 @@
+package crypto.preanalysis;
+
+import soot.BodyTransformer;
+import soot.MethodOrMethodContext;
+import soot.Scene;
+import soot.SootMethod;
+import soot.jimple.toolkits.callgraph.ReachableMethods;
+import soot.util.queue.QueueReader;
+
+import java.util.HashMap;
+
+public abstract class PreTransformer extends BodyTransformer {
+
+ private boolean applied;
+
+ public PreTransformer() {
+ applied = false;
+ }
+
+ public final void apply() {
+ if (isApplied()) {
+ return;
+ }
+
+ /* Following the concept of Soot, each transformer is applied to each method
+ * body individually. It may be more efficient to apply all transformers at once
+ * to a method body.
+ */
+ ReachableMethods reachableMethods = Scene.v().getReachableMethods();
+ QueueReader listener = reachableMethods.listener();
+ while (listener.hasNext()) {
+ SootMethod method = listener.next().method();
+ if (method.hasActiveBody()) {
+ internalTransform(method.getActiveBody(), "preTrans", new HashMap<>());
+ }
+ }
+ applied = true;
+ }
+
+ public boolean isApplied() {
+ return applied;
+ }
+}
diff --git a/CryptoAnalysis/src/main/java/crypto/preanalysis/TransformerSetup.java b/CryptoAnalysis/src/main/java/crypto/preanalysis/TransformerSetup.java
new file mode 100644
index 000000000..385aec318
--- /dev/null
+++ b/CryptoAnalysis/src/main/java/crypto/preanalysis/TransformerSetup.java
@@ -0,0 +1,48 @@
+package crypto.preanalysis;
+
+import boomerang.preanalysis.BoomerangPretransformer;
+import crypto.rules.CrySLRule;
+
+import java.util.List;
+
+public class TransformerSetup {
+
+ private static TransformerSetup instance;
+
+ public void setupPreTransformer(List rules) {
+ // Transformer related to the analysis
+ setupCastTransformer();
+ setupExceptionAwareTransformer(rules);
+
+ // Transformer related to Boomerang
+ setupBoomerangTransformer();
+ }
+
+ public void setupCastTransformer() {
+ CastTransformer.v().reset();
+ CastTransformer.v().apply();
+ }
+
+ public void setupExceptionAwareTransformer(List rules) {
+ for (CrySLRule rule : rules) {
+ ExceptionAwareTransformer transformer = new ExceptionAwareTransformer(rule);
+ transformer.apply();
+ }
+ }
+
+ public void setupBoomerangTransformer() {
+ BoomerangPretransformer.v().reset();
+ BoomerangPretransformer.v().apply();
+ }
+
+ public static TransformerSetup v() {
+ if (instance == null) {
+ instance = new TransformerSetup();
+ }
+ return instance;
+ }
+
+ public void reset() {
+ instance = null;
+ }
+}
diff --git a/CryptoAnalysis/src/main/java/crypto/typestate/CrySLMethodToSootMethod.java b/CryptoAnalysis/src/main/java/crypto/typestate/CrySLMethodToSootMethod.java
index 2b7e5a2c4..41ab75c37 100644
--- a/CryptoAnalysis/src/main/java/crypto/typestate/CrySLMethodToSootMethod.java
+++ b/CryptoAnalysis/src/main/java/crypto/typestate/CrySLMethodToSootMethod.java
@@ -74,8 +74,12 @@ private Collection _convert(CrySLMethod label) {
for(SootClass c : classes) {
for (SootMethod m : c.getMethods()) {
if (m.getName().equals(methodNameWithoutDeclaringClass) && m.getParameterCount() == noOfParams) {
- if (parametersMatch(label.getParameters(), m.getParameterTypes())){
+ if (parametersMatch(label.getParameters(), m.getParameterTypes())) {
res.add(m);
+
+ // Set the class defining the target method to phantom to avoid analyzing the method,
+ // if it is defined in a superclass
+ c.setPhantomClass();
}
}
}
diff --git a/CryptoAnalysis/src/test/java/test/UsagePatternTestingFramework.java b/CryptoAnalysis/src/test/java/test/UsagePatternTestingFramework.java
index 4113a939c..d58c41dfb 100644
--- a/CryptoAnalysis/src/test/java/test/UsagePatternTestingFramework.java
+++ b/CryptoAnalysis/src/test/java/test/UsagePatternTestingFramework.java
@@ -1,28 +1,18 @@
package test;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Sets;
-import com.google.common.collect.Table;
-import com.google.common.collect.Table.Cell;
-
import boomerang.BackwardQuery;
import boomerang.Query;
import boomerang.callgraph.ObservableDynamicICFG;
import boomerang.callgraph.ObservableICFG;
import boomerang.jimple.Statement;
import boomerang.jimple.Val;
-import boomerang.preanalysis.BoomerangPretransformer;
import boomerang.results.ForwardBoomerangResults;
+import com.google.common.base.Joiner;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
+import com.google.common.collect.Table;
+import com.google.common.collect.Table.Cell;
import crypto.analysis.AnalysisSeedWithSpecification;
import crypto.analysis.CrySLAnalysisListener;
import crypto.analysis.CrySLResultsReporter;
@@ -48,6 +38,7 @@
import crypto.extractparameter.CallSiteWithParamIndex;
import crypto.extractparameter.ExtractedValue;
import crypto.interfaces.ISLConstraint;
+import crypto.preanalysis.TransformerSetup;
import crypto.rules.CrySLPredicate;
import crypto.rules.CrySLRule;
import soot.Body;
@@ -81,19 +72,31 @@
import test.core.selfrunning.ImprecisionException;
import typestate.TransitionFunction;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
public abstract class UsagePatternTestingFramework extends AbstractTestingFramework{
protected ObservableICFG icfg;
private JimpleBasedInterproceduralCFG staticIcfg;
- List rules;
+ private List rules = getRules();
@Override
protected SceneTransformer createAnalysisTransformer() throws ImprecisionException {
+
+ // Required since Soot 4.3.0
+ Options.v().setPhaseOption("jb.sils", "enabled:false");
+
return new SceneTransformer() {
- protected void internalTransform(String phaseName, @SuppressWarnings("rawtypes") Map options) {
- BoomerangPretransformer.v().reset();
- BoomerangPretransformer.v().apply();
+ protected void internalTransform(String phaseName, Map options) {
+ TransformerSetup.v().setupPreTransformer(rules);
+
staticIcfg = new JimpleBasedInterproceduralCFG(true);
// icfg = new ObservableStaticICFG(new JimpleBasedInterproceduralCFG(true));
icfg = new ObservableDynamicICFG(true);
@@ -348,7 +351,7 @@ public void addProgress(int processedSeeds, int workListsize) {
return reporters;
}
};
- scanner.scan(getRules());
+ scanner.scan(rules);
List unsound = Lists.newLinkedList();
List imprecise = Lists.newLinkedList();
@@ -389,7 +392,8 @@ private List getRules() {
@Override
public List excludedPackages() {
List excludedPackages = super.excludedPackages();
- for(CrySLRule r : getRules()) {
+
+ for (CrySLRule r : rules) {
excludedPackages.add(r.getClassName());
}
return excludedPackages;
diff --git a/CryptoAnalysis/src/test/java/tests/headless/BouncyCastleHeadlessTest.java b/CryptoAnalysis/src/test/java/tests/headless/BouncyCastleHeadlessTest.java
index 0bf91fab3..142d4aac3 100644
--- a/CryptoAnalysis/src/test/java/tests/headless/BouncyCastleHeadlessTest.java
+++ b/CryptoAnalysis/src/test/java/tests/headless/BouncyCastleHeadlessTest.java
@@ -40,6 +40,10 @@ public void testBCMacExamples() {
setErrorsCount("", RequiredPredicateError.class, 1);
setErrorsCount("", RequiredPredicateError.class, 3);
+ // Class from BouncyCastle should not be analyzed
+ //setErrorsCount("", RequiredPredicateError.class, 1);
+ setErrorsCount(RequiredPredicateError.class, new FindingsType.FalsePositives(1, "Analysis should not go into BouncyCastle class"), "");
+
scanner.exec();
assertErrors();
}
@@ -108,7 +112,7 @@ public void testBCDigestExamples() {
setErrorsCount("", RequiredPredicateError.class, 1);
setErrorsCount("", TypestateError.class, 2);
- setErrorsCount("", TypestateError.class, 3);
+ setErrorsCount("", TypestateError.class, 4);
scanner.exec();
assertErrors();