diff --git a/.github/actions/performance/action.yml b/.github/actions/performance/action.yml new file mode 100644 index 000000000..e9a8d4d09 --- /dev/null +++ b/.github/actions/performance/action.yml @@ -0,0 +1,70 @@ +name: Test Performance + +inputs: + test-results-path: + description: "Path to the test results directory" + required: true + source-branch: + description: "Branch that holds the file with previous results" + required: true + current-results: + description: "File that stores previous results" + required: true + output-file: + description: "File where the results are storted in" + required: true + +runs: + using: "composite" + steps: + - name: Aggregate test results from multiple directories + run: | + total_time=0 + + if [ -d ${{ inputs.test-results-path }} ]; then + echo "Processing directory: ${{ inputs.test-results-path }}" + + for file in ${{ inputs.test-results-path }}/*.txt; do + if [ -f "$file" ]; then + echo "Processing file: $file" + + # Extract the time elapsed from each relevant line in the file and sum it up + file_time=$(grep -oP "Time elapsed: \K[\d\.]+" "$file" | awk '{sum += $1} END {print sum}') + if [ -n "$file_time" ]; then + echo "Time found: $file_time seconds" + total_time=$(echo "$total_time + $file_time" | bc) + else + echo "No time elapsed found in file: $file" + fi + else + echo "No files found in directory: ${{ inputs.test-results-path }}" + fi + done + else + echo "Directory does not exist: ${{ inputs.test-results-path }}" + fi + + # Convert total time to minutes, seconds, and milliseconds + total_time_int=$(printf "%.0f" "$total_time") + minutes=$((total_time_int / 60)) + seconds=$((total_time_int % 60)) + milliseconds=$(printf "%.0f" "$(echo "($total_time - $total_time_int) * 1000" | bc)") + + echo "Total Time Calculated: ${minutes}m ${seconds}s ${milliseconds}ms" + timestamp=$(date +"%Y-%m-%d %H:%M:%S") + echo "${timestamp}, Total Time: ${minutes}m ${seconds}s ${milliseconds}ms" >> ${{ inputs.output-file }} + shell: bash + + - name: Combine current and past results + run: | + git checkout ${{ inputs.source-branch }} + if [ -f ${{ inputs.current-results }} ]; then + git checkout ${{ inputs.source-branch }} ${{ inputs.current-results }} + cat ${{ inputs.output-file }} >> ${{ inputs.current-results }} + mv ${{ inputs.current-results }} ${{ inputs.output-file }} + fi + shell: bash + + - name: Switch to default branch + run: git checkout ${{ github.ref_name }} + shell: bash diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 391b9bebf..de86b9794 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -2,12 +2,7 @@ name: Build And Test (Basic) description: Basic build and tests for the submodules on each push and pull request on: - push: - branches-ignore: - - master - - develop pull_request: - types: [opened, reopened] workflow_dispatch: env: diff --git a/.github/workflows/deploy_and_release.yml b/.github/workflows/deploy_and_release.yml index cc5e0835f..83979b5e0 100644 --- a/.github/workflows/deploy_and_release.yml +++ b/.github/workflows/deploy_and_release.yml @@ -31,6 +31,21 @@ jobs: OSSRH_USERNAME: ${{ secrets.SONATYPE_USER }} OSSRH_PASSWORD: ${{ secrets.SONATYPE_PW }} + synchronize: + runs-on: ubuntu-latest + needs: deployment + steps: + - name: Checkout source code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Synchronize master and develop + run: | + gh pr create -B develop -H master -t "Synchronize version in master and develop" -b "Update the version in `develop` from `master`" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + release: runs-on: ubuntu-latest needs: deployment @@ -77,7 +92,7 @@ jobs: - name: Zip JavaCryptographicArchitecture folder run: | echo "Zipping the JavaCryptographicArchitecture folder..." - zip -r JavaCryptographicArchitecture.zip CryptoAnalysis/src/main/resources/JavaCryptographicArchitecture + zip -r JavaCryptographicArchitecture.zip CryptoAnalysis/src/test/resources/rules/JavaCryptographicArchitecture - name: Create GitHub Release run: | diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml new file mode 100644 index 000000000..3d6f63026 --- /dev/null +++ b/.github/workflows/performance.yml @@ -0,0 +1,182 @@ +name: Performance Analysis + +on: + workflow_dispatch: + #inputs: + # analysis: + # type: boolean + # required: false + # default: false + # android: + # type: boolean + # required: false + # default: false + # soot: + # type: boolean + # required: false + # default: false + +env: + JAVA_VERSION: 17 + +jobs: + performance-analysis: + runs-on: ubuntu-latest + steps: + - name: Checkout source code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Build and test Analysis + uses: ./.github/actions/analysis + with: + java-version: ${{ env.JAVA_VERSION }} + + - name: Create or update gh-pages-output directory + run: mkdir -p gh-pages-output + + - name: Extract performance + uses: ./.github/actions/performance + with: + test-results-path: CryptoAnalysis/shippable/testresults + source-branch: gh-pages + current-results: analysis_history.txt + output-file: gh-pages-output/analysis_history.txt + + - name: Store Analysis performance + uses: actions/upload-artifact@v4 + with: + name: analysis-performance + path: gh-pages-output/analysis_history.txt + + performance-android: + runs-on: ubuntu-latest + steps: + - name: Checkout source code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Build and test Android Scanner + uses: ./.github/actions/scanner-android + with: + java-version: ${{ env.JAVA_VERSION }} + + - name: Create or update gh-pages-output directory + run: mkdir -p gh-pages-output + + - name: Extract performance + uses: ./.github/actions/performance + with: + test-results-path: HeadlessAndroidScanner/shippable/testresults + source-branch: gh-pages + current-results: android_history.txt + output-file: gh-pages-output/android_history.txt + + - name: Store Android performance + uses: actions/upload-artifact@v4 + with: + name: android-performance + path: gh-pages-output/android_history.txt + + performance-soot: + runs-on: ubuntu-latest + steps: + - name: Checkout source code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Build and test JavaScanner with Soot + uses: ./.github/actions/scanner-soot + with: + java-version: ${{ env.JAVA_VERSION }} + + - name: Create or update gh-pages-output directory + run: mkdir -p gh-pages-output + + - name: Extract performance + uses: ./.github/actions/performance + with: + test-results-path: HeadlessJavaScanner/shippable/testresults + source-branch: gh-pages + current-results: soot_history.txt + output-file: gh-pages-output/soot_history.txt + + - name: Store Soot performance + uses: actions/upload-artifact@v4 + with: + name: soot-performance + path: gh-pages-output/soot_history.txt + + performance-report: + runs-on: ubuntu-latest + needs: [performance-analysis, performance-android, performance-soot] + steps: + - name: Checkout source code + uses: actions/checkout@v4 + with: + ref: gh-pages + + - name: Load performance files + uses: actions/download-artifact@v4 + with: + path: gh-pages-output + merge-multiple: true + + - name: Generate HTML report + run: | + echo "" > gh-pages-output/index.html + echo "
" >> gh-pages-output/index.html + + echo "

Analysis

" >> gh-pages-output/index.html + + echo "

AndroidScanner

" >> gh-pages-output/index.html + + echo "

JavaScanner (Soot)

" >> gh-pages-output/index.html + + echo "
" >> gh-pages-output/index.html + echo "" >> gh-pages-output/index.html + + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./gh-pages-output + + - name: Delete artifacts + uses: geekyeggo/delete-artifact@v5 + with: + failOnError: false + name: | + analysis-performance + android-performance + soot-performance diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml index 894f1638b..6ca3ce780 100644 --- a/.github/workflows/style.yml +++ b/.github/workflows/style.yml @@ -14,6 +14,13 @@ jobs: steps: - name: Checkout source code uses: actions/checkout@v4 + # Set up Java version + - name: Set up Java 17 + uses: actions/setup-java@v4 + with: + distribution: adopt + java-package: jdk + java-version: 17 # Restores Maven dependecies - name: Restore local Maven repository uses: actions/cache@v4 diff --git a/CryptoAnalysis/pom.xml b/CryptoAnalysis/pom.xml index fba3340cc..c95574625 100644 --- a/CryptoAnalysis/pom.xml +++ b/CryptoAnalysis/pom.xml @@ -75,6 +75,11 @@ jackson-databind 2.18.2 + + org.graphper + graph-support + 1.4.0 + diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/EnsuredCrySLPredicate.java b/CryptoAnalysis/src/main/java/crypto/analysis/AbstractPredicate.java similarity index 52% rename from CryptoAnalysis/src/main/java/crypto/analysis/EnsuredCrySLPredicate.java rename to CryptoAnalysis/src/main/java/crypto/analysis/AbstractPredicate.java index 6c33d3bba..fd3c20082 100644 --- a/CryptoAnalysis/src/main/java/crypto/analysis/EnsuredCrySLPredicate.java +++ b/CryptoAnalysis/src/main/java/crypto/analysis/AbstractPredicate.java @@ -3,13 +3,20 @@ import crypto.extractparameter.CallSiteWithExtractedValue; import crysl.rule.CrySLPredicate; import java.util.Collection; +import java.util.Objects; -public class EnsuredCrySLPredicate { +/** + * Super class for predicates that are propagated during the analysis. Each predicate is either an + * {@link EnsuredPredicate} or an {@link UnEnsuredPredicate}. The former ones keep track of all + * predicates from the ENSURES section where no violations from a rule are found. The latter ones + * are propagated to keep track of predicates and seeds if there is a violation. + */ +public abstract class AbstractPredicate { private final CrySLPredicate predicate; private final Collection parametersToValues; - public EnsuredCrySLPredicate( + public AbstractPredicate( CrySLPredicate predicate, Collection parametersToValues) { this.predicate = predicate; this.parametersToValues = parametersToValues; @@ -23,27 +30,14 @@ public Collection getParametersToValues() { return parametersToValues; } - public String toString() { - return "Proved " + predicate.getPredName(); - } - @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((predicate == null) ? 0 : predicate.hashCode()); - return result; + return Objects.hash(predicate); } @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - EnsuredCrySLPredicate other = (EnsuredCrySLPredicate) obj; - if (predicate == null) { - if (other.predicate != null) return false; - } else if (!predicate.equals(other.predicate)) return false; - return true; + return obj instanceof AbstractPredicate other + && Objects.equals(predicate, other.getPredicate()); } } diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/AlternativeReqPredicate.java b/CryptoAnalysis/src/main/java/crypto/analysis/AlternativeReqPredicate.java index ec51d68ef..222f1e505 100644 --- a/CryptoAnalysis/src/main/java/crypto/analysis/AlternativeReqPredicate.java +++ b/CryptoAnalysis/src/main/java/crypto/analysis/AlternativeReqPredicate.java @@ -4,90 +4,89 @@ import crysl.rule.CrySLPredicate; import crysl.rule.ISLConstraint; import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.Objects; +import java.util.Set; import java.util.stream.Collectors; +/** + * Wrapper class for required predicates with alternatives. Predicates from the REQUIRES section may + * have the following form: + * + *
{@code
+ * REQUIRES
+ *    generatedKey[...] || generatedPubKey[...] || generatedPrivKey[...];
+ * }
+ * + * According to the CrySL specification, "generatedKey" is the base predicate that determines the + * statement where the predicates should be ensured. If an alternative refers to some other + * statement, it is ignored for this predicate. + */ public class AlternativeReqPredicate implements ISLConstraint { - private final List alternatives; - private final Statement stmt; - private final int paramIndex; + private final RequiredCrySLPredicate basePredicate; + private final Collection allAlternatives; + private final Collection relAlternatives; - public AlternativeReqPredicate(CrySLPredicate alternativeOne, Statement stmt, int paramIndex) { - this.alternatives = new ArrayList<>(); - this.alternatives.add(alternativeOne); - this.stmt = stmt; - this.paramIndex = paramIndex; + public AlternativeReqPredicate( + RequiredCrySLPredicate basePredicate, + Collection allAlternatives, + Collection relAlternatives) { + this.basePredicate = basePredicate; + this.allAlternatives = List.copyOf(allAlternatives); + this.relAlternatives = Set.copyOf(relAlternatives); } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((alternatives == null) ? 0 : alternatives.hashCode()); - result = prime * result + ((stmt == null) ? 0 : stmt.hashCode()); - result = prime * result + paramIndex; - return result; + public Collection getAllAlternatives() { + return allAlternatives; } - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - AlternativeReqPredicate other = (AlternativeReqPredicate) obj; - if (alternatives == null) { - if (other.alternatives != null) return false; - } else if (!alternatives.equals(other.alternatives)) return false; - if (stmt == null) { - return other.stmt == null; - } else if (!stmt.equals(other.stmt)) { - return false; - } - - return paramIndex == other.paramIndex; + public Collection getRelAlternatives() { + return relAlternatives; } public Statement getLocation() { - return stmt; - } - - public int getParamIndex() { - return paramIndex; + return basePredicate.getLocation(); } @Override - public String toString() { - return alternatives.stream() - .map(CrySLPredicate::toString) - .collect(Collectors.joining(" OR ")) - + " @ " - + stmt - + " @ index " - + paramIndex; + public List getInvolvedVarNames() { + List involvedVarNames = new ArrayList<>(); + for (CrySLPredicate alt : allAlternatives) { + involvedVarNames.addAll(alt.getInvolvedVarNames()); + } + return involvedVarNames; } @Override public String getName() { - return alternatives.stream() + return allAlternatives.stream() .map(CrySLPredicate::getName) .collect(Collectors.joining(" OR ")); } @Override - public List getInvolvedVarNames() { - List involvedVarNames = new ArrayList<>(); - for (CrySLPredicate alt : alternatives) { - involvedVarNames.addAll(alt.getInvolvedVarNames()); - } - return involvedVarNames; + public int hashCode() { + return Objects.hash(allAlternatives, relAlternatives); } - public List getAlternatives() { - return alternatives; + @Override + public boolean equals(Object obj) { + return obj instanceof AlternativeReqPredicate other + && Objects.equals(allAlternatives, other.getAllAlternatives()) + && Objects.equals(relAlternatives, other.getRelAlternatives()); } - public void addAlternative(CrySLPredicate newAlt) { - alternatives.add(newAlt); + @Override + public String toString() { + return allAlternatives.stream() + .map(CrySLPredicate::toString) + .collect(Collectors.joining(" OR ")) + + " (Rel: " + + relAlternatives.stream() + .map(e -> e.getPred().toString()) + .collect(Collectors.joining(", ")) + + ")"; } } diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/AnalysisSeedWithEnsuredPredicate.java b/CryptoAnalysis/src/main/java/crypto/analysis/AnalysisSeedWithEnsuredPredicate.java index eee9d5c3b..4f5f8684d 100644 --- a/CryptoAnalysis/src/main/java/crypto/analysis/AnalysisSeedWithEnsuredPredicate.java +++ b/CryptoAnalysis/src/main/java/crypto/analysis/AnalysisSeedWithEnsuredPredicate.java @@ -9,6 +9,7 @@ import com.google.common.collect.Multimap; import crysl.rule.CrySLPredicate; import java.util.Collection; +import java.util.Objects; import typestate.TransitionFunction; public class AnalysisSeedWithEnsuredPredicate extends IAnalysisSeed { @@ -104,23 +105,21 @@ public void expectPredicate( } } - public void addEnsuredPredicate(EnsuredCrySLPredicate predicate) { + public void addEnsuredPredicate(AbstractPredicate predicate) { for (Statement statement : expectedPredicates.keySet()) { Collection predicateOnSeeds = expectedPredicates.get(statement); for (ExpectedPredicateOnSeed predOnSeed : predicateOnSeeds) { - if (!predOnSeed.getPredicate().equals(predicate.getPredicate())) { + if (!predOnSeed.predicate().equals(predicate.getPredicate())) { continue; } - if (!(predOnSeed.getSeed() instanceof AnalysisSeedWithSpecification)) { + if (!(predOnSeed.seed() instanceof AnalysisSeedWithSpecification seedWithSpec)) { continue; } - AnalysisSeedWithSpecification seedWithSpec = - (AnalysisSeedWithSpecification) predOnSeed.getSeed(); - seedWithSpec.addEnsuredPredicate(predicate, statement, predOnSeed.getParamIndex()); + seedWithSpec.addEnsuredPredicate(predicate, statement, predOnSeed.paramIndex()); } } @@ -131,7 +130,7 @@ public void addEnsuredPredicate(EnsuredCrySLPredicate predicate) { @Override public int hashCode() { - return super.hashCode(); + return Objects.hash(super.hashCode()); } @Override diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/AnalysisSeedWithSpecification.java b/CryptoAnalysis/src/main/java/crypto/analysis/AnalysisSeedWithSpecification.java index bea8f9bd2..8f961dbcc 100644 --- a/CryptoAnalysis/src/main/java/crypto/analysis/AnalysisSeedWithSpecification.java +++ b/CryptoAnalysis/src/main/java/crypto/analysis/AnalysisSeedWithSpecification.java @@ -14,7 +14,6 @@ import crypto.analysis.errors.AbstractError; import crypto.analysis.errors.ForbiddenMethodError; import crypto.analysis.errors.IncompleteOperationError; -import crypto.analysis.errors.RequiredPredicateError; import crypto.analysis.errors.TypestateError; import crypto.constraints.ConstraintSolver; import crypto.constraints.EvaluableConstraint; @@ -40,6 +39,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; import typestate.TransitionFunction; @@ -57,11 +57,11 @@ public class AnalysisSeedWithSpecification extends IAnalysisSeed { private final Map allCallsOnObject; private final Collection requiringSeeds = new HashSet<>(); - private final Multimap> ensuredPredicates = + private final Multimap> ensuredPredicates = HashMultimap.create(); - private final Multimap> hiddenPredicates = + private final Multimap> hiddenPredicates = HashMultimap.create(); - private final Collection indirectlyEnsuredPredicates = new HashSet<>(); + private final Collection indirectlyEnsuredPredicates = new HashSet<>(); public AnalysisSeedWithSpecification( CryptoScanner scanner, @@ -121,6 +121,7 @@ private void evaluateForbiddenMethods() { ForbiddenMethodError error = new ForbiddenMethodError( this, statement, specification, declaredMethod, alternatives); + this.addError(error); scanner.getAnalysisReporter().reportError(this, error); } } @@ -172,12 +173,10 @@ private void evaluateTypestateOrder() { private void typeStateChangeAtStatement(Statement statement, State stateNode) { if (typeStateChange.put(statement, stateNode)) { - if (stateNode instanceof ReportingErrorStateNode) { - ReportingErrorStateNode errorStateNode = (ReportingErrorStateNode) stateNode; - + if (stateNode instanceof ReportingErrorStateNode errorStateNode) { TypestateError typestateError = new TypestateError( - this, statement, specification, errorStateNode.getExpectedCalls()); + this, statement, specification, errorStateNode.expectedCalls()); this.addError(typestateError); scanner.getAnalysisReporter().reportError(this, typestateError); } @@ -202,11 +201,10 @@ private void evaluateIncompleteOperations() { continue; } - if (!(n.to() instanceof WrappedState)) { + if (!(n.to() instanceof WrappedState wrappedState)) { continue; } - WrappedState wrappedState = (WrappedState) n.to(); for (TransitionEdge t : specification.getUsagePattern().getAllTransitions()) { if (t.getLeft().equals(wrappedState.delegate()) && !t.from().equals(t.to())) { Collection labels = t.getLabel(); @@ -303,7 +301,14 @@ private boolean isMethodToAcceptingState(DeclaredMethod method) { @Override public void expectPredicate( Statement statement, CrySLPredicate predicate, IAnalysisSeed seed, int paramIndex) { - expectedPredicates.put(statement, new ExpectedPredicateOnSeed(predicate, seed, paramIndex)); + CrySLPredicate expectedPred; + if (predicate.isNegated()) { + expectedPred = predicate.invertNegation(); + } else { + expectedPred = predicate; + } + expectedPredicates.put( + statement, new ExpectedPredicateOnSeed(expectedPred, seed, paramIndex)); } public void addRequiringSeed(AnalysisSeedWithSpecification seed) { @@ -322,20 +327,17 @@ public void computeExpectedPredicates(Collection seeds) { private void initializeDependantSeedsFromRequiredPredicates(Collection seeds) { Multimap> reqPreds = HashMultimap.create(); for (ISLConstraint constraint : constraintSolver.getRequiredPredicates()) { - if (constraint instanceof RequiredCrySLPredicate) { - RequiredCrySLPredicate reqPred = (RequiredCrySLPredicate) constraint; - + if (constraint instanceof RequiredCrySLPredicate reqPred) { Map.Entry entry = new AbstractMap.SimpleEntry<>(reqPred.getPred(), reqPred.getParamIndex()); reqPreds.put(reqPred.getLocation(), entry); - } else if (constraint instanceof AlternativeReqPredicate) { - AlternativeReqPredicate altPred = (AlternativeReqPredicate) constraint; + } else if (constraint instanceof AlternativeReqPredicate altPred) { + for (RequiredCrySLPredicate reqPred : altPred.getRelAlternatives()) { + CrySLPredicate predicate = reqPred.getPred(); - for (CrySLPredicate predicate : altPred.getAlternatives()) { Map.Entry entry = - new AbstractMap.SimpleEntry<>(predicate, altPred.getParamIndex()); - - reqPreds.put(altPred.getLocation(), entry); + new AbstractMap.SimpleEntry<>(predicate, reqPred.getParamIndex()); + reqPreds.put(reqPred.getLocation(), entry); } } } @@ -362,7 +364,8 @@ private void initializeDependantSeedsFromRequiredPredicates(Collection requiredSeeds = computeRequiredSeeds(statement, base, seeds); for (IAnalysisSeed seed : requiredSeeds) { - seed.expectPredicate(statement, predicate, this, paramIndex); + seed.expectPredicate( + statement, predicate.toNormalCrySLPredicate(), this, paramIndex); if (seed instanceof AnalysisSeedWithSpecification) { ((AnalysisSeedWithSpecification) seed).addRequiringSeed(this); @@ -374,7 +377,8 @@ private void initializeDependantSeedsFromRequiredPredicates(Collection requiredSeeds = computeRequiredSeeds(statement, param, seeds); for (IAnalysisSeed seed : requiredSeeds) { - seed.expectPredicate(statement, predicate, this, paramIndex); + seed.expectPredicate( + statement, predicate.toNormalCrySLPredicate(), this, paramIndex); if (seed instanceof AnalysisSeedWithSpecification) { ((AnalysisSeedWithSpecification) seed).addRequiringSeed(this); @@ -445,7 +449,7 @@ private void initializeDependantSeedsFromEnsuringPredicates(Collection methods = @@ -462,7 +466,8 @@ private void initializeDependantSeedsFromEnsuringPredicates(Collection dependentAssignSeeds = computeGeneratedAssignSeeds(statement, allocVal, seeds); for (IAnalysisSeed seed : dependentAssignSeeds) { - this.expectPredicate(statement, predicate, seed, -1); + this.expectPredicate( + statement, predicate.toNormalCrySLPredicate(), seed, -1); } } @@ -475,7 +480,8 @@ private void initializeDependantSeedsFromEnsuringPredicates(Collection dependantParamSeeds = computeGeneratedParameterSeeds(entry.getKey(), paramVal, seeds); for (IAnalysisSeed seed : dependantParamSeeds) { - this.expectPredicate(statement, predicate, seed, i); + this.expectPredicate( + statement, predicate.toNormalCrySLPredicate(), seed, i); } } } @@ -546,92 +552,103 @@ private Collection computeGeneratedParameterSeeds( return result; } + /** + * Ensure the predicates from the ENSURES section and transfer them to this seed or other seeds. + * If there are no violations for the rule, propagate an {@link EnsuredPredicate}. Otherwise, if + * there is at least one violation, collect them and propagate a corresponding {@link + * UnEnsuredPredicate}. + */ public void ensurePredicates() { + // Check whether all constraints from the CONSTRAINTS and REQUIRES section is satisfied boolean satisfiesConstraintSystem = isConstraintSystemSatisfied(); Collection expectedPredStatements = expectedPredicates.keySet(); + // TODO Check for relevant predicates? Collection predsToBeEnsured = new HashSet<>(specification.getPredicates()); - for (EnsuredCrySLPredicate predicate : indirectlyEnsuredPredicates) { + for (AbstractPredicate predicate : indirectlyEnsuredPredicates) { predsToBeEnsured.add(predicate.getPredicate().toNormalCrySLPredicate()); } for (CrySLPredicate predToBeEnsured : predsToBeEnsured) { + Collection violations = new HashSet<>(); - for (Statement statement : expectedPredStatements) { - boolean isPredicateGeneratingStateAvailable = false; + // Check whether there is a ForbiddenMethodError from previous checks + if (errorCollection.stream().anyMatch(e -> e instanceof ForbiddenMethodError)) { + violations.add(UnEnsuredPredicate.Violations.CallToForbiddenMethod); + } + + if (!satisfiesConstraintSystem) { + violations.add(UnEnsuredPredicate.Violations.ConstraintsAreNotSatisfied); + } - if (!expectedPredicatesAtStatement(statement) - .contains(predToBeEnsured.toNormalCrySLPredicate())) { + // Check whether there is a predicate condition and whether it is satisfied + if (predToBeEnsured.getConstraint().isPresent() + && isPredConditionViolated(predToBeEnsured)) { + violations.add(UnEnsuredPredicate.Violations.ConditionIsNotSatisfied); + } + + for (Statement statement : expectedPredStatements) { + Collection expectedPreds = expectedPredicatesAtStatement(statement); + if (!expectedPreds.contains(predToBeEnsured.toNormalCrySLPredicate())) { continue; } + /* Check for all states whether an accepting state is reached: + * 1) All states are accepting -> Predicate is generated + * 2) No state is accepting -> Predicate is definitely not generated + * 3) There are generating and non-generating states -> At least one + * dataflow path leads to a non-generating state s.t. the predicate + * is not generated (over approximation) + */ Collection states = getStatesAtStatement(statement); - - for (State state : states) { - // Check, whether the predicate should be generated in state - if (!isPredicateGeneratingState(predToBeEnsured, state)) { - continue; - } - - // Check, whether the predicate is not negated in state - if (isPredicateNegatingState(predToBeEnsured, state)) { - continue; - } - - isPredicateGeneratingStateAvailable = true; - EnsuredCrySLPredicate ensPred; - if (!satisfiesConstraintSystem && predToBeEnsured.getConstraint().isEmpty()) { - // predicate has no condition, but the constraint system is not satisfied - ensPred = - new HiddenPredicate( - predToBeEnsured, - constraintSolver.getCollectedValues(), - this, - HiddenPredicate.HiddenPredicateType - .ConstraintsAreNotSatisfied); - } else if (predToBeEnsured.getConstraint().isPresent() - && isPredConditionViolated(predToBeEnsured)) { - // predicate has condition, but condition is not satisfied - ensPred = - new HiddenPredicate( - predToBeEnsured, - constraintSolver.getCollectedValues(), - this, - HiddenPredicate.HiddenPredicateType - .ConditionIsNotSatisfied); - } else { - // constraints are satisfied and predicate has no condition or the condition - // is satisfied - ensPred = - new EnsuredCrySLPredicate( - predToBeEnsured, constraintSolver.getCollectedValues()); - } - - ensurePredicateAtStatement(ensPred, statement); + boolean allStatesNonGenerating = + states.stream() + .noneMatch(s -> doesStateGeneratePredicate(s, predToBeEnsured)); + boolean someStatesNonGenerating = + states.stream() + .anyMatch(s -> !doesStateGeneratePredicate(s, predToBeEnsured)); + + Collection allViolations = new HashSet<>(violations); + if (allStatesNonGenerating) { + allViolations.add(UnEnsuredPredicate.Violations.GeneratingStateIsNeverReached); + } else if (someStatesNonGenerating) { + /* TODO + * Due to a bug, IDEal returns the states [0,1] whenever there is a + * single call to a method, e.g. Object o = new Object(); o.m();. After + * the call to m1(), o is always in state 0 and 1, although it should only be 1 + */ + // allViolations.add(UnEnsuredPredicate.Violations.GeneratingStateMayNotBeReached); } - if (!isPredicateGeneratingStateAvailable) { - /* The predicate is not ensured in any state. However, we propagate a hidden predicate - * for all typestate changing statements because the predicate could have been ensured - * if a generating state had been reached - */ - HiddenPredicate hiddenPredicate = - new HiddenPredicate( - predToBeEnsured, + AbstractPredicate generatedPred; + if (!allViolations.isEmpty()) { + generatedPred = + new UnEnsuredPredicate( + predToBeEnsured.toNormalCrySLPredicate(), constraintSolver.getCollectedValues(), this, - HiddenPredicate.HiddenPredicateType - .GeneratingStateIsNeverReached); - ensurePredicateAtStatement(hiddenPredicate, statement); + allViolations); + } else { + generatedPred = + new EnsuredPredicate( + predToBeEnsured.toNormalCrySLPredicate(), + constraintSolver.getCollectedValues()); } + + ensurePredicateAtStatement(generatedPred, statement); } } scanner.getAnalysisReporter().ensuredPredicates(this, ensuredPredicates); } - private void ensurePredicateAtStatement(EnsuredCrySLPredicate ensPred, Statement statement) { + private boolean doesStateGeneratePredicate(State state, CrySLPredicate predicate) { + return isPredicateGeneratingState(predicate, state) + && !isPredicateNegatingState(predicate, state); + } + + private void ensurePredicateAtStatement(AbstractPredicate ensPred, Statement statement) { if (hasThisParameter(ensPred.getPredicate())) { this.addEnsuredPredicate(ensPred, statement, -1); scanner.getAnalysisReporter().onGeneratedPredicate(this, ensPred, this, statement); @@ -644,22 +661,16 @@ private void ensurePredicateAtStatement(EnsuredCrySLPredicate ensPred, Statement Collection expectedPredsAtStatement = expectedPredicates.get(statement); for (ExpectedPredicateOnSeed expectedPredicateOnSeed : expectedPredsAtStatement) { - CrySLPredicate predicate = expectedPredicateOnSeed.getPredicate(); - IAnalysisSeed seed = expectedPredicateOnSeed.getSeed(); - int paramIndex = expectedPredicateOnSeed.getParamIndex(); + CrySLPredicate predicate = expectedPredicateOnSeed.predicate(); + IAnalysisSeed seed = expectedPredicateOnSeed.seed(); + int paramIndex = expectedPredicateOnSeed.paramIndex(); if (predicate.equals(ensPred.getPredicate())) { - if (seed instanceof AnalysisSeedWithSpecification) { - AnalysisSeedWithSpecification seedWithSpec = - (AnalysisSeedWithSpecification) seed; - + if (seed instanceof AnalysisSeedWithSpecification seedWithSpec) { seedWithSpec.addEnsuredPredicateFromOtherRule(ensPred, statement, paramIndex); scanner.getAnalysisReporter() .onGeneratedPredicate(this, ensPred, seedWithSpec, statement); - } else if (seed instanceof AnalysisSeedWithEnsuredPredicate) { - AnalysisSeedWithEnsuredPredicate seedWithoutSpec = - (AnalysisSeedWithEnsuredPredicate) seed; - + } else if (seed instanceof AnalysisSeedWithEnsuredPredicate seedWithoutSpec) { seedWithoutSpec.addEnsuredPredicate(ensPred); scanner.getAnalysisReporter() .onGeneratedPredicate(this, ensPred, seedWithoutSpec, statement); @@ -669,7 +680,7 @@ private void ensurePredicateAtStatement(EnsuredCrySLPredicate ensPred, Statement } private void addEnsuredPredicateFromOtherRule( - EnsuredCrySLPredicate pred, Statement statement, int paramIndex) { + AbstractPredicate pred, Statement statement, int paramIndex) { addEnsuredPredicate(pred, statement, paramIndex); indirectlyEnsuredPredicates.add(pred); } @@ -707,16 +718,14 @@ private Collection getStatesAtStatement(Statement statement) { } public void addEnsuredPredicate( - EnsuredCrySLPredicate ensPred, Statement statement, int paramIndex) { - if (ensPred instanceof HiddenPredicate) { - HiddenPredicate hiddenPredicate = (HiddenPredicate) ensPred; - - Map.Entry predAtIndex = - new AbstractMap.SimpleEntry<>(hiddenPredicate, paramIndex); + AbstractPredicate ensPred, Statement statement, int paramIndex) { + if (ensPred instanceof UnEnsuredPredicate unEnsuredPredicate) { + Map.Entry predAtIndex = + new AbstractMap.SimpleEntry<>(unEnsuredPredicate, paramIndex); hiddenPredicates.put(statement, predAtIndex); - } else { - Map.Entry predAtIndex = - new AbstractMap.SimpleEntry<>(ensPred, paramIndex); + } else if (ensPred instanceof EnsuredPredicate ensuredPredicate) { + Map.Entry predAtIndex = + new AbstractMap.SimpleEntry<>(ensuredPredicate, paramIndex); ensuredPredicates.put(statement, predAtIndex); } } @@ -771,12 +780,10 @@ private boolean isPredicateNegatingState(CrySLPredicate ensPred, State stateNode // Negated predicate does not have a condition, i.e. no "after" -> predicate is negated // in all states - if (!(negPred instanceof CrySLCondPredicate)) { + if (!(negPred instanceof CrySLCondPredicate condNegPred)) { return true; } - CrySLCondPredicate condNegPred = (CrySLCondPredicate) negPred; - for (StateNode s : condNegPred.getConditionalMethods()) { if (WrappedState.of(s).equals(stateNode)) { return true; @@ -822,6 +829,7 @@ private void checkInternalConstraints() { Collection violatedConstraints = constraintSolver.evaluateConstraints(); for (AbstractError violatedConstraint : violatedConstraints) { + this.addError(violatedConstraint); scanner.getAnalysisReporter().reportError(this, violatedConstraint); } @@ -855,96 +863,126 @@ private boolean isConstraintSystemSatisfied() { * @return remainingPredicates predicates that are not satisfied */ public Collection computeMissingPredicates() { - Collection requiredPredicates = constraintSolver.getRequiredPredicates(); - Collection remainingPredicates = new HashSet<>(requiredPredicates); + Collection violatedReqPreds = computeViolatedRequiredPredicates(); + Collection violatedAltPreds = + computeViolatedAlternativePredicates(); - for (ISLConstraint pred : requiredPredicates) { - if (pred instanceof RequiredCrySLPredicate) { - RequiredCrySLPredicate reqPred = (RequiredCrySLPredicate) pred; + Collection result = new HashSet<>(); + result.addAll(violatedReqPreds); + result.addAll(violatedAltPreds); - // If a negated predicate is ensured, a PredicateContradictionError has to be - // reported - if (reqPred.getPred().isNegated()) { - remainingPredicates.remove(pred); - continue; - } + return result; + } - // Check for basic required predicates, e.g. randomized - Collection> predsAtStatement = - ensuredPredicates.get(reqPred.getLocation()); - int reqParamIndex = reqPred.getParamIndex(); - for (Map.Entry ensPredAtIndex : predsAtStatement) { - if (doReqPredAndEnsPredMatch( - reqPred.getPred(), reqParamIndex, ensPredAtIndex)) { - remainingPredicates.remove(pred); - } - } - } else if (pred instanceof AlternativeReqPredicate) { - AlternativeReqPredicate altPred = (AlternativeReqPredicate) pred; - Collection alternatives = altPred.getAlternatives(); - Collection positives = - alternatives.stream() - .filter(e -> !e.isNegated()) - .collect(Collectors.toList()); - Collection negatives = - alternatives.stream() - .filter(CrySLPredicate::isNegated) - .collect(Collectors.toList()); - int altParamIndex = altPred.getParamIndex(); - - boolean satisfied = false; - Collection ensuredNegatives = - alternatives.stream() - .filter(CrySLPredicate::isNegated) - .collect(Collectors.toList()); - - Collection> predsAtStatement = - ensuredPredicates.get(altPred.getLocation()); - for (Map.Entry ensPredAtIndex : predsAtStatement) { - // If any positive alternative is satisfied, the whole predicate is satisfied - if (positives.stream() - .anyMatch( - e -> - doReqPredAndEnsPredMatch( - e, altParamIndex, ensPredAtIndex))) { - satisfied = true; - } + public Collection computeViolatedRequiredPredicates() { + Collection requiredPredicates = new HashSet<>(); - // Remove all negated alternatives that are ensured - Collection violatedNegAlternatives = - negatives.stream() - .filter( - e -> - doReqPredAndEnsPredMatch( - e, altParamIndex, ensPredAtIndex)) - .collect(Collectors.toList()); - ensuredNegatives.removeAll(violatedNegAlternatives); - } + Collection reqPreds = constraintSolver.getRequiredPredicates(); + for (ISLConstraint constraint : reqPreds) { + if (constraint instanceof RequiredCrySLPredicate reqPred) { + requiredPredicates.add(reqPred); + } + } + + Collection remainingPredicates = new HashSet<>(requiredPredicates); - if (satisfied || !ensuredNegatives.isEmpty()) { - remainingPredicates.remove(pred); + // Remove all ensured predicates from the required predicates set -> only not ensured + // predicates are left + for (RequiredCrySLPredicate reqPred : requiredPredicates) { + // If a negated predicate is ensured, a PredicateContradictionError has to be reported + if (reqPred.getPred().isNegated()) { + remainingPredicates.remove(reqPred); + continue; + } + + // Check for basic required predicates, e.g. randomized + Collection> predsAtStatement = + ensuredPredicates.get(reqPred.getLocation()); + int reqParamIndex = reqPred.getParamIndex(); + for (Map.Entry ensPredAtIndex : predsAtStatement) { + if (doReqPredAndEnsPredMatch(reqPred.getPred(), reqParamIndex, ensPredAtIndex)) { + remainingPredicates.remove(reqPred); } } } // Check conditional required predicates - for (ISLConstraint rem : new HashSet<>(remainingPredicates)) { - if (rem instanceof RequiredCrySLPredicate) { - RequiredCrySLPredicate singlePred = (RequiredCrySLPredicate) rem; + for (RequiredCrySLPredicate rem : new HashSet<>(remainingPredicates)) { + if (isPredConditionViolated(rem.getPred())) { + remainingPredicates.remove(rem); + } + } - if (isPredConditionViolated(singlePred.getPred())) { - remainingPredicates.remove(singlePred); + return remainingPredicates; + } + + public Collection computeViolatedAlternativePredicates() { + Collection alternativeReqPredicates = new HashSet<>(); + + Collection reqPreds = constraintSolver.getRequiredPredicates(); + for (ISLConstraint constraint : reqPreds) { + if (constraint instanceof AlternativeReqPredicate reqPred) { + alternativeReqPredicates.add(reqPred); + } + } + + Collection remainingPredicates = + new HashSet<>(alternativeReqPredicates); + + for (AlternativeReqPredicate altPred : alternativeReqPredicates) { + Collection positives = new HashSet<>(); + Collection negatives = new HashSet<>(); + + Collection relAlternatives = altPred.getRelAlternatives(); + for (RequiredCrySLPredicate reqPred : relAlternatives) { + CrySLPredicate predicate = reqPred.getPred(); + + if (predicate.isNegated()) { + negatives.add(reqPred); + } else { + positives.add(reqPred); + } + } + + boolean satisfied = false; + + // If any positive alternative is satisfied, the whole predicate is satisfied + for (RequiredCrySLPredicate positive : positives) { + CrySLPredicate predicate = positive.getPred(); + int paramIndex = positive.getParamIndex(); + + Collection> predsAtStatement = + ensuredPredicates.get(altPred.getLocation()); + for (Map.Entry ensPred : predsAtStatement) { + if (doReqPredAndEnsPredMatch(predicate, paramIndex, ensPred)) { + satisfied = true; + } } - } else if (rem instanceof AlternativeReqPredicate) { - Collection altPred = - ((AlternativeReqPredicate) rem).getAlternatives(); + } + + Collection ensuredNegatives = new HashSet<>(negatives); - if (altPred.parallelStream().anyMatch(this::isPredConditionViolated)) { - remainingPredicates.remove(rem); + // Remove all negated predicates that are ensured + for (RequiredCrySLPredicate negative : negatives) { + CrySLPredicate predicate = negative.getPred(); + int paramIndex = negative.getParamIndex(); + + Collection> predsAtStatement = + ensuredPredicates.get(altPred.getLocation()); + for (Map.Entry ensPred : predsAtStatement) { + if (doReqPredAndEnsPredMatch(predicate, paramIndex, ensPred)) { + ensuredNegatives.remove(negative); + } } } + + if (satisfied || !ensuredNegatives.isEmpty()) { + remainingPredicates.remove(altPred); + } } + // TODO Check condition + return remainingPredicates; } @@ -953,9 +991,7 @@ public Collection computeContradictedPredicates() { Collection contradictedPredicates = new HashSet<>(); for (ISLConstraint pred : requiredPredicates) { - if (pred instanceof RequiredCrySLPredicate) { - RequiredCrySLPredicate reqPred = (RequiredCrySLPredicate) pred; - + if (pred instanceof RequiredCrySLPredicate reqPred) { // Only negated predicates can be contradicted if (!reqPred.getPred().isNegated()) { continue; @@ -967,10 +1003,10 @@ public Collection computeContradictedPredicates() { // Check for basic negated required predicates, e.g. randomized CrySLPredicate invertedPred = reqPred.getPred().invertNegation(); - Collection> predsAtStatement = + Collection> predsAtStatement = ensuredPredicates.get(reqPred.getLocation()); - for (Map.Entry ensPredAtIndex : predsAtStatement) { + for (Map.Entry ensPredAtIndex : predsAtStatement) { if (doReqPredAndEnsPredMatch( invertedPred, reqPred.getParamIndex(), ensPredAtIndex)) { contradictedPredicates.add(reqPred); @@ -985,9 +1021,15 @@ public Collection computeContradictedPredicates() { private boolean doReqPredAndEnsPredMatch( CrySLPredicate reqPred, int reqPredIndex, - Map.Entry ensPred) { - return reqPred.equals(ensPred.getKey().getPredicate()) - && doPredsMatch(reqPred, ensPred.getKey()) + Map.Entry ensPred) { + CrySLPredicate predToCheck; + if (reqPred.isNegated()) { + predToCheck = reqPred.invertNegation(); + } else { + predToCheck = reqPred; + } + return predToCheck.equals(ensPred.getKey().getPredicate()) + && doPredsMatch(predToCheck, ensPred.getKey()) && reqPredIndex == ensPred.getValue(); } @@ -1009,44 +1051,33 @@ private boolean isPredConditionViolated(CrySLPredicate pred) { .orElse(false); } - public Collection retrieveErrorsForPredCondition(CrySLPredicate pred) { - // Check, whether the predicate has a condition - if (pred.getConstraint().isEmpty()) { - return Collections.emptyList(); - } - - // TODO the condition should be reported itself? - ISLConstraint condition = pred.getConstraint().get(); - return Collections.emptyList(); - } - - private boolean doPredsMatch(CrySLPredicate pred, EnsuredCrySLPredicate ensPred) { + private boolean doPredsMatch(CrySLPredicate pred, AbstractPredicate ensPred) { boolean requiredPredicatesExist = true; for (int i = 0; i < pred.getParameters().size(); i++) { String var = pred.getParameters().get(i).getName(); if (isOfNonTrackableType(var)) { continue; - } else if (pred.getInvolvedVarNames().contains(var)) { + } + if (pred.getInvolvedVarNames().contains(var)) { final String parameterI = ensPred.getPredicate().getParameters().get(i).getName(); Collection actVals = Collections.emptySet(); Collection expVals = Collections.emptySet(); - for (CallSiteWithExtractedValue cswpi : ensPred.getParametersToValues()) { - if (cswpi.getCallSiteWithParam().getVarName().equals(parameterI)) { - actVals = retrieveValueFromUnit(cswpi); + for (CallSiteWithExtractedValue callSite : ensPred.getParametersToValues()) { + if (callSite.callSiteWithParam().varName().equals(parameterI)) { + actVals = retrieveValueFromUnit(callSite); } } - for (CallSiteWithExtractedValue cswpi : constraintSolver.getCollectedValues()) { - if (cswpi.getCallSiteWithParam().getVarName().equals(var)) { - expVals = retrieveValueFromUnit(cswpi); + for (CallSiteWithExtractedValue callSite : constraintSolver.getCollectedValues()) { + if (callSite.callSiteWithParam().varName().equals(var)) { + expVals = retrieveValueFromUnit(callSite); } } String splitter = ""; int index = -1; - if (pred.getParameters().get(i) instanceof CrySLObject) { - CrySLObject obj = (CrySLObject) pred.getParameters().get(i); + if (pred.getParameters().get(i) instanceof CrySLObject obj) { if (obj.getSplitter() != null) { splitter = obj.getSplitter().getSplitter(); index = obj.getSplitter().getIndex(); @@ -1069,47 +1100,69 @@ private boolean doPredsMatch(CrySLPredicate pred, EnsuredCrySLPredicate ensPred) return requiredPredicatesExist; } - public void addHiddenPredicatesToError(RequiredPredicateError reqPredError) { - for (CrySLPredicate pred : reqPredError.getContradictedPredicates()) { - Collection hiddenPredicatesEnsuringReqPred = new HashSet<>(); + public Collection extractHiddenPredicates( + AlternativeReqPredicate predicate) { + Collection result = new HashSet<>(); - for (Map.Entry entry : hiddenPredicates.values()) { - HiddenPredicate hiddenPredicate = entry.getKey(); + for (RequiredCrySLPredicate reqPred : predicate.getRelAlternatives()) { + Collection extractedPreds = extractHiddenPredicates(reqPred); - if (hiddenPredicate.getPredicate().equals(pred) - && doPredsMatch(pred, hiddenPredicate)) { - hiddenPredicatesEnsuringReqPred.add(hiddenPredicate); - } + result.addAll(extractedPreds); + } + + return result; + } + + public Collection extractHiddenPredicates( + RequiredCrySLPredicate predicate) { + return extractHiddenPredicates( + predicate.getLocation(), predicate.getPred(), predicate.getParamIndex()); + } + + private Collection extractHiddenPredicates( + Statement statement, CrySLPredicate predicate, int index) { + Collection result = new HashSet<>(); + + if (!hiddenPredicates.containsKey(statement)) { + return result; + } + + Collection> hiddenPreds = + hiddenPredicates.get(statement); + for (Map.Entry entry : hiddenPreds) { + if (entry.getValue() != index) { + continue; } - reqPredError.addHiddenPredicates(hiddenPredicatesEnsuringReqPred); + UnEnsuredPredicate unEnsuredPredicate = entry.getKey(); + + if (unEnsuredPredicate.getPredicate().equals(predicate) + && doPredsMatch(predicate, unEnsuredPredicate)) { + result.add(unEnsuredPredicate); + } } + + return result; } private Collection retrieveValueFromUnit(CallSiteWithExtractedValue callSite) { Collection values = new ArrayList<>(); - Statement statement = callSite.getCallSiteWithParam().stmt(); + Statement statement = callSite.callSiteWithParam().statement(); if (statement.isAssign()) { Val rightSide = statement.getRightOp(); - if (rightSide.isConstant()) { - values.add(retrieveConstantFromValue(rightSide)); + if (rightSide.isIntConstant()) { + values.add(String.valueOf(rightSide.getIntValue())); + } else if (rightSide.isLongConstant()) { + values.add(String.valueOf(rightSide.getLongValue())); + } else if (rightSide.isStringConstant()) { + values.add(rightSide.getStringValue()); } } return values; } - private String retrieveConstantFromValue(Val val) { - if (val.isStringConstant()) { - return val.getStringValue(); - } else if (val.isIntConstant()) { - return String.valueOf(val.getIntValue()); - } else { - return ""; - } - } - private static final Collection trackedTypes = Arrays.asList("java.lang.String", "int", "java.lang.Integer"); @@ -1136,20 +1189,13 @@ public Map getAllCallsOnObject() { @Override public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + ((specification == null) ? 0 : specification.hashCode()); - return result; + return Objects.hash(super.hashCode(), specification); } @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (!super.equals(obj)) return false; - if (getClass() != obj.getClass()) return false; - AnalysisSeedWithSpecification other = (AnalysisSeedWithSpecification) obj; - if (specification == null) { - return other.specification == null; - } else return specification.equals(other.specification); + return super.equals(obj) + && obj instanceof AnalysisSeedWithSpecification other + && Objects.equals(specification, other.specification); } } diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/CryptoScanner.java b/CryptoAnalysis/src/main/java/crypto/analysis/CryptoScanner.java index 4195b8e40..5dc14552c 100644 --- a/CryptoAnalysis/src/main/java/crypto/analysis/CryptoScanner.java +++ b/CryptoAnalysis/src/main/java/crypto/analysis/CryptoScanner.java @@ -1,7 +1,5 @@ package crypto.analysis; -import boomerang.Query; -import boomerang.debugger.Debugger; import boomerang.scene.CallGraph; import boomerang.scene.DataFlowScope; import boomerang.scene.Method; @@ -17,6 +15,9 @@ import crypto.listener.IAnalysisListener; import crypto.listener.IErrorListener; import crypto.listener.IResultsListener; +import crypto.reporting.Reporter; +import crypto.reporting.ReporterFactory; +import crypto.visualization.Visualizer; import crysl.CrySLParser; import crysl.rule.CrySLRule; import java.io.IOException; @@ -28,7 +29,7 @@ import java.util.List; import java.util.Map; import java.util.Set; -import typestate.TransitionFunction; +import org.graphper.draw.ExecuteException; public abstract class CryptoScanner { @@ -112,6 +113,46 @@ protected final void scan() { analysisReporter.afterAnalysis(); } + protected final void createReports( + Collection formats, + String reportDirectory, + boolean visualization) { + if (reportDirectory == null + && formats.stream() + .anyMatch( + e -> + Set.of( + Reporter.ReportFormat.TXT, + Reporter.ReportFormat.CSV, + Reporter.ReportFormat.CSV_SUMMARY, + Reporter.ReportFormat.SARIF) + .contains(e))) { + throw new RuntimeException("Cannot create report without existing report directory"); + } + + if (visualization && reportDirectory == null) { + throw new RuntimeException( + "Cannot create visualization without existing report directory"); + } + + Collection reporters = + ReporterFactory.createReporters(formats, reportDirectory, ruleset); + for (Reporter reporter : reporters) { + reporter.createAnalysisReport( + getDiscoveredSeeds(), getCollectedErrors(), getStatistics()); + } + + if (visualization) { + try { + Visualizer visualizer = new Visualizer(reportDirectory); + visualizer.createVisualization(getDiscoveredSeeds()); + } catch (IOException | ExecuteException e) { + throw new CryptoAnalysisException( + "Couldn't create visualization: " + e.getMessage()); + } + } + } + public final Collection getRuleset() { return ruleset; } @@ -175,10 +216,6 @@ protected DataFlowScope createDataFlowScope() { return new CryptoAnalysisDataFlowScope(ruleset, Collections.emptySet()); } - public Debugger debugger(Query query) { - return new Debugger<>(); - } - public SparseCFGCache.SparsificationStrategy getSparsificationStrategy() { return SparseCFGCache.SparsificationStrategy.NONE; } diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/EnsuredPredicate.java b/CryptoAnalysis/src/main/java/crypto/analysis/EnsuredPredicate.java new file mode 100644 index 000000000..c1f23c1b6 --- /dev/null +++ b/CryptoAnalysis/src/main/java/crypto/analysis/EnsuredPredicate.java @@ -0,0 +1,34 @@ +package crypto.analysis; + +import crypto.extractparameter.CallSiteWithExtractedValue; +import crysl.rule.CrySLPredicate; +import java.util.Collection; +import java.util.Objects; + +/** + * Wrapper class for a single {@link CrySLPredicate} to keep track of ensured predicate during the + * analysis. A predicate is only ensured if there are no violations for a corresponding rule. + * Otherwise, the analysis propagates an {@link UnEnsuredPredicate}. + */ +public class EnsuredPredicate extends AbstractPredicate { + + public EnsuredPredicate( + CrySLPredicate predicate, Collection parametersToValues) { + super(predicate, parametersToValues); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj) && obj instanceof EnsuredPredicate; + } + + @Override + public String toString() { + return "Ensured: " + getPredicate().getPredName(); + } +} diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/HiddenPredicate.java b/CryptoAnalysis/src/main/java/crypto/analysis/HiddenPredicate.java deleted file mode 100644 index 6ecc4cb97..000000000 --- a/CryptoAnalysis/src/main/java/crypto/analysis/HiddenPredicate.java +++ /dev/null @@ -1,122 +0,0 @@ -package crypto.analysis; - -import com.google.common.collect.Lists; -import crypto.analysis.errors.AbstractError; -import crypto.analysis.errors.ConstraintError; -import crypto.analysis.errors.HardCodedError; -import crypto.analysis.errors.ImpreciseValueExtractionError; -import crypto.analysis.errors.IncompleteOperationError; -import crypto.analysis.errors.InstanceOfError; -import crypto.analysis.errors.NeverTypeOfError; -import crypto.analysis.errors.RequiredPredicateError; -import crypto.analysis.errors.TypestateError; -import crypto.extractparameter.CallSiteWithExtractedValue; -import crysl.rule.CrySLPredicate; -import java.util.Collection; -import java.util.stream.Collectors; - -public class HiddenPredicate extends EnsuredCrySLPredicate { - - private final AnalysisSeedWithSpecification generatingSeed; - private final HiddenPredicateType type; - - public HiddenPredicate( - CrySLPredicate predicate, - Collection parametersToValues, - AnalysisSeedWithSpecification generatingSeed, - HiddenPredicateType type) { - super(predicate, parametersToValues); - this.generatingSeed = generatingSeed; - this.type = type; - } - - public AnalysisSeedWithSpecification getGeneratingSeed() { - return generatingSeed; - } - - public enum HiddenPredicateType { - GeneratingStateIsNeverReached, - ConstraintsAreNotSatisfied, - ConditionIsNotSatisfied - } - - public HiddenPredicateType getType() { - return type; - } - - /** - * Node: Errors are only in complete count at the end of the analysis. - * - * @return errors list of all preceding errors - */ - public Collection getPrecedingErrors() { - Collection results = Lists.newArrayList(); - Collection allErrors = generatingSeed.getErrors(); - switch (type) { - case GeneratingStateIsNeverReached: - Collection typestateErrors = - allErrors.stream() - .filter( - e -> - (e instanceof IncompleteOperationError - || e instanceof TypestateError)) - .collect(Collectors.toList()); - if (typestateErrors.isEmpty()) { - // Seed object has no typestate errors that might be responsible for this hidden - // predicate - // TODO: report new info error type to report, - // that the seeds object could potentially ensure the missing predicate which - // might cause further subsequent errors - // but therefore requires a call to the predicate generating statement - } - - // TODO: check whether the generating state is not reached due to a typestate error - return allErrors; - - case ConstraintsAreNotSatisfied: - // Generating state was reached but constraints are not satisfied. - // Thus, return all constraints & required predicate errors. - return allErrors.stream() - .filter( - e -> - (e instanceof RequiredPredicateError - || e instanceof ConstraintError - || e instanceof HardCodedError - || e instanceof ImpreciseValueExtractionError - || e instanceof InstanceOfError - || e instanceof NeverTypeOfError)) - .collect(Collectors.toList()); - case ConditionIsNotSatisfied: - // Generating state was reached but the predicates condition is not satisfied. - // Thus, return all errors that causes the condition to be not satisfied - Collection precedingErrors = - Lists.newArrayList( - generatingSeed.retrieveErrorsForPredCondition(this.getPredicate())); - // This method is called from a RequiredPredicateError that wants to retrieve its - // preceding errors. - // In this case, preceding errors are not reported yet because the predicate - // condition wasn't required to be satisfied. - // Since the hidden predicate is required to be an ensured predicate, we can assume - // the condition required to be satisfied. - // Thus, we report all errors that causes the condition to be not satisfied. - // precedingErrors.forEach(e -> - // this.generatingSeed.scanner.getAnalysisListener().reportError(generatingSeed, - // e)); - precedingErrors.forEach( - e -> - this.generatingSeed - .scanner - .getAnalysisReporter() - .reportError(generatingSeed, e)); - // Further, preceding errors can be of type RequiredPredicateError. - // Thus, we have to recursively map preceding errors for the newly reported errors. - for (AbstractError e : precedingErrors) { - if (e instanceof RequiredPredicateError) { - ((RequiredPredicateError) e).mapPrecedingErrors(); - } - } - return precedingErrors; - } - return results; - } -} diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/IAnalysisSeed.java b/CryptoAnalysis/src/main/java/crypto/analysis/IAnalysisSeed.java index 9e6626d2b..bab7222b9 100644 --- a/CryptoAnalysis/src/main/java/crypto/analysis/IAnalysisSeed.java +++ b/CryptoAnalysis/src/main/java/crypto/analysis/IAnalysisSeed.java @@ -9,12 +9,9 @@ import com.google.common.collect.Multimap; import crypto.analysis.errors.AbstractError; import crysl.rule.CrySLPredicate; -import java.math.BigInteger; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; import java.util.Collection; import java.util.HashSet; +import java.util.Objects; import typestate.TransitionFunction; public abstract class IAnalysisSeed { @@ -25,56 +22,11 @@ public abstract class IAnalysisSeed { protected final Multimap expectedPredicates = HashMultimap.create(); - protected static final class ExpectedPredicateOnSeed { - - private final CrySLPredicate predicate; - private final IAnalysisSeed seed; - private final int paramIndex; - - public ExpectedPredicateOnSeed( - CrySLPredicate predicate, IAnalysisSeed seed, int paramIndex) { - this.predicate = predicate; - this.seed = seed; - this.paramIndex = paramIndex; - } - - public CrySLPredicate getPredicate() { - return predicate; - } - - public IAnalysisSeed getSeed() { - return seed; - } - - public int getParamIndex() { - return paramIndex; - } - - @Override - public int hashCode() { - return Arrays.hashCode(new Object[] {predicate, seed, paramIndex}); - } - - @Override - public boolean equals(Object obj) { - if (getClass() != obj.getClass()) return false; - ExpectedPredicateOnSeed other = (ExpectedPredicateOnSeed) obj; - - return predicate.equals(other.getPredicate()) - && seed.equals(other.getSeed()) - && paramIndex == other.getParamIndex(); - } - - @Override - public String toString() { - return predicate + " for " + seed + " @ " + paramIndex; - } - } + protected record ExpectedPredicateOnSeed( + CrySLPredicate predicate, IAnalysisSeed seed, int paramIndex) {} private final Statement origin; private final Val fact; - private String objectId; - private boolean secure = true; public IAnalysisSeed( CryptoScanner scanner, @@ -104,7 +56,7 @@ protected Collection expectedPredicatesAtStatement(Statement sta Collection expectedPredicateOnSeeds = expectedPredicates.get(statement); for (ExpectedPredicateOnSeed expectedPredicateOnSeed : expectedPredicateOnSeeds) { - predicates.add(expectedPredicateOnSeed.getPredicate()); + predicates.add(expectedPredicateOnSeed.predicate()); } return predicates; @@ -127,11 +79,7 @@ public Type getType() { } public boolean isSecure() { - return secure; - } - - public void setSecure(boolean secure) { - this.secure = secure; + return errorCollection.isEmpty(); } public ForwardBoomerangResults getAnalysisResults() { @@ -150,38 +98,16 @@ public CryptoScanner getScanner() { return scanner; } - public String getObjectId() { - if (objectId == null) { - MessageDigest md; - try { - md = MessageDigest.getInstance("SHA-256"); - } catch (NoSuchAlgorithmException e) { - return null; - } - this.objectId = new BigInteger(1, md.digest(this.toString().getBytes())).toString(16); - } - return this.objectId; - } - @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - - if (!(obj instanceof IAnalysisSeed)) return false; - IAnalysisSeed other = (IAnalysisSeed) obj; - - if (!origin.equals(other.getOrigin())) return false; - return fact.equals(other.getFact()); + return obj instanceof IAnalysisSeed other + && Objects.equals(origin, other.origin) + && Objects.equals(fact, other.fact); } @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((origin == null) ? 0 : origin.hashCode()); - result = prime * result + ((fact == null) ? 0 : fact.hashCode()); - return result; + return Objects.hash(origin, fact); } @Override diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/PredicateHandler.java b/CryptoAnalysis/src/main/java/crypto/analysis/PredicateHandler.java index 98068b080..9d358a12e 100644 --- a/CryptoAnalysis/src/main/java/crypto/analysis/PredicateHandler.java +++ b/CryptoAnalysis/src/main/java/crypto/analysis/PredicateHandler.java @@ -1,8 +1,10 @@ package crypto.analysis; +import crypto.analysis.errors.AbstractError; +import crypto.analysis.errors.AbstractRequiredPredicateError; +import crypto.analysis.errors.AlternativeReqPredicateError; import crypto.analysis.errors.PredicateContradictionError; import crypto.analysis.errors.RequiredPredicateError; -import crysl.rule.ISLConstraint; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -13,7 +15,7 @@ public class PredicateHandler { private final CryptoScanner cryptoScanner; - private final Map> + private final Map> requiredPredicateErrors; public PredicateHandler(CryptoScanner cryptoScanner) { @@ -23,13 +25,15 @@ public PredicateHandler(CryptoScanner cryptoScanner) { public void checkPredicates() { runPredicateMechanism(); - collectMissingRequiredPredicates(); collectContradictingPredicates(); + collectMissingRequiredPredicates(); reportRequiredPredicateErrors(); + + // Connections are only available once all errors have been reported + connectSubsequentErrors(); } private void runPredicateMechanism() { - for (AnalysisSeedWithSpecification seed : cryptoScanner.getAnalysisSeedsWithSpec()) { seed.computeExpectedPredicates(cryptoScanner.getDiscoveredSeeds()); } @@ -42,58 +46,70 @@ private void runPredicateMechanism() { } } + private void collectContradictingPredicates() { + for (AnalysisSeedWithSpecification seed : cryptoScanner.getAnalysisSeedsWithSpec()) { + Collection contradictedPredicates = + seed.computeContradictedPredicates(); + + for (RequiredCrySLPredicate pred : contradictedPredicates) { + PredicateContradictionError error = + new PredicateContradictionError( + seed, pred.getLocation(), seed.getSpecification(), pred.getPred()); + seed.addError(error); + cryptoScanner.getAnalysisReporter().reportError(seed, error); + } + } + } + private void collectMissingRequiredPredicates() { for (AnalysisSeedWithSpecification seed : cryptoScanner.getAnalysisSeedsWithSpec()) { requiredPredicateErrors.put(seed, new ArrayList<>()); - Collection missingPredicates = seed.computeMissingPredicates(); - for (ISLConstraint pred : missingPredicates) { - if (pred instanceof RequiredCrySLPredicate) { - RequiredCrySLPredicate reqPred = (RequiredCrySLPredicate) pred; + Collection violatedReqPreds = + seed.computeViolatedRequiredPredicates(); + for (RequiredCrySLPredicate reqPred : violatedReqPreds) { + Collection hiddenPreds = seed.extractHiddenPredicates(reqPred); - RequiredPredicateError reqPredError = new RequiredPredicateError(seed, reqPred); - addRequiredPredicateErrorOnSeed(reqPredError, seed); - } else if (pred instanceof AlternativeReqPredicate) { - AlternativeReqPredicate altReqPred = (AlternativeReqPredicate) pred; + RequiredPredicateError reqPredError = + new RequiredPredicateError(seed, reqPred, hiddenPreds); + requiredPredicateErrors.get(seed).add(reqPredError); + } - RequiredPredicateError reqPredError = - new RequiredPredicateError(seed, altReqPred); - addRequiredPredicateErrorOnSeed(reqPredError, seed); - } + Collection violatedAltPreds = + seed.computeViolatedAlternativePredicates(); + for (AlternativeReqPredicate altPred : violatedAltPreds) { + Collection hiddenPreds = seed.extractHiddenPredicates(altPred); + + AlternativeReqPredicateError reqPredError = + new AlternativeReqPredicateError(seed, altPred, hiddenPreds); + requiredPredicateErrors.get(seed).add(reqPredError); } } } - private void addRequiredPredicateErrorOnSeed( - RequiredPredicateError reqPredError, AnalysisSeedWithSpecification seed) { - seed.addHiddenPredicatesToError(reqPredError); - seed.addError(reqPredError); - requiredPredicateErrors.get(seed).add(reqPredError); - } - private void reportRequiredPredicateErrors() { - for (Map.Entry> entry : - requiredPredicateErrors.entrySet()) { - AnalysisSeedWithSpecification seed = entry.getKey(); + for (AnalysisSeedWithSpecification seed : requiredPredicateErrors.keySet()) { + Collection errors = requiredPredicateErrors.get(seed); - for (RequiredPredicateError reqPredError : entry.getValue()) { - reqPredError.mapPrecedingErrors(); + for (AbstractRequiredPredicateError reqPredError : errors) { + seed.addError(reqPredError); cryptoScanner.getAnalysisReporter().reportError(seed, reqPredError); } } } - private void collectContradictingPredicates() { - for (AnalysisSeedWithSpecification seed : cryptoScanner.getAnalysisSeedsWithSpec()) { - Collection contradictedPredicates = - seed.computeContradictedPredicates(); + private void connectSubsequentErrors() { + for (AnalysisSeedWithSpecification seed : requiredPredicateErrors.keySet()) { + Collection errors = requiredPredicateErrors.get(seed); - for (RequiredCrySLPredicate pred : contradictedPredicates) { - PredicateContradictionError error = - new PredicateContradictionError( - seed, pred.getLocation(), seed.getSpecification(), pred.getPred()); - seed.addError(error); - cryptoScanner.getAnalysisReporter().reportError(seed, error); + for (AbstractRequiredPredicateError error : errors) { + for (UnEnsuredPredicate unEnsuredPredicate : error.getHiddenPredicates()) { + Collection precedingErrors = + unEnsuredPredicate.getPrecedingErrors(); + + precedingErrors.forEach(error::addPrecedingError); + precedingErrors.forEach(e -> e.addSubsequentError(error)); + } } } } diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/RequiredCrySLPredicate.java b/CryptoAnalysis/src/main/java/crypto/analysis/RequiredCrySLPredicate.java index d5d84d2d3..11813dade 100644 --- a/CryptoAnalysis/src/main/java/crypto/analysis/RequiredCrySLPredicate.java +++ b/CryptoAnalysis/src/main/java/crypto/analysis/RequiredCrySLPredicate.java @@ -4,7 +4,19 @@ import crysl.rule.CrySLPredicate; import crysl.rule.ISLConstraint; import java.util.List; +import java.util.Objects; +/** + * Wrapper class for predicates from the REQUIRES section. This class only stores single predicates, + * that is, predicates of the form + * + *
{@code
+ * REQUIRES
+ *    generatedKey[...];
+ * }
+ * + * If a predicate has alternatives, a {@link AlternativeReqPredicate} is used. + */ public class RequiredCrySLPredicate implements ISLConstraint { private final CrySLPredicate predicate; @@ -19,31 +31,15 @@ public RequiredCrySLPredicate(CrySLPredicate predicate, Statement statement, int @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((predicate == null) ? 0 : predicate.hashCode()); - result = prime * result + ((statement == null) ? 0 : statement.hashCode()); - result = prime * result + paramIndex; - return result; + return Objects.hash(predicate, statement, paramIndex); } @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - RequiredCrySLPredicate other = (RequiredCrySLPredicate) obj; - if (predicate == null) { - if (other.predicate != null) return false; - } else if (!predicate.equals(other.predicate)) return false; - if (statement == null) { - if (other.statement != null) { - return false; - } - } else if (!statement.equals(other.statement)) { - return false; - } - return paramIndex == other.paramIndex; + return obj instanceof RequiredCrySLPredicate other + && Objects.equals(predicate, other.predicate) + && Objects.equals(statement, other.statement) + && paramIndex == other.paramIndex; } public CrySLPredicate getPred() { diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/SeedGenerator.java b/CryptoAnalysis/src/main/java/crypto/analysis/SeedGenerator.java index e14f4ef1f..669f08066 100644 --- a/CryptoAnalysis/src/main/java/crypto/analysis/SeedGenerator.java +++ b/CryptoAnalysis/src/main/java/crypto/analysis/SeedGenerator.java @@ -1,6 +1,5 @@ package crypto.analysis; -import boomerang.debugger.Debugger; import boomerang.results.ForwardBoomerangResults; import boomerang.scene.CallGraph; import boomerang.scene.DataFlowScope; @@ -10,7 +9,6 @@ import crypto.typestate.TypestateAnalysis; import crypto.typestate.TypestateDefinition; import crysl.rule.CrySLRule; -import ideal.IDEALSeedSolver; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -42,12 +40,6 @@ public DataFlowScope getDataFlowScope() { return scanner.getDataFlowScope(); } - @Override - public Debugger getDebugger( - IDEALSeedSolver idealSeedSolver) { - return scanner.debugger(idealSeedSolver.getSeed()); - } - @Override public int getTimeout() { return scanner.getTimeout(); diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/UnEnsuredPredicate.java b/CryptoAnalysis/src/main/java/crypto/analysis/UnEnsuredPredicate.java new file mode 100644 index 000000000..ca8a6d60a --- /dev/null +++ b/CryptoAnalysis/src/main/java/crypto/analysis/UnEnsuredPredicate.java @@ -0,0 +1,147 @@ +package crypto.analysis; + +import crypto.analysis.errors.AbstractConstraintsError; +import crypto.analysis.errors.AbstractError; +import crypto.analysis.errors.AbstractOrderError; +import crypto.analysis.errors.ForbiddenMethodError; +import crypto.analysis.errors.PredicateConstraintError; +import crypto.extractparameter.CallSiteWithExtractedValue; +import crysl.rule.CrySLPredicate; +import java.util.Collection; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +/** + * Wrapper class for a single {@link CrySLPredicate} that could not be ensured during the analysis. + * If a seed cannot generate a predicate due to some violations from its CrySL rule, the analysis + * keeps track of those violations and the seed s.t. other seeds can reason about why the predicate + * was not ensured. This way, the analysis can connect corresponding subsequent errors. + * + *

See the paper + */ +public class UnEnsuredPredicate extends AbstractPredicate { + + private final AnalysisSeedWithSpecification generatingSeed; + private final Collection violations; + + /** Collection of violations that may cause a predicate to be not ensured */ + public enum Violations { + /** Violation if there is a call to a method from the FORBIDDEN section. */ + CallToForbiddenMethod, + + /** + * Violation if there is an unsatisfied constraint. Constraints include basic constraints + * from the CONSTRAINTS section and required predicates from the REQUIRES section. + */ + ConstraintsAreNotSatisfied, + + /** + * Violation if the condition of predicate from the ENSURES section is not satisfied. Note + * that the analysis does not report an error because the condition is not required to be + * satisfied. + */ + ConditionIsNotSatisfied, + + /** + * Violation if there are dataflow paths where the seed does not reach an accepting state to + * generate a predicate. + */ + GeneratingStateMayNotBeReached, + + /** + * Violation if there is no dataflow path where the seed reaches an accepting state to + * generate a predicate. + */ + GeneratingStateIsNeverReached + } + + public UnEnsuredPredicate( + CrySLPredicate predicate, + Collection parametersToValues, + AnalysisSeedWithSpecification generatingSeed, + Collection violations) { + super(predicate, parametersToValues); + + this.generatingSeed = generatingSeed; + this.violations = Set.copyOf(violations); + } + + public AnalysisSeedWithSpecification getGeneratingSeed() { + return generatingSeed; + } + + public Collection getViolations() { + return violations; + } + + /** + * Compute the preceding errors that cause the predicate stored in this class to be not ensured. + * + * @return the errors that cause the predicate to be not ensured + */ + public Collection getPrecedingErrors() { + Collection result = new HashSet<>(); + + // Collect all ForbiddenMethodErrors + if (violations.contains(Violations.CallToForbiddenMethod)) { + Collection forbiddenMethodErrors = + generatingSeed.getErrors().stream() + .filter(e -> e instanceof ForbiddenMethodError) + .toList(); + result.addAll(forbiddenMethodErrors); + } + + /* Collect the ConstraintErrors. This includes error violating constraints from the + * CONSTRAINTS section and violated predicates from the REQUIRES section. + */ + if (violations.contains(Violations.ConstraintsAreNotSatisfied)) { + Collection constraintErrors = + generatingSeed.getErrors().stream() + .filter(e -> e instanceof AbstractConstraintsError) + .toList(); + result.addAll(constraintErrors); + } + + /* If the predicate condition in the ENSURES section is not satisfied, a + * PredicateConstraintError is created. Note that these errors are not reported since + * they are not required to be satisfied. However, a corresponding error indicate that + * the condition is not satisfied. + */ + if (violations.contains(Violations.ConditionIsNotSatisfied)) { + PredicateConstraintError error = + new PredicateConstraintError(generatingSeed, getPredicate()); + result.add(error); + } + + // Collect all errors that cause the seed to not reach an accepting state + if (violations.contains(Violations.GeneratingStateMayNotBeReached) + || violations.contains(Violations.GeneratingStateIsNeverReached)) { + Collection orderError = + generatingSeed.getErrors().stream() + .filter(e -> e instanceof AbstractOrderError) + .toList(); + result.addAll(orderError); + } + + return result; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), generatingSeed, violations); + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj) + && obj instanceof UnEnsuredPredicate other + && Objects.equals(generatingSeed, other.getGeneratingSeed()) + && Objects.equals(violations, other.getViolations()); + } + + @Override + public String toString() { + return "Hidden: " + getPredicate().getPredName(); + } +} diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/errors/AbstractConstraintsError.java b/CryptoAnalysis/src/main/java/crypto/analysis/errors/AbstractConstraintsError.java new file mode 100644 index 000000000..b52f40f7a --- /dev/null +++ b/CryptoAnalysis/src/main/java/crypto/analysis/errors/AbstractConstraintsError.java @@ -0,0 +1,25 @@ +package crypto.analysis.errors; + +import boomerang.scene.Statement; +import crypto.analysis.IAnalysisSeed; +import crysl.rule.CrySLRule; + +/** + * Super class for all errors that violate a constraint from the CONSTRAINTS and REQUIRES section + */ +public abstract class AbstractConstraintsError extends AbstractError { + + public AbstractConstraintsError(IAnalysisSeed seed, Statement errorStmt, CrySLRule rule) { + super(seed, errorStmt, rule); + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj); + } +} diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/errors/AbstractError.java b/CryptoAnalysis/src/main/java/crypto/analysis/errors/AbstractError.java index a48aafb39..f82a7cd92 100644 --- a/CryptoAnalysis/src/main/java/crypto/analysis/errors/AbstractError.java +++ b/CryptoAnalysis/src/main/java/crypto/analysis/errors/AbstractError.java @@ -5,10 +5,10 @@ import crypto.analysis.IAnalysisSeed; import crysl.rule.CrySLMethod; import crysl.rule.CrySLRule; -import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Map; +import java.util.Objects; public abstract class AbstractError { @@ -16,16 +16,16 @@ public abstract class AbstractError { private final Statement errorStmt; private final CrySLRule rule; - private final Collection causedByErrors; // preceding - private final Collection willCauseErrors; // subsequent + private final Collection precedingErrors; // preceding + private final Collection subsequentErrors; // subsequent public AbstractError(IAnalysisSeed seed, Statement errorStmt, CrySLRule rule) { this.seed = seed; this.errorStmt = errorStmt; this.rule = rule; - this.causedByErrors = new HashSet<>(); - this.willCauseErrors = new HashSet<>(); + this.precedingErrors = new HashSet<>(); + this.subsequentErrors = new HashSet<>(); } public abstract String toErrorMarkerString(); @@ -50,24 +50,28 @@ public int getLineNumber() { return errorStmt.getStartLineNumber(); } - public void addCausingError(AbstractError parent) { - causedByErrors.add(parent); + public void addPrecedingError(AbstractError error) { + precedingErrors.add(error); } public void addCausingError(Collection parents) { - causedByErrors.addAll(parents); + precedingErrors.addAll(parents); } public void addSubsequentError(AbstractError subsequentError) { - willCauseErrors.add(subsequentError); + subsequentErrors.add(subsequentError); + } + + public Collection getPrecedingErrors() { + return precedingErrors; } public Collection getSubsequentErrors() { - return this.willCauseErrors; + return subsequentErrors; } public Collection getRootErrors() { - return this.causedByErrors; + return this.precedingErrors; } public String toString() { @@ -112,34 +116,14 @@ protected String formatMethodName(CrySLMethod method) { @Override public int hashCode() { - return Arrays.hashCode(new Object[] {seed, errorStmt, rule}); + return Objects.hash(seed, errorStmt, rule); } @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - - AbstractError other = (AbstractError) obj; - if (seed == null) { - if (other.getSeed() != null) return false; - } else if (!seed.equals(other.getSeed())) { - return false; - } - - if (errorStmt == null) { - if (other.getErrorStatement() != null) return false; - } else if (!errorStmt.equals(other.getErrorStatement())) { - return false; - } - - if (rule == null) { - if (other.getRule() != null) return false; - } else if (!rule.equals(other.getRule())) { - return false; - } - - return true; + return obj instanceof AbstractError other + && Objects.equals(seed, other.seed) + && Objects.equals(errorStmt, other.errorStmt) + && Objects.equals(rule, other.rule); } } diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/errors/AbstractOrderError.java b/CryptoAnalysis/src/main/java/crypto/analysis/errors/AbstractOrderError.java new file mode 100644 index 000000000..a8a7d1893 --- /dev/null +++ b/CryptoAnalysis/src/main/java/crypto/analysis/errors/AbstractOrderError.java @@ -0,0 +1,23 @@ +package crypto.analysis.errors; + +import boomerang.scene.Statement; +import crypto.analysis.IAnalysisSeed; +import crysl.rule.CrySLRule; + +/** Super class for all errors from the ORDER section */ +public abstract class AbstractOrderError extends AbstractError { + + public AbstractOrderError(IAnalysisSeed seed, Statement errorStmt, CrySLRule rule) { + super(seed, errorStmt, rule); + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj); + } +} diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/errors/AbstractRequiredPredicateError.java b/CryptoAnalysis/src/main/java/crypto/analysis/errors/AbstractRequiredPredicateError.java new file mode 100644 index 000000000..8b899ab63 --- /dev/null +++ b/CryptoAnalysis/src/main/java/crypto/analysis/errors/AbstractRequiredPredicateError.java @@ -0,0 +1,58 @@ +package crypto.analysis.errors; + +import boomerang.scene.Statement; +import crypto.analysis.IAnalysisSeed; +import crypto.analysis.UnEnsuredPredicate; +import crysl.rule.CrySLRule; +import java.util.Collection; +import java.util.Objects; +import java.util.Set; + +/** + * Super class for errors that work with a {@link UnEnsuredPredicate}. Currently, there are {@link + * RequiredPredicateError} that hold errors with single violated predicates and {@link + * AlternativeReqPredicateError} that hold errors for violated predicates with alternatives. + */ +public abstract class AbstractRequiredPredicateError extends AbstractConstraintsError { + + private final Collection unEnsuredPredicates; + + public AbstractRequiredPredicateError( + IAnalysisSeed seed, + Statement errorStmt, + CrySLRule rule, + Collection unEnsuredPredicates) { + super(seed, errorStmt, rule); + + this.unEnsuredPredicates = Set.copyOf(unEnsuredPredicates); + } + + public Collection getHiddenPredicates() { + return unEnsuredPredicates; + } + + protected String getParamIndexAsText(int paramIndex) { + return switch (paramIndex) { + case -1 -> "Return value"; + case 0 -> "First parameter"; + case 1 -> "Second parameter"; + case 2 -> "Third parameter"; + case 3 -> "Fourth parameter"; + case 4 -> "Fifth parameter"; + case 5 -> "Sixth parameter"; + default -> (paramIndex + 1) + "th parameter"; + }; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), unEnsuredPredicates); + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj) + && obj instanceof AbstractRequiredPredicateError other + && Objects.equals(unEnsuredPredicates, other.getHiddenPredicates()); + } +} diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/errors/AlternativeReqPredicateError.java b/CryptoAnalysis/src/main/java/crypto/analysis/errors/AlternativeReqPredicateError.java new file mode 100644 index 000000000..eedff51e5 --- /dev/null +++ b/CryptoAnalysis/src/main/java/crypto/analysis/errors/AlternativeReqPredicateError.java @@ -0,0 +1,97 @@ +package crypto.analysis.errors; + +import crypto.analysis.AlternativeReqPredicate; +import crypto.analysis.AnalysisSeedWithSpecification; +import crypto.analysis.RequiredCrySLPredicate; +import crypto.analysis.UnEnsuredPredicate; +import crysl.rule.CrySLPredicate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +/** + * Error that models a violation of required predicates with alternatives. Predicates from the + * REQUIRES section may have the form + * + *

{@code
+ * REQUIRES
+ *    generatedKey[...] || generatedPubKey[...] || generatedPrivKey[...];
+ * }
+ * + * If the base predicate "generatedKey" and any (relevant) alternative is not ensured, an error of + * this class is reported. + */ +public class AlternativeReqPredicateError extends AbstractRequiredPredicateError { + + private final Collection contradictedPredicate; + private final Collection relevantPredicates; + + public AlternativeReqPredicateError( + AnalysisSeedWithSpecification seed, + AlternativeReqPredicate violatedPred, + Collection unEnsuredPredicates) { + super(seed, violatedPred.getLocation(), seed.getSpecification(), unEnsuredPredicates); + + this.contradictedPredicate = List.copyOf(violatedPred.getAllAlternatives()); + this.relevantPredicates = Set.copyOf(violatedPred.getRelAlternatives()); + } + + public Collection getContradictedPredicate() { + return contradictedPredicate; + } + + public Collection getRelevantPredicates() { + return relevantPredicates; + } + + @Override + public String toErrorMarkerString() { + Collection added = new HashSet<>(); + + List msg = new ArrayList<>(); + for (RequiredCrySLPredicate pred : relevantPredicates) { + StringBuilder temp = new StringBuilder(); + temp.append(getParamIndexAsText(pred.getParamIndex())); + + if (pred.getPred().isNegated()) { + temp.append(" is generated as "); + } else { + temp.append(" was not properly generated as "); + } + temp.append(pred.getPred().getPredName()); + + msg.add(temp.toString()); + added.add(pred.getPred()); + } + + for (CrySLPredicate pred : contradictedPredicate) { + if (added.contains(pred)) { + continue; + } + msg.add(pred.getPredName() + " was not ensured (not relevant)"); + } + + return String.join(" AND ", msg); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), contradictedPredicate, relevantPredicates); + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj) + && obj instanceof AlternativeReqPredicateError other + && Objects.equals(contradictedPredicate, other.getContradictedPredicate()) + && Objects.equals(relevantPredicates, other.getRelevantPredicates()); + } + + @Override + public String toString() { + return "AlternativeReqPredicateError: " + toErrorMarkerString(); + } +} diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/errors/CallToError.java b/CryptoAnalysis/src/main/java/crypto/analysis/errors/CallToError.java index 58818d6fe..db46b93dc 100644 --- a/CryptoAnalysis/src/main/java/crypto/analysis/errors/CallToError.java +++ b/CryptoAnalysis/src/main/java/crypto/analysis/errors/CallToError.java @@ -3,10 +3,10 @@ import crypto.analysis.IAnalysisSeed; import crysl.rule.CrySLMethod; import crysl.rule.CrySLRule; -import java.util.Arrays; import java.util.Collection; +import java.util.Objects; -public class CallToError extends AbstractError { +public class CallToError extends AbstractConstraintsError { private final Collection requiredMethods; @@ -31,22 +31,14 @@ public String toErrorMarkerString() { @Override public int hashCode() { - return Arrays.hashCode(new Object[] {super.hashCode(), requiredMethods}); + return Objects.hash(super.hashCode(), requiredMethods); } @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - - CallToError other = (CallToError) obj; - if (!super.equals(other)) return false; - if (requiredMethods == null) { - return other.getRequiredMethods() == null; - } else { - return requiredMethods.equals(other.getRequiredMethods()); - } + return super.equals(obj) + && obj instanceof CallToError other + && Objects.equals(requiredMethods, other.getRequiredMethods()); } @Override diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/errors/ConstraintError.java b/CryptoAnalysis/src/main/java/crypto/analysis/errors/ConstraintError.java index 2017362cb..27f2ee185 100644 --- a/CryptoAnalysis/src/main/java/crypto/analysis/errors/ConstraintError.java +++ b/CryptoAnalysis/src/main/java/crypto/analysis/errors/ConstraintError.java @@ -13,10 +13,10 @@ import crysl.rule.CrySLSplitter; import crysl.rule.CrySLValueConstraint; import crysl.rule.ISLConstraint; -import java.util.Arrays; import java.util.Collection; +import java.util.Objects; -public class ConstraintError extends AbstractError { +public class ConstraintError extends AbstractConstraintsError { private final CallSiteWithExtractedValue callSite; private final ISLConstraint violatedConstraint; @@ -26,7 +26,7 @@ public ConstraintError( CallSiteWithExtractedValue cs, CrySLRule rule, ISLConstraint constraint) { - super(seed, cs.getCallSiteWithParam().stmt(), rule); + super(seed, cs.callSiteWithParam().statement(), rule); this.callSite = cs; this.violatedConstraint = constraint; @@ -49,24 +49,20 @@ private String evaluateBrokenConstraint(final ISLConstraint constraint) { StringBuilder msg = new StringBuilder(); if (constraint instanceof CrySLValueConstraint) { return evaluateValueConstraint((CrySLValueConstraint) constraint); - } else if (constraint instanceof CrySLArithmeticConstraint) { - final CrySLArithmeticConstraint brokenArthConstraint = - (CrySLArithmeticConstraint) constraint; - msg.append(brokenArthConstraint.getLeft()); + } else if (constraint instanceof CrySLArithmeticConstraint brokenArithConstraint) { + msg.append(brokenArithConstraint.getLeft()); msg.append(" "); - msg.append(brokenArthConstraint.getOperator()); + msg.append(brokenArithConstraint.getOperator()); msg.append(" "); - msg.append(brokenArthConstraint.getRight()); - } else if (constraint instanceof CrySLComparisonConstraint) { - final CrySLComparisonConstraint brokenCompCons = (CrySLComparisonConstraint) constraint; + msg.append(brokenArithConstraint.getRight()); + } else if (constraint instanceof CrySLComparisonConstraint brokenCompCons) { msg.append(" Variable "); msg.append(brokenCompCons.getLeft().getLeft().getName()); msg.append(" must be "); msg.append(evaluateCompOp(brokenCompCons.getOperator())); msg.append(" "); msg.append(brokenCompCons.getRight().getLeft().getName()); - } else if (constraint instanceof CrySLConstraint) { - final CrySLConstraint crySLConstraint = (CrySLConstraint) constraint; + } else if (constraint instanceof CrySLConstraint crySLConstraint) { final ISLConstraint leftSide = crySLConstraint.getLeft(); final ISLConstraint rightSide = crySLConstraint.getRight(); switch (crySLConstraint.getOperator()) { @@ -91,21 +87,14 @@ private String evaluateBrokenConstraint(final ISLConstraint constraint) { } private String evaluateCompOp(CrySLComparisonConstraint.CompOp operator) { - switch (operator) { - case ge: - return "at least"; - case g: - return "greater than"; - case l: - return "lesser than"; - case le: - return "at most"; - case eq: - return "equal to"; - case neq: - return "not equal to"; - } - return ""; + return switch (operator) { + case ge -> "at least"; + case g -> "greater than"; + case l -> "lesser than"; + case le -> "at most"; + case eq -> "equal to"; + case neq -> "not equal to"; + }; } private String evaluateValueConstraint(final CrySLValueConstraint brokenConstraint) { @@ -113,7 +102,7 @@ private String evaluateValueConstraint(final CrySLValueConstraint brokenConstrai msg.append(" should be any of "); CrySLSplitter splitter = brokenConstraint.getVar().getSplitter(); if (splitter != null) { - Statement stmt = callSite.getCallSiteWithParam().stmt(); + Statement stmt = callSite.callSiteWithParam().statement(); String[] splitValues = new String[] {""}; if (stmt.isAssign()) { Val rightSide = stmt.getRightOp(); @@ -135,10 +124,8 @@ private String evaluateValueConstraint(final CrySLValueConstraint brokenConstrai } } } - } else { - // splitValues = - // filterQuotes(stmt.getInvokeExpr().getUseBoxes().get(0).getValue().toString()).split(splitter.getSplitter()); } + if (splitValues.length >= splitter.getIndex()) { for (int i = 0; i < splitter.getIndex(); i++) { msg.append(splitValues[i]); @@ -165,29 +152,15 @@ public static String filterQuotes(final String dirty) { @Override public int hashCode() { - return Arrays.hashCode(new Object[] {super.hashCode(), callSite, violatedConstraint}); + return Objects.hash(super.hashCode(), callSite, violatedConstraint); } @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (!super.equals(obj)) return false; - if (getClass() != obj.getClass()) return false; - - ConstraintError other = (ConstraintError) obj; - if (callSite == null) { - if (other.getCallSiteWithExtractedValue() != null) return false; - } else if (!callSite.equals(other.getCallSiteWithExtractedValue())) { - return false; - } - - if (violatedConstraint == null) { - if (other.getViolatedConstraint() != null) return false; - } else if (!violatedConstraint.equals(other.getViolatedConstraint())) { - return false; - } - - return true; + return super.equals(obj) + && obj instanceof ConstraintError other + && Objects.equals(callSite, other.getCallSiteWithExtractedValue()) + && Objects.equals(violatedConstraint, other.getViolatedConstraint()); } @Override diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/errors/ForbiddenMethodError.java b/CryptoAnalysis/src/main/java/crypto/analysis/errors/ForbiddenMethodError.java index 6b497c807..b6f25545d 100644 --- a/CryptoAnalysis/src/main/java/crypto/analysis/errors/ForbiddenMethodError.java +++ b/CryptoAnalysis/src/main/java/crypto/analysis/errors/ForbiddenMethodError.java @@ -5,23 +5,14 @@ import crypto.analysis.IAnalysisSeed; import crysl.rule.CrySLMethod; import crysl.rule.CrySLRule; -import java.util.Arrays; import java.util.Collection; -import java.util.HashSet; +import java.util.Objects; public class ForbiddenMethodError extends AbstractError { private final DeclaredMethod calledMethod; private final Collection alternatives; - public ForbiddenMethodError( - IAnalysisSeed seed, - Statement errorLocation, - CrySLRule rule, - DeclaredMethod calledMethod) { - this(seed, errorLocation, rule, calledMethod, new HashSet<>()); - } - public ForbiddenMethodError( IAnalysisSeed seed, Statement errorLocation, @@ -60,29 +51,15 @@ public String toErrorMarkerString() { @Override public int hashCode() { - return Arrays.hashCode(new Object[] {super.hashCode(), calledMethod, alternatives}); + return Objects.hash(super.hashCode(), calledMethod, alternatives); } @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (!super.equals(obj)) return false; - if (getClass() != obj.getClass()) return false; - - ForbiddenMethodError other = (ForbiddenMethodError) obj; - if (calledMethod == null) { - if (other.getCalledMethod() != null) return false; - } else if (!calledMethod.equals(other.getCalledMethod())) { - return false; - } - - if (alternatives == null) { - if (other.getAlternatives() != null) return false; - } else if (!alternatives.equals(other.getAlternatives())) { - return false; - } - - return true; + return super.equals(obj) + && obj instanceof ForbiddenMethodError other + && Objects.equals(calledMethod, other.getCalledMethod()) + && Objects.equals(alternatives, other.getAlternatives()); } @Override diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/errors/HardCodedError.java b/CryptoAnalysis/src/main/java/crypto/analysis/errors/HardCodedError.java index 452978b1d..db1715fea 100644 --- a/CryptoAnalysis/src/main/java/crypto/analysis/errors/HardCodedError.java +++ b/CryptoAnalysis/src/main/java/crypto/analysis/errors/HardCodedError.java @@ -4,9 +4,9 @@ import crypto.extractparameter.CallSiteWithExtractedValue; import crysl.rule.CrySLRule; import crysl.rule.ISLConstraint; -import java.util.Arrays; +import java.util.Objects; -public class HardCodedError extends AbstractError { +public class HardCodedError extends AbstractConstraintsError { private final CallSiteWithExtractedValue extractedValue; private final ISLConstraint violatedConstraint; @@ -16,7 +16,7 @@ public HardCodedError( CallSiteWithExtractedValue cs, CrySLRule rule, ISLConstraint constraint) { - super(seed, cs.getCallSiteWithParam().stmt(), rule); + super(seed, cs.callSiteWithParam().statement(), rule); this.extractedValue = cs; this.violatedConstraint = constraint; @@ -37,29 +37,15 @@ public String toErrorMarkerString() { @Override public int hashCode() { - return Arrays.hashCode(new Object[] {super.hashCode(), extractedValue, violatedConstraint}); + return Objects.hash(super.hashCode(), extractedValue, violatedConstraint); } @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (!super.equals(obj)) return false; - if (getClass() != obj.getClass()) return false; - - HardCodedError other = (HardCodedError) obj; - if (extractedValue == null) { - if (other.getExtractedValue() != null) return false; - } else if (!extractedValue.equals(other.getExtractedValue())) { - return false; - } - - if (violatedConstraint == null) { - if (other.getViolatedConstraint() != null) return false; - } else if (!violatedConstraint.equals(other.getViolatedConstraint())) { - return false; - } - - return true; + return super.equals(obj) + && obj instanceof HardCodedError other + && Objects.equals(extractedValue, other.getExtractedValue()) + && Objects.equals(violatedConstraint, other.getViolatedConstraint()); } @Override diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/errors/ImpreciseValueExtractionError.java b/CryptoAnalysis/src/main/java/crypto/analysis/errors/ImpreciseValueExtractionError.java index 1dbc26a87..fadfdda96 100644 --- a/CryptoAnalysis/src/main/java/crypto/analysis/errors/ImpreciseValueExtractionError.java +++ b/CryptoAnalysis/src/main/java/crypto/analysis/errors/ImpreciseValueExtractionError.java @@ -4,9 +4,9 @@ import crypto.analysis.IAnalysisSeed; import crysl.rule.CrySLRule; import crysl.rule.ISLConstraint; -import java.util.Arrays; +import java.util.Objects; -public class ImpreciseValueExtractionError extends AbstractError { +public class ImpreciseValueExtractionError extends AbstractConstraintsError { private final ISLConstraint violatedConstraint; @@ -29,23 +29,14 @@ public String toErrorMarkerString() { @Override public int hashCode() { - return Arrays.hashCode(new Object[] {super.hashCode(), violatedConstraint}); + return Objects.hash(super.hashCode(), violatedConstraint); } @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (!super.equals(obj)) return false; - if (getClass() != obj.getClass()) return false; - - ImpreciseValueExtractionError other = (ImpreciseValueExtractionError) obj; - if (violatedConstraint == null) { - if (other.violatedConstraint != null) return false; - } else if (!violatedConstraint.equals(other.violatedConstraint)) { - return false; - } - - return true; + return super.equals(obj) + && obj instanceof ImpreciseValueExtractionError other + && Objects.equals(violatedConstraint, other.getViolatedConstraint()); } @Override diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/errors/IncompleteOperationError.java b/CryptoAnalysis/src/main/java/crypto/analysis/errors/IncompleteOperationError.java index 4d59f9ecd..2f48ec82f 100644 --- a/CryptoAnalysis/src/main/java/crypto/analysis/errors/IncompleteOperationError.java +++ b/CryptoAnalysis/src/main/java/crypto/analysis/errors/IncompleteOperationError.java @@ -5,8 +5,8 @@ import crypto.analysis.IAnalysisSeed; import crysl.rule.CrySLMethod; import crysl.rule.CrySLRule; -import java.util.Arrays; import java.util.Collection; +import java.util.Objects; /** * This class defines-IncompleteOperationError: @@ -19,7 +19,7 @@ * decryption, this may render the code dead. This error heavily depends on the computed call graph * (CHA by default). */ -public class IncompleteOperationError extends AbstractError { +public class IncompleteOperationError extends AbstractOrderError { private final Collection expectedMethodCalls; private final boolean multiplePaths; @@ -112,23 +112,15 @@ private String getErrorMarkerStringForMultipleDataflowPaths() { @Override public int hashCode() { - return Arrays.hashCode(new Object[] {super.hashCode(), expectedMethodCalls, multiplePaths}); + return Objects.hash(super.hashCode(), expectedMethodCalls, multiplePaths); } @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (!super.equals(obj)) return false; - if (getClass() != obj.getClass()) return false; - - IncompleteOperationError other = (IncompleteOperationError) obj; - if (expectedMethodCalls == null) { - if (other.getExpectedMethodCalls() != null) return false; - } else if (expectedMethodCalls != other.getExpectedMethodCalls()) { - return false; - } - - return multiplePaths == other.isMultiplePaths(); + return super.equals(obj) + && obj instanceof IncompleteOperationError other + && Objects.equals(expectedMethodCalls, other.getExpectedMethodCalls()) + && multiplePaths == other.isMultiplePaths(); } @Override diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/errors/InstanceOfError.java b/CryptoAnalysis/src/main/java/crypto/analysis/errors/InstanceOfError.java index a558a5ec9..c34e4a6b4 100644 --- a/CryptoAnalysis/src/main/java/crypto/analysis/errors/InstanceOfError.java +++ b/CryptoAnalysis/src/main/java/crypto/analysis/errors/InstanceOfError.java @@ -6,9 +6,9 @@ import crysl.rule.CrySLPredicate; import crysl.rule.CrySLRule; import crysl.rule.ISLConstraint; -import java.util.Arrays; +import java.util.Objects; -public class InstanceOfError extends AbstractError { +public class InstanceOfError extends AbstractConstraintsError { private final CallSiteWithExtractedValue extractedValue; private final CrySLPredicate violatedConstraint; @@ -18,7 +18,7 @@ public InstanceOfError( CallSiteWithExtractedValue cs, CrySLRule rule, CrySLPredicate constraint) { - super(seed, cs.getCallSiteWithParam().stmt(), rule); + super(seed, cs.callSiteWithParam().statement(), rule); this.extractedValue = cs; this.violatedConstraint = constraint; @@ -41,29 +41,15 @@ public String toErrorMarkerString() { @Override public int hashCode() { - return Arrays.hashCode(new Object[] {super.hashCode(), extractedValue, violatedConstraint}); + return Objects.hash(super.hashCode(), extractedValue, violatedConstraint); } @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (!super.equals(obj)) return false; - if (getClass() != obj.getClass()) return false; - - InstanceOfError other = (InstanceOfError) obj; - if (extractedValue == null) { - if (other.getExtractedValue() != null) return false; - } else if (!extractedValue.equals(other.getExtractedValue())) { - return false; - } - - if (violatedConstraint == null) { - if (other.getViolatedConstraint() != null) return false; - } else if (!violatedConstraint.equals(other.getViolatedConstraint())) { - return false; - } - - return true; + return super.equals(obj) + && obj instanceof InstanceOfError other + && Objects.equals(extractedValue, other.getExtractedValue()) + && Objects.equals(violatedConstraint, other.getViolatedConstraint()); } @Override diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/errors/NeverTypeOfError.java b/CryptoAnalysis/src/main/java/crypto/analysis/errors/NeverTypeOfError.java index e1bc9b033..0eb5e2b0e 100644 --- a/CryptoAnalysis/src/main/java/crypto/analysis/errors/NeverTypeOfError.java +++ b/CryptoAnalysis/src/main/java/crypto/analysis/errors/NeverTypeOfError.java @@ -6,9 +6,9 @@ import crysl.rule.CrySLPredicate; import crysl.rule.CrySLRule; import crysl.rule.ISLConstraint; -import java.util.Arrays; +import java.util.Objects; -public class NeverTypeOfError extends AbstractError { +public class NeverTypeOfError extends AbstractConstraintsError { private final CallSiteWithExtractedValue extractedValue; private final CrySLPredicate violatedConstraint; @@ -18,7 +18,7 @@ public NeverTypeOfError( CallSiteWithExtractedValue cs, CrySLRule rule, CrySLPredicate constraint) { - super(seed, cs.getCallSiteWithParam().stmt(), rule); + super(seed, cs.callSiteWithParam().statement(), rule); this.extractedValue = cs; this.violatedConstraint = constraint; @@ -41,29 +41,15 @@ public String toErrorMarkerString() { @Override public int hashCode() { - return Arrays.hashCode(new Object[] {super.hashCode(), extractedValue, violatedConstraint}); + return Objects.hash(super.hashCode(), extractedValue, violatedConstraint); } @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (!super.equals(obj)) return false; - if (getClass() != obj.getClass()) return false; - - NeverTypeOfError other = (NeverTypeOfError) obj; - if (extractedValue == null) { - if (other.getExtractedValue() != null) return false; - } else if (!extractedValue.equals(other.getExtractedValue())) { - return false; - } - - if (violatedConstraint == null) { - if (other.getViolatedConstraint() != null) return false; - } else if (!violatedConstraint.equals(other.getViolatedConstraint())) { - return false; - } - - return true; + return super.equals(obj) + && obj instanceof NeverTypeOfError other + && Objects.equals(extractedValue, other.getExtractedValue()) + && Objects.equals(violatedConstraint, other.getViolatedConstraint()); } @Override diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/errors/NoCallToError.java b/CryptoAnalysis/src/main/java/crypto/analysis/errors/NoCallToError.java index 5db72f317..53e69930e 100644 --- a/CryptoAnalysis/src/main/java/crypto/analysis/errors/NoCallToError.java +++ b/CryptoAnalysis/src/main/java/crypto/analysis/errors/NoCallToError.java @@ -3,8 +3,9 @@ import boomerang.scene.Statement; import crypto.analysis.IAnalysisSeed; import crysl.rule.CrySLRule; +import java.util.Objects; -public class NoCallToError extends AbstractError { +public class NoCallToError extends AbstractConstraintsError { public NoCallToError(IAnalysisSeed seed, Statement statement, CrySLRule rule) { super(seed, statement, rule); @@ -17,12 +18,12 @@ public String toErrorMarkerString() { @Override public int hashCode() { - return super.hashCode(); + return Objects.hash(super.hashCode()); } @Override public boolean equals(Object obj) { - return super.equals(obj); + return super.equals(obj) && obj instanceof NoCallToError; } @Override diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/errors/PredicateConstraintError.java b/CryptoAnalysis/src/main/java/crypto/analysis/errors/PredicateConstraintError.java new file mode 100644 index 000000000..764464e4b --- /dev/null +++ b/CryptoAnalysis/src/main/java/crypto/analysis/errors/PredicateConstraintError.java @@ -0,0 +1,59 @@ +package crypto.analysis.errors; + +import crypto.analysis.AnalysisSeedWithSpecification; +import crysl.rule.CrySLPredicate; +import java.util.Objects; + +/** + * This class represents an internal error if the constraint of a predicate to be ensured is + * violated and is only used to propagate HiddenPredicates. For example, we have the following + * ENSURES block: + * + *
{@code
+ * ENSURES
+ *    algorithm in {"AES"} => generatedKey[...]
+ * }
+ * + * If the algorithm is not "AES", the predicate "generatedKey" is not ensured. Instead, the analysis + * propagates a HiddenPredicate with the cause that the constraint is not satisfied to have a valid + * reason. This class then simply indicates that the predicate's constraint is not satisfied. This + * error is/should be not reported. + */ +public class PredicateConstraintError extends AbstractError { + + private final CrySLPredicate predicate; + + public PredicateConstraintError(AnalysisSeedWithSpecification seed, CrySLPredicate predicate) { + super(seed, seed.getOrigin(), seed.getSpecification()); + + this.predicate = predicate; + } + + public CrySLPredicate getPredicate() { + return predicate; + } + + @Override + public String toErrorMarkerString() { + return "Cannot ensure predicate " + + predicate.getPredName() + + " because its constraint is not satisfied"; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), predicate); + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj) + && obj instanceof PredicateConstraintError other + && Objects.equals(predicate, other.getPredicate()); + } + + @Override + public String toString() { + return "PredicateConstraintError: " + toErrorMarkerString(); + } +} diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/errors/PredicateContradictionError.java b/CryptoAnalysis/src/main/java/crypto/analysis/errors/PredicateContradictionError.java index 5cf2f60f7..fa4375904 100644 --- a/CryptoAnalysis/src/main/java/crypto/analysis/errors/PredicateContradictionError.java +++ b/CryptoAnalysis/src/main/java/crypto/analysis/errors/PredicateContradictionError.java @@ -4,9 +4,9 @@ import crypto.analysis.IAnalysisSeed; import crysl.rule.CrySLPredicate; import crysl.rule.CrySLRule; -import java.util.Arrays; +import java.util.Objects; -public class PredicateContradictionError extends AbstractError { +public class PredicateContradictionError extends AbstractConstraintsError { private final CrySLPredicate contradictedPredicate; @@ -31,23 +31,14 @@ public String toErrorMarkerString() { @Override public int hashCode() { - return Arrays.hashCode(new Object[] {super.hashCode(), contradictedPredicate}); + return Objects.hash(super.hashCode(), contradictedPredicate); } @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (!super.equals(obj)) return false; - if (getClass() != obj.getClass()) return false; - - PredicateContradictionError other = (PredicateContradictionError) obj; - if (contradictedPredicate == null) { - if (other.getContradictedPredicate() != null) return false; - } else if (!contradictedPredicate.equals(other.getContradictedPredicate())) { - return false; - } - - return true; + return super.equals(obj) + && obj instanceof PredicateContradictionError other + && Objects.equals(contradictedPredicate, other.getContradictedPredicate()); } @Override diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/errors/RequiredPredicateError.java b/CryptoAnalysis/src/main/java/crypto/analysis/errors/RequiredPredicateError.java index 5cee34c21..8fcaa8386 100644 --- a/CryptoAnalysis/src/main/java/crypto/analysis/errors/RequiredPredicateError.java +++ b/CryptoAnalysis/src/main/java/crypto/analysis/errors/RequiredPredicateError.java @@ -1,67 +1,40 @@ package crypto.analysis.errors; -import crypto.analysis.AlternativeReqPredicate; import crypto.analysis.AnalysisSeedWithSpecification; -import crypto.analysis.HiddenPredicate; import crypto.analysis.RequiredCrySLPredicate; +import crypto.analysis.UnEnsuredPredicate; import crysl.rule.CrySLPredicate; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.stream.Collectors; +import java.util.Objects; /** - * Creates {@link RequiredPredicateError} for all Required Predicate error generates - * RequiredPredicateError + * This error models the violation of predicates from the REQUIRES section. An error is only + * reported for single predicates, that is, predicates of the form + * + *
{@code
+ * REQUIRES
+ *    generatedKey[...];
+ * }
+ * + * If a predicate has alternatives, an {@link AlternativeReqPredicateError} is reported. */ -public class RequiredPredicateError extends AbstractError { +public class RequiredPredicateError extends AbstractRequiredPredicateError { - private final Collection hiddenPredicates; - private final Collection contradictedPredicates; + private final CrySLPredicate contradictedPredicate; private final int paramIndex; public RequiredPredicateError( - AnalysisSeedWithSpecification seed, RequiredCrySLPredicate violatedPred) { - super(seed, violatedPred.getLocation(), seed.getSpecification()); + AnalysisSeedWithSpecification seed, + RequiredCrySLPredicate violatedPred, + Collection unEnsuredPredicates) { + super(seed, violatedPred.getLocation(), seed.getSpecification(), unEnsuredPredicates); - this.hiddenPredicates = new HashSet<>(); - this.contradictedPredicates = Collections.singletonList(violatedPred.getPred()); + this.contradictedPredicate = violatedPred.getPred(); this.paramIndex = violatedPred.getParamIndex(); } - public RequiredPredicateError( - AnalysisSeedWithSpecification seed, AlternativeReqPredicate violatedPred) { - super(seed, violatedPred.getLocation(), seed.getSpecification()); - - this.hiddenPredicates = new HashSet<>(); - this.contradictedPredicates = violatedPred.getAlternatives(); - this.paramIndex = violatedPred.getParamIndex(); - } - - public void addHiddenPredicates(Collection hiddenPredicates) { - this.hiddenPredicates.addAll(hiddenPredicates); - } - - public void mapPrecedingErrors() { - for (HiddenPredicate hiddenPredicate : hiddenPredicates) { - Collection precedingErrors = hiddenPredicate.getPrecedingErrors(); - this.addCausingError(precedingErrors); - precedingErrors.forEach(e -> e.addSubsequentError(this)); - } - } - - /** - * This method returns a list of contradicting predicates - * - * @return list of contradicting predicates - */ - public Collection getContradictedPredicates() { - return contradictedPredicates; - } - - public Collection getHiddenPredicates() { - return hiddenPredicates; + public CrySLPredicate getContradictedPredicates() { + return contradictedPredicate; } public int getParamIndex() { @@ -70,13 +43,9 @@ public int getParamIndex() { @Override public String toErrorMarkerString() { - StringBuilder msg = new StringBuilder(getParamIndexAsText()); + StringBuilder msg = new StringBuilder(getParamIndexAsText(paramIndex)); msg.append(" was not properly generated as "); - String predicateName = - getContradictedPredicates().stream() - .map(CrySLPredicate::getPredName) - .collect(Collectors.joining(" OR ")); - String[] parts = predicateName.split("(?=[A-Z])"); + String[] parts = contradictedPredicate.getPredName().split("(?=[A-Z])"); msg.append(parts[0]); for (int i = 1; i < parts.length; i++) { msg.append(parts[i]); @@ -84,65 +53,17 @@ public String toErrorMarkerString() { return msg.toString(); } - private String getParamIndexAsText() { - String res; - switch (paramIndex) { - case -1: - return "Return value"; - case 0: - res = "First "; - break; - case 1: - res = "Second "; - break; - case 2: - res = "Third "; - break; - case 3: - res = "Fourth "; - break; - case 4: - res = "Fifth "; - break; - case 5: - res = "Sixth "; - break; - default: - res = (paramIndex + 1) + "th "; - break; - } - res += "parameter"; - return res; - } - @Override public int hashCode() { - return Arrays.hashCode( - new Object[] { - super.hashCode(), hiddenPredicates, contradictedPredicates, paramIndex - }); + return Objects.hash(super.hashCode(), contradictedPredicate, paramIndex); } @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (!super.equals(obj)) return false; - if (getClass() != obj.getClass()) return false; - - RequiredPredicateError other = (RequiredPredicateError) obj; - if (hiddenPredicates == null) { - if (other.getHiddenPredicates() != null) return false; - } else if (!hiddenPredicates.equals(other.hiddenPredicates)) { - return false; - } - - if (contradictedPredicates == null) { - if (other.getContradictedPredicates() != null) return false; - } else if (!contradictedPredicates.equals(other.getContradictedPredicates())) { - return false; - } - - return paramIndex == other.getParamIndex(); + return super.equals(obj) + && obj instanceof RequiredPredicateError other + && Objects.equals(contradictedPredicate, other.getContradictedPredicates()) + && paramIndex == other.getParamIndex(); } @Override diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/errors/TypestateError.java b/CryptoAnalysis/src/main/java/crypto/analysis/errors/TypestateError.java index 632a0bd33..750095f91 100644 --- a/CryptoAnalysis/src/main/java/crypto/analysis/errors/TypestateError.java +++ b/CryptoAnalysis/src/main/java/crypto/analysis/errors/TypestateError.java @@ -4,10 +4,10 @@ import crypto.analysis.IAnalysisSeed; import crysl.rule.CrySLMethod; import crysl.rule.CrySLRule; -import java.util.Arrays; import java.util.Collection; +import java.util.Objects; -public class TypestateError extends AbstractError { +public class TypestateError extends AbstractOrderError { private final Collection expectedMethodCalls; @@ -44,23 +44,14 @@ public String toErrorMarkerString() { @Override public int hashCode() { - return Arrays.hashCode(new Object[] {super.hashCode(), expectedMethodCalls}); + return Objects.hash(super.hashCode(), expectedMethodCalls); } @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (!super.equals(obj)) return false; - if (getClass() != obj.getClass()) return false; - - TypestateError other = (TypestateError) obj; - if (expectedMethodCalls == null) { - if (other.getExpectedMethodCalls() != null) return false; - } else if (!expectedMethodCalls.equals(other.getExpectedMethodCalls())) { - return false; - } - - return true; + return super.equals(obj) + && obj instanceof TypestateError other + && Objects.equals(expectedMethodCalls, other.getExpectedMethodCalls()); } @Override diff --git a/CryptoAnalysis/src/main/java/crypto/analysis/errors/UncaughtExceptionError.java b/CryptoAnalysis/src/main/java/crypto/analysis/errors/UncaughtExceptionError.java index 31b57b360..bf98725a5 100644 --- a/CryptoAnalysis/src/main/java/crypto/analysis/errors/UncaughtExceptionError.java +++ b/CryptoAnalysis/src/main/java/crypto/analysis/errors/UncaughtExceptionError.java @@ -4,7 +4,7 @@ import boomerang.scene.WrappedClass; import crypto.analysis.IAnalysisSeed; import crysl.rule.CrySLRule; -import java.util.Arrays; +import java.util.Objects; public class UncaughtExceptionError extends AbstractError { @@ -27,22 +27,13 @@ public String toErrorMarkerString() { @Override public int hashCode() { - return Arrays.hashCode(new Object[] {super.hashCode(), exception}); + return Objects.hash(super.hashCode(), exception); } @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (!super.equals(obj)) return false; - if (getClass() != obj.getClass()) return false; - - UncaughtExceptionError other = (UncaughtExceptionError) obj; - if (exception == null) { - if (other.getException() != null) return false; - } else if (!exception.equals(other.getException())) { - return false; - } - - return true; + return super.equals(obj) + && obj instanceof UncaughtExceptionError other + && Objects.equals(exception, other.getException()); } } diff --git a/CryptoAnalysis/src/main/java/crypto/constraints/ComparisonConstraint.java b/CryptoAnalysis/src/main/java/crypto/constraints/ComparisonConstraint.java index 95d137ecc..54e914ad3 100644 --- a/CryptoAnalysis/src/main/java/crypto/constraints/ComparisonConstraint.java +++ b/CryptoAnalysis/src/main/java/crypto/constraints/ComparisonConstraint.java @@ -183,8 +183,8 @@ private Map extractValueAsInt( try { for (Map.Entry value : valueCollection.entrySet()) { - ExtractedValue extractedValue = value.getValue().getExtractedValue(); - if (extractedValue.getVal().equals(Val.zero())) { + ExtractedValue extractedValue = value.getValue().extractedValue(); + if (extractedValue.val().equals(Val.zero())) { continue; } diff --git a/CryptoAnalysis/src/main/java/crypto/constraints/ConstraintSolver.java b/CryptoAnalysis/src/main/java/crypto/constraints/ConstraintSolver.java index 226ecaa03..08d60c0a3 100644 --- a/CryptoAnalysis/src/main/java/crypto/constraints/ConstraintSolver.java +++ b/CryptoAnalysis/src/main/java/crypto/constraints/ConstraintSolver.java @@ -5,7 +5,6 @@ import boomerang.scene.DataFlowScope; import boomerang.scene.Statement; import boomerang.scene.sparse.SparseCFGCache; -import com.google.common.collect.Lists; import crypto.analysis.AlternativeReqPredicate; import crypto.analysis.AnalysisSeedWithSpecification; import crypto.analysis.RequiredCrySLPredicate; @@ -23,7 +22,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; +import java.util.List; public class ConstraintSolver { @@ -153,16 +154,15 @@ private void partitionConstraints() { Collection involvedVarNames = new HashSet<>(cons.getInvolvedVarNames()); for (CallSiteWithExtractedValue callSite : this.getCollectedValues()) { - CallSiteWithParamIndex callSiteWithParamIndex = callSite.getCallSiteWithParam(); - involvedVarNames.remove(callSiteWithParamIndex.getVarName()); + CallSiteWithParamIndex callSiteWithParamIndex = callSite.callSiteWithParam(); + involvedVarNames.remove(callSiteWithParamIndex.varName()); } if (!involvedVarNames.isEmpty()) { continue; } - if (cons instanceof CrySLPredicate) { - CrySLPredicate predicate = (CrySLPredicate) cons; + if (cons instanceof CrySLPredicate predicate) { if (predefinedPreds.contains(predicate.getPredName())) { relConstraints.add(predicate); continue; @@ -178,14 +178,31 @@ private void partitionConstraints() { requiredPredicates.add(pred); } } - } else if (cons instanceof CrySLConstraint) { - ISLConstraint left = ((CrySLConstraint) cons).getLeft(); + } else if (cons instanceof CrySLConstraint constraint) { + ISLConstraint left = constraint.getLeft(); if (left instanceof CrySLPredicate && !predefinedPreds.contains(((CrySLPredicate) left).getPredName())) { - requiredPredicates.addAll( - collectAlternativePredicates( - (CrySLConstraint) cons, new ArrayList<>())); + + List allAlts = new ArrayList<>(); + extractAlternativePredicates(constraint, allAlts); + Collections.reverse(allAlts); + + if (allAlts.isEmpty()) { + continue; + } + + // Use the left pred as the base predicate to determine the statement + Collection basePreds = + retrieveValuesForPred(allAlts.get(0)); + for (RequiredCrySLPredicate reqPred : basePreds) { + Collection relAlts = + getRelevantPredicates(reqPred, allAlts); + + AlternativeReqPredicate altPred = + new AlternativeReqPredicate(reqPred, allAlts, relAlts); + requiredPredicates.add(altPred); + } } else { relConstraints.add(cons); } @@ -195,56 +212,40 @@ private void partitionConstraints() { } } - private Collection collectAlternativePredicates( - CrySLConstraint cons, Collection alts) { + private void extractAlternativePredicates(CrySLConstraint cons, List alts) { CrySLPredicate left = (CrySLPredicate) cons.getLeft(); + alts.add(left); - if (alts.isEmpty()) { - for (CallSiteWithExtractedValue callSite : this.getCollectedValues()) { - CallSiteWithParamIndex cwpi = callSite.getCallSiteWithParam(); - - for (ICrySLPredicateParameter p : left.getParameters()) { - if (p.getName().equals("transformation")) { - continue; - } + ISLConstraint right = cons.getRight(); + if (right instanceof CrySLPredicate predicate) { + alts.add(predicate); + } else if (right instanceof CrySLConstraint constraint) { + extractAlternativePredicates(constraint, alts); + } + } - if (cwpi.getVarName().equals(p.getName())) { - alts.add(new AlternativeReqPredicate(left, cwpi.stmt(), cwpi.getIndex())); - } - } - } + private Collection getRelevantPredicates( + RequiredCrySLPredicate basePred, Collection predicates) { + Collection result = new HashSet<>(); - // Extract predicates with 'this' as parameter - if (left.getParameters().stream().anyMatch(param -> param.getName().equals("this"))) { - AlternativeReqPredicate altPred = - new AlternativeReqPredicate(left, seed.getOrigin(), -1); + for (CrySLPredicate pred : predicates) { + Collection reqPreds = retrieveValuesForPred(pred); - if (!alts.contains(altPred)) { - alts.add(altPred); + for (RequiredCrySLPredicate reqPred : reqPreds) { + if (reqPred.getLocation().equals(basePred.getLocation())) { + result.add(reqPred); } } - } else { - for (AlternativeReqPredicate alt : alts) { - alt.addAlternative(left); - } } - if (cons.getRight() instanceof CrySLPredicate) { - for (AlternativeReqPredicate alt : alts) { - alt.addAlternative((CrySLPredicate) cons.getRight()); - } - } else { - return collectAlternativePredicates((CrySLConstraint) cons.getRight(), alts); - } - - return alts; + return result; } private Collection retrieveValuesForPred(CrySLPredicate pred) { - Collection result = Lists.newArrayList(); + Collection result = new ArrayList<>(); for (CallSiteWithExtractedValue callSite : this.getCollectedValues()) { - CallSiteWithParamIndex cwpi = callSite.getCallSiteWithParam(); + CallSiteWithParamIndex cwpi = callSite.callSiteWithParam(); for (ICrySLPredicateParameter p : pred.getParameters()) { // TODO: FIX Cipher rule @@ -253,12 +254,12 @@ private Collection retrieveValuesForPred(CrySLPredicate } // Predicates with _ can have any type - if (cwpi.getVarName().equals("_")) { + if (cwpi.varName().equals("_")) { continue; } - if (cwpi.getVarName().equals(p.getName())) { - result.add(new RequiredCrySLPredicate(pred, cwpi.stmt(), cwpi.getIndex())); + if (cwpi.varName().equals(p.getName())) { + result.add(new RequiredCrySLPredicate(pred, cwpi.statement(), cwpi.index())); } } } diff --git a/CryptoAnalysis/src/main/java/crypto/constraints/EvaluableConstraint.java b/CryptoAnalysis/src/main/java/crypto/constraints/EvaluableConstraint.java index 9cf077312..84da0248f 100644 --- a/CryptoAnalysis/src/main/java/crypto/constraints/EvaluableConstraint.java +++ b/CryptoAnalysis/src/main/java/crypto/constraints/EvaluableConstraint.java @@ -75,25 +75,25 @@ protected Collection getErrors() { protected Map extractValueAsString(String varName) { Map varVal = Maps.newHashMap(); for (CallSiteWithExtractedValue callSite : context.getCollectedValues()) { - CallSiteWithParamIndex wrappedCallSite = callSite.getCallSiteWithParam(); - Statement statement = wrappedCallSite.stmt(); + CallSiteWithParamIndex wrappedCallSite = callSite.callSiteWithParam(); + Statement statement = wrappedCallSite.statement(); - if (!wrappedCallSite.getVarName().equals(varName)) { + if (!wrappedCallSite.varName().equals(varName)) { continue; } - ExtractedValue extractedValue = callSite.getExtractedValue(); - Statement allocSite = extractedValue.getInitialStatement(); + ExtractedValue extractedValue = callSite.extractedValue(); + Statement allocSite = extractedValue.initialStatement(); InvokeExpr invoker = statement.getInvokeExpr(); if (statement.equals(allocSite)) { String constant = - retrieveConstantFromValue(invoker.getArg(wrappedCallSite.getIndex())); + retrieveConstantFromValue(invoker.getArg(wrappedCallSite.index())); varVal.put(constant, callSite); } else if (allocSite.isAssign()) { - if (extractedValue.getVal().isConstant()) { + if (extractedValue.val().isConstant()) { String retrieveConstantFromValue = - retrieveConstantFromValue(extractedValue.getVal()); + retrieveConstantFromValue(extractedValue.val()); int pos = -1; for (int i = 0; i < invoker.getArgs().size(); i++) { @@ -114,7 +114,7 @@ protected Map extractValueAsString(String va retrieveConstantFromValue, new CallSiteWithExtractedValue(wrappedCallSite, extractedValue)); } - } else if (extractedValue.getVal().isNewExpr()) { + } else if (extractedValue.val().isNewExpr()) { varVal.putAll(extractSootArray(wrappedCallSite, extractedValue)); } } @@ -131,8 +131,8 @@ protected Map extractValueAsString(String va */ protected Map extractSootArray( CallSiteWithParamIndex callSite, ExtractedValue allocSite) { - Val arrayLocal = allocSite.getVal(); - Method method = callSite.stmt().getMethod(); + Val arrayLocal = allocSite.val(); + Method method = callSite.statement().getMethod(); Map arrVal = Maps.newHashMap(); @@ -186,7 +186,7 @@ private String retrieveConstantFromValue(Val val) { protected Map extractArray(ExtractedValue extractedValue) { Map result = new HashMap<>(); - Statement statement = extractedValue.getInitialStatement(); + Statement statement = extractedValue.initialStatement(); if (!statement.isAssign()) { return result; } @@ -269,8 +269,8 @@ protected boolean couldNotExtractValues( } for (CallSiteWithExtractedValue callSite : extractedValueMap.values()) { - Statement statement = callSite.getCallSiteWithParam().stmt(); - Val extractedVal = callSite.getExtractedValue().getVal(); + Statement statement = callSite.callSiteWithParam().statement(); + Val extractedVal = callSite.extractedValue().val(); if (extractedVal.equals(Val.zero())) { ImpreciseValueExtractionError extractionError = diff --git a/CryptoAnalysis/src/main/java/crypto/constraints/PredicateConstraint.java b/CryptoAnalysis/src/main/java/crypto/constraints/PredicateConstraint.java index a5e4e8c3f..dc0cebaa6 100644 --- a/CryptoAnalysis/src/main/java/crypto/constraints/PredicateConstraint.java +++ b/CryptoAnalysis/src/main/java/crypto/constraints/PredicateConstraint.java @@ -123,13 +123,13 @@ private void evaluateNeverTypeOfPredicate(CrySLPredicate neverTypeOfPredicate) { CrySLObject parameterType = objects.get(1); for (CallSiteWithExtractedValue callSite : context.getCollectedValues()) { - CallSiteWithParamIndex cs = callSite.getCallSiteWithParam(); + CallSiteWithParamIndex cs = callSite.callSiteWithParam(); - if (!variable.getName().equals(cs.getVarName())) { + if (!variable.getName().equals(cs.varName())) { continue; } - Collection types = callSite.getExtractedValue().getTypes(); + Collection types = callSite.extractedValue().types(); for (Type type : types) { if (!parameterType.getJavaType().equals(type.toString())) { continue; @@ -157,13 +157,13 @@ private void evaluateHardCodedPredicate(CrySLPredicate hardCodedPredicate) { CrySLObject variable = objects.get(0); for (CallSiteWithExtractedValue callSite : context.getCollectedValues()) { - CallSiteWithParamIndex cs = callSite.getCallSiteWithParam(); + CallSiteWithParamIndex cs = callSite.callSiteWithParam(); - if (!variable.getVarName().equals(cs.getVarName())) { + if (!variable.getVarName().equals(cs.varName())) { continue; } - ExtractedValue extractedValue = callSite.getExtractedValue(); + ExtractedValue extractedValue = callSite.extractedValue(); if (isHardCodedVariable(extractedValue) || isHardCodedArray(extractedValue)) { HardCodedError hardCodedError = new HardCodedError( @@ -188,14 +188,14 @@ private void evaluateInstanceOfPredicate(CrySLPredicate instanceOfPredicate) { CrySLObject parameterType = objects.get(1); for (CallSiteWithExtractedValue callSite : context.getCollectedValues()) { - CallSiteWithParamIndex cs = callSite.getCallSiteWithParam(); + CallSiteWithParamIndex cs = callSite.callSiteWithParam(); - if (!variable.getName().equals(cs.getVarName())) { + if (!variable.getName().equals(cs.varName())) { continue; } boolean isSubType = false; - Collection types = callSite.getExtractedValue().getTypes(); + Collection types = callSite.extractedValue().types(); for (Type type : types) { if (type.isNullType()) { continue; @@ -250,26 +250,26 @@ private List parametersToCryslObjects( public boolean isHardCodedVariable(ExtractedValue val) { // Check for basic constants - if (val.getVal().isConstant()) { - LOGGER.debug("Value {} is hard coded", val.getVal()); + if (val.val().isConstant()) { + LOGGER.debug("Value {} is hard coded", val.val()); return true; } - Statement statement = val.getInitialStatement(); + Statement statement = val.initialStatement(); // Objects initialized with 'new' are hard coded if (!statement.isAssign()) { - LOGGER.debug("Value {} is not hard coded", val.getVal()); + LOGGER.debug("Value {} is not hard coded", val.val()); return false; } Val rightOp = statement.getRightOp(); if (rightOp.isNewExpr()) { - LOGGER.debug("Value {} is hard coded", val.getVal()); + LOGGER.debug("Value {} is hard coded", val.val()); return true; } - LOGGER.debug("Value {} is not hard coded", val.getVal()); + LOGGER.debug("Value {} is not hard coded", val.val()); return false; } diff --git a/CryptoAnalysis/src/main/java/crypto/constraints/ValueConstraint.java b/CryptoAnalysis/src/main/java/crypto/constraints/ValueConstraint.java index cac54f0de..7e10c8ed4 100644 --- a/CryptoAnalysis/src/main/java/crypto/constraints/ValueConstraint.java +++ b/CryptoAnalysis/src/main/java/crypto/constraints/ValueConstraint.java @@ -10,7 +10,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; public class ValueConstraint extends EvaluableConstraint { @@ -28,9 +27,7 @@ public void evaluate() { } List lowerCaseValues = - valCons.getValueRange().parallelStream() - .map(String::toLowerCase) - .collect(Collectors.toList()); + valCons.getValueRange().parallelStream().map(String::toLowerCase).toList(); for (Map.Entry val : values) { if (!lowerCaseValues.contains(val.getKey().toLowerCase())) { ConstraintError error = diff --git a/CryptoAnalysis/src/main/java/crypto/extractparameter/CallSiteWithExtractedValue.java b/CryptoAnalysis/src/main/java/crypto/extractparameter/CallSiteWithExtractedValue.java index fe26c6ead..59debc10a 100644 --- a/CryptoAnalysis/src/main/java/crypto/extractparameter/CallSiteWithExtractedValue.java +++ b/CryptoAnalysis/src/main/java/crypto/extractparameter/CallSiteWithExtractedValue.java @@ -1,31 +1,14 @@ package crypto.extractparameter; import boomerang.scene.Val; -import java.util.Arrays; -public class CallSiteWithExtractedValue { - - private final CallSiteWithParamIndex callSiteWithParam; - private final ExtractedValue extractedValue; - - public CallSiteWithExtractedValue( - CallSiteWithParamIndex callSiteWithParam, ExtractedValue extractedValue) { - this.callSiteWithParam = callSiteWithParam; - this.extractedValue = extractedValue; - } - - public CallSiteWithParamIndex getCallSiteWithParam() { - return callSiteWithParam; - } - - public ExtractedValue getExtractedValue() { - return extractedValue; - } +public record CallSiteWithExtractedValue( + CallSiteWithParamIndex callSiteWithParam, ExtractedValue extractedValue) { @Override public String toString() { String res; - switch (callSiteWithParam.getIndex()) { + switch (callSiteWithParam.index()) { case -1: return "Return value"; case 0: @@ -47,12 +30,12 @@ public String toString() { res = "Sixth "; break; default: - res = (callSiteWithParam.getIndex() + 1) + "th "; + res = (callSiteWithParam.index() + 1) + "th "; break; } res += "parameter"; if (extractedValue != null) { - Val allocVal = extractedValue.getVal(); + Val allocVal = extractedValue.val(); if (allocVal.isConstant()) { res += " (with value " + allocVal.getVariableName() + ")"; @@ -60,31 +43,4 @@ public String toString() { } return res; } - - @Override - public int hashCode() { - return Arrays.hashCode(new Object[] {callSiteWithParam, extractedValue}); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - - CallSiteWithExtractedValue other = (CallSiteWithExtractedValue) obj; - if (callSiteWithParam == null) { - if (other.getCallSiteWithParam() != null) return false; - } else if (!callSiteWithParam.equals(other.getCallSiteWithParam())) { - return false; - } - - if (extractedValue == null) { - if (other.getExtractedValue() != null) return false; - } else if (!extractedValue.equals(other.getExtractedValue())) { - return false; - } - - return true; - } } diff --git a/CryptoAnalysis/src/main/java/crypto/extractparameter/CallSiteWithParamIndex.java b/CryptoAnalysis/src/main/java/crypto/extractparameter/CallSiteWithParamIndex.java index 64646bbac..27e9a9d32 100644 --- a/CryptoAnalysis/src/main/java/crypto/extractparameter/CallSiteWithParamIndex.java +++ b/CryptoAnalysis/src/main/java/crypto/extractparameter/CallSiteWithParamIndex.java @@ -1,65 +1,11 @@ package crypto.extractparameter; import boomerang.scene.Statement; -import boomerang.scene.Val; -public class CallSiteWithParamIndex { - - private final Statement statement; - private final Val fact; - private final String varName; - private final int index; - - public CallSiteWithParamIndex(Statement statement, Val fact, int index, String varName) { - this.statement = statement; - this.fact = fact; - this.index = index; - this.varName = varName; - } - - public Statement stmt() { - return statement; - } - - public Val fact() { - return fact; - } - - public int getIndex() { - return index; - } - - public String getVarName() { - return varName; - } +public record CallSiteWithParamIndex(Statement statement, int index, String varName) { @Override public String toString() { - return varName + " at " + stmt() + " and " + index; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + index; - result = prime * result + ((statement == null) ? 0 : statement.hashCode()); - result = prime * result + ((varName == null) ? 0 : varName.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - CallSiteWithParamIndex other = (CallSiteWithParamIndex) obj; - if (index != other.index) return false; - if (statement == null) { - if (other.statement != null) return false; - } else if (!statement.equals(other.statement)) return false; - if (varName == null) { - return other.varName == null; - } else return varName.equals(other.varName); + return varName + " at " + statement + " and " + index; } } diff --git a/CryptoAnalysis/src/main/java/crypto/extractparameter/ExtractParameterAnalysis.java b/CryptoAnalysis/src/main/java/crypto/extractparameter/ExtractParameterAnalysis.java index 3bb54bc2a..940f23d7d 100644 --- a/CryptoAnalysis/src/main/java/crypto/extractparameter/ExtractParameterAnalysis.java +++ b/CryptoAnalysis/src/main/java/crypto/extractparameter/ExtractParameterAnalysis.java @@ -78,9 +78,7 @@ private void addQueryAtCallSite(Statement statement, String varNameInSpec, int i for (ForwardQuery paramQuery : filteredQueries) { Val val = paramQuery.var(); - if (val instanceof AllocVal) { - AllocVal allocVal = (AllocVal) val; - + if (val instanceof AllocVal allocVal) { Map.Entry entry = new AbstractMap.SimpleEntry<>( allocVal.getAllocVal(), @@ -95,8 +93,7 @@ private void addQueryAtCallSite(Statement statement, String varNameInSpec, int i } CallSiteWithParamIndex callSiteWithParam = - new CallSiteWithParamIndex( - statement, parameter, index, varNameInSpec); + new CallSiteWithParamIndex(statement, index, varNameInSpec); Collection types = results.getPropagationType(); // If no value could be extracted, add the zero value to indicate it diff --git a/CryptoAnalysis/src/main/java/crypto/extractparameter/ExtractParameterQuery.java b/CryptoAnalysis/src/main/java/crypto/extractparameter/ExtractParameterQuery.java index 04a6dfea1..c09dbddfd 100644 --- a/CryptoAnalysis/src/main/java/crypto/extractparameter/ExtractParameterQuery.java +++ b/CryptoAnalysis/src/main/java/crypto/extractparameter/ExtractParameterQuery.java @@ -5,9 +5,9 @@ import boomerang.results.BackwardBoomerangResults; import boomerang.scene.ControlFlowGraph; import boomerang.scene.Val; -import java.util.Arrays; import java.util.Collection; import java.util.HashSet; +import java.util.Objects; import wpds.impl.Weight; public class ExtractParameterQuery extends BackwardQuery { @@ -62,15 +62,13 @@ public String toString() { @Override public int hashCode() { - return Arrays.hashCode(new Object[] {super.hashCode(), index}); + return Objects.hash(super.hashCode(), index); } @Override public boolean equals(Object obj) { - if (!super.equals(obj)) return false; - if (getClass() != obj.getClass()) return false; - - ExtractParameterQuery other = (ExtractParameterQuery) obj; - return index == other.index; + return super.equals(obj) + && obj instanceof ExtractParameterQuery other + && index == other.index; } } diff --git a/CryptoAnalysis/src/main/java/crypto/extractparameter/ExtractedValue.java b/CryptoAnalysis/src/main/java/crypto/extractparameter/ExtractedValue.java index 296a95029..9915dc2fd 100644 --- a/CryptoAnalysis/src/main/java/crypto/extractparameter/ExtractedValue.java +++ b/CryptoAnalysis/src/main/java/crypto/extractparameter/ExtractedValue.java @@ -3,68 +3,12 @@ import boomerang.scene.Statement; import boomerang.scene.Type; import boomerang.scene.Val; -import java.util.Arrays; import java.util.Collection; -public class ExtractedValue { - - private final Val val; - private final Statement initialStatement; - private final Collection types; - - public ExtractedValue(Val val, Statement initialStatement, Collection types) { - this.val = val; - this.initialStatement = initialStatement; - this.types = types; - } - - public Val getVal() { - return val; - } - - public Statement getInitialStatement() { - return initialStatement; - } - - public Collection getTypes() { - return types; - } +public record ExtractedValue(Val val, Statement initialStatement, Collection types) { @Override public String toString() { - return "Extracted Value: " + val + " with type " + types; - } - - @Override - public int hashCode() { - return Arrays.hashCode(new Object[] {val, initialStatement, types}); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - - ExtractedValue other = (ExtractedValue) obj; - if (val == null) { - if (other.getVal() != null) return false; - } else if (!val.equals(other.getVal())) { - return false; - } - - if (initialStatement == null) { - if (other.getInitialStatement() != null) return false; - } else if (!initialStatement.equals(other.getInitialStatement())) { - return false; - } - - if (types == null) { - if (other.getTypes() != null) return false; - } else if (!types.equals(other.getTypes())) { - return false; - } - - return true; + return "Extracted Value: " + val + " with types " + types; } } diff --git a/CryptoAnalysis/src/main/java/crypto/listener/AnalysisReporter.java b/CryptoAnalysis/src/main/java/crypto/listener/AnalysisReporter.java index 049f8ffd5..aafd27500 100644 --- a/CryptoAnalysis/src/main/java/crypto/listener/AnalysisReporter.java +++ b/CryptoAnalysis/src/main/java/crypto/listener/AnalysisReporter.java @@ -6,9 +6,11 @@ import boomerang.scene.Statement; import boomerang.scene.Val; import com.google.common.collect.Multimap; -import crypto.analysis.EnsuredCrySLPredicate; +import crypto.analysis.AbstractPredicate; +import crypto.analysis.EnsuredPredicate; import crypto.analysis.IAnalysisSeed; import crypto.analysis.errors.AbstractError; +import crypto.analysis.errors.AlternativeReqPredicateError; import crypto.analysis.errors.CallToError; import crypto.analysis.errors.ConstraintError; import crypto.analysis.errors.ForbiddenMethodError; @@ -183,7 +185,7 @@ public void afterPredicateCheck() { public void onGeneratedPredicate( IAnalysisSeed fromSeed, - EnsuredCrySLPredicate predicate, + AbstractPredicate predicate, IAnalysisSeed toPred, Statement statement) { for (IResultsListener listener : resultsListeners) { @@ -222,60 +224,45 @@ public void checkedConstraints( public void ensuredPredicates( IAnalysisSeed seed, - Multimap> predicates) { + Multimap> predicates) { for (IResultsListener listener : resultsListeners) { listener.ensuredPredicates(seed, predicates); } } public void reportError(IAnalysisSeed seed, AbstractError error) { - seed.setSecure(false); - for (IAnalysisListener analysisListener : analysisListeners) { analysisListener.onReportedError(seed, error); } for (IErrorListener errorListener : errorListeners) { - if (error instanceof CallToError) { - CallToError callToError = (CallToError) error; + if (error instanceof CallToError callToError) { errorListener.reportError(callToError); - } else if (error instanceof ConstraintError) { - ConstraintError constraintError = (ConstraintError) error; + } else if (error instanceof ConstraintError constraintError) { errorListener.reportError(constraintError); - } else if (error instanceof ForbiddenMethodError) { - ForbiddenMethodError forbiddenMethodError = (ForbiddenMethodError) error; + } else if (error instanceof ForbiddenMethodError forbiddenMethodError) { errorListener.reportError(forbiddenMethodError); - } else if (error instanceof HardCodedError) { - HardCodedError hardCodedError = (HardCodedError) error; + } else if (error instanceof HardCodedError hardCodedError) { errorListener.reportError(hardCodedError); - } else if (error instanceof ImpreciseValueExtractionError) { - ImpreciseValueExtractionError impreciseError = - (ImpreciseValueExtractionError) error; + } else if (error instanceof ImpreciseValueExtractionError impreciseError) { errorListener.reportError(impreciseError); - } else if (error instanceof IncompleteOperationError) { - IncompleteOperationError incompleteError = (IncompleteOperationError) error; + } else if (error instanceof IncompleteOperationError incompleteError) { errorListener.reportError(incompleteError); - } else if (error instanceof InstanceOfError) { - InstanceOfError instanceOfError = (InstanceOfError) error; + } else if (error instanceof InstanceOfError instanceOfError) { errorListener.reportError(instanceOfError); - } else if (error instanceof NeverTypeOfError) { - NeverTypeOfError neverTypeOfError = (NeverTypeOfError) error; + } else if (error instanceof NeverTypeOfError neverTypeOfError) { errorListener.reportError(neverTypeOfError); - } else if (error instanceof NoCallToError) { - NoCallToError noCallToError = (NoCallToError) error; + } else if (error instanceof NoCallToError noCallToError) { errorListener.reportError(noCallToError); - } else if (error instanceof PredicateContradictionError) { - PredicateContradictionError contradictionError = - (PredicateContradictionError) error; + } else if (error instanceof PredicateContradictionError contradictionError) { errorListener.reportError(contradictionError); - } else if (error instanceof RequiredPredicateError) { - RequiredPredicateError predicateError = (RequiredPredicateError) error; + } else if (error instanceof RequiredPredicateError predicateError) { + errorListener.reportError(predicateError); + } else if (error instanceof AlternativeReqPredicateError predicateError) { errorListener.reportError(predicateError); - } else if (error instanceof TypestateError) { - TypestateError typestateError = (TypestateError) error; + } else if (error instanceof TypestateError typestateError) { errorListener.reportError(typestateError); - } else if (error instanceof UncaughtExceptionError) { - UncaughtExceptionError exceptionError = (UncaughtExceptionError) error; + } else if (error instanceof UncaughtExceptionError exceptionError) { errorListener.reportError(exceptionError); } else { errorListener.reportError(error); diff --git a/CryptoAnalysis/src/main/java/crypto/listener/ErrorCollector.java b/CryptoAnalysis/src/main/java/crypto/listener/ErrorCollector.java index 90e408c7f..1f901da2f 100644 --- a/CryptoAnalysis/src/main/java/crypto/listener/ErrorCollector.java +++ b/CryptoAnalysis/src/main/java/crypto/listener/ErrorCollector.java @@ -5,6 +5,7 @@ import com.google.common.collect.HashBasedTable; import com.google.common.collect.Table; import crypto.analysis.errors.AbstractError; +import crypto.analysis.errors.AlternativeReqPredicateError; import crypto.analysis.errors.CallToError; import crypto.analysis.errors.ConstraintError; import crypto.analysis.errors.ForbiddenMethodError; @@ -98,6 +99,11 @@ public void reportError(RequiredPredicateError requiredPredicateError) { addErrorToCollection(requiredPredicateError); } + @Override + public void reportError(AlternativeReqPredicateError alternativeReqPredicateError) { + addErrorToCollection(alternativeReqPredicateError); + } + @Override public void reportError(TypestateError typestateError) { addErrorToCollection(typestateError); diff --git a/CryptoAnalysis/src/main/java/crypto/listener/IErrorListener.java b/CryptoAnalysis/src/main/java/crypto/listener/IErrorListener.java index 0a75f890f..2fe5798d4 100644 --- a/CryptoAnalysis/src/main/java/crypto/listener/IErrorListener.java +++ b/CryptoAnalysis/src/main/java/crypto/listener/IErrorListener.java @@ -1,6 +1,7 @@ package crypto.listener; import crypto.analysis.errors.AbstractError; +import crypto.analysis.errors.AlternativeReqPredicateError; import crypto.analysis.errors.CallToError; import crypto.analysis.errors.ConstraintError; import crypto.analysis.errors.ForbiddenMethodError; @@ -39,6 +40,8 @@ public interface IErrorListener { void reportError(RequiredPredicateError requiredPredicateError); + void reportError(AlternativeReqPredicateError alternativeReqPredicateError); + void reportError(TypestateError typestateError); void reportError(UncaughtExceptionError uncaughtExceptionError); diff --git a/CryptoAnalysis/src/main/java/crypto/listener/IResultsListener.java b/CryptoAnalysis/src/main/java/crypto/listener/IResultsListener.java index aaef32b58..b77023344 100644 --- a/CryptoAnalysis/src/main/java/crypto/listener/IResultsListener.java +++ b/CryptoAnalysis/src/main/java/crypto/listener/IResultsListener.java @@ -5,7 +5,8 @@ import boomerang.scene.CallGraph; import boomerang.scene.Statement; import com.google.common.collect.Multimap; -import crypto.analysis.EnsuredCrySLPredicate; +import crypto.analysis.AbstractPredicate; +import crypto.analysis.EnsuredPredicate; import crypto.analysis.IAnalysisSeed; import crypto.analysis.errors.AbstractError; import crypto.extractparameter.CallSiteWithExtractedValue; @@ -36,11 +37,11 @@ void checkedConstraints( void generatedPredicate( IAnalysisSeed fromSeed, - EnsuredCrySLPredicate predicate, + AbstractPredicate predicate, IAnalysisSeed toSeed, Statement statement); void ensuredPredicates( IAnalysisSeed seed, - Multimap> predicates); + Multimap> predicates); } diff --git a/CryptoAnalysis/src/main/java/crypto/reporting/ReportGenerator.java b/CryptoAnalysis/src/main/java/crypto/reporting/ReportGenerator.java index 646d591d8..3e0b71c9c 100644 --- a/CryptoAnalysis/src/main/java/crypto/reporting/ReportGenerator.java +++ b/CryptoAnalysis/src/main/java/crypto/reporting/ReportGenerator.java @@ -45,7 +45,6 @@ public static String generateReport( report.append("\t\tStatement: ").append(seed.getOrigin()).append("\n"); report.append("\t\tLine: ").append(seed.getOrigin().getStartLineNumber()).append("\n"); report.append("\t\tMethod: ").append(seed.getMethod()).append("\n"); - report.append("\t\tSHA-256: ").append(seed.getObjectId()).append("\n"); report.append("\t\tSecure: ").append(seed.isSecure()).append("\n"); } diff --git a/CryptoAnalysis/src/main/java/crypto/reporting/Reporter.java b/CryptoAnalysis/src/main/java/crypto/reporting/Reporter.java index 8fdd3d7ed..74b7fe133 100644 --- a/CryptoAnalysis/src/main/java/crypto/reporting/Reporter.java +++ b/CryptoAnalysis/src/main/java/crypto/reporting/Reporter.java @@ -33,9 +33,9 @@ public enum ReportFormat { protected Reporter(String outputDir, Collection ruleset) throws IOException { if (outputDir == null) { - throw new RuntimeException( - "Cannot create report without directory (try using --reportDir or setOutputDirectory)"); + throw new RuntimeException("Cannot create report without report directory"); } + this.outputFile = new File(outputDir); this.ruleset = ruleset; diff --git a/CryptoAnalysis/src/main/java/crypto/typestate/LabeledMatcherTransition.java b/CryptoAnalysis/src/main/java/crypto/typestate/LabeledMatcherTransition.java index 78cc40e39..9e0b8078f 100644 --- a/CryptoAnalysis/src/main/java/crypto/typestate/LabeledMatcherTransition.java +++ b/CryptoAnalysis/src/main/java/crypto/typestate/LabeledMatcherTransition.java @@ -3,8 +3,8 @@ import boomerang.scene.DeclaredMethod; import crypto.utils.MatcherUtils; import crysl.rule.CrySLMethod; -import java.util.Arrays; import java.util.Collection; +import java.util.Objects; import java.util.Optional; import typestate.finiteautomata.MatcherTransition; import typestate.finiteautomata.State; @@ -52,17 +52,14 @@ public String toString() { } @Override - public boolean equals(Object other) { - if (!super.equals(other)) { - return false; - } - - LabeledMatcherTransition matcherTransition = (LabeledMatcherTransition) other; - return this.methods.equals(matcherTransition.getMethods()); + public boolean equals(Object obj) { + return super.equals(obj) + && obj instanceof LabeledMatcherTransition other + && Objects.equals(methods, other.getMethods()); } @Override public int hashCode() { - return Arrays.hashCode(new Object[] {super.hashCode(), from(), to(), methods}); + return Objects.hash(super.hashCode(), from(), to(), methods); } } diff --git a/CryptoAnalysis/src/main/java/crypto/typestate/ReportingErrorStateNode.java b/CryptoAnalysis/src/main/java/crypto/typestate/ReportingErrorStateNode.java index 9b090ee23..e346a6217 100644 --- a/CryptoAnalysis/src/main/java/crypto/typestate/ReportingErrorStateNode.java +++ b/CryptoAnalysis/src/main/java/crypto/typestate/ReportingErrorStateNode.java @@ -4,17 +4,7 @@ import java.util.Collection; import typestate.finiteautomata.State; -public class ReportingErrorStateNode implements State { - - private final Collection expectedCalls; - - public ReportingErrorStateNode(Collection expectedCalls) { - this.expectedCalls = expectedCalls; - } - - public Collection getExpectedCalls() { - return expectedCalls; - } +public record ReportingErrorStateNode(Collection expectedCalls) implements State { @Override public boolean isErrorState() { @@ -35,14 +25,4 @@ public boolean isAccepting() { public String toString() { return "ERR"; } - - @Override - public int hashCode() { - return this.getClass().hashCode(); - } - - @Override - public boolean equals(Object obj) { - return obj instanceof ReportingErrorStateNode; - } } diff --git a/CryptoAnalysis/src/main/java/crypto/typestate/TypestateAnalysis.java b/CryptoAnalysis/src/main/java/crypto/typestate/TypestateAnalysis.java index bf041a297..b603adee6 100644 --- a/CryptoAnalysis/src/main/java/crypto/typestate/TypestateAnalysis.java +++ b/CryptoAnalysis/src/main/java/crypto/typestate/TypestateAnalysis.java @@ -46,11 +46,10 @@ public void runTypestateAnalysis() { Collection seeds = analysisScope.computeSeeds(); for (Query seed : seeds) { - if (!(seed instanceof ForwardSeedQuery)) { + if (!(seed instanceof ForwardSeedQuery query)) { continue; } - ForwardSeedQuery query = (ForwardSeedQuery) seed; runTypestateAnalysisForSeed(query); } } @@ -90,7 +89,7 @@ public CallGraph callGraph() { @Override public Debugger debugger( IDEALSeedSolver idealSeedSolver) { - return definition.getDebugger(idealSeedSolver); + return new Debugger<>(); } @Override @@ -118,11 +117,10 @@ public Map> getRes WeightedForwardQuery, ForwardBoomerangResults> entry : resultHandler.getResults().entrySet()) { - if (!(entry.getKey() instanceof ForwardSeedQuery)) { + if (!(entry.getKey() instanceof ForwardSeedQuery forwardSeedQuery)) { continue; } - ForwardSeedQuery forwardSeedQuery = (ForwardSeedQuery) entry.getKey(); results.put(forwardSeedQuery, entry.getValue()); } return results; diff --git a/CryptoAnalysis/src/main/java/crypto/typestate/TypestateDefinition.java b/CryptoAnalysis/src/main/java/crypto/typestate/TypestateDefinition.java index ed39b3f1c..5c7a76572 100644 --- a/CryptoAnalysis/src/main/java/crypto/typestate/TypestateDefinition.java +++ b/CryptoAnalysis/src/main/java/crypto/typestate/TypestateDefinition.java @@ -1,12 +1,9 @@ package crypto.typestate; -import boomerang.debugger.Debugger; import boomerang.scene.CallGraph; import boomerang.scene.DataFlowScope; import crysl.rule.CrySLRule; -import ideal.IDEALSeedSolver; import java.util.Collection; -import typestate.TransitionFunction; public interface TypestateDefinition { @@ -16,7 +13,5 @@ public interface TypestateDefinition { DataFlowScope getDataFlowScope(); - Debugger getDebugger(IDEALSeedSolver idealSeedSolver); - int getTimeout(); } diff --git a/CryptoAnalysis/src/main/java/crypto/typestate/WrappedState.java b/CryptoAnalysis/src/main/java/crypto/typestate/WrappedState.java index 74740fe84..00c8cfe02 100644 --- a/CryptoAnalysis/src/main/java/crypto/typestate/WrappedState.java +++ b/CryptoAnalysis/src/main/java/crypto/typestate/WrappedState.java @@ -1,6 +1,7 @@ package crypto.typestate; import crysl.rule.StateNode; +import java.util.Objects; import typestate.finiteautomata.State; public class WrappedState implements State { @@ -46,22 +47,12 @@ public boolean isInitialState() { @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((delegate == null) ? 0 : delegate.hashCode()); - return result; + return Objects.hash(delegate); } @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - WrappedState other = (WrappedState) obj; - if (delegate == null) { - if (other.delegate != null) return false; - } else if (!delegate.equals(other.delegate)) return false; - return true; + return obj instanceof WrappedState other && Objects.equals(delegate, other.delegate()); } @Override diff --git a/CryptoAnalysis/src/main/java/crypto/visualization/Visualizer.java b/CryptoAnalysis/src/main/java/crypto/visualization/Visualizer.java new file mode 100644 index 000000000..e8022fbb0 --- /dev/null +++ b/CryptoAnalysis/src/main/java/crypto/visualization/Visualizer.java @@ -0,0 +1,111 @@ +package crypto.visualization; + +import crypto.analysis.IAnalysisSeed; +import crypto.analysis.errors.AbstractError; +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import org.graphper.api.Cluster; +import org.graphper.api.FileType; +import org.graphper.api.Graphviz; +import org.graphper.api.Line; +import org.graphper.api.Subgraph; +import org.graphper.api.attributes.Rank; +import org.graphper.draw.ExecuteException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Visualizer { + + private static final Logger LOGGER = LoggerFactory.getLogger(Visualizer.class); + private static final String VISUALIZATION_NAME = "visualization"; + + private final File outputFile; + + public Visualizer(String outputDir) throws IOException { + if (outputDir == null) { + throw new NullPointerException("OutputDir must not be null"); + } + + this.outputFile = new File(outputDir); + + if (!outputFile.exists()) { + throw new IOException("Directory " + outputFile.getAbsolutePath() + " does not exist"); + } + + if (!outputFile.isDirectory()) { + throw new IOException(outputFile.getAbsolutePath() + " is not a directory"); + } + } + + public void createVisualization(Collection seeds) + throws ExecuteException, IOException { + + Graphviz.GraphvizBuilder builder = Graphviz.digraph(); + + Map errorToNode = new HashMap<>(); + for (IAnalysisSeed seed : seeds) { + Map errorToNodeForSeed = new HashMap<>(); + + for (AbstractError error : seed.getErrors()) { + WrappedNode node = new WrappedNode(error); + + builder.addNode(node.asGraphicalNode()); + errorToNodeForSeed.put(error, node); + } + + if (!errorToNodeForSeed.isEmpty()) { + Cluster cluster = createClusterForSeed(seed, errorToNodeForSeed); + builder.cluster(cluster); + } + + errorToNode.putAll(errorToNodeForSeed); + } + + Collection lines = createLines(errorToNode); + for (Line line : lines) { + builder.addLine(line); + } + + Graphviz graphviz = builder.build(); + graphviz.toFile(FileType.PNG).save(outputFile.getAbsolutePath(), VISUALIZATION_NAME); + LOGGER.info( + "Written visualization to {}", + outputFile.getAbsolutePath() + File.separator + VISUALIZATION_NAME + ".png"); + } + + private Cluster createClusterForSeed( + IAnalysisSeed seed, Map errorToNode) { + Subgraph.SubgraphBuilder subgraphBuilder = Subgraph.builder().rank(Rank.SAME); + + for (AbstractError error : errorToNode.keySet()) { + subgraphBuilder.addNode(errorToNode.get(error).asGraphicalNode()); + } + + Subgraph subgraph = subgraphBuilder.build(); + + return WrappedCluster.forSeed(seed, subgraph).asGraphicalCluster(); + } + + private Collection createLines(Map errorToNode) { + Collection result = new HashSet<>(); + + for (AbstractError error : errorToNode.keySet()) { + WrappedNode from = errorToNode.get(error); + + for (AbstractError subError : error.getSubsequentErrors()) { + if (errorToNode.containsKey(subError)) { + WrappedNode to = errorToNode.get(subError); + + Line line = WrappedLine.forLine(from, to).asGraphicalLine(); + result.add(line); + } + } + } + + return result; + } +} diff --git a/CryptoAnalysis/src/main/java/crypto/visualization/WrappedCluster.java b/CryptoAnalysis/src/main/java/crypto/visualization/WrappedCluster.java new file mode 100644 index 000000000..57c9c89ab --- /dev/null +++ b/CryptoAnalysis/src/main/java/crypto/visualization/WrappedCluster.java @@ -0,0 +1,55 @@ +package crypto.visualization; + +import crypto.analysis.IAnalysisSeed; +import java.util.Objects; +import org.graphper.api.Cluster; +import org.graphper.api.Subgraph; +import org.graphper.api.attributes.ClusterShapeEnum; +import org.graphper.api.attributes.Color; +import org.graphper.api.attributes.Labeljust; + +public class WrappedCluster { + + private final IAnalysisSeed seed; + private final Subgraph subgraph; + private Cluster cluster; + + private WrappedCluster(IAnalysisSeed seed, Subgraph subgraph) { + this.seed = seed; + this.subgraph = subgraph; + } + + public static WrappedCluster forSeed(IAnalysisSeed seed, Subgraph subgraph) { + return new WrappedCluster(seed, subgraph); + } + + public Cluster asGraphicalCluster() { + if (cluster == null) { + cluster = + Cluster.builder() + .subgraph(subgraph) + .label(" " + seed.getFact().getVariableName()) + .labeljust(Labeljust.LEFT) + .shape(ClusterShapeEnum.RECT) + .bgColor(Color.ofRGB("#E8E8E8")) // Gray-ish + .build(); + } + + return cluster; + } + + @Override + public int hashCode() { + return Objects.hash(seed); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof WrappedCluster other && Objects.equals(seed, other.seed); + } + + @Override + public String toString() { + return "Cluster: " + seed; + } +} diff --git a/CryptoAnalysis/src/main/java/crypto/visualization/WrappedLine.java b/CryptoAnalysis/src/main/java/crypto/visualization/WrappedLine.java new file mode 100644 index 000000000..12bbab5d1 --- /dev/null +++ b/CryptoAnalysis/src/main/java/crypto/visualization/WrappedLine.java @@ -0,0 +1,45 @@ +package crypto.visualization; + +import java.util.Objects; +import org.graphper.api.Line; + +public class WrappedLine { + + private final WrappedNode from; + private final WrappedNode to; + private Line line; + + private WrappedLine(WrappedNode from, WrappedNode to) { + this.from = from; + this.to = to; + } + + public static WrappedLine forLine(WrappedNode from, WrappedNode to) { + return new WrappedLine(from, to); + } + + public Line asGraphicalLine() { + if (line == null) { + line = Line.builder(from.asGraphicalNode(), to.asGraphicalNode()).build(); + } + + return line; + } + + @Override + public int hashCode() { + return Objects.hash(from, to); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof WrappedLine other + && Objects.equals(from, other.from) + && Objects.equals(to, other.to); + } + + @Override + public String toString() { + return from + " -> " + to; + } +} diff --git a/CryptoAnalysis/src/main/java/crypto/visualization/WrappedNode.java b/CryptoAnalysis/src/main/java/crypto/visualization/WrappedNode.java new file mode 100644 index 000000000..ec4217ef9 --- /dev/null +++ b/CryptoAnalysis/src/main/java/crypto/visualization/WrappedNode.java @@ -0,0 +1,76 @@ +package crypto.visualization; + +import crypto.analysis.errors.AbstractConstraintsError; +import crypto.analysis.errors.AbstractError; +import crypto.analysis.errors.AbstractOrderError; +import crypto.analysis.errors.AbstractRequiredPredicateError; +import crypto.analysis.errors.ForbiddenMethodError; +import crypto.analysis.errors.PredicateConstraintError; +import java.util.Objects; +import org.graphper.api.Node; +import org.graphper.api.attributes.Color; +import org.graphper.api.attributes.NodeShapeEnum; + +public class WrappedNode { + + private final AbstractError error; + private Node graphicalNode; + + public WrappedNode(AbstractError error) { + this.error = error; + } + + public Node asGraphicalNode() { + if (graphicalNode == null) { + graphicalNode = + Node.builder() + .label(getLabel()) + .shape(NodeShapeEnum.RECT) + .fillColor(getColor()) + .build(); + } + + return graphicalNode; + } + + private String getLabel() { + return error.getClass().getSimpleName() + + "\nClass: " + + error.getErrorStatement().getMethod().getDeclaringClass() + + "\n" + + error.getErrorStatement() + + "\nLine: " + + error.getLineNumber(); + } + + private Color getColor() { + if (error instanceof ForbiddenMethodError) { + return Color.ofRGB("#9AF6FF"); // turquoise-ish + } else if (error instanceof AbstractOrderError) { + return Color.ofRGB("#FFF7AB"); // Yellow-ish + } else if (error instanceof AbstractRequiredPredicateError) { + return Color.ofRGB("#FFEBB2"); // Orange-ish + } else if (error instanceof AbstractConstraintsError) { + return Color.ofRGB("#C1D4FF"); // Blue-ish + } else if (error instanceof PredicateConstraintError) { + return Color.INDIGO; + } else { + return Color.WHITE; + } + } + + @Override + public int hashCode() { + return Objects.hash(error); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof WrappedNode other && Objects.equals(error, other.error); + } + + @Override + public String toString() { + return "Node: " + error; + } +} diff --git a/CryptoAnalysis/src/test/java/test/UsagePatternErrorListener.java b/CryptoAnalysis/src/test/java/test/UsagePatternErrorListener.java index 5a85d8c68..95e773b47 100644 --- a/CryptoAnalysis/src/test/java/test/UsagePatternErrorListener.java +++ b/CryptoAnalysis/src/test/java/test/UsagePatternErrorListener.java @@ -1,6 +1,7 @@ package test; import crypto.analysis.errors.AbstractError; +import crypto.analysis.errors.AlternativeReqPredicateError; import crypto.analysis.errors.CallToError; import crypto.analysis.errors.ConstraintError; import crypto.analysis.errors.ForbiddenMethodError; @@ -192,6 +193,16 @@ public void reportError(RequiredPredicateError requiredPredicateError) { } } + @Override + public void reportError(AlternativeReqPredicateError alternativeReqPredicateError) { + for (Assertion a : assertions) { + if (a instanceof PredicateErrorCountAssertion) { + PredicateErrorCountAssertion errorCountAssertion = (PredicateErrorCountAssertion) a; + errorCountAssertion.increaseCount(); + } + } + } + @Override public void reportError(TypestateError typestateError) { for (Assertion a : assertions) { diff --git a/CryptoAnalysis/src/test/java/test/UsagePatternResultsListener.java b/CryptoAnalysis/src/test/java/test/UsagePatternResultsListener.java index dbaa88eaa..fd444d2af 100644 --- a/CryptoAnalysis/src/test/java/test/UsagePatternResultsListener.java +++ b/CryptoAnalysis/src/test/java/test/UsagePatternResultsListener.java @@ -9,7 +9,8 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import com.google.common.collect.Table; -import crypto.analysis.EnsuredCrySLPredicate; +import crypto.analysis.AbstractPredicate; +import crypto.analysis.EnsuredPredicate; import crypto.analysis.IAnalysisSeed; import crypto.analysis.errors.AbstractError; import crypto.extractparameter.CallSiteWithExtractedValue; @@ -102,7 +103,7 @@ public void checkedConstraints( @Override public void generatedPredicate( IAnalysisSeed fromSeed, - EnsuredCrySLPredicate predicate, + AbstractPredicate predicate, IAnalysisSeed toSeed, Statement statement) { for (Assertion a : assertions) { @@ -155,7 +156,7 @@ public void generatedPredicate( @Override public void ensuredPredicates( IAnalysisSeed seed, - Multimap> predicates) { + Multimap> predicates) { for (Assertion a : assertions) { if (a instanceof HasEnsuredPredicateAssertion) { HasEnsuredPredicateAssertion assertion = (HasEnsuredPredicateAssertion) a; @@ -166,10 +167,10 @@ public void ensuredPredicates( Collection values = seed.getAnalysisResults().asStatementValWeightTable().columnKeySet(); - Collection> ensuredPreds = + Collection> ensuredPreds = predicates.get(assertion.getStmt()); - for (Map.Entry ensPred : ensuredPreds) { + for (Map.Entry ensPred : ensuredPreds) { assertion.reported(values, ensPred.getKey()); } } @@ -183,10 +184,10 @@ public void ensuredPredicates( Collection values = seed.getAnalysisResults().asStatementValWeightTable().columnKeySet(); - Collection> ensuredPreds = + Collection> ensuredPreds = predicates.get(assertion.getStmt()); - for (Map.Entry ensPred : ensuredPreds) { + for (Map.Entry ensPred : ensuredPreds) { assertion.reported(values, ensPred.getKey()); } } diff --git a/CryptoAnalysis/src/test/java/test/UsagePatternTestingFramework.java b/CryptoAnalysis/src/test/java/test/UsagePatternTestingFramework.java index 6b7426552..2f6b1c0dd 100644 --- a/CryptoAnalysis/src/test/java/test/UsagePatternTestingFramework.java +++ b/CryptoAnalysis/src/test/java/test/UsagePatternTestingFramework.java @@ -95,6 +95,7 @@ protected DataFlowScope createDataFlowScope() { protected SceneTransformer createAnalysisTransformer() throws ImprecisionException { Options.v().setPhaseOption("jb", "use-original-names:false"); + Options.v().set_keep_line_number(true); return new SceneTransformer() { diff --git a/CryptoAnalysis/src/test/java/test/assertions/ExtractedValueAssertion.java b/CryptoAnalysis/src/test/java/test/assertions/ExtractedValueAssertion.java index 2e3811705..2ac539a3a 100644 --- a/CryptoAnalysis/src/test/java/test/assertions/ExtractedValueAssertion.java +++ b/CryptoAnalysis/src/test/java/test/assertions/ExtractedValueAssertion.java @@ -19,13 +19,13 @@ public ExtractedValueAssertion(Statement stmt, int index) { public void computedValues(Collection collectedValues) { for (CallSiteWithExtractedValue callSite : collectedValues) { - Statement statement = callSite.getCallSiteWithParam().stmt(); + Statement statement = callSite.callSiteWithParam().statement(); - if (callSite.getExtractedValue().getVal().equals(Val.zero())) { + if (callSite.extractedValue().val().equals(Val.zero())) { continue; } - if (statement.equals(stmt) && callSite.getCallSiteWithParam().getIndex() == index) { + if (statement.equals(stmt) && callSite.callSiteWithParam().index() == index) { satisfied = true; } } diff --git a/CryptoAnalysis/src/test/java/test/assertions/HasEnsuredPredicateAssertion.java b/CryptoAnalysis/src/test/java/test/assertions/HasEnsuredPredicateAssertion.java index e274a512e..39aab9e75 100644 --- a/CryptoAnalysis/src/test/java/test/assertions/HasEnsuredPredicateAssertion.java +++ b/CryptoAnalysis/src/test/java/test/assertions/HasEnsuredPredicateAssertion.java @@ -2,8 +2,8 @@ import boomerang.scene.Statement; import boomerang.scene.Val; -import crypto.analysis.EnsuredCrySLPredicate; -import crypto.analysis.HiddenPredicate; +import crypto.analysis.AbstractPredicate; +import crypto.analysis.UnEnsuredPredicate; import java.util.Collection; import test.Assertion; @@ -38,8 +38,8 @@ public Statement getStmt() { return stmt; } - public void reported(Collection seed, EnsuredCrySLPredicate pred) { - if (!seed.contains(val) || pred instanceof HiddenPredicate) { + public void reported(Collection seed, AbstractPredicate pred) { + if (!seed.contains(val) || pred instanceof UnEnsuredPredicate) { return; } @@ -53,7 +53,14 @@ public String toString() { if (predName == null) { return "Expected a predicate for " + val.getVariableName() + " @ " + stmt; } else { - return "Expected '" + predName + "' ensured on " + val.getVariableName() + " @ " + stmt; + return "Expected '" + + predName + + "' ensured on " + + val.getVariableName() + + " @ " + + stmt + + " @ line " + + stmt.getStartLineNumber(); } } } diff --git a/CryptoAnalysis/src/test/java/test/assertions/HasGeneratedPredicateAssertion.java b/CryptoAnalysis/src/test/java/test/assertions/HasGeneratedPredicateAssertion.java index f07a3ca5c..7e8406219 100644 --- a/CryptoAnalysis/src/test/java/test/assertions/HasGeneratedPredicateAssertion.java +++ b/CryptoAnalysis/src/test/java/test/assertions/HasGeneratedPredicateAssertion.java @@ -2,8 +2,8 @@ import boomerang.scene.Statement; import boomerang.scene.Val; -import crypto.analysis.EnsuredCrySLPredicate; -import crypto.analysis.HiddenPredicate; +import crypto.analysis.AbstractPredicate; +import crypto.analysis.UnEnsuredPredicate; import java.util.Collection; import test.Assertion; @@ -28,8 +28,8 @@ public boolean isImprecise() { return false; } - public void reported(Collection seed, EnsuredCrySLPredicate predicate) { - if (seed.contains(val) && !(predicate instanceof HiddenPredicate)) { + public void reported(Collection seed, AbstractPredicate predicate) { + if (seed.contains(val) && !(predicate instanceof UnEnsuredPredicate)) { satisfied = true; } } @@ -40,6 +40,11 @@ public Statement getStatement() { @Override public String toString() { - return "Expected " + val.getVariableName() + " to generate a predicate @ " + statement; + return "Expected " + + val.getVariableName() + + " to generate a predicate @ " + + statement + + " @ line " + + statement.getStartLineNumber(); } } diff --git a/CryptoAnalysis/src/test/java/test/assertions/HasNotGeneratedPredicateAssertion.java b/CryptoAnalysis/src/test/java/test/assertions/HasNotGeneratedPredicateAssertion.java index d4e309f83..7d6e28785 100644 --- a/CryptoAnalysis/src/test/java/test/assertions/HasNotGeneratedPredicateAssertion.java +++ b/CryptoAnalysis/src/test/java/test/assertions/HasNotGeneratedPredicateAssertion.java @@ -2,8 +2,8 @@ import boomerang.scene.Statement; import boomerang.scene.Val; -import crypto.analysis.EnsuredCrySLPredicate; -import crypto.analysis.HiddenPredicate; +import crypto.analysis.AbstractPredicate; +import crypto.analysis.UnEnsuredPredicate; import java.util.Collection; import test.Assertion; @@ -32,8 +32,8 @@ public Statement getStatement() { return statement; } - public void reported(Collection seed, EnsuredCrySLPredicate predicate) { - if (seed.contains(val) && !(predicate instanceof HiddenPredicate)) { + public void reported(Collection seed, AbstractPredicate predicate) { + if (seed.contains(val) && !(predicate instanceof UnEnsuredPredicate)) { imprecise = true; } } @@ -43,6 +43,8 @@ public String toString() { return "Did not expected " + val.getVariableName() + " to generate a predicate @ " - + statement; + + statement + + " @ line " + + statement.getStartLineNumber(); } } diff --git a/CryptoAnalysis/src/test/java/test/assertions/NotHasEnsuredPredicateAssertion.java b/CryptoAnalysis/src/test/java/test/assertions/NotHasEnsuredPredicateAssertion.java index 55db56df8..5b71ebb53 100644 --- a/CryptoAnalysis/src/test/java/test/assertions/NotHasEnsuredPredicateAssertion.java +++ b/CryptoAnalysis/src/test/java/test/assertions/NotHasEnsuredPredicateAssertion.java @@ -2,8 +2,8 @@ import boomerang.scene.Statement; import boomerang.scene.Val; -import crypto.analysis.EnsuredCrySLPredicate; -import crypto.analysis.HiddenPredicate; +import crypto.analysis.AbstractPredicate; +import crypto.analysis.UnEnsuredPredicate; import java.util.Collection; import test.Assertion; @@ -38,8 +38,8 @@ public Statement getStmt() { return stmt; } - public void reported(Collection seed, EnsuredCrySLPredicate pred) { - if (!seed.contains(val) || pred instanceof HiddenPredicate) { + public void reported(Collection seed, AbstractPredicate pred) { + if (!seed.contains(val) || pred instanceof UnEnsuredPredicate) { return; } @@ -51,14 +51,21 @@ public void reported(Collection seed, EnsuredCrySLPredicate pred) { @Override public String toString() { if (predName == null) { - return "Did not expect a predicate for " + val.getVariableName() + " @ " + stmt; + return "Did not expect a predicate for " + + val.getVariableName() + + " @ " + + stmt + + " @ line " + + stmt.getStartLineNumber(); } else { return "Did not expect '" + predName + "' ensured on " + val.getVariableName() + " @ " - + stmt; + + stmt + + " @ line " + + stmt.getStartLineNumber(); } } } diff --git a/CryptoAnalysis/src/test/java/tests/error/predicate/requiredpredicate/RequiredPredicatesTest.java b/CryptoAnalysis/src/test/java/tests/error/predicate/requiredpredicate/RequiredPredicatesTest.java index b4da5ed44..1b072e460 100644 --- a/CryptoAnalysis/src/test/java/tests/error/predicate/requiredpredicate/RequiredPredicatesTest.java +++ b/CryptoAnalysis/src/test/java/tests/error/predicate/requiredpredicate/RequiredPredicatesTest.java @@ -28,10 +28,12 @@ public void pred1OnPos1() { A noPred1OnA = new A(); Assertions.notHasEnsuredPredicate(noPred1OnA); + // correct Requires r1 = new Requires(); r1.pred1onPos1(pred1OnA); Assertions.hasGeneratedPredicate(r1); + // 1 required error Requires r2 = new Requires(); r2.pred1onPos1(noPred1OnA); Assertions.hasNotGeneratedPredicate(r2); @@ -39,7 +41,6 @@ public void pred1OnPos1() { Assertions.predicateErrors(1); } - @Ignore("Predicate that are not checked yet are assumed to be true") @Test public void notPred1onPos1() { A pred1OnA = new A(); @@ -49,15 +50,17 @@ public void notPred1onPos1() { A noPred1OnA = new A(); Assertions.notHasEnsuredPredicate(noPred1OnA); + // correct Requires r1 = new Requires(); r1.notPred1onPos1(noPred1OnA); Assertions.hasGeneratedPredicate(r1); + // 1 contradiction error Requires r2 = new Requires(); r2.notPred1onPos1(pred1OnA); Assertions.hasNotGeneratedPredicate(r2); - Assertions.predicateErrors(1); + Assertions.predicateContradictionErrors(1); } // AND @@ -72,18 +75,22 @@ public void pred1onPos1_AND_pred1onPos2() { A noPred1onA = new A(); Assertions.notHasEnsuredPredicate(noPred1onA); + // correct Requires r1 = new Requires(); r1.pred1onPos1_AND_pred1onPos2(pred1onA, pred1onA); Assertions.hasGeneratedPredicate(r1); + // 1 required error Requires r2 = new Requires(); r2.pred1onPos1_AND_pred1onPos2(pred1onA, noPred1onA); Assertions.hasNotGeneratedPredicate(r2); + // 1 required error Requires r3 = new Requires(); r3.pred1onPos1_AND_pred1onPos2(noPred1onA, pred1onA); Assertions.hasNotGeneratedPredicate(r3); + // 1 required + 1 required error Requires r4 = new Requires(); r4.pred1onPos1_AND_pred1onPos2(noPred1onA, noPred1onA); Assertions.hasNotGeneratedPredicate(r4); @@ -91,19 +98,6 @@ public void pred1onPos1_AND_pred1onPos2() { Assertions.predicateErrors(4); } - @Test - public void test() { - A noPred1onA = new A(); - Assertions.notHasEnsuredPredicate(noPred1onA); - - Requires r4 = new Requires(); - r4.pred1onPos1_AND_pred1onPos2(noPred1onA, noPred1onA); - Assertions.notHasEnsuredPredicate(r4); - - Assertions.predicateErrors(2); - } - - @Ignore @Test public void pred1onPos1_AND_notPred1onPos2() { A pred1onA = new A(); @@ -113,26 +107,30 @@ public void pred1onPos1_AND_notPred1onPos2() { A noPredOnA = new A(); Assertions.notHasEnsuredPredicate(noPredOnA); + // correct Requires r1 = new Requires(); r1.pred1onPos1_AND_notPred1onPos2(pred1onA, noPredOnA); - Assertions.hasEnsuredPredicate(r1); + Assertions.hasGeneratedPredicate(r1); + // 1 required + 1 contradiction error Requires r2 = new Requires(); r2.pred1onPos1_AND_notPred1onPos2(noPredOnA, pred1onA); - Assertions.notHasEnsuredPredicate(r2); + Assertions.hasNotGeneratedPredicate(r2); + // 1 contradiction error Requires r3 = new Requires(); r3.pred1onPos1_AND_notPred1onPos2(pred1onA, pred1onA); - Assertions.notHasEnsuredPredicate(r3); + Assertions.hasNotGeneratedPredicate(r3); + // 1 required error Requires r4 = new Requires(); r4.pred1onPos1_AND_notPred1onPos2(noPredOnA, noPredOnA); - Assertions.notHasEnsuredPredicate(r4); + Assertions.hasNotGeneratedPredicate(r4); - Assertions.predicateErrors(4); + Assertions.predicateErrors(2); + Assertions.predicateContradictionErrors(2); } - @Ignore @Test public void notPred1onPos1_AND_pred1onPos2() { A pred1onA = new A(); @@ -142,26 +140,30 @@ public void notPred1onPos1_AND_pred1onPos2() { A noPredOnA = new A(); Assertions.notHasEnsuredPredicate(noPredOnA); + // correct Requires r1 = new Requires(); r1.notPred1onPos1_AND_pred1onPos2(noPredOnA, pred1onA); - Assertions.hasEnsuredPredicate(r1); + Assertions.hasGeneratedPredicate(r1); + // 1 contradiction + 1 required error Requires r2 = new Requires(); r2.notPred1onPos1_AND_pred1onPos2(pred1onA, noPredOnA); - Assertions.notHasEnsuredPredicate(r2); + Assertions.hasNotGeneratedPredicate(r2); + // 1 contradiction error Requires r3 = new Requires(); r3.notPred1onPos1_AND_pred1onPos2(pred1onA, pred1onA); - Assertions.notHasEnsuredPredicate(r3); + Assertions.hasNotGeneratedPredicate(r3); + // 1 required error Requires r4 = new Requires(); r4.notPred1onPos1_AND_pred1onPos2(noPredOnA, noPredOnA); - Assertions.notHasEnsuredPredicate(r4); + Assertions.hasNotGeneratedPredicate(r4); - Assertions.predicateErrors(4); + Assertions.predicateErrors(2); + Assertions.predicateContradictionErrors(2); } - @Ignore @Test public void notPred1onPos1_AND_notPred1onPos2() { A pred1onA = new A(); @@ -171,23 +173,28 @@ public void notPred1onPos1_AND_notPred1onPos2() { A noPredOnA = new A(); Assertions.notHasEnsuredPredicate(noPredOnA); + // correct Requires r1 = new Requires(); r1.notPred1onPos1_AND_notPred1onPos2(noPredOnA, noPredOnA); Assertions.hasGeneratedPredicate(r1); + // 1 contradiction error Requires r2 = new Requires(); r2.notPred1onPos1_AND_notPred1onPos2(pred1onA, noPredOnA); Assertions.hasNotGeneratedPredicate(r2); + // 1 contradiction error Requires r3 = new Requires(); - r3.notPred1onPos1_AND_notPred1onPos2(pred1onA, pred1onA); + r3.notPred1onPos1_AND_notPred1onPos2(noPredOnA, pred1onA); Assertions.hasNotGeneratedPredicate(r3); + // 2 contradiction error Requires r4 = new Requires(); - r4.notPred1onPos1_AND_notPred1onPos2(noPredOnA, pred1onA); + r4.notPred1onPos1_AND_notPred1onPos2(pred1onA, pred1onA); Assertions.hasNotGeneratedPredicate(r4); - Assertions.predicateErrors(3); + Assertions.predicateErrors(0); + Assertions.predicateContradictionErrors(4); } // multi predicates @@ -204,26 +211,29 @@ public void pred1onPos1_AND_pred2onPos2() { A noPredOnA = new A(); Assertions.notHasEnsuredPredicate(noPredOnA); + // correct Requires r1 = new Requires(); r1.pred1onPos1_AND_pred2onPos2(pred1onA, pred2onA); Assertions.hasGeneratedPredicate(r1); + // 1 required error Requires r2 = new Requires(); r2.pred1onPos1_AND_pred2onPos2(pred1onA, noPredOnA); Assertions.hasNotGeneratedPredicate(r2); + // 1 required error Requires r3 = new Requires(); - r3.pred1onPos1_AND_pred2onPos2(noPredOnA, noPredOnA); + r3.pred1onPos1_AND_pred2onPos2(noPredOnA, pred2onA); Assertions.hasNotGeneratedPredicate(r3); + // 1 required + 1 required error Requires r4 = new Requires(); - r4.pred1onPos1_AND_pred2onPos2(noPredOnA, pred2onA); + r4.pred1onPos1_AND_pred2onPos2(noPredOnA, noPredOnA); Assertions.hasNotGeneratedPredicate(r4); Assertions.predicateErrors(4); } - @Ignore("Predicate that are not checked yet are assumed to be true") @Test public void pred1onPos1_AND_notPred2onPos2() { A pred1onA = new A(); @@ -237,26 +247,30 @@ public void pred1onPos1_AND_notPred2onPos2() { A noPredOnA = new A(); Assertions.notHasEnsuredPredicate(noPredOnA); + // correct Requires r1 = new Requires(); r1.pred1onPos1_AND_notPred2onPos2(pred1onA, noPredOnA); - Assertions.hasEnsuredPredicate(r1); + Assertions.hasGeneratedPredicate(r1); + // 1 required + 1 contradiction error Requires r2 = new Requires(); r2.pred1onPos1_AND_notPred2onPos2(noPredOnA, pred2onA); - Assertions.notHasEnsuredPredicate(r2); + Assertions.hasNotGeneratedPredicate(r2); + // 1 contradiction error Requires r3 = new Requires(); r3.pred1onPos1_AND_notPred2onPos2(pred1onA, pred2onA); - Assertions.notHasEnsuredPredicate(r3); + Assertions.hasNotGeneratedPredicate(r3); + // 1 required error Requires r4 = new Requires(); r4.pred1onPos1_AND_notPred2onPos2(noPredOnA, noPredOnA); - Assertions.notHasEnsuredPredicate(r4); + Assertions.hasNotGeneratedPredicate(r4); - Assertions.predicateErrors(4); + Assertions.predicateErrors(2); + Assertions.predicateContradictionErrors(2); } - @Ignore("Predicate that are not checked yet are assumed to be true") @Test public void notPred1onPos1_AND_pred2onPos2() { A pred1onA = new A(); @@ -270,26 +284,30 @@ public void notPred1onPos1_AND_pred2onPos2() { A noPredOnA = new A(); Assertions.notHasEnsuredPredicate(noPredOnA); + // correct Requires r1 = new Requires(); r1.notPred1onPos1_AND_pred2onPos2(noPredOnA, pred2onA); - Assertions.hasEnsuredPredicate(r1); + Assertions.hasGeneratedPredicate(r1); + // 1 contradiction + 1 required error Requires r2 = new Requires(); r2.notPred1onPos1_AND_pred2onPos2(pred1onA, noPredOnA); - Assertions.notHasEnsuredPredicate(r2); + Assertions.hasNotGeneratedPredicate(r2); + // 1 contradiction Requires r3 = new Requires(); r3.notPred1onPos1_AND_pred2onPos2(pred1onA, pred2onA); - Assertions.notHasEnsuredPredicate(r3); + Assertions.hasNotGeneratedPredicate(r3); + // 1 required error Requires r4 = new Requires(); r4.notPred1onPos1_AND_pred2onPos2(noPredOnA, noPredOnA); Assertions.notHasEnsuredPredicate(r4); - Assertions.predicateErrors(4); + Assertions.predicateErrors(2); + Assertions.predicateContradictionErrors(2); } - @Ignore("Predicate that are not checked yet are assumed to be true") @Test public void notPred1onPos1_AND_notPred2onPos2() { A pred1onA = new A(); @@ -303,30 +321,33 @@ public void notPred1onPos1_AND_notPred2onPos2() { A noPredOnA = new A(); Assertions.notHasEnsuredPredicate(noPredOnA); + // correct Requires r1 = new Requires(); r1.notPred1onPos1_AND_notPred2onPos2(noPredOnA, noPredOnA); - Assertions.hasEnsuredPredicate(r1); + Assertions.hasGeneratedPredicate(r1); + // 1 contradiction error Requires r2 = new Requires(); r2.notPred1onPos1_AND_notPred2onPos2(pred1onA, noPredOnA); - Assertions.notHasEnsuredPredicate(r2); + Assertions.hasNotGeneratedPredicate(r2); + // 1 contradiction error Requires r3 = new Requires(); - r3.notPred1onPos1_AND_notPred2onPos2(pred1onA, pred2onA); - Assertions.notHasEnsuredPredicate(r3); + r3.notPred1onPos1_AND_notPred2onPos2(noPredOnA, pred2onA); + Assertions.hasNotGeneratedPredicate(r3); + // 1 contradiction + 1 contradiction error Requires r4 = new Requires(); - r4.notPred1onPos1_AND_notPred2onPos2(noPredOnA, pred2onA); - Assertions.notHasEnsuredPredicate(r4); + r4.notPred1onPos1_AND_notPred2onPos2(pred1onA, pred2onA); + Assertions.hasNotGeneratedPredicate(r4); - Assertions.predicateErrors(4); + Assertions.predicateErrors(0); + Assertions.predicateContradictionErrors(4); } // OR // same predicate - @Ignore( - "Requires negated conditional predicates. Alternative predicate have to belong to the same object") @Test public void pred1onPos1_OR_pred1onPos2() { A pred1onA = new A(); @@ -339,25 +360,25 @@ public void pred1onPos1_OR_pred1onPos2() { // assert true Requires r1 = new Requires(); r1.pred1onPos1_OR_pred1onPos2(pred1onA, pred1onA); - Assertions.hasEnsuredPredicate(r1); + Assertions.hasGeneratedPredicate(r1); Requires r2 = new Requires(); r2.pred1onPos1_OR_pred1onPos2(pred1onA, noPredOnA); - Assertions.hasEnsuredPredicate(r2); + Assertions.hasGeneratedPredicate(r2); Requires r3 = new Requires(); r3.pred1onPos1_OR_pred1onPos2(noPredOnA, pred1onA); - Assertions.hasEnsuredPredicate(r3); + Assertions.hasGeneratedPredicate(r3); // assert false Requires r4 = new Requires(); r4.pred1onPos1_OR_pred1onPos2(noPredOnA, noPredOnA); - Assertions.notHasEnsuredPredicate(r4); + Assertions.hasNotGeneratedPredicate(r4); - Assertions.predicateErrors(2); // two, because each parameter will be reported + // one, because both parameters belong to the same alternative predicate + Assertions.predicateErrors(1); } - @Ignore @Test public void pred1onPos1_OR_notPred1onPos2() { A pred1onA = new A(); @@ -370,25 +391,25 @@ public void pred1onPos1_OR_notPred1onPos2() { // assert true Requires r1 = new Requires(); r1.pred1onPos1_OR_notPred1onPos2(pred1onA, noPredOnA); - Assertions.hasEnsuredPredicate(r1); + Assertions.hasGeneratedPredicate(r1); Requires r2 = new Requires(); r2.pred1onPos1_OR_notPred1onPos2(pred1onA, pred1onA); - Assertions.hasEnsuredPredicate(r2); + Assertions.hasGeneratedPredicate(r2); Requires r3 = new Requires(); r3.pred1onPos1_OR_notPred1onPos2(noPredOnA, noPredOnA); - Assertions.hasEnsuredPredicate(r3); + Assertions.hasGeneratedPredicate(r3); // assert false Requires r4 = new Requires(); r4.pred1onPos1_OR_notPred1onPos2(noPredOnA, pred1onA); - Assertions.notHasEnsuredPredicate(r4); + Assertions.hasNotGeneratedPredicate(r4); - Assertions.predicateErrors(2); // two, because each parameter will be reported + // one, because both parameters belong to the same alternative predicate + Assertions.predicateErrors(1); } - @Ignore @Test public void notPred1onPos1_OR_pred1onPos2() { A pred1onA = new A(); @@ -401,25 +422,25 @@ public void notPred1onPos1_OR_pred1onPos2() { // assert true Requires r1 = new Requires(); r1.notPred1onPos1_OR_pred1onPos2(noPredOnA, pred1onA); - Assertions.hasEnsuredPredicate(r1); + Assertions.hasGeneratedPredicate(r1); Requires r2 = new Requires(); r2.notPred1onPos1_OR_pred1onPos2(noPredOnA, noPredOnA); - Assertions.hasEnsuredPredicate(r2); + Assertions.hasGeneratedPredicate(r2); Requires r3 = new Requires(); r3.notPred1onPos1_OR_pred1onPos2(pred1onA, pred1onA); - Assertions.hasEnsuredPredicate(r3); + Assertions.hasGeneratedPredicate(r3); // assert false Requires r4 = new Requires(); r4.notPred1onPos1_OR_pred1onPos2(pred1onA, noPredOnA); - Assertions.notHasEnsuredPredicate(r4); + Assertions.hasNotGeneratedPredicate(r4); - Assertions.predicateErrors(2); // two, because each parameter will be reported + // one, because both parameters belong to the same alternative predicate + Assertions.predicateErrors(1); } - @Ignore @Test public void notPred1onPos1_OR_notPred1onPos2() { A pred1onA = new A(); @@ -436,28 +457,29 @@ public void notPred1onPos1_OR_notPred1onPos2() { // assert true Requires r1 = new Requires(); r1.notPred1onPos1_OR_notPred1onPos2(noPredOnA, noPredOnA); - Assertions.hasEnsuredPredicate(r1); + Assertions.hasGeneratedPredicate(r1); Requires r2 = new Requires(); r2.notPred1onPos1_OR_notPred1onPos2(noPredOnA, pred1onA); - Assertions.hasEnsuredPredicate(r2); + Assertions.hasGeneratedPredicate(r2); Requires r3 = new Requires(); r3.notPred1onPos1_OR_notPred1onPos2(pred1onA, noPredOnA); - Assertions.hasEnsuredPredicate(r3); + Assertions.hasGeneratedPredicate(r3); // assert false Requires r4 = new Requires(); r4.notPred1onPos1_OR_notPred1onPos2(pred1onA, pred1onA2); - Assertions.notHasEnsuredPredicate(r4); + Assertions.hasNotGeneratedPredicate(r4); - Assertions.predicateErrors(2); // two, because each parameter will be reported + // one, because both parameters belong to the same alternative predicate + Assertions.predicateErrors(1); } // multi predicates @Ignore( - "Can be tested since negated conditions in the REQUIRES section are not supported" - + "Alternative predicates on different objects o1 and o2 (p1[o1] || p2[o2] have to be rewritten as" + "Cannot be tested since negated conditions in the REQUIRES section are not supported" + + "Alternative predicates on different objects o1 and o2 (p1[o1] || p2[o2]) have to be rewritten as" + "!p1[o1] => p2[o2]; and !p2[o2] => p1[o1];") @Test public void pred1onPos1_OR_pred2onPos2() { @@ -475,25 +497,25 @@ public void pred1onPos1_OR_pred2onPos2() { // assert true Requires r1 = new Requires(); r1.pred1onPos1_OR_pred2onPos2(pred1onA, pred2onA); - Assertions.hasEnsuredPredicate(r1); + Assertions.hasGeneratedPredicate(r1); Requires r2 = new Requires(); r2.pred1onPos1_OR_pred2onPos2(pred1onA, noPredOnA); - Assertions.hasEnsuredPredicate(r2); + Assertions.hasGeneratedPredicate(r2); Requires r3 = new Requires(); r3.pred1onPos1_OR_pred2onPos2(noPredOnA, pred2onA); - Assertions.hasEnsuredPredicate(r3); + Assertions.hasGeneratedPredicate(r3); // assert false Requires r4 = new Requires(); r4.pred1onPos1_OR_pred2onPos2(noPredOnA, noPredOnA); - Assertions.notHasEnsuredPredicate(r4); + Assertions.hasNotGeneratedPredicate(r4); - Assertions.predicateErrors(2); // two, because each parameter will be reported + // one, because both parameters belong to the same alternative predicate + Assertions.predicateErrors(1); } - @Ignore("Predicate that are not checked yet are assumed to be true") @Test public void pred1onP1_OR_notPred2onP2() { A pred1onA = new A(); @@ -510,25 +532,25 @@ public void pred1onP1_OR_notPred2onP2() { // assert true Requires r1 = new Requires(); r1.pred1onPos1_OR_notPred2onPos2(pred1onA, noPredOnA); - Assertions.hasEnsuredPredicate(r1); + Assertions.hasGeneratedPredicate(r1); Requires r2 = new Requires(); r2.pred1onPos1_OR_notPred2onPos2(pred1onA, pred2onA); - Assertions.hasEnsuredPredicate(r2); + Assertions.hasGeneratedPredicate(r2); Requires r3 = new Requires(); r3.pred1onPos1_OR_notPred2onPos2(noPredOnA, noPredOnA); - Assertions.hasEnsuredPredicate(r3); + Assertions.hasGeneratedPredicate(r3); // assert false Requires r4 = new Requires(); r4.pred1onPos1_OR_notPred2onPos2(noPredOnA, pred2onA); - Assertions.notHasEnsuredPredicate(r4); + Assertions.hasNotGeneratedPredicate(r4); - Assertions.predicateErrors(2); // two, because each parameter will be reported + // one, because both parameters belong to the same alternative predicate + Assertions.predicateErrors(1); } - @Ignore("Predicate that are not checked yet are assumed to be true") @Test public void notPred1onP1_OR_pred2onP2() { A pred1onA = new A(); @@ -545,25 +567,25 @@ public void notPred1onP1_OR_pred2onP2() { // assert true Requires r1 = new Requires(); r1.notPred1onPos1_OR_pred2onPos2(noPredOnA, pred2onA); - Assertions.hasEnsuredPredicate(r1); + Assertions.hasGeneratedPredicate(r1); Requires r2 = new Requires(); r2.notPred1onPos1_OR_pred2onPos2(pred1onA, pred2onA); - Assertions.hasEnsuredPredicate(r2); + Assertions.hasGeneratedPredicate(r2); Requires r3 = new Requires(); r3.notPred1onPos1_OR_pred2onPos2(noPredOnA, noPredOnA); - Assertions.hasEnsuredPredicate(r3); + Assertions.hasGeneratedPredicate(r3); // assert false Requires r4 = new Requires(); r4.notPred1onPos1_OR_pred2onPos2(pred1onA, noPredOnA); - Assertions.notHasEnsuredPredicate(r4); + Assertions.hasNotGeneratedPredicate(r4); - Assertions.predicateErrors(2); // two, because each parameter will be reported + // one, because both parameters belong to the same alternative predicate + Assertions.predicateErrors(1); } - @Ignore("Predicate that are not checked yet are assumed to be true") @Test public void notPred1onP1_OR_notPred2onP2() { A pred1onA = new A(); @@ -580,26 +602,26 @@ public void notPred1onP1_OR_notPred2onP2() { // assert true Requires r1 = new Requires(); r1.notPred1onPos1_OR_notPred2onPos2(noPredOnA, noPredOnA); - Assertions.hasEnsuredPredicate(r1); + Assertions.hasGeneratedPredicate(r1); Requires r2 = new Requires(); r2.notPred1onPos1_OR_notPred2onPos2(pred1onA, noPredOnA); - Assertions.hasEnsuredPredicate(r2); + Assertions.hasGeneratedPredicate(r2); Requires r3 = new Requires(); r3.notPred1onPos1_OR_notPred2onPos2(noPredOnA, pred2onA); - Assertions.hasEnsuredPredicate(r3); + Assertions.hasGeneratedPredicate(r3); // assert false Requires r4 = new Requires(); r4.notPred1onPos1_OR_notPred2onPos2(pred1onA, pred2onA); - Assertions.notHasEnsuredPredicate(r4); + Assertions.hasNotGeneratedPredicate(r4); - Assertions.predicateErrors(2); // two, because each parameter will be reported + // one, because both parameters belong to the same alternative predicate + Assertions.predicateErrors(1); } // 3 cases same predicate - @Ignore("Negated conditions are not supported see above") @Test public void pred1onPos1_OR_pred1onPos2_OR_pred1onPos3() { A pred1onA = new A(); @@ -612,40 +634,41 @@ public void pred1onPos1_OR_pred1onPos2_OR_pred1onPos3() { // assert true Requires r1 = new Requires(); r1.pred1onPos1_OR_pred1onPos2_OR_pred1onPos3(pred1onA, pred1onA, pred1onA); - Assertions.hasEnsuredPredicate(r1); + Assertions.hasGeneratedPredicate(r1); Requires r2 = new Requires(); r2.pred1onPos1_OR_pred1onPos2_OR_pred1onPos3(noPredOnA, pred1onA, pred1onA); - Assertions.hasEnsuredPredicate(r2); + Assertions.hasGeneratedPredicate(r2); Requires r3 = new Requires(); r3.pred1onPos1_OR_pred1onPos2_OR_pred1onPos3(pred1onA, noPredOnA, pred1onA); - Assertions.hasEnsuredPredicate(r3); + Assertions.hasGeneratedPredicate(r3); Requires r4 = new Requires(); r4.pred1onPos1_OR_pred1onPos2_OR_pred1onPos3(pred1onA, pred1onA, noPredOnA); - Assertions.hasEnsuredPredicate(r4); + Assertions.hasGeneratedPredicate(r4); + Requires r5 = new Requires(); r5.pred1onPos1_OR_pred1onPos2_OR_pred1onPos3(noPredOnA, noPredOnA, pred1onA); - Assertions.hasEnsuredPredicate(r5); + Assertions.hasGeneratedPredicate(r5); Requires r6 = new Requires(); r6.pred1onPos1_OR_pred1onPos2_OR_pred1onPos3(pred1onA, noPredOnA, noPredOnA); - Assertions.hasEnsuredPredicate(r6); + Assertions.hasGeneratedPredicate(r6); Requires r7 = new Requires(); r7.pred1onPos1_OR_pred1onPos2_OR_pred1onPos3(noPredOnA, pred1onA, noPredOnA); - Assertions.hasEnsuredPredicate(r7); + Assertions.hasGeneratedPredicate(r7); // assert false Requires r8 = new Requires(); r8.pred1onPos1_OR_pred1onPos2_OR_pred1onPos3(noPredOnA, noPredOnA, noPredOnA); - Assertions.notHasEnsuredPredicate(r8); + Assertions.hasNotGeneratedPredicate(r8); - Assertions.predicateErrors(3); // three, because each parameter will be reported + // one, because all three parameters belong to the same alternative predicate + Assertions.predicateErrors(1); } - @Ignore @Test public void pred1onPos1_OR_notPred1onPos2_OR_pred1onPos3() { A pred1onA = new A(); @@ -658,41 +681,41 @@ public void pred1onPos1_OR_notPred1onPos2_OR_pred1onPos3() { // assert true Requires r1 = new Requires(); r1.pred1onPos1_OR_notPred1onPos2_OR_pred1onPos3(pred1onA, pred1onA, pred1onA); - Assertions.hasEnsuredPredicate(r1); + Assertions.hasGeneratedPredicate(r1); Requires r2 = new Requires(); r2.pred1onPos1_OR_notPred1onPos2_OR_pred1onPos3(noPredOnA, pred1onA, pred1onA); - Assertions.hasEnsuredPredicate(r2); + Assertions.hasGeneratedPredicate(r2); Requires r3 = new Requires(); r3.pred1onPos1_OR_notPred1onPos2_OR_pred1onPos3(pred1onA, noPredOnA, pred1onA); - Assertions.hasEnsuredPredicate(r3); + Assertions.hasGeneratedPredicate(r3); Requires r4 = new Requires(); r4.pred1onPos1_OR_notPred1onPos2_OR_pred1onPos3(pred1onA, pred1onA, noPredOnA); - Assertions.hasEnsuredPredicate(r4); + Assertions.hasGeneratedPredicate(r4); Requires r5 = new Requires(); r5.pred1onPos1_OR_notPred1onPos2_OR_pred1onPos3(noPredOnA, noPredOnA, pred1onA); - Assertions.hasEnsuredPredicate(r5); + Assertions.hasGeneratedPredicate(r5); Requires r6 = new Requires(); r6.pred1onPos1_OR_notPred1onPos2_OR_pred1onPos3(pred1onA, noPredOnA, noPredOnA); - Assertions.hasEnsuredPredicate(r6); + Assertions.hasGeneratedPredicate(r6); Requires r7 = new Requires(); r7.pred1onPos1_OR_notPred1onPos2_OR_pred1onPos3(noPredOnA, noPredOnA, noPredOnA); - Assertions.hasEnsuredPredicate(r7); + Assertions.hasGeneratedPredicate(r7); // assert false Requires r8 = new Requires(); r8.pred1onPos1_OR_notPred1onPos2_OR_pred1onPos3(noPredOnA, pred1onA, noPredOnA); - Assertions.notHasEnsuredPredicate(r8); + Assertions.hasNotGeneratedPredicate(r8); - Assertions.predicateErrors(3); // three, because each parameter will be reported + // one, because all three parameters belong to the same alternative predicate + Assertions.predicateErrors(1); } - @Ignore @Test public void notPred1onPos1_OR_pred1onPos2_OR_pred1onPos3() { A pred1onA = new A(); @@ -705,41 +728,41 @@ public void notPred1onPos1_OR_pred1onPos2_OR_pred1onPos3() { // assert true Requires r1 = new Requires(); r1.notPred1onPos1_OR_pred1onPos2_OR_pred1onPos3(pred1onA, pred1onA, pred1onA); - Assertions.hasEnsuredPredicate(r1); + Assertions.hasGeneratedPredicate(r1); Requires r2 = new Requires(); r2.notPred1onPos1_OR_pred1onPos2_OR_pred1onPos3(noPredOnA, pred1onA, pred1onA); - Assertions.hasEnsuredPredicate(r2); + Assertions.hasGeneratedPredicate(r2); Requires r3 = new Requires(); r3.notPred1onPos1_OR_pred1onPos2_OR_pred1onPos3(pred1onA, noPredOnA, pred1onA); - Assertions.hasEnsuredPredicate(r3); + Assertions.hasGeneratedPredicate(r3); Requires r4 = new Requires(); r4.notPred1onPos1_OR_pred1onPos2_OR_pred1onPos3(pred1onA, pred1onA, noPredOnA); - Assertions.hasEnsuredPredicate(r4); + Assertions.hasGeneratedPredicate(r4); Requires r5 = new Requires(); r5.notPred1onPos1_OR_pred1onPos2_OR_pred1onPos3(noPredOnA, noPredOnA, pred1onA); - Assertions.hasEnsuredPredicate(r5); + Assertions.hasGeneratedPredicate(r5); Requires r6 = new Requires(); r6.notPred1onPos1_OR_pred1onPos2_OR_pred1onPos3(noPredOnA, pred1onA, noPredOnA); - Assertions.hasEnsuredPredicate(r6); + Assertions.hasGeneratedPredicate(r6); Requires r7 = new Requires(); r7.notPred1onPos1_OR_pred1onPos2_OR_pred1onPos3(noPredOnA, noPredOnA, noPredOnA); - Assertions.hasEnsuredPredicate(r7); + Assertions.hasGeneratedPredicate(r7); // assert false Requires r8 = new Requires(); r8.notPred1onPos1_OR_pred1onPos2_OR_pred1onPos3(pred1onA, noPredOnA, noPredOnA); - Assertions.notHasEnsuredPredicate(r8); + Assertions.hasNotGeneratedPredicate(r8); - Assertions.predicateErrors(3); // three, because each parameter will be reported + // one, because all three parameters belong to the same alternative predicate + Assertions.predicateErrors(1); } - @Ignore @Test public void notPred1onPos1_OR_notPred1onPos2_OR_pred1onPos3() { A pred1onA = new A(); @@ -752,41 +775,41 @@ public void notPred1onPos1_OR_notPred1onPos2_OR_pred1onPos3() { // assert true Requires r1 = new Requires(); r1.notPred1onPos1_OR_notPred1onPos2_OR_pred1onPos3(pred1onA, pred1onA, pred1onA); - Assertions.hasEnsuredPredicate(r1); + Assertions.hasGeneratedPredicate(r1); Requires r2 = new Requires(); r2.notPred1onPos1_OR_notPred1onPos2_OR_pred1onPos3(noPredOnA, pred1onA, pred1onA); - Assertions.hasEnsuredPredicate(r2); + Assertions.hasGeneratedPredicate(r2); Requires r3 = new Requires(); r3.notPred1onPos1_OR_notPred1onPos2_OR_pred1onPos3(pred1onA, noPredOnA, pred1onA); - Assertions.hasEnsuredPredicate(r3); + Assertions.hasGeneratedPredicate(r3); Requires r4 = new Requires(); r4.notPred1onPos1_OR_notPred1onPos2_OR_pred1onPos3(pred1onA, noPredOnA, noPredOnA); - Assertions.hasEnsuredPredicate(r4); + Assertions.hasGeneratedPredicate(r4); Requires r5 = new Requires(); r5.notPred1onPos1_OR_notPred1onPos2_OR_pred1onPos3(noPredOnA, noPredOnA, pred1onA); - Assertions.hasEnsuredPredicate(r5); + Assertions.hasGeneratedPredicate(r5); Requires r6 = new Requires(); r6.notPred1onPos1_OR_notPred1onPos2_OR_pred1onPos3(noPredOnA, pred1onA, noPredOnA); - Assertions.hasEnsuredPredicate(r6); + Assertions.hasGeneratedPredicate(r6); Requires r7 = new Requires(); r7.notPred1onPos1_OR_notPred1onPos2_OR_pred1onPos3(noPredOnA, noPredOnA, noPredOnA); - Assertions.hasEnsuredPredicate(r7); + Assertions.hasGeneratedPredicate(r7); // assert false Requires r8 = new Requires(); r8.notPred1onPos1_OR_notPred1onPos2_OR_pred1onPos3(pred1onA, pred1onA, noPredOnA); - Assertions.notHasEnsuredPredicate(r8); + Assertions.hasNotGeneratedPredicate(r8); - Assertions.predicateErrors(3); // three, because each parameter will be reported + // one, because all three parameters belong to the same alternative predicate + Assertions.predicateErrors(1); } - @Ignore @Test public void pred1onPos1_OR_pred1onPos2_OR_notPred1onPos3() { A pred1onA = new A(); @@ -799,42 +822,41 @@ public void pred1onPos1_OR_pred1onPos2_OR_notPred1onPos3() { // assert true Requires r1 = new Requires(); r1.pred1onPos1_OR_pred1onPos2_OR_notPred1onPos3(pred1onA, pred1onA, pred1onA); - Assertions.hasEnsuredPredicate(r1); + Assertions.hasGeneratedPredicate(r1); Requires r2 = new Requires(); r2.pred1onPos1_OR_pred1onPos2_OR_notPred1onPos3(noPredOnA, pred1onA, pred1onA); - Assertions.hasEnsuredPredicate(r2); + Assertions.hasGeneratedPredicate(r2); Requires r3 = new Requires(); r3.pred1onPos1_OR_pred1onPos2_OR_notPred1onPos3(pred1onA, noPredOnA, pred1onA); - Assertions.hasEnsuredPredicate(r3); + Assertions.hasGeneratedPredicate(r3); Requires r4 = new Requires(); r4.pred1onPos1_OR_pred1onPos2_OR_notPred1onPos3(pred1onA, noPredOnA, noPredOnA); - Assertions.hasEnsuredPredicate(r4); + Assertions.hasGeneratedPredicate(r4); Requires r5 = new Requires(); r5.pred1onPos1_OR_pred1onPos2_OR_notPred1onPos3(pred1onA, pred1onA, noPredOnA); - Assertions.hasEnsuredPredicate(r5); + Assertions.hasGeneratedPredicate(r5); Requires r6 = new Requires(); r6.pred1onPos1_OR_pred1onPos2_OR_notPred1onPos3(noPredOnA, pred1onA, noPredOnA); - Assertions.hasEnsuredPredicate(r6); + Assertions.hasGeneratedPredicate(r6); + Requires r7 = new Requires(); r7.pred1onPos1_OR_pred1onPos2_OR_notPred1onPos3(noPredOnA, noPredOnA, noPredOnA); - Assertions.hasEnsuredPredicate(r7); + Assertions.hasGeneratedPredicate(r7); // assert false Requires r8 = new Requires(); r8.pred1onPos1_OR_pred1onPos2_OR_notPred1onPos3(noPredOnA, noPredOnA, pred1onA); - Assertions.notHasEnsuredPredicate(r8); + Assertions.hasNotGeneratedPredicate(r8); - Assertions.hasEnsuredPredicate(pred1onA); - Assertions.notHasEnsuredPredicate(noPredOnA); - Assertions.predicateErrors(3); // three, because each parameter will be reported + // one, because all three parameters belong to the same alternative predicate + Assertions.predicateErrors(1); } - @Ignore @Test public void pred1onPos1_OR_notPred1onPos2_OR_notPred1onPos3() { A pred1onA = new A(); @@ -847,41 +869,41 @@ public void pred1onPos1_OR_notPred1onPos2_OR_notPred1onPos3() { // assert true Requires r1 = new Requires(); r1.pred1onPos1_OR_notPred1onPos2_OR_notPred1onPos3(pred1onA, pred1onA, pred1onA); - Assertions.hasEnsuredPredicate(r1); + Assertions.hasGeneratedPredicate(r1); Requires r2 = new Requires(); r2.pred1onPos1_OR_notPred1onPos2_OR_notPred1onPos3(noPredOnA, noPredOnA, pred1onA); - Assertions.hasEnsuredPredicate(r2); + Assertions.hasGeneratedPredicate(r2); Requires r3 = new Requires(); r3.pred1onPos1_OR_notPred1onPos2_OR_notPred1onPos3(pred1onA, noPredOnA, pred1onA); - Assertions.hasEnsuredPredicate(r3); + Assertions.hasGeneratedPredicate(r3); Requires r4 = new Requires(); r4.pred1onPos1_OR_notPred1onPos2_OR_notPred1onPos3(pred1onA, noPredOnA, noPredOnA); - Assertions.hasEnsuredPredicate(r4); + Assertions.hasGeneratedPredicate(r4); Requires r5 = new Requires(); r5.pred1onPos1_OR_notPred1onPos2_OR_notPred1onPos3(pred1onA, pred1onA, noPredOnA); - Assertions.hasEnsuredPredicate(r5); + Assertions.hasGeneratedPredicate(r5); Requires r6 = new Requires(); r6.pred1onPos1_OR_notPred1onPos2_OR_notPred1onPos3(noPredOnA, pred1onA, noPredOnA); - Assertions.hasEnsuredPredicate(r6); + Assertions.hasGeneratedPredicate(r6); Requires r7 = new Requires(); r7.pred1onPos1_OR_notPred1onPos2_OR_notPred1onPos3(noPredOnA, noPredOnA, noPredOnA); - Assertions.hasEnsuredPredicate(r7); + Assertions.hasGeneratedPredicate(r7); // assert false Requires r8 = new Requires(); r8.pred1onPos1_OR_notPred1onPos2_OR_notPred1onPos3(noPredOnA, pred1onA, pred1onA); - Assertions.notHasEnsuredPredicate(r8); + Assertions.hasNotGeneratedPredicate(r8); - Assertions.predicateErrors(3); // three, because each parameter will be reported + // one, because all three parameters belong to the same alternative predicate + Assertions.predicateErrors(1); } - @Ignore @Test public void notPred1onPos1_OR_pred1onPos2_OR_notPred1onPos3() { A pred1onA = new A(); @@ -894,39 +916,41 @@ public void notPred1onPos1_OR_pred1onPos2_OR_notPred1onPos3() { // assert true Requires r1 = new Requires(); r1.notPred1onPos1_OR_pred1onPos2_OR_notPred1onPos3(pred1onA, pred1onA, pred1onA); - Assertions.hasEnsuredPredicate(r1); + Assertions.hasGeneratedPredicate(r1); Requires r2 = new Requires(); r2.notPred1onPos1_OR_pred1onPos2_OR_notPred1onPos3(noPredOnA, noPredOnA, pred1onA); - Assertions.hasEnsuredPredicate(r2); + Assertions.hasGeneratedPredicate(r2); Requires r3 = new Requires(); r3.notPred1onPos1_OR_pred1onPos2_OR_notPred1onPos3(noPredOnA, pred1onA, pred1onA); - Assertions.hasEnsuredPredicate(r3); + Assertions.hasGeneratedPredicate(r3); Requires r4 = new Requires(); r4.notPred1onPos1_OR_pred1onPos2_OR_notPred1onPos3(pred1onA, noPredOnA, noPredOnA); - Assertions.hasEnsuredPredicate(r4); + Assertions.hasGeneratedPredicate(r4); + Requires r5 = new Requires(); r5.notPred1onPos1_OR_pred1onPos2_OR_notPred1onPos3(pred1onA, pred1onA, noPredOnA); - Assertions.hasEnsuredPredicate(r5); + Assertions.hasGeneratedPredicate(r5); Requires r6 = new Requires(); r6.notPred1onPos1_OR_pred1onPos2_OR_notPred1onPos3(noPredOnA, pred1onA, noPredOnA); - Assertions.hasEnsuredPredicate(r6); + Assertions.hasGeneratedPredicate(r6); + Requires r7 = new Requires(); r7.notPred1onPos1_OR_pred1onPos2_OR_notPred1onPos3(noPredOnA, noPredOnA, noPredOnA); - Assertions.hasEnsuredPredicate(r7); + Assertions.hasGeneratedPredicate(r7); // assert false Requires r8 = new Requires(); r8.notPred1onPos1_OR_pred1onPos2_OR_notPred1onPos3(pred1onA, noPredOnA, pred1onA); - Assertions.notHasEnsuredPredicate(r8); + Assertions.hasNotGeneratedPredicate(r8); - Assertions.predicateErrors(3); // three, because each parameter will be reported + // one, because all three parameters belong to the same alternative predicate + Assertions.predicateErrors(1); } - @Ignore @Test public void notPred1onPos1_OR_notPred1onPos2_OR_notPred1onPos3() { A pred1onA = new A(); @@ -939,38 +963,39 @@ public void notPred1onPos1_OR_notPred1onPos2_OR_notPred1onPos3() { // assert true Requires r1 = new Requires(); r1.notPred1onPos1_OR_notPred1onPos2_OR_notPred1onPos3(pred1onA, noPredOnA, pred1onA); - Assertions.hasEnsuredPredicate(r1); + Assertions.hasGeneratedPredicate(r1); Requires r2 = new Requires(); r2.notPred1onPos1_OR_notPred1onPos2_OR_notPred1onPos3(noPredOnA, noPredOnA, pred1onA); - Assertions.hasEnsuredPredicate(r2); + Assertions.hasGeneratedPredicate(r2); Requires r3 = new Requires(); r3.notPred1onPos1_OR_notPred1onPos2_OR_notPred1onPos3(noPredOnA, pred1onA, pred1onA); - Assertions.hasEnsuredPredicate(r3); + Assertions.hasGeneratedPredicate(r3); Requires r4 = new Requires(); r4.notPred1onPos1_OR_notPred1onPos2_OR_notPred1onPos3(pred1onA, noPredOnA, noPredOnA); - Assertions.hasEnsuredPredicate(r4); + Assertions.hasGeneratedPredicate(r4); Requires r5 = new Requires(); r5.notPred1onPos1_OR_notPred1onPos2_OR_notPred1onPos3(pred1onA, pred1onA, noPredOnA); - Assertions.hasEnsuredPredicate(r5); + Assertions.hasGeneratedPredicate(r5); Requires r6 = new Requires(); r6.notPred1onPos1_OR_notPred1onPos2_OR_notPred1onPos3(noPredOnA, pred1onA, noPredOnA); - Assertions.hasEnsuredPredicate(r6); + Assertions.hasGeneratedPredicate(r6); Requires r7 = new Requires(); r7.notPred1onPos1_OR_notPred1onPos2_OR_notPred1onPos3(noPredOnA, noPredOnA, noPredOnA); - Assertions.hasEnsuredPredicate(r7); + Assertions.hasGeneratedPredicate(r7); // assert false Requires r8 = new Requires(); r8.notPred1onPos1_OR_notPred1onPos2_OR_notPred1onPos3(pred1onA, pred1onA, pred1onA); - Assertions.notHasEnsuredPredicate(r8); + Assertions.hasNotGeneratedPredicate(r8); - Assertions.predicateErrors(3); // three, because each parameter will be reported + // one, because all three parameters belong to the same alternative predicate + Assertions.predicateErrors(1); } // IMPLICATE diff --git a/CryptoAnalysis/src/test/java/tests/jca/SecretKeyTest.java b/CryptoAnalysis/src/test/java/tests/jca/SecretKeyTest.java index 0c3de2c36..766a593a6 100644 --- a/CryptoAnalysis/src/test/java/tests/jca/SecretKeyTest.java +++ b/CryptoAnalysis/src/test/java/tests/jca/SecretKeyTest.java @@ -33,9 +33,9 @@ protected String getRulesetPath() { public void test() throws GeneralSecurityException { KeyGenerator generator = KeyGenerator.getInstance("AES"); SecretKey key = generator.generateKey(); - byte[] bytes = key.getEncoded(); - SecretKeySpec spec = new SecretKeySpec(bytes, "AES"); + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + cipher.init(Cipher.ENCRYPT_MODE, key); } @Test diff --git a/HeadlessAndroidScanner/src/main/java/de/fraunhofer/iem/android/AndroidSettings.java b/HeadlessAndroidScanner/src/main/java/de/fraunhofer/iem/android/AndroidSettings.java index 5d799608e..250dbcef4 100644 --- a/HeadlessAndroidScanner/src/main/java/de/fraunhofer/iem/android/AndroidSettings.java +++ b/HeadlessAndroidScanner/src/main/java/de/fraunhofer/iem/android/AndroidSettings.java @@ -4,7 +4,7 @@ import crypto.reporting.Reporter; import java.util.Collection; import java.util.HashSet; -import java.util.List; +import java.util.Set; import java.util.concurrent.Callable; import picocli.CommandLine; @@ -44,10 +44,15 @@ public class AndroidSettings implements Callable { + " Multiple formats should be split with a comma (e.g. CMD,TXT,CSV)") private String[] reportFormat = null; + @CommandLine.Option( + names = {"--visualization"}, + description = "Visualize the errors (requires --reportPath to be set)") + private boolean visualization = false; + private Collection reportFormats; public AndroidSettings() { - reportFormats = new HashSet<>(List.of(Reporter.ReportFormat.CMD)); + reportFormats = Set.of(Reporter.ReportFormat.CMD); } public void parseSettingsFromCLI(String[] settings) throws CryptoAnalysisParserException { @@ -56,7 +61,12 @@ public void parseSettingsFromCLI(String[] settings) throws CryptoAnalysisParserE int exitCode = parser.execute(settings); if (reportFormat != null) { - parseReportFormatValues(reportFormat); + reportFormats = parseReportFormatValues(reportFormat); + } + + if (visualization && reportPath == null) { + throw new CryptoAnalysisParserException( + "If visualization is enabled, the reportPath has to be set"); } if (exitCode != CommandLine.ExitCode.OK) { @@ -64,30 +74,31 @@ public void parseSettingsFromCLI(String[] settings) throws CryptoAnalysisParserE } } - private void parseReportFormatValues(String[] settings) throws CryptoAnalysisParserException { - reportFormats.clear(); + private Collection parseReportFormatValues(String[] settings) + throws CryptoAnalysisParserException { + Collection formats = new HashSet<>(); for (String format : settings) { String reportFormatValue = format.toLowerCase(); switch (reportFormatValue) { case "cmd": - reportFormats.add(Reporter.ReportFormat.CMD); + formats.add(Reporter.ReportFormat.CMD); break; case "txt": - reportFormats.add(Reporter.ReportFormat.TXT); + formats.add(Reporter.ReportFormat.TXT); break; case "sarif": - reportFormats.add(Reporter.ReportFormat.SARIF); + formats.add(Reporter.ReportFormat.SARIF); break; case "csv": - reportFormats.add(Reporter.ReportFormat.CSV); + formats.add(Reporter.ReportFormat.CSV); break; case "csv_summary": - reportFormats.add(Reporter.ReportFormat.CSV_SUMMARY); + formats.add(Reporter.ReportFormat.CSV_SUMMARY); break; case "github_annotation": - reportFormats.add(Reporter.ReportFormat.GITHUB_ANNOTATION); + formats.add(Reporter.ReportFormat.GITHUB_ANNOTATION); break; default: throw new CryptoAnalysisParserException( @@ -97,6 +108,8 @@ private void parseReportFormatValues(String[] settings) throws CryptoAnalysisPar + "Available options are: CMD, TXT, SARIF, CSV and CSV_SUMMARY.\n"); } } + + return formats; } public String getApkFile() { @@ -139,6 +152,14 @@ public void setReportPath(String reportPath) { this.reportPath = reportPath; } + public boolean isVisualization() { + return visualization; + } + + public void setVisualization(boolean visualization) { + this.visualization = visualization; + } + @Override public Integer call() throws Exception { return 0; diff --git a/HeadlessAndroidScanner/src/main/java/de/fraunhofer/iem/android/HeadlessAndroidScanner.java b/HeadlessAndroidScanner/src/main/java/de/fraunhofer/iem/android/HeadlessAndroidScanner.java index 9667918b8..b6bbd402a 100644 --- a/HeadlessAndroidScanner/src/main/java/de/fraunhofer/iem/android/HeadlessAndroidScanner.java +++ b/HeadlessAndroidScanner/src/main/java/de/fraunhofer/iem/android/HeadlessAndroidScanner.java @@ -5,7 +5,6 @@ import crypto.analysis.CryptoScanner; import crypto.exceptions.CryptoAnalysisParserException; import crypto.reporting.Reporter; -import crypto.reporting.ReporterFactory; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -58,20 +57,14 @@ public void run() { flowDroidSetup.setupFlowDroid(); additionalFrameworkSetup(); - // Initialize fields and reporters + // Initialize fields super.initialize(); - Collection reporters = - ReporterFactory.createReporters( - getReportFormats(), getReportDirectory(), super.getRuleset()); // Run the analysis super.scan(); // Report the errors - for (Reporter reporter : reporters) { - reporter.createAnalysisReport( - super.getDiscoveredSeeds(), super.getCollectedErrors(), super.getStatistics()); - } + super.createReports(getReportFormats(), getReportDirectory(), isVisualization()); } public String getApkFile() { @@ -102,5 +95,13 @@ public void setReportDirectory(String reportDirectory) { settings.setReportPath(reportDirectory); } + public boolean isVisualization() { + return settings.isVisualization(); + } + + public void setVisualization(boolean visualization) { + settings.setVisualization(visualization); + } + public void additionalFrameworkSetup() {} } diff --git a/HeadlessAndroidScanner/src/test/java/android/HeadlessAndroidTest.java b/HeadlessAndroidScanner/src/test/java/android/HeadlessAndroidTest.java index 76f3e5616..519295c10 100644 --- a/HeadlessAndroidScanner/src/test/java/android/HeadlessAndroidTest.java +++ b/HeadlessAndroidScanner/src/test/java/android/HeadlessAndroidTest.java @@ -1,5 +1,6 @@ package android; +import crypto.analysis.errors.AlternativeReqPredicateError; import crypto.analysis.errors.ConstraintError; import crypto.analysis.errors.ImpreciseValueExtractionError; import crypto.analysis.errors.IncompleteOperationError; @@ -17,9 +18,10 @@ public void testFalseCrypt() { scanner.run(); addExpectedErrors(ConstraintError.class, 6); - addExpectedErrors(RequiredPredicateError.class, 9); + addExpectedErrors(RequiredPredicateError.class, 7); + addExpectedErrors(AlternativeReqPredicateError.class, 2); addExpectedErrors(TypestateError.class, 1); - addExpectedErrors(IncompleteOperationError.class, 5); + addExpectedErrors(IncompleteOperationError.class, 4); addExpectedErrors(ImpreciseValueExtractionError.class, 1); assertErrors(scanner.getCollectedErrors()); diff --git a/HeadlessAndroidScanner/src/test/java/settings/CommandLineTest.java b/HeadlessAndroidScanner/src/test/java/settings/CommandLineTest.java index 41c561ee1..18080a552 100644 --- a/HeadlessAndroidScanner/src/test/java/settings/CommandLineTest.java +++ b/HeadlessAndroidScanner/src/test/java/settings/CommandLineTest.java @@ -21,6 +21,8 @@ public class CommandLineTest { private static final String REPORT_PATH = "--reportPath"; private static final String REPORT_FORMAT = "--reportFormat"; + private static final String VISUALIZATION = "--visualization"; + @Test public void testMinimalApplication() { String[] args = @@ -199,4 +201,39 @@ public void testReportFormat() { Reporter.ReportFormat.TXT, Reporter.ReportFormat.CSV)); } + + @Test + public void testVisualization() { + String reportPath = "path/to/report"; + String[] args = + new String[] { + APK_PATH, + EXAMPLE_APK_PATH, + PLATFORM_PATH, + EXAMPLE_PLATFORM_PATH, + RULES_DIR, + EXAMPLE_RULES_DIR, + VISUALIZATION, + REPORT_PATH, + reportPath + }; + HeadlessAndroidScanner scanner = HeadlessAndroidScanner.createFromCLISettings(args); + Assert.assertTrue(scanner.isVisualization()); + } + + @Test(expected = CryptoAnalysisParserException.class) + public void testInvalidVisualization() { + String[] args = + new String[] { + APK_PATH, + EXAMPLE_APK_PATH, + PLATFORM_PATH, + EXAMPLE_PLATFORM_PATH, + RULES_DIR, + EXAMPLE_RULES_DIR, + VISUALIZATION, + }; + HeadlessAndroidScanner scanner = HeadlessAndroidScanner.createFromCLISettings(args); + Assert.assertTrue(scanner.isVisualization()); + } } diff --git a/HeadlessAndroidScanner/src/test/java/settings/ProgramTest.java b/HeadlessAndroidScanner/src/test/java/settings/ProgramTest.java index d093e8d67..dfbc34f9d 100644 --- a/HeadlessAndroidScanner/src/test/java/settings/ProgramTest.java +++ b/HeadlessAndroidScanner/src/test/java/settings/ProgramTest.java @@ -87,4 +87,13 @@ public void testReportFormat() { Reporter.ReportFormat.TXT, Reporter.ReportFormat.CSV)); } + + @Test + public void testVisualization() { + HeadlessAndroidScanner scanner = + new HeadlessAndroidScanner( + EXAMPLE_APK_PATH, EXAMPLE_PLATFORM_PATH, EXAMPLE_RULES_DIR); + scanner.setVisualization(true); + Assert.assertTrue(scanner.isVisualization()); + } } diff --git a/HeadlessJavaScanner/src/main/java/de/fraunhofer/iem/scanner/HeadlessJavaScanner.java b/HeadlessJavaScanner/src/main/java/de/fraunhofer/iem/scanner/HeadlessJavaScanner.java index 98bd07208..ad092ba80 100644 --- a/HeadlessJavaScanner/src/main/java/de/fraunhofer/iem/scanner/HeadlessJavaScanner.java +++ b/HeadlessJavaScanner/src/main/java/de/fraunhofer/iem/scanner/HeadlessJavaScanner.java @@ -1,30 +1,22 @@ package de.fraunhofer.iem.scanner; -import boomerang.Query; -import boomerang.debugger.Debugger; -import boomerang.debugger.IDEVizDebugger; import boomerang.scene.CallGraph; import boomerang.scene.DataFlowScope; import boomerang.scene.sparse.SparseCFGCache; import crypto.analysis.CryptoAnalysisDataFlowScope; import crypto.analysis.CryptoScanner; -import crypto.exceptions.CryptoAnalysisException; import crypto.exceptions.CryptoAnalysisParserException; import crypto.reporting.Reporter; -import crypto.reporting.ReporterFactory; import de.fraunhofer.iem.framework.FrameworkSetup; import de.fraunhofer.iem.framework.OpalSetup; import de.fraunhofer.iem.framework.SootSetup; import de.fraunhofer.iem.framework.SootUpSetup; import de.fraunhofer.iem.scanner.ScannerSettings.CallGraphAlgorithm; -import java.io.File; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; -import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import typestate.TransitionFunction; public class HeadlessJavaScanner extends CryptoScanner { @@ -65,57 +57,16 @@ protected CallGraph constructCallGraph() { @Override public DataFlowScope createDataFlowScope() { - return new CryptoAnalysisDataFlowScope(super.getRuleset(), getIgnoredSections()); - } - - @Override - public Debugger debugger(Query query) { - if (settings.isVisualization()) { - - if (settings.getReportDirectory() == null) { - LOGGER.error( - "The visualization requires the --reportPath option. Disabling visualization..."); - return new Debugger<>(); - } - - File vizFile = - new File( - settings.getReportDirectory() - + File.separator - + "viz" - + File.separator - + query.var().getVariableName() - + ".json"); - boolean created = vizFile.getParentFile().mkdirs(); - - if (!created) { - LOGGER.error( - "Could not create directory {}. Disabling visualization...", - vizFile.getAbsolutePath()); - return new Debugger<>(); - } - - return new IDEVizDebugger<>(vizFile); - } - - return new Debugger<>(); + return new CryptoAnalysisDataFlowScope(super.getRuleset(), settings.getIgnoredSections()); } @Override public SparseCFGCache.SparsificationStrategy getSparsificationStrategy() { - switch (settings.getSparseStrategy()) { - case NONE: - return SparseCFGCache.SparsificationStrategy.NONE; - case TYPE_BASED: - return SparseCFGCache.SparsificationStrategy.TYPE_BASED; - case ALIAS_AWARE: - return SparseCFGCache.SparsificationStrategy.ALIAS_AWARE; - default: - LOGGER.error( - "Could not set sparsification strategy {}. Defaulting to NONE...", - settings.getSparseStrategy()); - return SparseCFGCache.SparsificationStrategy.NONE; - } + return switch (settings.getSparseStrategy()) { + case NONE -> SparseCFGCache.SparsificationStrategy.NONE; + case TYPE_BASED -> SparseCFGCache.SparsificationStrategy.TYPE_BASED; + case ALIAS_AWARE -> SparseCFGCache.SparsificationStrategy.ALIAS_AWARE; + }; } @Override @@ -129,37 +80,26 @@ public void run() { frameworkSetup.initializeFramework(); additionalFrameworkSetup(); - // Initialize fields and reporters + // Initialize fields super.initialize(); - Collection reporters = - ReporterFactory.createReporters( - getReportFormats(), getReportDirectory(), super.getRuleset()); // Run the analysis super.scan(); // Report the errors - for (Reporter reporter : reporters) { - reporter.createAnalysisReport( - super.getDiscoveredSeeds(), super.getCollectedErrors(), super.getStatistics()); - } + super.createReports(getReportFormats(), getReportDirectory(), isVisualization()); } private FrameworkSetup setupFramework() { - switch (settings.getFramework()) { - case SOOT: - return new SootSetup( - settings.getApplicationPath(), - settings.getCallGraph(), - settings.getSootPath()); - case SOOT_UP: - return new SootUpSetup(settings.getApplicationPath(), settings.getCallGraph()); - case OPAL: - return new OpalSetup(settings.getApplicationPath(), settings.getCallGraph()); - default: - throw new CryptoAnalysisException( - "Framework " + settings.getFramework().name() + " is not supported"); - } + return switch (settings.getFramework()) { + case SOOT -> + new SootSetup( + settings.getApplicationPath(), + settings.getCallGraph(), + settings.getSootPath()); + case SOOT_UP -> new SootUpSetup(settings.getApplicationPath(), settings.getCallGraph()); + case OPAL -> new OpalSetup(settings.getApplicationPath(), settings.getCallGraph()); + }; } public String getApplicationPath() { @@ -198,7 +138,7 @@ public void setReportDirectory(String reportDirectory) { settings.setReportDirectory(reportDirectory); } - public Set getReportFormats() { + public Collection getReportFormats() { return settings.getReportFormats(); } diff --git a/HeadlessJavaScanner/src/main/java/de/fraunhofer/iem/scanner/ScannerSettings.java b/HeadlessJavaScanner/src/main/java/de/fraunhofer/iem/scanner/ScannerSettings.java index 1e36ea824..ef3fe0d0c 100644 --- a/HeadlessJavaScanner/src/main/java/de/fraunhofer/iem/scanner/ScannerSettings.java +++ b/HeadlessJavaScanner/src/main/java/de/fraunhofer/iem/scanner/ScannerSettings.java @@ -64,7 +64,7 @@ public class ScannerSettings implements Callable { @CommandLine.Option( names = {"--visualization"}, - description = "Enable visualization") + description = "Visualize the errors (requires --reportPath to be set)") private boolean visualization = false; @CommandLine.Option( @@ -112,13 +112,13 @@ public enum SparseStrategy { private CallGraphAlgorithm callGraphAlgorithm; private Framework framework; - private Set reportFormats; + private Collection reportFormats; private Collection ignoredSections; private SparseStrategy sparseStrategy; public ScannerSettings() { callGraphAlgorithm = CallGraphAlgorithm.CHA; - reportFormats = new HashSet<>(List.of(Reporter.ReportFormat.CMD)); + reportFormats = Set.of(Reporter.ReportFormat.CMD); framework = Framework.SOOT; ignoredSections = new ArrayList<>(); sparseStrategy = SparseStrategy.NONE; @@ -130,23 +130,28 @@ public void parseSettingsFromCLI(String[] settings) throws CryptoAnalysisParserE int exitCode = parser.execute(settings); if (frameworkOption != null) { - parseFrameworkOption(frameworkOption); + framework = parseFrameworkOption(frameworkOption); } if (cg != null) { - parseControlGraphOption(cg); + callGraphAlgorithm = parseCallGraphOption(cg); } if (reportFormat != null) { - parseReportFormatValues(reportFormat); + reportFormats = parseReportFormatOption(reportFormat); } if (ignoreSectionsPath != null) { - parseIgnoredSections(ignoreSectionsPath); + ignoredSections = parseIgnoredSectionOption(ignoreSectionsPath); + } + + if (visualization && reportPath == null) { + throw new CryptoAnalysisParserException( + "If visualization is enabled, the reportPath has to be set"); } if (sparseStrategyInput != null) { - parseSparseStrategy(sparseStrategyInput); + sparseStrategy = parseSparseStrategyOption(sparseStrategyInput); } if (timeout < 0) { @@ -158,89 +163,77 @@ public void parseSettingsFromCLI(String[] settings) throws CryptoAnalysisParserE } } - private void parseFrameworkOption(String option) throws CryptoAnalysisParserException { + private Framework parseFrameworkOption(String option) throws CryptoAnalysisParserException { String frameworkValue = option.toLowerCase(); - switch (frameworkValue) { - case "soot": - framework = Framework.SOOT; - break; - case "soot_up": - framework = Framework.SOOT_UP; - break; - case "opal": - framework = Framework.OPAL; - break; - default: - throw new CryptoAnalysisParserException( - "Framework " + option + " is not supported"); - } + return switch (frameworkValue) { + case "soot" -> Framework.SOOT; + case "soot_up" -> Framework.SOOT_UP; + case "opal" -> Framework.OPAL; + default -> + throw new CryptoAnalysisParserException( + "Incorrect framework option: " + option); + }; } - private void parseControlGraphOption(String value) throws CryptoAnalysisParserException { - String CGValue = value.toLowerCase(); - - switch (CGValue) { - case "cha": - callGraphAlgorithm = CallGraphAlgorithm.CHA; - break; - case "spark": - callGraphAlgorithm = CallGraphAlgorithm.SPARK; - break; - case "sparklib": - callGraphAlgorithm = CallGraphAlgorithm.SPARK_LIB; - break; - default: - throw new CryptoAnalysisParserException( - "Incorrect value " - + CGValue - + " for --cg option. " - + "Available options are: CHA, SPARK and SPARKLIB.\n"); - } + private CallGraphAlgorithm parseCallGraphOption(String option) + throws CryptoAnalysisParserException { + String callGraphValue = option.toLowerCase(); + + return switch (callGraphValue) { + case "cha" -> CallGraphAlgorithm.CHA; + case "spark" -> CallGraphAlgorithm.SPARK; + case "sparklib" -> CallGraphAlgorithm.SPARK_LIB; + default -> + throw new CryptoAnalysisParserException( + "Incorrect call graph value: " + option); + }; } - private void parseReportFormatValues(String[] settings) throws CryptoAnalysisParserException { - reportFormats.clear(); + private Collection parseReportFormatOption(String[] settings) + throws CryptoAnalysisParserException { + Collection formats = new HashSet<>(); for (String format : settings) { String reportFormatValue = format.toLowerCase(); switch (reportFormatValue) { case "cmd": - reportFormats.add(Reporter.ReportFormat.CMD); + formats.add(Reporter.ReportFormat.CMD); break; case "txt": - reportFormats.add(Reporter.ReportFormat.TXT); + formats.add(Reporter.ReportFormat.TXT); break; case "sarif": - reportFormats.add(Reporter.ReportFormat.SARIF); + formats.add(Reporter.ReportFormat.SARIF); break; case "csv": - reportFormats.add(Reporter.ReportFormat.CSV); + formats.add(Reporter.ReportFormat.CSV); break; case "csv_summary": - reportFormats.add(Reporter.ReportFormat.CSV_SUMMARY); + formats.add(Reporter.ReportFormat.CSV_SUMMARY); break; case "github_annotation": - reportFormats.add(Reporter.ReportFormat.GITHUB_ANNOTATION); + formats.add(Reporter.ReportFormat.GITHUB_ANNOTATION); break; default: throw new CryptoAnalysisParserException( - "Incorrect value " - + reportFormatValue - + " for --reportFormat option. " - + "Available options are: CMD, TXT, SARIF, CSV and CSV_SUMMARY.\n"); + "Incorrect report format value: " + format); } } + + return formats; } - private void parseIgnoredSections(String path) throws CryptoAnalysisParserException { - final File ignorePackageFile = new File(path); + private Collection parseIgnoredSectionOption(String path) + throws CryptoAnalysisParserException { + Collection result = new ArrayList<>(); + File ignorePackageFile = new File(path); if (ignorePackageFile.isFile() && ignorePackageFile.canRead()) { try { List lines = Files.readLines(ignorePackageFile, Charset.defaultCharset()); - ignoredSections.addAll(lines); + result.addAll(lines); } catch (IOException e) { throw new CryptoAnalysisParserException( "Error while reading file " + ignorePackageFile + ": " + e.getMessage()); @@ -249,25 +242,21 @@ private void parseIgnoredSections(String path) throws CryptoAnalysisParserExcept throw new CryptoAnalysisParserException( ignorePackageFile + " is not a file or cannot be read"); } + + return result; } - private void parseSparseStrategy(String strategy) { - String strategyLowerCase = strategy.toLowerCase(); - - switch (strategyLowerCase) { - case "none": - sparseStrategy = SparseStrategy.NONE; - break; - case "type_based": - sparseStrategy = SparseStrategy.TYPE_BASED; - break; - case "alias_aware": - sparseStrategy = SparseStrategy.ALIAS_AWARE; - break; - default: - throw new CryptoAnalysisParserException( - sparseStrategy + " is not a valid sparsification strategy"); - } + private SparseStrategy parseSparseStrategyOption(String option) { + String strategyLowerCase = option.toLowerCase(); + + return switch (strategyLowerCase) { + case "none" -> SparseStrategy.NONE; + case "type_based" -> SparseStrategy.TYPE_BASED; + case "alias_aware" -> SparseStrategy.ALIAS_AWARE; + default -> + throw new CryptoAnalysisParserException( + "Incorrect sparsification strategy: " + option); + }; } public String getApplicationPath() { @@ -318,7 +307,7 @@ public void setReportDirectory(String reportDirectory) { this.reportPath = reportDirectory; } - public Set getReportFormats() { + public Collection getReportFormats() { return reportFormats; } diff --git a/HeadlessJavaScanner/src/test/java/scanner/setup/AbstractHeadlessTest.java b/HeadlessJavaScanner/src/test/java/scanner/setup/AbstractHeadlessTest.java index 658a3a687..7903d79b4 100644 --- a/HeadlessJavaScanner/src/test/java/scanner/setup/AbstractHeadlessTest.java +++ b/HeadlessJavaScanner/src/test/java/scanner/setup/AbstractHeadlessTest.java @@ -112,7 +112,7 @@ protected final void assertErrors( int difference = expected - actual; if (difference < 0) { report.add( - "\n\tFound " + "Found " + Math.abs(difference) + " too many errors of type " + errorType.getSimpleName() @@ -120,7 +120,7 @@ protected final void assertErrors( + methodWrapper); } else if (difference > 0) { report.add( - "\n\tFound " + "Found " + difference + " too few errors of type " + errorType.getSimpleName() @@ -148,7 +148,7 @@ protected final void assertErrors( int unexpectedErrors = getErrorsOfType(errorType, errors); report.add( - "\n\tFound " + "Found " + unexpectedErrors + " too many errors of type " + errorType.getSimpleName() diff --git a/HeadlessJavaScanner/src/test/java/scanner/targets/BouncyCastleHeadlessTest.java b/HeadlessJavaScanner/src/test/java/scanner/targets/BouncyCastleHeadlessTest.java index c15c0a6b7..25729efb5 100644 --- a/HeadlessJavaScanner/src/test/java/scanner/targets/BouncyCastleHeadlessTest.java +++ b/HeadlessJavaScanner/src/test/java/scanner/targets/BouncyCastleHeadlessTest.java @@ -1,5 +1,6 @@ package scanner.targets; +import crypto.analysis.errors.AlternativeReqPredicateError; import crypto.analysis.errors.ForbiddenMethodError; import crypto.analysis.errors.HardCodedError; import crypto.analysis.errors.ImpreciseValueExtractionError; @@ -41,7 +42,8 @@ public void testBCMacExamples() { new ErrorSpecification.Builder("gwt_crypto.GMacTest", "performTestOne", 0) .withTPs(ForbiddenMethodError.class, 1) .withTPs(NeverTypeOfError.class, 1) - .withTPs(RequiredPredicateError.class, 4) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 1) .withTPs(IncompleteOperationError.class, 1) .build()); addErrorSpecification( @@ -78,7 +80,8 @@ public void testBCSymmetricCipherExamples() { addErrorSpecification( new ErrorSpecification.Builder( "gcm_aes_example.GCMAESBouncyCastle", "processing", 2) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder( @@ -113,18 +116,18 @@ public void testBCAsymmetricCipherExamples() { .build()); addErrorSpecification( new ErrorSpecification.Builder("rsa_misuse.RSATest", "Decrypt", 2) - .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); // These two errors occur because AsymmetricCipherKeyPair ensures the predicate only after // the constructor call addErrorSpecification( new ErrorSpecification.Builder("rsa_nomisuse.RSATest", "Encrypt", 2) - .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder("rsa_nomisuse.RSATest", "Decrypt", 2) - .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); addErrorSpecification( @@ -133,7 +136,8 @@ public void testBCAsymmetricCipherExamples() { .build()); addErrorSpecification( new ErrorSpecification.Builder("crypto.RSAEngineTest", "testDecryptOne", 1) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 1) .withTPs(ImpreciseValueExtractionError.class, 1) .build()); addErrorSpecification( @@ -247,13 +251,15 @@ public void testBCSignerExamples() { addErrorSpecification( new ErrorSpecification.Builder("gwt_crypto.PSSBlindTest", "testSig", 6) .withTPs(IncompleteOperationError.class, 1) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(ImpreciseValueExtractionError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder("gwt_crypto.PSSTest", "testSig", 6) .withTPs(IncompleteOperationError.class, 1) - .withTPs(RequiredPredicateError.class, 2) + .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder( @@ -275,12 +281,12 @@ public void testBCSignerExamples() { addErrorSpecification( new ErrorSpecification.Builder("diqube.TicketSignatureService", "signTicket", 0) - .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder( "diqube.TicketSignatureService", "isValidTicketSignature", 1) - .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 1) .withTPs(ImpreciseValueExtractionError.class, 1) .build()); @@ -295,11 +301,13 @@ public void testBCSignerExamples() { addErrorSpecification( new ErrorSpecification.Builder("pattern.SignerTest", "testSignerGenerate", 0) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder("pattern.SignerTest", "testSignerVerify", 0) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); scanner.run(); @@ -315,7 +323,7 @@ public void testBCEllipticCurveExamples() { addErrorSpecification( new ErrorSpecification.Builder("crypto.ECElGamalEncryptorTest", "testOne", 0) - .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder("crypto.ECElGamalEncryptorTest", "testTwo", 0) @@ -354,11 +362,13 @@ public void testBCEllipticCurveExamples() { .build()); addErrorSpecification( new ErrorSpecification.Builder("params.ParametersWithRandomTest", "testOne", 1) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder("params.ParametersWithRandomTest", "testThree", 1) - .withTPs(RequiredPredicateError.class, 4) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder("params.ECDomainParametersTest", "testThree", 1) @@ -403,12 +413,14 @@ public void testBCEllipticCurveExamples() { addErrorSpecification( new ErrorSpecification.Builder( "transforms.ECNewPublicKeyTransformTest", "testOne", 1) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder( "transforms.ECNewPublicKeyTransformTest", "testTwo", 1) - .withTPs(RequiredPredicateError.class, 4) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 2) .build()); addErrorSpecification( new ErrorSpecification.Builder( @@ -419,28 +431,32 @@ public void testBCEllipticCurveExamples() { new ErrorSpecification.Builder( "transforms.ECNewPublicKeyTransformTest", "testFour", 1) .withTPs(IncompleteOperationError.class, 1) - .withTPs(RequiredPredicateError.class, 4) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 2) .build()); addErrorSpecification( new ErrorSpecification.Builder( "transforms.ECNewPublicKeyTransformTest", "testFive", 1) - .withTPs(RequiredPredicateError.class, 4) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 2) .build()); addErrorSpecification( new ErrorSpecification.Builder( "transforms.ECNewPublicKeyTransformTest", "testSix", 1) - .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 2) .build()); addErrorSpecification( new ErrorSpecification.Builder( "transforms.ECNewRandomessTransformTest", "testOne", 1) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder( "transforms.ECNewRandomessTransformTest", "testTwo", 1) - .withTPs(RequiredPredicateError.class, 4) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 2) .build()); addErrorSpecification( new ErrorSpecification.Builder( @@ -451,17 +467,19 @@ public void testBCEllipticCurveExamples() { new ErrorSpecification.Builder( "transforms.ECNewRandomessTransformTest", "testFour", 1) .withTPs(IncompleteOperationError.class, 1) - .withTPs(RequiredPredicateError.class, 4) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 2) .build()); addErrorSpecification( new ErrorSpecification.Builder( "transforms.ECNewRandomessTransformTest", "testFive", 1) - .withTPs(RequiredPredicateError.class, 4) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 2) .build()); addErrorSpecification( new ErrorSpecification.Builder( "transforms.ECNewRandomessTransformTest", "testSix", 1) - .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 2) .build()); addErrorSpecification( diff --git a/HeadlessJavaScanner/src/test/java/scanner/targets/BragaCryptoGoodUsesTest.java b/HeadlessJavaScanner/src/test/java/scanner/targets/BragaCryptoGoodUsesTest.java index f01d1da5f..27b388333 100644 --- a/HeadlessJavaScanner/src/test/java/scanner/targets/BragaCryptoGoodUsesTest.java +++ b/HeadlessJavaScanner/src/test/java/scanner/targets/BragaCryptoGoodUsesTest.java @@ -1,5 +1,6 @@ package scanner.targets; +import crypto.analysis.errors.AlternativeReqPredicateError; import crypto.analysis.errors.CallToError; import crypto.analysis.errors.ConstraintError; import crypto.analysis.errors.ForbiddenMethodError; @@ -66,7 +67,8 @@ public void alwaysDefineCSPExamples() { new ErrorSpecification.Builder("example.DefinedProvider7", "main", 1) .withTPs(ConstraintError.class, 1) .withTPs(IncompleteOperationError.class, 2) - .withTPs(RequiredPredicateError.class, 5) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 2) .build()); scanner.run(); @@ -88,7 +90,8 @@ public void avoidCodingErrorsExamples() { new ErrorSpecification.Builder("example.PBEwLargeCountAndRandomSalt", "main", 1) .withTPs(ConstraintError.class, 1) .withTPs(TypestateError.class, 1) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(ForbiddenMethodError.class, 1) .withTPs(IncompleteOperationError.class, 1) .build()); @@ -123,7 +126,8 @@ public void avoidConstantPwdPBEExamples() { new ErrorSpecification.Builder("example.PBEwParameterPassword", "main", 1) .withTPs(ConstraintError.class, 1) .withTPs(TypestateError.class, 1) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(ForbiddenMethodError.class, 1) .withTPs(IncompleteOperationError.class, 1) .build()); @@ -155,7 +159,8 @@ public void avoidDeterministicRSAExamples() { new ErrorSpecification.Builder("example.UseOAEPForRSA", "negativeTestCase", 0) .withTPs(ConstraintError.class, 3) .withTPs(IncompleteOperationError.class, 2) - .withTPs(RequiredPredicateError.class, 5) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 2) .build()); // positive test case @@ -170,7 +175,8 @@ public void avoidDeterministicRSAExamples() { new ErrorSpecification.Builder("example.UsePKCS1ForRSA", "negativeTestCase", 0) .withTPs(ConstraintError.class, 3) .withTPs(IncompleteOperationError.class, 2) - .withTPs(RequiredPredicateError.class, 5) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 2) .build()); scanner.run(); @@ -211,7 +217,8 @@ public void avoidHardcodedKeysExamples() { addErrorSpecification( new ErrorSpecification.Builder("example.UseDynamicKeyFor3DES", "main", 1) .withTPs(ConstraintError.class, 3) - .withTPs(RequiredPredicateError.class, 4) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); addErrorSpecification( @@ -258,7 +265,8 @@ public void avoidImproperKeyLenExamples() { new ErrorSpecification.Builder( "example.SecureConfig112bitsRSA_2048x256_1", "negativeTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -275,7 +283,8 @@ public void avoidImproperKeyLenExamples() { new ErrorSpecification.Builder( "example.SecureConfig112bitsRSA_2048x256_2", "negativeTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 5) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -349,7 +358,8 @@ public void avoidImproperKeyLenExamples() { new ErrorSpecification.Builder( "example.SecureConfig192bitsRSA_7680x384_1", "negativeTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -369,7 +379,8 @@ public void avoidImproperKeyLenExamples() { new ErrorSpecification.Builder( "example.SecureConfig192bitsRSA_7680x512_1", "negativeTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -391,7 +402,8 @@ public void avoidInsecureDefaultsExamples() { addErrorSpecification( new ErrorSpecification.Builder("example.UseQualifiedNameForPBE1", "main", 1) .withTPs(ConstraintError.class, 1) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(ForbiddenMethodError.class, 1) .withTPs(TypestateError.class, 1) .withTPs(IncompleteOperationError.class, 1) @@ -425,7 +437,8 @@ public void avoidInsecureDefaultsExamples() { "example.UseQualifiedNameForRSAOAEP", "negativeTestCase", 0) .withTPs(ConstraintError.class, 2) .withTPs(TypestateError.class, 1) - .withTPs(RequiredPredicateError.class, 5) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 2) .build()); // positive test case @@ -443,7 +456,8 @@ public void avoidInsecureDefaultsExamples() { "example.UseQualifiedParamsForRSAOAEP", "negativeTestCase", 0) .withTPs(ConstraintError.class, 2) .withTPs(TypestateError.class, 1) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .build()); scanner.run(); @@ -522,7 +536,8 @@ public void avoidInsecurePaddingExamples() { addErrorSpecification( new ErrorSpecification.Builder("example.OAEP_2048x256_1", "negativeTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -537,7 +552,8 @@ public void avoidInsecurePaddingExamples() { addErrorSpecification( new ErrorSpecification.Builder("example.OAEP_2048x256_2", "negativeTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 5) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -555,7 +571,8 @@ public void avoidInsecurePaddingExamples() { addErrorSpecification( new ErrorSpecification.Builder("example.OAEP_2048x384_1", "negativeTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -570,7 +587,8 @@ public void avoidInsecurePaddingExamples() { addErrorSpecification( new ErrorSpecification.Builder("example.OAEP_2048x384_2", "negativeTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 5) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -588,7 +606,8 @@ public void avoidInsecurePaddingExamples() { addErrorSpecification( new ErrorSpecification.Builder("example.OAEP_2048x512_1", "negativeTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -603,7 +622,8 @@ public void avoidInsecurePaddingExamples() { addErrorSpecification( new ErrorSpecification.Builder("example.OAEP_2048x512_2", "negativeTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 5) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1105,7 +1125,8 @@ public void doNotPrintSecretsExamples() { addErrorSpecification( new ErrorSpecification.Builder("example.DoNotPrintPrivKey1", "negativeTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 5) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1218,7 +1239,8 @@ public void secureConfigsRSAExamples() { new ErrorSpecification.Builder( "example.SecureConfig112bitsRSA_2048x256_1", "negativeTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1235,7 +1257,8 @@ public void secureConfigsRSAExamples() { new ErrorSpecification.Builder( "example.SecureConfig112bitsRSA_2048x256_2", "negativeTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 5) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1309,7 +1332,8 @@ public void secureConfigsRSAExamples() { new ErrorSpecification.Builder( "example.SecureConfig192bitsRSA_7680x384_1", "negativeTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1326,7 +1350,8 @@ public void secureConfigsRSAExamples() { new ErrorSpecification.Builder( "example.SecureConfig192bitsRSA_7680x384_2", "negativeTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 5) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1346,7 +1371,8 @@ public void secureConfigsRSAExamples() { new ErrorSpecification.Builder( "example.SecureConfig192bitsRSA_7680x512_1", "negativeTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1363,7 +1389,8 @@ public void secureConfigsRSAExamples() { new ErrorSpecification.Builder( "example.SecureConfig192bitsRSA_7680x512_2", "negativeTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 5) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); diff --git a/HeadlessJavaScanner/src/test/java/scanner/targets/BragaCryptoMisusesTest.java b/HeadlessJavaScanner/src/test/java/scanner/targets/BragaCryptoMisusesTest.java index ebae70404..a9273fadb 100644 --- a/HeadlessJavaScanner/src/test/java/scanner/targets/BragaCryptoMisusesTest.java +++ b/HeadlessJavaScanner/src/test/java/scanner/targets/BragaCryptoMisusesTest.java @@ -1,5 +1,6 @@ package scanner.targets; +import crypto.analysis.errors.AlternativeReqPredicateError; import crypto.analysis.errors.CallToError; import crypto.analysis.errors.ConstraintError; import crypto.analysis.errors.ForbiddenMethodError; @@ -228,23 +229,27 @@ public void constantKeyExamples() { addErrorSpecification( new ErrorSpecification.Builder("pkm.constantKey.ConstantKey3DES", "main", 1) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 4) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder("pkm.constantKey.ConstantKeyAES1", "main", 1) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder("pkm.constantKey.ConstantKeyAES2", "main", 1) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .withTPs(NeverTypeOfError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder("pkm.constantKey.ConstantKeyAES3", "main", 1) - .withTPs(RequiredPredicateError.class, 4) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .withTPs(NeverTypeOfError.class, 1) .build()); @@ -275,7 +280,8 @@ public void constPwd4PBEExamples() { addErrorSpecification( new ErrorSpecification.Builder("pkm.constPwd4PBE.ConstPassword4PBE1", "main", 1) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .withTPs(ForbiddenMethodError.class, 1) .withTPs(IncompleteOperationError.class, 1) @@ -284,7 +290,8 @@ public void constPwd4PBEExamples() { addErrorSpecification( new ErrorSpecification.Builder("pkm.constPwd4PBE.ConstPassword4PBE2", "main", 1) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .withTPs(ForbiddenMethodError.class, 1) .withTPs(IncompleteOperationError.class, 1) @@ -307,7 +314,8 @@ public void customCryptoExamples() { addErrorSpecification( new ErrorSpecification.Builder("wc.customCrypto.Manual3DES", "main", 1) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 4) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -352,7 +360,8 @@ public void deterministicCryptoExamples() { new ErrorSpecification.Builder( "pkc.enc.deterministicCrypto.DeterministicEncryptionRSA", "main", 1) .withTPs(ConstraintError.class, 7) - .withTPs(RequiredPredicateError.class, 5) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(IncompleteOperationError.class, 2) .build()); addErrorSpecification( @@ -361,7 +370,8 @@ public void deterministicCryptoExamples() { "main", 1) .withTPs(ConstraintError.class, 1) - .withTPs(RequiredPredicateError.class, 5) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(IncompleteOperationError.class, 2) .build()); addErrorSpecification( @@ -370,7 +380,8 @@ public void deterministicCryptoExamples() { "main", 1) .withTPs(ConstraintError.class, 3) - .withTPs(RequiredPredicateError.class, 5) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(IncompleteOperationError.class, 2) .build()); addErrorSpecification( @@ -379,7 +390,8 @@ public void deterministicCryptoExamples() { "main", 1) .withTPs(ConstraintError.class, 3) - .withTPs(RequiredPredicateError.class, 5) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(IncompleteOperationError.class, 2) .build()); @@ -700,11 +712,13 @@ public void insecureDefaultExamples() { .withTPs(ConstraintError.class, 1) .withTPs(ForbiddenMethodError.class, 1) .withTPs(IncompleteOperationError.class, 1) + .withTPs(RequiredPredicateError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder("pdf.insecureDefault.InsecureDefault3DES", "main", 1) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); addErrorSpecification( @@ -718,7 +732,8 @@ public void insecureDefaultExamples() { new ErrorSpecification.Builder( "pdf.insecureDefault.InsecureDefaultOAEP", "positiveTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -727,7 +742,8 @@ public void insecureDefaultExamples() { new ErrorSpecification.Builder( "pdf.insecureDefault.InsecureDefaultOAEP", "negativeTestCase", 0) .withTPs(ConstraintError.class, 3) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -743,7 +759,8 @@ public void insecureDefaultExamples() { new ErrorSpecification.Builder( "pdf.insecureDefault.InsecureDefaultRSA", "negativeTestCase", 0) .withTPs(ConstraintError.class, 1) - .withTPs(RequiredPredicateError.class, 5) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(IncompleteOperationError.class, 2) .build()); @@ -777,7 +794,8 @@ public void insecurePaddingExamples() { "negativeTestCase", 0) .withTPs(ConstraintError.class, 1) - .withTPs(RequiredPredicateError.class, 5) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(IncompleteOperationError.class, 2) .build()); @@ -798,7 +816,8 @@ public void insecurePaddingExamples() { "negativeTestCase", 0) .withTPs(ConstraintError.class, 3) - .withTPs(RequiredPredicateError.class, 5) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(IncompleteOperationError.class, 2) .build()); @@ -819,7 +838,8 @@ public void insecurePaddingExamples() { "negativeTestCase", 0) .withTPs(ConstraintError.class, 3) - .withTPs(RequiredPredicateError.class, 5) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(IncompleteOperationError.class, 2) .build()); @@ -982,14 +1002,16 @@ public void insecureStreamCipherExamples() { addErrorSpecification( new ErrorSpecification.Builder( "pdf.insecureStreamCipher.ConfusingBlockAndStream", "main", 1) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .withTPs(NeverTypeOfError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder( "pdf.insecureStreamCipher.MalealableStreamCipher", "main", 1) - .withTPs(RequiredPredicateError.class, 5) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 2) .withTPs(IncompleteOperationError.class, 1) .withTPs(NeverTypeOfError.class, 1) @@ -1098,7 +1120,8 @@ public void keyReuseInStreamCipherExamples() { addErrorSpecification( new ErrorSpecification.Builder( "pkm.keyReuseInStreamCipher.KeyReuseStreamCipher1", "main", 1) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .withTPs(CallToError.class, 1) .withTPs(NeverTypeOfError.class, 1) @@ -1106,28 +1129,32 @@ public void keyReuseInStreamCipherExamples() { addErrorSpecification( new ErrorSpecification.Builder( "pkm.keyReuseInStreamCipher.KeyReuseStreamCipher2", "main", 1) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .withTPs(CallToError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder( "pkm.keyReuseInStreamCipher.KeyReuseStreamCipher3", "main", 1) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .withTPs(CallToError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder( "pkm.keyReuseInStreamCipher.KeyReuseStreamCipher4", "main", 1) - .withTPs(RequiredPredicateError.class, 8) + .withTPs(RequiredPredicateError.class, 6) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .withTPs(CallToError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder( "pkm.keyReuseInStreamCipher.KeyReuseStreamCipher5", "main", 1) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .withTPs(CallToError.class, 1) .build()); @@ -1149,7 +1176,8 @@ public void nonceReuseExamples() { addErrorSpecification( new ErrorSpecification.Builder("ivm.nonceReuse.NonceReuse1", "main", 1) .withTPs(TypestateError.class, 1) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(CallToError.class, 1) .build()); @@ -1184,7 +1212,8 @@ public void paramsPBEExamples() { addErrorSpecification( new ErrorSpecification.Builder("cib.paramsPBE.PBEwConstSalt1", "main", 1) .withTPs(ConstraintError.class, 1) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(ForbiddenMethodError.class, 1) .withTPs(TypestateError.class, 1) .withTPs(IncompleteOperationError.class, 1) @@ -1193,7 +1222,8 @@ public void paramsPBEExamples() { addErrorSpecification( new ErrorSpecification.Builder("cib.paramsPBE.PBEwSmallCount1", "main", 1) .withTPs(ConstraintError.class, 1) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(ForbiddenMethodError.class, 1) .withTPs(TypestateError.class, 1) .withTPs(IncompleteOperationError.class, 1) @@ -1202,7 +1232,8 @@ public void paramsPBEExamples() { addErrorSpecification( new ErrorSpecification.Builder("cib.paramsPBE.PBEwSmallSalt", "main", 1) .withTPs(ConstraintError.class, 1) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(ForbiddenMethodError.class, 1) .withTPs(TypestateError.class, 1) .withTPs(IncompleteOperationError.class, 1) @@ -1286,7 +1317,8 @@ public void printPrivSecKeyExamples() { new ErrorSpecification.Builder( "cib.printPrivSecKey.PrintPrivKey1", "negativeTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 5) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1349,13 +1381,15 @@ public void riskyInsecureCryptoExamples() { .withTPs(ConstraintError.class, 2) .withTPs(ForbiddenMethodError.class, 1) .withTPs(IncompleteOperationError.class, 1) + .withTPs(RequiredPredicateError.class, 2) .build()); addErrorSpecification( new ErrorSpecification.Builder( "wc.riskyInsecureCrypto.InsecureCrypto3DES", "main", 1) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1363,7 +1397,8 @@ public void riskyInsecureCryptoExamples() { new ErrorSpecification.Builder( "wc.riskyInsecureCrypto.InsecureCryptoBlowfish", "main", 1) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1371,7 +1406,8 @@ public void riskyInsecureCryptoExamples() { new ErrorSpecification.Builder( "wc.riskyInsecureCrypto.InsecureCryptoDES", "main", 1) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1379,7 +1415,8 @@ public void riskyInsecureCryptoExamples() { new ErrorSpecification.Builder( "wc.riskyInsecureCrypto.InsecureCryptoDES_StreamCipher", "main", 1) .withTPs(ConstraintError.class, 5) - .withTPs(RequiredPredicateError.class, 12) + .withTPs(RequiredPredicateError.class, 4) + .withTPs(AlternativeReqPredicateError.class, 8) .withTPs(TypestateError.class, 5) .build()); @@ -1387,7 +1424,8 @@ public void riskyInsecureCryptoExamples() { new ErrorSpecification.Builder( "wc.riskyInsecureCrypto.InsecureCryptoRC4_StreamCipher", "main", 1) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1421,14 +1459,16 @@ public void sideChannelAttacksExamples() { addErrorSpecification( new ErrorSpecification.Builder("pdf.sideChannelAttacks.PaddingOracle", "oracle", 2) .withTPs(ConstraintError.class, 1) - .withTPs(RequiredPredicateError.class, 2) + .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder( "pdf.sideChannelAttacks.PaddingOracle", "encripta", 0) .withTPs(ConstraintError.class, 1) - .withTPs(RequiredPredicateError.class, 2) + .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); addErrorSpecification( @@ -1513,13 +1553,15 @@ public void undefinedCSPExamples() { addErrorSpecification( new ErrorSpecification.Builder("cai.undefinedCSP.UndefinedProvider7", "main", 1) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder("cai.undefinedCSP.UndefinedProvider8", "main", 1) .withTPs(ConstraintError.class, 1) - .withTPs(RequiredPredicateError.class, 5) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(IncompleteOperationError.class, 2) .build()); @@ -1544,7 +1586,8 @@ public void weakConfigsRSAExamples() { "positiveTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 6) + .withTPs(RequiredPredicateError.class, 4) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1555,7 +1598,8 @@ public void weakConfigsRSAExamples() { "negativeTestCase", 0) .withTPs(ConstraintError.class, 3) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1566,7 +1610,8 @@ public void weakConfigsRSAExamples() { "positiveTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 6) + .withTPs(RequiredPredicateError.class, 4) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1577,7 +1622,8 @@ public void weakConfigsRSAExamples() { "negativeTestCase", 0) .withTPs(ConstraintError.class, 3) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1588,7 +1634,8 @@ public void weakConfigsRSAExamples() { "positiveTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 6) + .withTPs(RequiredPredicateError.class, 4) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1599,7 +1646,8 @@ public void weakConfigsRSAExamples() { "negativeTestCase", 0) .withTPs(ConstraintError.class, 3) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1610,7 +1658,8 @@ public void weakConfigsRSAExamples() { "positiveTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 6) + .withTPs(RequiredPredicateError.class, 4) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1621,7 +1670,8 @@ public void weakConfigsRSAExamples() { "negativeTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1632,7 +1682,8 @@ public void weakConfigsRSAExamples() { "positiveTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 6) + .withTPs(RequiredPredicateError.class, 4) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1643,7 +1694,8 @@ public void weakConfigsRSAExamples() { "negativeTestCase", 0) .withTPs(ConstraintError.class, 3) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1654,7 +1706,8 @@ public void weakConfigsRSAExamples() { "positiveTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 6) + .withTPs(RequiredPredicateError.class, 4) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1665,7 +1718,8 @@ public void weakConfigsRSAExamples() { "negativeTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1676,7 +1730,8 @@ public void weakConfigsRSAExamples() { "positiveTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 6) + .withTPs(RequiredPredicateError.class, 4) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1687,7 +1742,8 @@ public void weakConfigsRSAExamples() { "negativeTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1698,7 +1754,8 @@ public void weakConfigsRSAExamples() { "positiveTestCase", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 6) + .withTPs(RequiredPredicateError.class, 4) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); @@ -1709,7 +1766,8 @@ public void weakConfigsRSAExamples() { "negativeTestCase", 0) .withTPs(ConstraintError.class, 3) - .withTPs(RequiredPredicateError.class, 7) + .withTPs(RequiredPredicateError.class, 5) + .withTPs(AlternativeReqPredicateError.class, 2) .withTPs(TypestateError.class, 1) .build()); diff --git a/HeadlessJavaScanner/src/test/java/scanner/targets/CogniCryptGeneratedCodeTest.java b/HeadlessJavaScanner/src/test/java/scanner/targets/CogniCryptGeneratedCodeTest.java index 29aa6717e..8d5fa156e 100644 --- a/HeadlessJavaScanner/src/test/java/scanner/targets/CogniCryptGeneratedCodeTest.java +++ b/HeadlessJavaScanner/src/test/java/scanner/targets/CogniCryptGeneratedCodeTest.java @@ -1,5 +1,6 @@ package scanner.targets; +import crypto.analysis.errors.AlternativeReqPredicateError; import crypto.analysis.errors.CallToError; import crypto.analysis.errors.HardCodedError; import crypto.analysis.errors.RequiredPredicateError; @@ -31,11 +32,12 @@ public void fileEncryptor() { .build()); addErrorSpecification( new ErrorSpecification.Builder("Crypto.Enc", "encrypt", 2) - .withFPs(RequiredPredicateError.class, 1, "Mystery") + .withFPs(AlternativeReqPredicateError.class, 1, "Mystery") .build()); addErrorSpecification( new ErrorSpecification.Builder("Crypto.Enc", "decrypt", 2) - .withFPs(RequiredPredicateError.class, 2, "Mystery") + .withFPs(RequiredPredicateError.class, 1, "Mystery") + .withFPs(AlternativeReqPredicateError.class, 1, "Mystery") .build()); scanner.run(); diff --git a/HeadlessJavaScanner/src/test/java/scanner/targets/CryptoGuardTest.java b/HeadlessJavaScanner/src/test/java/scanner/targets/CryptoGuardTest.java index 83214db1c..88b26149b 100644 --- a/HeadlessJavaScanner/src/test/java/scanner/targets/CryptoGuardTest.java +++ b/HeadlessJavaScanner/src/test/java/scanner/targets/CryptoGuardTest.java @@ -1,5 +1,6 @@ package scanner.targets; +import crypto.analysis.errors.AlternativeReqPredicateError; import crypto.analysis.errors.ConstraintError; import crypto.analysis.errors.HardCodedError; import crypto.analysis.errors.ImpreciseValueExtractionError; @@ -48,7 +49,8 @@ public void brokenCryptoExamples() { new ErrorSpecification.Builder( "example.brokencrypto.BrokenCryptoABICase2", "doCrypto", 1) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 2) + .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 1) .withTPs(IncompleteOperationError.class, 1) .build()); // ABICase3, ABICase4, ABICase9 not included as tests due to being similar to ABICase1 and @@ -60,7 +62,8 @@ public void brokenCryptoExamples() { new ErrorSpecification.Builder( "example.brokencrypto.BrokenCryptoABICase5", "doCrypto", 0) .withTPs(ConstraintError.class, 1) - .withTPs(RequiredPredicateError.class, 2) + .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 1) .withTPs(IncompleteOperationError.class, 1) .withTPs(ImpreciseValueExtractionError.class, 1) .build()); @@ -71,7 +74,8 @@ public void brokenCryptoExamples() { addErrorSpecification( new ErrorSpecification.Builder("example.brokencrypto.BrokenCryptoBBCase3", "go", 0) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 2) + .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 1) .withTPs(IncompleteOperationError.class, 1) .build()); // BBCase1, BBCase2, BBCase4, BBCase5 not included as tests due to being similar to BBCase3 @@ -192,7 +196,8 @@ public void insecureAsymmetricCryptoExamples() { "go", 2) .withTPs(IncompleteOperationError.class, 2) - .withTPs(RequiredPredicateError.class, 4) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 2) .build()); // This test case corresponds to the following project in CryptoGuard: @@ -211,9 +216,10 @@ public void insecureAsymmetricCryptoExamples() { "go", 2) .withTPs(IncompleteOperationError.class, 2) - .withTPs(RequiredPredicateError.class, 4) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 2) .build()); - // In the case above, misuse is caught correctly, but the keysize is reported to be 0 + // In the case above, misuse is caught correctly, but the key size is reported to be 0 // and not 1024, as it really is. This is caused because of the structure of the project // as explained in the issue: https://github.com/CROSSINGTUD/CryptoAnalysis/issues/163 @@ -226,7 +232,8 @@ public void insecureAsymmetricCryptoExamples() { 0) .withTPs(ConstraintError.class, 1) .withTPs(IncompleteOperationError.class, 2) - .withTPs(RequiredPredicateError.class, 5) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 2) .build()); scanner.run(); diff --git a/HeadlessJavaScanner/src/test/java/scanner/targets/IgnoreSectionsTest.java b/HeadlessJavaScanner/src/test/java/scanner/targets/IgnoreSectionsTest.java index a52b70c18..f52df1c9f 100644 --- a/HeadlessJavaScanner/src/test/java/scanner/targets/IgnoreSectionsTest.java +++ b/HeadlessJavaScanner/src/test/java/scanner/targets/IgnoreSectionsTest.java @@ -1,5 +1,6 @@ package scanner.targets; +import crypto.analysis.errors.AlternativeReqPredicateError; import crypto.analysis.errors.ConstraintError; import crypto.analysis.errors.IncompleteOperationError; import crypto.analysis.errors.RequiredPredicateError; @@ -39,7 +40,8 @@ public void ignoreNoPackages() { addErrorSpecification( new ErrorSpecification.Builder("example.PredicateMissingExample", "main", 1) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 2) + .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder("example.TypestateErrorExample", "main", 1) @@ -116,7 +118,8 @@ public void ignoreClassesExample() { addErrorSpecification( new ErrorSpecification.Builder("example.PredicateMissingExample", "main", 1) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 2) + .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder("example.TypestateErrorExample", "main", 1) diff --git a/HeadlessJavaScanner/src/test/java/scanner/targets/MUBenchExamplesTest.java b/HeadlessJavaScanner/src/test/java/scanner/targets/MUBenchExamplesTest.java index e2934d5e0..6d6257f39 100644 --- a/HeadlessJavaScanner/src/test/java/scanner/targets/MUBenchExamplesTest.java +++ b/HeadlessJavaScanner/src/test/java/scanner/targets/MUBenchExamplesTest.java @@ -1,5 +1,6 @@ package scanner.targets; +import crypto.analysis.errors.AlternativeReqPredicateError; import crypto.analysis.errors.ConstraintError; import crypto.analysis.errors.IncompleteOperationError; import crypto.analysis.errors.NeverTypeOfError; @@ -81,7 +82,8 @@ public void muBenchExamples() { addErrorSpecification( new ErrorSpecification.Builder("example.CipherUsesNonRandomKeyExample", "main", 1) .withTPs(NeverTypeOfError.class, 1) - .withTPs(RequiredPredicateError.class, 2) + .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); // This test case corresponds to the following project in MUBench having this misuse: diff --git a/HeadlessJavaScanner/src/test/java/scanner/targets/ReportFormatTest.java b/HeadlessJavaScanner/src/test/java/scanner/targets/ReportFormatTest.java index 022826fc2..22b85db68 100644 --- a/HeadlessJavaScanner/src/test/java/scanner/targets/ReportFormatTest.java +++ b/HeadlessJavaScanner/src/test/java/scanner/targets/ReportFormatTest.java @@ -23,6 +23,7 @@ public class ReportFormatTest extends AbstractHeadlessTest { private static final String csvSummaryReportPath = rootPath + "CryptoAnalysis-Report-Summary.csv"; private static final String sarifReportPath = rootPath + "CryptoAnalysis-Report.json"; + private static final String visualizationPath = rootPath + "visualization.png"; @Before public void setup() { @@ -152,6 +153,24 @@ public void testMultipleFormatsCreation() { Assert.assertTrue(sarifReport.exists()); } + @Test + public void testVisualization() { + File vizFile = new File(visualizationPath); + if (vizFile.exists()) { + vizFile.delete(); + } + String mavenProjectPath = + new File("../CryptoAnalysisTargets/ReportFormatExample").getAbsolutePath(); + MavenProject mavenProject = createAndCompile(mavenProjectPath); + + HeadlessJavaScanner scanner = createScanner(mavenProject); + scanner.setReportDirectory(outputDir.getAbsolutePath()); + scanner.setVisualization(true); + scanner.run(); + + Assert.assertTrue(vizFile.exists()); + } + @After public void tearDown() { try { diff --git a/HeadlessJavaScanner/src/test/java/scanner/targets/ReportedIssueTest.java b/HeadlessJavaScanner/src/test/java/scanner/targets/ReportedIssueTest.java index 9313843b0..f43500db5 100644 --- a/HeadlessJavaScanner/src/test/java/scanner/targets/ReportedIssueTest.java +++ b/HeadlessJavaScanner/src/test/java/scanner/targets/ReportedIssueTest.java @@ -1,5 +1,6 @@ package scanner.targets; +import crypto.analysis.errors.AlternativeReqPredicateError; import crypto.analysis.errors.ConstraintError; import crypto.analysis.errors.HardCodedError; import crypto.analysis.errors.IncompleteOperationError; @@ -46,7 +47,7 @@ public void reportedIssues() { addErrorSpecification( new ErrorSpecification.Builder("issue81.Encryption", "encrypt", 2) .withTPs(ConstraintError.class, 1) - .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder("issue81.Encryption", "generateKey", 1) @@ -71,13 +72,15 @@ public void reportedIssues() { addErrorSpecification( new ErrorSpecification.Builder("issue70.ClientProtocolDecoder", "decryptAES", 1) .withTPs(ConstraintError.class, 1) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder("issue69.Issue69", "encryptByPublicKey", 1) .withTPs(IncompleteOperationError.class, 1) - .withTPs(RequiredPredicateError.class, 4) + .withTPs(RequiredPredicateError.class, 3) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); addErrorSpecification( @@ -93,7 +96,7 @@ public void reportedIssues() { .build()); addErrorSpecification( new ErrorSpecification.Builder("issue68.AESCryptor", "encryptImpl", 1) - .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder("issue68.AESCryptor", "", 1) @@ -102,7 +105,8 @@ public void reportedIssues() { .build()); addErrorSpecification( new ErrorSpecification.Builder("issue68.AESCryptor", "decryptImpl", 1) - .withTPs(RequiredPredicateError.class, 2) + .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); addErrorSpecification( new ErrorSpecification.Builder( @@ -166,7 +170,7 @@ public void issue271Test() { } @Test - public void issue270() { + public void issue270Test() { // Related to https://github.com/CROSSINGTUD/CryptoAnalysis/issues/270 String mavenProjectPath = new File("../CryptoAnalysisTargets/Bugfixes/issue270").getAbsolutePath(); diff --git a/HeadlessJavaScanner/src/test/java/scanner/targets/SootJava9ConfigurationTest.java b/HeadlessJavaScanner/src/test/java/scanner/targets/SootJava9ConfigurationTest.java index 0fc3eddd7..0679d0242 100644 --- a/HeadlessJavaScanner/src/test/java/scanner/targets/SootJava9ConfigurationTest.java +++ b/HeadlessJavaScanner/src/test/java/scanner/targets/SootJava9ConfigurationTest.java @@ -2,6 +2,7 @@ import static org.junit.Assume.assumeTrue; +import crypto.analysis.errors.AlternativeReqPredicateError; import crypto.analysis.errors.ConstraintError; import crypto.analysis.errors.IncompleteOperationError; import crypto.analysis.errors.RequiredPredicateError; @@ -67,7 +68,8 @@ public void testJava8Project() { addErrorSpecification( new ErrorSpecification.Builder("example.PredicateMissingExample", "main", 1) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 2) + .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); addErrorSpecification( diff --git a/HeadlessJavaScanner/src/test/java/scanner/targets/StaticAnalysisDemoTest.java b/HeadlessJavaScanner/src/test/java/scanner/targets/StaticAnalysisDemoTest.java index 9c00506f5..b14996f9c 100644 --- a/HeadlessJavaScanner/src/test/java/scanner/targets/StaticAnalysisDemoTest.java +++ b/HeadlessJavaScanner/src/test/java/scanner/targets/StaticAnalysisDemoTest.java @@ -1,5 +1,6 @@ package scanner.targets; +import crypto.analysis.errors.AlternativeReqPredicateError; import crypto.analysis.errors.ConstraintError; import crypto.analysis.errors.HardCodedError; import crypto.analysis.errors.ImpreciseValueExtractionError; @@ -32,7 +33,8 @@ public void cogniCryptDemoExamples() { addErrorSpecification( new ErrorSpecification.Builder("example.PredicateMissingExample", "main", 1) .withTPs(ConstraintError.class, 2) - .withTPs(RequiredPredicateError.class, 2) + .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); addErrorSpecification( @@ -123,7 +125,7 @@ public void glassfishExample() { new ErrorSpecification.Builder( "org.glassfish.grizzly.config.ssl.CustomClass", "init", 2) .withTPs(ConstraintError.class, 1) - .withTPs(RequiredPredicateError.class, 1) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); addErrorSpecification( @@ -150,7 +152,8 @@ public void oracleExample() { .withTPs(ConstraintError.class, 2) .withTPs(TypestateError.class, 1) .withTPs(NeverTypeOfError.class, 1) - .withTPs(RequiredPredicateError.class, 3) + .withTPs(RequiredPredicateError.class, 2) + .withTPs(AlternativeReqPredicateError.class, 1) .build()); addErrorSpecification( diff --git a/HeadlessJavaScanner/src/test/java/settings/CommandLineTest.java b/HeadlessJavaScanner/src/test/java/settings/CommandLineTest.java index ce468d02e..6ac4294e0 100644 --- a/HeadlessJavaScanner/src/test/java/settings/CommandLineTest.java +++ b/HeadlessJavaScanner/src/test/java/settings/CommandLineTest.java @@ -253,6 +253,23 @@ public void testInvalidReportFormat() { @Test public void testVisualization() { + String reportPath = "path/to/report"; + String[] args = + new String[] { + APP_PATH, + EXAMPLE_APP_PATH, + RULES_DIR, + EXAMPLE_RULES_DIR, + VISUALIZATION, + REPORT_PATH, + reportPath + }; + HeadlessJavaScanner scanner = HeadlessJavaScanner.createFromCLISettings(args); + Assert.assertTrue(scanner.isVisualization()); + } + + @Test(expected = CryptoAnalysisParserException.class) + public void testInvalidVisualization() { String[] args = new String[] { APP_PATH, EXAMPLE_APP_PATH, RULES_DIR, EXAMPLE_RULES_DIR, VISUALIZATION diff --git a/README.md b/README.md index dea79faf2..d028b2f63 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,54 @@ The static analysis CogniCryptSAST takes rules written in the specifi and performs a static analysis based on the specification of the rules. CrySL is a domain-specific language (DSL) designed to encode usage specifications for cryptographic libaries (e.g., the [JCA](https://docs.oracle.com/en/java/javase/14/security/java-cryptography-architecture-jca-reference-guide.html) in particular). More information on CrySL and the static analysis may be found in [this paper](http://drops.dagstuhl.de/opus/volltexte/2018/9215/). +## Running CognitCryptSAST + +Let's assume we have the following program with some violations: + +```java +import java.security.GeneralSecurityException; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import javax.crypto.Cipher; + +public class Example { + + public static void main(String[] args) throws GeneralSecurityException { + // Constraint Error: "DES" is not allowed + KeyGenerator generator = KeyGenerator.getInstance("DES"); // r0 + + // Constraint Error: Key size of 64 is not allowed + generator.init(64); + + // KeyGenerator is not correctly initialized + // RequiredPredicateEror: Generated key is not secure + SecretKey key = generator.generateKey(); // r1 + + // Constraint Error: "DES" is not allowed + Cipher cipher = Cipher.getInstance("DES"); // r2 + + // RequiredPredicateError: "key" is not securely generated + cipher.init(Cipher.ENCRYPT_MODE, key); + + // IncompleteOperationError: Cipher object is not used + } +} +``` + +Using the [JCA rules](https://github.com/CROSSINGTUD/Crypto-API-Rules/tree/master/JavaCryptographicArchitecture/src), we execute the following command on a compiled version of this program: + +```bash +java -jar HeadlessJavaScanner-x.y.z-jar-with-dependencies.jar --appPath ./Examples.jar --rulesDir ./JCA-CrySL-rules.zip --reportFormat CMD --reportPath ./output/ --visualization +``` + +CogniCryptSAST runs the analysis and prints a report to the command line. In total, it reports 3 `ConstraintErrors`, 2 `RequiredPredicateErrors` and 1 `IncompleteOperationError`, and their positions in the original programs. Additionally, since we use `--visualization`, it creates the following image `visualization.png` in the directory `./output/`: + +![visualization.png](misc/visualization.png) + +You can see that two `ConstraintErrors` on the object `r0` (KeyGenerator) cause a `RequiredPredicateError` on the object `r1` (SecretKey) which in turn causes a `RequiredPredicateError` on the object `r2` (Cipher). Additionally, there is another `ConstraintError` and `IncompleteOperationError` on the Cipher object. Note that the variables and statements correspond to the intermediate representation Jimple. You can match the variables to the command line output that lists all analyzed objects. + + ## Structure We provide the implementation of the static analysis of CogniCrypt in: * `CryptoAnalysis` contains the components for the actual analysis @@ -17,25 +65,19 @@ We further provide two SAST tools that allow the analysis of Java and Android ap ## Releases -You can checkout a pre-compiled version of CogniCryptSAST [here](https://github.com/CROSSINGTUD/CryptoAnalysis/releases). We recommend using the latest version. - -Download the two files: -* CryptoAnalysis-x.y.z-jar-with-dependencies.jar -* JCA-CrySL-rules.zip - -You can find CogniCryptSAST also on [Maven Central](https://central.sonatype.com/artifact/de.fraunhofer.iem/CryptoAnalysis). +You can checkout a pre-compiled version of CogniCryptSAST [here](https://github.com/CROSSINGTUD/CryptoAnalysis/releases). We recommend using the latest version. You can find CogniCryptSAST also on [Maven Central](https://central.sonatype.com/artifact/de.fraunhofer.iem/CryptoAnalysis). ## Checkout and Build CogniCryptSAST uses Maven as build tool. You can compile and build this project via -```mvn clean package -DskipTests=true```. +```mvn clean package -DskipTests```. The packaged `jar` artifacts including all dependencies can be found in `/apps`. Building requires at least Java 17. ## CogniCryptSAST for Java Applications -CogniCryptSAST can be started in headless mode (i.e., detached from Eclipse) via the file `HeadlessJavaScanner-x.y.z-jar-with-dependencies.jar`. It requires two arguments: +CogniCryptSAST can be started in headless mode as CLI tool via the file `HeadlessJavaScanner-x.y.z-jar-with-dependencies.jar`. It requires two arguments: * The path to the directory of the CrySL (source code format) rule files. The source code for the rules which contain specification for the JCA is found [here](https://github.com/CROSSINGTUD/Crypto-API-Rules). * The path of the application to be analyzed (.jar file or the root compilation output folder which contains the .class files in subdirectories) @@ -45,13 +87,7 @@ java -jar HeadlessJavaScanner-x.y.z-jar-with-dependencies.jar --appPath ``` -For an easy start we prepared a .jar containing classes with crypto misuses. The source code for these misuses is found [here](https://github.com/CROSSINGTUD/CryptoAnalysis/tree/develop/CryptoAnalysisTargets/CogniCryptDemoExample/src/main/java/example). To run CogniCryptSAST on these classes, simply execute the following command. - -``` -java -jar HeadlessJavaScanner-x.y.z-jar-with-dependencies.jar - --rulesDir $(pwd)/CryptoAnalysis-Core/src/main/resources/JavaCryptographicArchitecture - --appPath $(pwd)/CryptoAnalysisTargets/CogniCryptDemoExample/Examples.jar -``` +For an easy start we prepared a .jar containing classes with crypto misuses. The source code for these misuses is found [here](https://github.com/CROSSINGTUD/CryptoAnalysis/tree/develop/CryptoAnalysisTargets/CogniCryptDemoExample/src/main/java/example). Other additional arguments that can be used are as follows: @@ -61,7 +97,7 @@ Other additional arguments that can be used are as follows: --identifier --reportPath --reportFormat (possible values are CMD, TXT, SARIF, CSV, CSV_SUMMARY) ---visualization (enables the visualization, but also requires --reportPath option to be set) +--visualization (Create a visualization of all errors (requires --reportPath option to be set)) --dstats (disables the output of the analysis statistics in the reports) --ignoreSections (Text file with packages (e.g. `de.example.*`), classes (e.g. `de.example.exmapleClass`) or methods (e.g. `de.example.exampleClass.exampleMethod`), one per line. Those packages, classes and methods are ignored during the analysis) --timeout (Timeout for seeds in milliseconds. If a seed exceeds this value, CryptoAnalysis aborts the typestate and extract parameter analysis and continues with the results computed so far. (default: 10000)) @@ -113,12 +149,7 @@ CogniCryptSAST supports different report formats, which can be set by - `CSV_SUMMARY`: The report is written to the file `CryptoAnalysis-Report-Summary.csv` and contains a summary of the analysis results. Compared to the `CSV` format, this format does not provide concrete information about the errors, it only lists the amount of each misuse type. This option was previously implemented by the `CSV` option, which has been changed to provide more detailed information about the errors in the CSV format. - `GITHUB_ANNOTATION`: Works like `CMD` but also outputs all violations as annotations when running inside as a GitHub Action. -If the `--reportformat` option is not specified, CogniCryptSAST defaults to the `CMD` option. It also allows the usage of multiple different formats for the same analysis (e.g. `--reportformat CMD,TXT,CSV` creates a report, which is printed to the command line and is written to a text and CSV file). If the option `--reportPath ` is set, the reports are created in the specified directory. - -## Updating CrySL Rules - -The tool takes CrySL rules in their source code formats (crysl). You can adapt the rules in any text editor. -Additionaly, the [Eclipse plugin CogniCrypt](https://github.com/CROSSINGTUD/CogniCrypt) ships with a CrySL editor to modify the rules with IDE support (e.g., content assist, auto completion, etc.). A step-by-step-explanation on how edit CrySL rules is avialable at the tool's website [cognicrypt.org](https://www.eclipse.org/cognicrypt/documentation/crysl/). +If the `--reportformat` option is not specified, CogniCryptSAST defaults to the `CMD` option. It also allows the usage of multiple different formats for the same analysis (e.g. `--reportformat CMD,TXT,CSV` creates a report, which is printed to the command line and is written to a text and CSV file). If the option `--reportPath ` is set, the reports (and the visualization) are created in the specified directory. ## CogniCryptSAST for Android Applications @@ -131,7 +162,7 @@ CogniCryptSAST can also be run on Android Applications using the Andr ``` java -jar HeadlessAndroidScanner-x.y.z-jar-with-dependencies.jar --rulesDir - --platformDirectory + --platformDirectory --appPath ``` Optional parameters are `--reportPath` and `--reportFormat`. They have the same functionality as the `HeadlessJavaScanner-x.y.z-jar-with-dependencies.jar` (see above). @@ -145,3 +176,4 @@ We hare happy for every contribution from the community! * [Contributing](CONTRIBUTING.md) for details on issues and merge requests. * [Coding Guidles](CODING.md) for this project. + diff --git a/misc/visualization.png b/misc/visualization.png new file mode 100644 index 000000000..bcec9a00b Binary files /dev/null and b/misc/visualization.png differ diff --git a/pom.xml b/pom.xml index b2e46012f..6666d7af1 100644 --- a/pom.xml +++ b/pom.xml @@ -287,6 +287,7 @@ -Xmx8G -Xms256M -Xss8M -Dmaven.home="${maven.home}" false + ${project.basedir}/shippable/testresults @@ -450,8 +451,8 @@ + contexts because they require specific keys from the GitHub remote. Include + this profile by setting the -Pdeployment flag. --> deployment