diff --git a/.github/workflows/maven-publish.yml b/.github/workflows/maven-publish.yml index dfce9b50a..ceffc63a4 100644 --- a/.github/workflows/maven-publish.yml +++ b/.github/workflows/maven-publish.yml @@ -20,7 +20,7 @@ jobs: - name: Set up JDK uses: actions/setup-java@v5 with: - java-version: '17' + java-version: '21' distribution: 'temurin' - name: Deploy to GitHub Packages run: mvn --batch-mode deploy diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index c58031174..1d4c551db 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -10,39 +10,43 @@ name: Java CI with Maven permissions: contents: write - packages: write on: push: - branches: [ "main", "dev/*" ] + branches: ["main", "dev/*"] pull_request: - branches: [ "main", "dev/*" ] + branches: ["main", "dev/*"] jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 - - name: Set up JDK 17 - uses: actions/setup-java@v5 - with: - java-version: '17' - distribution: 'temurin' - cache: maven - - name: Build with Maven - run: mvn -B clean package - - name: Create CBOM - uses: cbomkit/cbomkit-action@v2.2.0 - id: cbom - # Persist CBOM after a job has completed and share - # that CBOM with another job in the same workflow. - - name: Commit changes to new branch - uses: actions/upload-artifact@v7 - with: - name: "CBOM" - path: ${{ steps.cbom.outputs.pattern }} - if-no-files-found: warn - # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive - #- name: Update dependency graph - # uses: advanced-security/maven-dependency-submission-action@v5 - # if: github.event_name != 'pull_request' + - uses: actions/checkout@v6 + + - name: Set up JDK 21 + uses: actions/setup-java@v5 + with: + java-version: "21" + distribution: "temurin" + cache: maven + + - name: Build with Maven + run: mvn -B clean package + + - name: Create CBOM + uses: cbomkit/cbomkit-action@v2.2.0 + id: cbom + # Persist CBOM after a job has completed and share + # that CBOM with another job in the same workflow. + + - name: Upload CBOM artifact + uses: actions/upload-artifact@v7 + with: + name: "CBOM" + path: ${{ steps.cbom.outputs.pattern }} + if-no-files-found: warn + + # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive + #- name: Update dependency graph + # uses: advanced-security/maven-dependency-submission-action@v5 + # if: github.event_name != 'pull_request' diff --git a/README.md b/README.md index 96cdacf39..0c1aacb47 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@ [![License](https://img.shields.io/github/license/cbomkit/sonar-cryptography.svg?)](https://opensource.org/licenses/Apache-2.0) [![Current Release](https://img.shields.io/github/release/cbomkit/sonar-cryptography.svg?logo=IBM)](https://github.com/cbomkit/sonar-cryptography/releases) - This repository contains a SonarQube Plugin that detects cryptographic assets in source code and generates [CBOM](https://cyclonedx.org/capabilities/cbom/). It is part of **the [CBOMKit](https://github.com/cbomkit) toolset**. @@ -23,11 +22,10 @@ It is part of **the [CBOMKit](https://github.com/cbomkit) toolset**. ## Version compatibility | Plugin Version | SonarQube Version | -|-----------------|--------------------------------| +| --------------- | ------------------------------ | | 1.3.7 and up | SonarQube 9.9 (LTS) and up | -| 1.3.2 and 1.3.6 | SonarQube 9.8 (LTS) up to 10.8 | -| 1.2.0 to 1.3.1 | SonarQube 9.8 (LTS) up to 10.4 | - +| 1.3.2 and 1.3.6 | SonarQube 9.8 (LTS) up to 10.8 | +| 1.2.0 to 1.3.1 | SonarQube 9.8 (LTS) up to 10.4 | ## Supported languages and libraries @@ -39,53 +37,58 @@ It is part of **the [CBOMKit](https://github.com/cbomkit) toolset**. | Go | [crypto](https://pkg.go.dev/crypto) (*standard library*) | 100%[^2] | | | [golang.org/x/crypto](https://pkg.go.dev/golang.org/x/crypto) | Partial[^3] | | C# | [System.Security.Cryptography](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography) | In development[^4] | - +| C/C++ | [OpenSSL](https://www.openssl.org/) | Partial[^5] | [^1]: We only cover the BouncyCastle *light-weight API* according to [this specification](https://javadoc.io/static/org.bouncycastle/bctls-jdk14/1.80/specifications.html) + [^2]: All packages under [`crypto`](https://pkg.go.dev/crypto@go1.25.6#section-directories) are covered except `crypto/x509` + [^3]: Covers `golang.org/x/crypto/hkdf`, `golang.org/x/crypto/pbkdf2`, and `golang.org/x/crypto/sha3` [^4]: C# support uses an [ANTLR v7 grammar](https://github.com/antlr/grammars-v4/tree/master/csharp) to parse source files directly. The current csharp support only covers the language support and does not contain detection rules other than the rules used for verifying the detection engine. **This is not yet meant for active usage!** **Known limitations of the detection engine:** no cross-method variable tracking (only single-method scope), only works for c# v7, string-based matching (no type resolution) +[^5]: Covers OpenSSL EVP API (ciphers, digests, MACs, KDFs, key agreement, key generation, signatures), legacy API, SSL/TLS functions, and PRNG. Requires the [sonar-cxx](https://github.com/SonarOpenCommunity/sonar-cxx) plugin. + > [!NOTE] > The plugin is designed in a modular way so that it can be extended to support additional languages and recognition rules to support more libraries. -> - To add support for another language or cryptography library, see [*Extending the Sonar Cryptography Plugin to add support for another language or cryptography library*](./docs/LANGUAGE_SUPPORT.md) -> - If you just want to know more about the syntax for writing new detection rules, see [*Writing new detection rules for the Sonar Cryptography Plugin*](./docs/DETECTION_RULE_STRUCTURE.md) +> +> - To add support for another language or cryptography library, see [_Extending the Sonar Cryptography Plugin to add support for another language or cryptography library_](./docs/LANGUAGE_SUPPORT.md) +> - If you just want to know more about the syntax for writing new detection rules, see [_Writing new detection rules for the Sonar Cryptography Plugin_](./docs/DETECTION_RULE_STRUCTURE.md) ## Installation -> [!NOTE] -> To run the plugin, you need a running SonarQube instance with one of the supported +> [!NOTE] +> To run the plugin, you need a running SonarQube instance with one of the supported > versions. If you don't have one but want to try the plugin, you can use the -> included Docker Compose to set up a development environment. See +> included Docker Compose to set up a development environment. See > [here](CONTRIBUTING.md#build) for instructions. Copy the plugin (the JAR file from the [latest releases](https://github.com/cbomkit/sonar-cryptography/releases)) -to `$SONARQUBE_HOME/extensions/plugins` and restart +to `$SONARQUBE_HOME/extensions/plugins` and restart SonarQube ([more](https://docs.sonarqube.org/latest/setup-and-upgrade/install-a-plugin/)). ## Using -The plugin provides new inventory rules (Cbomkit Cryptography Repository) regarding the use of cryptography for +The plugin provides new inventory rules (Cbomkit Cryptography Repository) regarding the use of cryptography for the supported languages. -If you enable these rules, a source code scan creates a cryptographic inventory by creating a -[CBOM](https://cyclonedx.org/capabilities/cbom/) with all cryptographic assets and writing +If you enable these rules, a source code scan creates a cryptographic inventory by creating a +[CBOM](https://cyclonedx.org/capabilities/cbom/) with all cryptographic assets and writing a `cbom.json` to the scan directory. ### Add Cryptography Rules to your Quality Profile This plugin incorporates rules specifically focused on cryptography. -> To generate a Cryptography Bill of Materials (CBOM), it is mandatory to activate at +> To generate a Cryptography Bill of Materials (CBOM), it is mandatory to activate at > least one of these cryptography-related rules. ![Activate Rules Crypto Rules](docs/images/rules.png) -As of the current version, the plugin contains one single rule for creating a cryptographic inventory. +As of the current version, the plugin contains one single rule for creating a cryptographic inventory. Future updates may introduce additional rules to expand functionality. ### Scan Source Code -Now you can follow the [SonarQube documentation](https://docs.sonarqube.org/latest/analyzing-source-code/overview/) +Now you can follow the [SonarQube documentation](https://docs.sonarqube.org/latest/analyzing-source-code/overview/) to start your first scan. ### Visualizing your CBOM @@ -188,6 +191,7 @@ The plugin generates a `cbom.json` file in [CycloneDX CBOM format](https://cyclo ``` The CBOM includes: + - **Algorithms**: Hash functions, ciphers, key exchange mechanisms with their parameters - **Keys and secrets**: Private keys, secret keys, and other cryptographic materials - **Evidence**: Source file locations where each asset was detected @@ -267,10 +271,10 @@ Run with `go run gen_package.go`, then delete the script. 2. **Check for dependencies**: Some packages depend on types from other packages. Common dependencies: -| Package | May require | -|---------|-------------| -| `crypto/hmac` | `hash` | -| `crypto/cipher` | `io` | +| Package | May require | +| ----------------- | ------------ | +| `crypto/hmac` | `hash` | +| `crypto/cipher` | `io` | | `crypto/*` (most) | `io`, `hash` | 3. **Add mapping entry** to `mapping_generated.go` in alphabetical order: @@ -283,17 +287,17 @@ Run with `go run gen_package.go`, then delete the script. ### File naming convention -| Package Path | Export Data File | -|--------------|------------------| -| `crypto/hmac` | `crypto_hmac.o` | -| `crypto/elliptic` | `crypto_elliptic.o` | +| Package Path | Export Data File | +| ---------------------------- | ------------------- | +| `crypto/hmac` | `crypto_hmac.o` | +| `crypto/elliptic` | `crypto_elliptic.o` | | `golang.org/x/crypto/bcrypt` | `x_crypto_bcrypt.o` | ## Help and troubleshooting -If you encounter difficulties or unexpected results while installing the plugin with SonarQube, or when trying to scan a repository, please check out our guide [*Testing your configuration and troubleshooting*](docs/TROUBLESHOOTING.md) to run our plugin with step-by-step instructions. +If you encounter difficulties or unexpected results while installing the plugin with SonarQube, or when trying to scan a repository, please check out our guide [_Testing your configuration and troubleshooting_](docs/TROUBLESHOOTING.md) to run our plugin with step-by-step instructions. ## Contribution Guidelines @@ -305,4 +309,4 @@ start a discussion using [GitHub Discussions](https://github.com/cbomkit/sonar-c ## License -[Apache License 2.0](LICENSE.txt) \ No newline at end of file +[Apache License 2.0](LICENSE.txt) diff --git a/cpp/pom.xml b/cpp/pom.xml new file mode 100644 index 000000000..6b515b27d --- /dev/null +++ b/cpp/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + + com.ibm + sonar-cryptography + 2.0.0-SNAPSHOT + + + cpp + + + 17 + 17 + UTF-8 + + + + + com.ibm + engine + 2.0.0-SNAPSHOT + + + com.ibm + output + 2.0.0-SNAPSHOT + + + com.ibm + enricher + 2.0.0-SNAPSHOT + + + com.ibm + rules + 2.0.0-SNAPSHOT + compile + + + org.sonarsource.analyzer-commons + sonar-analyzer-test-commons + 2.18.0.3393 + test + + + diff --git a/cpp/src/main/java/com/ibm/plugin/CxxAggregator.java b/cpp/src/main/java/com/ibm/plugin/CxxAggregator.java new file mode 100644 index 000000000..eba143379 --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/CxxAggregator.java @@ -0,0 +1,68 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin; + +import com.ibm.engine.language.ILanguageSupport; +import com.ibm.engine.language.LanguageSupporter; +import com.ibm.mapper.model.INode; +import com.ibm.output.IAggregator; +import com.sonar.cxx.sslr.api.AstNode; +import com.sonar.cxx.sslr.api.Grammar; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nonnull; +import org.sonar.cxx.squidbridge.SquidAstVisitorContext; +import org.sonar.cxx.squidbridge.api.Symbol; +import org.sonar.cxx.squidbridge.checks.SquidCheck; + +public final class CxxAggregator implements IAggregator { + + private static ILanguageSupport< + SquidCheck, AstNode, Symbol, SquidAstVisitorContext> + cxxLanguageSupport = LanguageSupporter.cxxLanguageSupporter(); + private static List detectedNodes = new ArrayList<>(); + + private CxxAggregator() { + // nothing + } + + public static void addNodes(@Nonnull List newNodes) { + detectedNodes.addAll(newNodes); + IAggregator.log(newNodes); + } + + @Nonnull + public static List getDetectedNodes() { + return Collections.unmodifiableList(detectedNodes); + } + + @Nonnull + public static ILanguageSupport< + SquidCheck, AstNode, Symbol, SquidAstVisitorContext> + getLanguageSupport() { + return cxxLanguageSupport; + } + + public static void reset() { + cxxLanguageSupport = LanguageSupporter.cxxLanguageSupporter(); + detectedNodes = new ArrayList<>(); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/CxxCheckRegistrar.java b/cpp/src/main/java/com/ibm/plugin/CxxCheckRegistrar.java new file mode 100644 index 000000000..98877cfd1 --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/CxxCheckRegistrar.java @@ -0,0 +1,48 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin; + +import java.util.List; +import org.sonar.cxx.squidbridge.api.CxxCustomRuleRepository; +import org.sonarsource.api.sonarlint.SonarLintSide; + +/** + * Registers C++ cryptography detection rules with the sonar-cxx analysis framework. + * + *

This class implements the {@link CxxCustomRuleRepository} interface provided by sonar-cxx, + * which allows external plugins to register custom checks that will be executed during C++ code + * analysis. + * + *

The sonar-cxx plugin will discover this class via service loading and invoke the {@link + * #checkClasses()} method to obtain the list of check classes to instantiate and run. + */ +@SonarLintSide +public class CxxCheckRegistrar implements CxxCustomRuleRepository { + + @Override + public String repositoryKey() { + return CxxScannerRuleDefinition.REPOSITORY_KEY; + } + + @Override + public List> checkClasses() { + return CxxRuleList.getChecks(); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/CxxRuleList.java b/cpp/src/main/java/com/ibm/plugin/CxxRuleList.java new file mode 100644 index 000000000..867164c28 --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/CxxRuleList.java @@ -0,0 +1,48 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin; + +import com.ibm.plugin.rules.CxxInventoryRule; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nonnull; + +public final class CxxRuleList { + + private CxxRuleList() {} + + public static @Nonnull List> getChecks() { + List> checks = new ArrayList<>(); + checks.addAll(getCxxChecks()); + checks.addAll(getCxxTestChecks()); + return Collections.unmodifiableList(checks); + } + + /** These rules are going to target MAIN code only */ + public static @Nonnull List> getCxxChecks() { + return List.of(CxxInventoryRule.class); + } + + /** These rules are going to target TEST code only */ + public static @Nonnull List> getCxxTestChecks() { + return List.of(); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/CxxScannerRuleDefinition.java b/cpp/src/main/java/com/ibm/plugin/CxxScannerRuleDefinition.java new file mode 100644 index 000000000..5fe5aa857 --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/CxxScannerRuleDefinition.java @@ -0,0 +1,61 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin; + +import java.util.Collections; +import java.util.Objects; +import java.util.Set; +import org.sonar.api.SonarRuntime; +import org.sonar.api.server.rule.RulesDefinition; +import org.sonarsource.analyzer.commons.RuleMetadataLoader; + +public class CxxScannerRuleDefinition implements RulesDefinition { + public static final String REPOSITORY_KEY = "sonar-cpp-crypto"; + public static final String REPOSITORY_NAME = "Sonar Cryptography"; + public static final String LANGUAGE_KEY = "cxx"; + + // Add the rule keys of the rules which need to be considered as template-rules + private static final Set RULE_TEMPLATES_KEY = Collections.emptySet(); + + private static final String RESOURCE_BASE_PATH = "/org/sonar/l10n/cpp/rules/cpp"; + + private final SonarRuntime sonarRuntime; + + public CxxScannerRuleDefinition(SonarRuntime sonarRuntime) { + this.sonarRuntime = sonarRuntime; + } + + @Override + public void define(Context context) { + NewRepository repository = + context.createRepository(REPOSITORY_KEY, LANGUAGE_KEY).setName(REPOSITORY_NAME); + + RuleMetadataLoader ruleMetadataLoader = + new RuleMetadataLoader(RESOURCE_BASE_PATH, this.sonarRuntime); + ruleMetadataLoader.addRulesByAnnotatedClass(repository, CxxRuleList.getChecks()); + + RULE_TEMPLATES_KEY.stream() + .map(repository::rule) + .filter(Objects::nonNull) + .forEach(rule -> rule.setTemplate(true)); + + repository.done(); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/rules/CxxInventoryRule.java b/cpp/src/main/java/com/ibm/plugin/rules/CxxInventoryRule.java new file mode 100644 index 000000000..367265768 --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/rules/CxxInventoryRule.java @@ -0,0 +1,58 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules; + +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.mapper.model.INode; +import com.ibm.plugin.rules.detection.CxxBaseDetectionRule; +import com.ibm.plugin.rules.detection.CxxDetectionRules; +import com.ibm.plugin.translation.reorganizer.CxxReorganizerRules; +import com.ibm.rules.InventoryRule; +import com.ibm.rules.issue.Issue; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.List; +import javax.annotation.Nonnull; +import org.sonar.check.Rule; + +/** + * C++ Inventory Rule for detecting cryptographic assets. + * + *

This rule scans C++ source files for cryptographic API usage and reports findings for + * inventory purposes. Detected assets are exported to the Cryptographic Bill of Materials (CBOM) + * output. + */ +@Rule(key = "Inventory") +public class CxxInventoryRule extends CxxBaseDetectionRule { + + public CxxInventoryRule() { + super(true, CxxDetectionRules.rules(), CxxReorganizerRules.rules()); + } + + protected CxxInventoryRule(@Nonnull List> detectionRules) { + super(true, detectionRules, CxxReorganizerRules.rules()); + } + + @Override + @Nonnull + public List> report( + @Nonnull AstNode markerTree, @Nonnull List translatedNodes) { + return new InventoryRule().report(markerTree, translatedNodes); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/rules/detection/CxxBaseDetectionRule.java b/cpp/src/main/java/com/ibm/plugin/rules/detection/CxxBaseDetectionRule.java new file mode 100644 index 000000000..c1e4fee9a --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/rules/detection/CxxBaseDetectionRule.java @@ -0,0 +1,173 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection; + +import com.ibm.common.IObserver; +import com.ibm.engine.detection.Finding; +import com.ibm.engine.executive.DetectionExecutive; +import com.ibm.engine.language.cxx.CxxScanContext; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.reorganizer.IReorganizerRule; +import com.ibm.plugin.CxxAggregator; +import com.ibm.plugin.translation.CxxTranslationProcess; +import com.ibm.plugin.translation.reorganizer.CxxReorganizerRules; +import com.ibm.rules.IReportableDetectionRule; +import com.ibm.rules.issue.Issue; +import com.sonar.cxx.sslr.api.AstNode; +import com.sonar.cxx.sslr.api.AstNodeType; +import com.sonar.cxx.sslr.api.Grammar; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nonnull; +import org.sonar.cxx.parser.CxxGrammarImpl; +import org.sonar.cxx.squidbridge.SquidAstVisitorContext; +import org.sonar.cxx.squidbridge.api.AstNodeTraversal; +import org.sonar.cxx.squidbridge.api.Symbol; +import org.sonar.cxx.squidbridge.checks.SquidCheck; +import org.sonar.cxx.utils.CxxAstNodeHelper; + +/** + * Base class for C++ cryptography detection rules. + * + *

This class extends {@link SquidCheck} to integrate with the sonar-cxx analysis framework and + * implements the observer pattern to receive detection findings from the engine. + * + *

The detection flow works as follows: + * + *

    + *
  1. sonar-cxx calls {@link #visitFile(AstNode)} for each C++ file + *
  2. We traverse the AST looking for function calls and constructor invocations + *
  3. For each relevant node, we create a {@link DetectionExecutive} and start detection + *
  4. When a finding is detected, {@link #update(Finding)} is called + *
  5. The finding is translated, reorganized, enriched, and optionally reported + *
+ */ +public abstract class CxxBaseDetectionRule extends SquidCheck + implements IObserver< + Finding< + SquidCheck, + AstNode, + Symbol, + SquidAstVisitorContext>>, + IReportableDetectionRule { + + /** Node types to detect: function calls, new expressions, and enum specifiers. */ + private static final AstNodeType[] DETECTION_NODE_TYPES = { + CxxGrammarImpl.postfixExpression, CxxGrammarImpl.newExpression, CxxGrammarImpl.enumSpecifier + }; + + private final boolean isInventory; + @Nonnull protected final CxxTranslationProcess cxxTranslationProcess; + @Nonnull protected final List> detectionRules; + + protected CxxBaseDetectionRule() { + this.isInventory = false; + this.detectionRules = CxxDetectionRules.rules(); + this.cxxTranslationProcess = new CxxTranslationProcess(CxxReorganizerRules.rules()); + } + + protected CxxBaseDetectionRule( + final boolean isInventory, + @Nonnull List> detectionRules, + @Nonnull List reorganizerRules) { + this.isInventory = isInventory; + this.detectionRules = detectionRules; + this.cxxTranslationProcess = new CxxTranslationProcess(reorganizerRules); + } + + /** + * Called when visiting a file. Traverses the AST to find detection targets. + * + * @param astNode The root AST node of the file + */ + @Override + public void visitFile(@Nonnull AstNode astNode) { + // Traverse the entire AST looking for function calls, new expressions, and enums + AstNodeTraversal.traverse(astNode, DETECTION_NODE_TYPES, this::processNode); + } + + /** + * Processes a single AST node for potential cryptographic detection. + * + * @param node The AST node to process + */ + private void processNode(@Nonnull AstNode node) { + // Only process actual function calls and constructor calls, not all postfix expressions + if (node.is(CxxGrammarImpl.postfixExpression)) { + if (!CxxAstNodeHelper.isFunctionCall(node) + && !CxxAstNodeHelper.isConstructorCall(node)) { + return; + } + } + + detectionRules.forEach( + rule -> { + DetectionExecutive< + SquidCheck, + AstNode, + Symbol, + SquidAstVisitorContext> + detectionExecutive = + CxxAggregator.getLanguageSupport() + .createDetectionExecutive( + node, + rule, + new CxxScanContext(this.getContext())); + detectionExecutive.subscribe(this); + detectionExecutive.start(); + }); + } + + /** + * Called when a finding is detected by the engine. + * + * @param finding A finding containing detection store information. + */ + @Override + public void update( + @Nonnull + Finding< + SquidCheck, + AstNode, + Symbol, + SquidAstVisitorContext> + finding) { + final List nodes = cxxTranslationProcess.initiate(finding.detectionStore()); + if (isInventory) { + CxxAggregator.addNodes(nodes); + } + // report + this.report(finding.getMarkerTree(), nodes) + .forEach( + issue -> + finding.detectionStore() + .getScanContext() + .reportIssue(this, issue.tree(), issue.message())); + } + + @Override + @Nonnull + public List> report( + @Nonnull AstNode markerTree, @Nonnull List translatedNodes) { + // override by higher level rule, to report an issue + return Collections.emptyList(); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/rules/detection/CxxDetectionRules.java b/cpp/src/main/java/com/ibm/plugin/rules/detection/CxxDetectionRules.java new file mode 100644 index 000000000..fe40c21cf --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/rules/detection/CxxDetectionRules.java @@ -0,0 +1,58 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection; + +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.plugin.rules.detection.openssl.OpenSSLDetectionRules; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.List; +import java.util.stream.Stream; +import javax.annotation.Nonnull; + +/** + * Registry of C++ cryptography detection rules. + * + *

This class aggregates all detection rules for C++ cryptographic libraries. Detection rules are + * organized by library (e.g., OpenSSL, BoringSSL, libsodium). + * + *

To add new detection rules: + * + *

    + *
  1. Create a new package under {@code rules.detection} for the library + *
  2. Create detection rule classes following the pattern in Java module + *
  3. Create a {@code *DetectionRules} class that returns all rules for the library + *
  4. Add the rules to the stream in {@link #rules()} + *
+ */ +public final class CxxDetectionRules { + private CxxDetectionRules() { + // private + } + + /** + * Returns all C++ cryptography detection rules. + * + * @return List of all detection rules + */ + @Nonnull + public static List> rules() { + return Stream.of(OpenSSLDetectionRules.rules().stream()).flatMap(i -> i).toList(); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/OpenSSLDetectionRules.java b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/OpenSSLDetectionRules.java new file mode 100644 index 000000000..59c7e76da --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/OpenSSLDetectionRules.java @@ -0,0 +1,89 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.openssl; + +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.plugin.rules.detection.openssl.cipher.OpenSSLEvpCipher; +import com.ibm.plugin.rules.detection.openssl.cipher.OpenSSLEvpCipherFetch; +import com.ibm.plugin.rules.detection.openssl.digest.OpenSSLEvpMessageDigest; +import com.ibm.plugin.rules.detection.openssl.kdf.OpenSSLEvpKdf; +import com.ibm.plugin.rules.detection.openssl.keyagreement.OpenSSLEvpKeyAgreement; +import com.ibm.plugin.rules.detection.openssl.keygen.OpenSSLEvpKeyGen; +import com.ibm.plugin.rules.detection.openssl.legacy.OpenSSLLegacyCipher; +import com.ibm.plugin.rules.detection.openssl.legacy.OpenSSLLegacyDh; +import com.ibm.plugin.rules.detection.openssl.legacy.OpenSSLLegacyDigest; +import com.ibm.plugin.rules.detection.openssl.legacy.OpenSSLLegacyDsa; +import com.ibm.plugin.rules.detection.openssl.legacy.OpenSSLLegacyEc; +import com.ibm.plugin.rules.detection.openssl.legacy.OpenSSLLegacyMac; +import com.ibm.plugin.rules.detection.openssl.legacy.OpenSSLLegacyRsa; +import com.ibm.plugin.rules.detection.openssl.mac.OpenSSLEvpMac; +import com.ibm.plugin.rules.detection.openssl.rand.OpenSSLRand; +import com.ibm.plugin.rules.detection.openssl.signature.OpenSSLEvpSignature; +import com.ibm.plugin.rules.detection.openssl.ssl.OpenSSLLibssl; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.List; +import java.util.stream.Stream; +import javax.annotation.Nonnull; + +/** + * Aggregates all OpenSSL cryptography detection rules. + * + *

This class collects detection rules from all OpenSSL API categories: + * + *

    + *
  • EVP message digest functions ({@code EVP_sha256}, {@code EVP_md5}, etc.) + *
  • EVP cipher functions ({@code EVP_aes_256_gcm}, {@code EVP_chacha20_poly1305}, etc.) + *
  • EVP MAC functions ({@code EVP_MAC_fetch} with HMAC, CMAC, GMAC, etc.) + *
  • SSL/TLS protocol functions ({@code TLS_method}, {@code SSL_CTX_new}, etc.) + *
+ */ +public final class OpenSSLDetectionRules { + + private OpenSSLDetectionRules() { + // private + } + + @Nonnull + public static List> rules() { + return Stream.of( + // EVP API - Modern OpenSSL 3.x functions + OpenSSLEvpCipher.rules().stream(), + OpenSSLEvpCipherFetch.rules().stream(), + OpenSSLEvpMessageDigest.rules().stream(), + OpenSSLEvpMac.rules().stream(), + OpenSSLEvpSignature.rules().stream(), + OpenSSLEvpKeyGen.rules().stream(), + OpenSSLEvpKdf.rules().stream(), + OpenSSLEvpKeyAgreement.rules().stream(), + OpenSSLRand.rules().stream(), + // Legacy API - Deprecated but widely used + OpenSSLLegacyCipher.rules().stream(), + OpenSSLLegacyDigest.rules().stream(), + OpenSSLLegacyMac.rules().stream(), + OpenSSLLegacyRsa.rules().stream(), + OpenSSLLegacyDsa.rules().stream(), + OpenSSLLegacyEc.rules().stream(), + OpenSSLLegacyDh.rules().stream(), + // SSL/TLS Protocol API + OpenSSLLibssl.rules().stream()) + .flatMap(i -> i) + .toList(); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/cipher/OpenSSLEvpCipher.java b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/cipher/OpenSSLEvpCipher.java new file mode 100644 index 000000000..321fd9046 --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/cipher/OpenSSLEvpCipher.java @@ -0,0 +1,2170 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.openssl.cipher; + +import com.ibm.engine.model.context.CipherContext; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.List; +import javax.annotation.Nonnull; + +/** + * Detection rules for OpenSSL EVP cipher algorithm specifiers. + * + *

These rules detect calls to OpenSSL functions that return EVP_CIPHER pointers, identifying the + * specific cipher algorithm, key size, and mode of operation. Each function (e.g., {@code + * EVP_aes_256_gcm()}) maps to a known cipher specification. + * + *

Covers all OpenSSL symmetric ciphers including AES, Camellia, ARIA, SM4, DES, ChaCha20, + * Blowfish, CAST5, RC2/4/5, IDEA, and SEED. + */ +@SuppressWarnings("java:S1192") +public final class OpenSSLEvpCipher { + + private static final String BUNDLE = "OpenSSL"; + + // ==================================================================== + // AES (Advanced Encryption Standard) + // ==================================================================== + + // AES-128 + private static final IDetectionRule EVP_AES_128_CBC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_128_cbc") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-CBC")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_128_ECB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_128_ecb") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-ECB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_128_GCM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_128_gcm") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-GCM")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_128_CTR = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_128_ctr") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-CTR")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_128_CCM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_128_ccm") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-CCM")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_128_CFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_128_cfb") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-CFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_128_CFB1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_128_cfb1") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-CFB1")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_128_CFB8 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_128_cfb8") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-CFB8")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_128_CFB128 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_128_cfb128") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-CFB128")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_128_OFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_128_ofb") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-OFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_128_XTS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_128_xts") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-XTS")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_128_OCB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_128_ocb") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-OCB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_128_WRAP = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_128_wrap") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-WRAP")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_128_WRAP_PAD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_128_wrap_pad") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-WRAP-PAD")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // AES-192 + private static final IDetectionRule EVP_AES_192_CBC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_192_cbc") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-192-CBC")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_192_ECB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_192_ecb") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-192-ECB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_192_GCM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_192_gcm") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-192-GCM")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_192_CTR = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_192_ctr") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-192-CTR")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_192_CCM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_192_ccm") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-192-CCM")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_192_CFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_192_cfb") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-192-CFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_192_CFB1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_192_cfb1") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-192-CFB1")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_192_CFB8 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_192_cfb8") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-192-CFB8")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_192_CFB128 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_192_cfb128") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-192-CFB128")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_192_OFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_192_ofb") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-192-OFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_192_OCB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_192_ocb") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-192-OCB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_192_WRAP = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_192_wrap") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-192-WRAP")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_192_WRAP_PAD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_192_wrap_pad") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-192-WRAP-PAD")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // AES-256 + private static final IDetectionRule EVP_AES_256_CBC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_256_cbc") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-CBC")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_256_ECB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_256_ecb") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-ECB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_256_GCM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_256_gcm") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-GCM")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_256_CTR = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_256_ctr") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-CTR")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_256_CCM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_256_ccm") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-CCM")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_256_CFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_256_cfb") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-CFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_256_CFB1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_256_cfb1") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-CFB1")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_256_CFB8 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_256_cfb8") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-CFB8")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_256_CFB128 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_256_cfb128") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-CFB128")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_256_OFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_256_ofb") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-OFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_256_XTS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_256_xts") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-XTS")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_256_OCB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_256_ocb") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-OCB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_256_WRAP = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_256_wrap") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-WRAP")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_256_WRAP_PAD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_256_wrap_pad") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-WRAP-PAD")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Camellia + // ==================================================================== + + // Camellia-128 + private static final IDetectionRule EVP_CAMELLIA_128_ECB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_camellia_128_ecb") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-128-ECB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAMELLIA_128_CBC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_camellia_128_cbc") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-128-CBC")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAMELLIA_128_CFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_camellia_128_cfb") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-128-CFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAMELLIA_128_CFB1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_camellia_128_cfb1") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-128-CFB1")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAMELLIA_128_CFB8 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_camellia_128_cfb8") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-128-CFB8")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAMELLIA_128_CFB128 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_camellia_128_cfb128") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-128-CFB128")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAMELLIA_128_OFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_camellia_128_ofb") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-128-OFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAMELLIA_128_CTR = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_camellia_128_ctr") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-128-CTR")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // Camellia-192 + private static final IDetectionRule EVP_CAMELLIA_192_ECB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_camellia_192_ecb") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-192-ECB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAMELLIA_192_CBC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_camellia_192_cbc") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-192-CBC")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAMELLIA_192_CFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_camellia_192_cfb") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-192-CFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAMELLIA_192_CFB1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_camellia_192_cfb1") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-192-CFB1")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAMELLIA_192_CFB8 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_camellia_192_cfb8") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-192-CFB8")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAMELLIA_192_CFB128 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_camellia_192_cfb128") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-192-CFB128")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAMELLIA_192_OFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_camellia_192_ofb") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-192-OFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAMELLIA_192_CTR = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_camellia_192_ctr") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-192-CTR")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // Camellia-256 + private static final IDetectionRule EVP_CAMELLIA_256_ECB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_camellia_256_ecb") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-256-ECB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAMELLIA_256_CBC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_camellia_256_cbc") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-256-CBC")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAMELLIA_256_CFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_camellia_256_cfb") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-256-CFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAMELLIA_256_CFB1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_camellia_256_cfb1") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-256-CFB1")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAMELLIA_256_CFB8 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_camellia_256_cfb8") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-256-CFB8")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAMELLIA_256_CFB128 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_camellia_256_cfb128") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-256-CFB128")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAMELLIA_256_OFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_camellia_256_ofb") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-256-OFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAMELLIA_256_CTR = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_camellia_256_ctr") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-256-CTR")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // ARIA + // ==================================================================== + + // ARIA-128 + private static final IDetectionRule EVP_ARIA_128_ECB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_128_ecb") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-128-ECB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_128_CBC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_128_cbc") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-128-CBC")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_128_CFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_128_cfb") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-128-CFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_128_CFB1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_128_cfb1") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-128-CFB1")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_128_CFB8 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_128_cfb8") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-128-CFB8")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_128_CFB128 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_128_cfb128") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-128-CFB128")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_128_OFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_128_ofb") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-128-OFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_128_CTR = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_128_ctr") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-128-CTR")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_128_GCM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_128_gcm") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-128-GCM")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_128_CCM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_128_ccm") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-128-CCM")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ARIA-192 + private static final IDetectionRule EVP_ARIA_192_ECB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_192_ecb") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-192-ECB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_192_CBC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_192_cbc") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-192-CBC")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_192_CFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_192_cfb") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-192-CFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_192_CFB1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_192_cfb1") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-192-CFB1")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_192_CFB8 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_192_cfb8") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-192-CFB8")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_192_CFB128 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_192_cfb128") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-192-CFB128")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_192_OFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_192_ofb") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-192-OFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_192_CTR = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_192_ctr") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-192-CTR")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_192_GCM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_192_gcm") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-192-GCM")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_192_CCM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_192_ccm") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-192-CCM")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ARIA-256 + private static final IDetectionRule EVP_ARIA_256_ECB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_256_ecb") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-256-ECB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_256_CBC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_256_cbc") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-256-CBC")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_256_CFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_256_cfb") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-256-CFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_256_CFB1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_256_cfb1") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-256-CFB1")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_256_CFB8 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_256_cfb8") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-256-CFB8")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_256_CFB128 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_256_cfb128") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-256-CFB128")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_256_OFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_256_ofb") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-256-OFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_256_CTR = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_256_ctr") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-256-CTR")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_256_GCM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_256_gcm") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-256-GCM")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_ARIA_256_CCM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aria_256_ccm") + .shouldBeDetectedAs(new ValueActionFactory<>("ARIA-256-CCM")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // SM4 (Chinese National Standard) + // ==================================================================== + + private static final IDetectionRule EVP_SM4_ECB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_sm4_ecb") + .shouldBeDetectedAs(new ValueActionFactory<>("SM4-ECB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_SM4_CBC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_sm4_cbc") + .shouldBeDetectedAs(new ValueActionFactory<>("SM4-CBC")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_SM4_CFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_sm4_cfb") + .shouldBeDetectedAs(new ValueActionFactory<>("SM4-CFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_SM4_CFB128 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_sm4_cfb128") + .shouldBeDetectedAs(new ValueActionFactory<>("SM4-CFB128")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_SM4_OFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_sm4_ofb") + .shouldBeDetectedAs(new ValueActionFactory<>("SM4-OFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_SM4_CTR = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_sm4_ctr") + .shouldBeDetectedAs(new ValueActionFactory<>("SM4-CTR")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_SM4_GCM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_sm4_gcm") + .shouldBeDetectedAs(new ValueActionFactory<>("SM4-GCM")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_SM4_CCM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_sm4_ccm") + .shouldBeDetectedAs(new ValueActionFactory<>("SM4-CCM")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_SM4_XTS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_sm4_xts") + .shouldBeDetectedAs(new ValueActionFactory<>("SM4-XTS")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // DES / 3DES + // ==================================================================== + + private static final IDetectionRule EVP_DES_CBC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_des_cbc") + .shouldBeDetectedAs(new ValueActionFactory<>("DES-CBC")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_DES_ECB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_des_ecb") + .shouldBeDetectedAs(new ValueActionFactory<>("DES-ECB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_DES_EDE3_CBC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_des_ede3_cbc") + .shouldBeDetectedAs(new ValueActionFactory<>("DESede3-CBC")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // Single DES additional modes + private static final IDetectionRule EVP_DES_CFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_des_cfb") + .shouldBeDetectedAs(new ValueActionFactory<>("DES-CFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_DES_CFB1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_des_cfb1") + .shouldBeDetectedAs(new ValueActionFactory<>("DES-CFB1")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_DES_CFB8 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_des_cfb8") + .shouldBeDetectedAs(new ValueActionFactory<>("DES-CFB8")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_DES_CFB64 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_des_cfb64") + .shouldBeDetectedAs(new ValueActionFactory<>("DES-CFB64")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_DES_OFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_des_ofb") + .shouldBeDetectedAs(new ValueActionFactory<>("DES-OFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // 3DES EDE (2-key) + private static final IDetectionRule EVP_DES_EDE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_des_ede") + .shouldBeDetectedAs(new ValueActionFactory<>("DESede")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_DES_EDE_ECB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_des_ede_ecb") + .shouldBeDetectedAs(new ValueActionFactory<>("DESede-ECB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_DES_EDE_CBC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_des_ede_cbc") + .shouldBeDetectedAs(new ValueActionFactory<>("DESede-CBC")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_DES_EDE_CFB64 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_des_ede_cfb64") + .shouldBeDetectedAs(new ValueActionFactory<>("DESede-CFB64")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_DES_EDE_OFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_des_ede_ofb") + .shouldBeDetectedAs(new ValueActionFactory<>("DESede-OFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // 3DES EDE3 (3-key) additional modes + private static final IDetectionRule EVP_DES_EDE3 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_des_ede3") + .shouldBeDetectedAs(new ValueActionFactory<>("DESede3")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_DES_EDE3_ECB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_des_ede3_ecb") + .shouldBeDetectedAs(new ValueActionFactory<>("DESede3-ECB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_DES_EDE3_CFB1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_des_ede3_cfb1") + .shouldBeDetectedAs(new ValueActionFactory<>("DESede3-CFB1")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_DES_EDE3_CFB8 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_des_ede3_cfb8") + .shouldBeDetectedAs(new ValueActionFactory<>("DESede3-CFB8")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_DES_EDE3_CFB64 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_des_ede3_cfb64") + .shouldBeDetectedAs(new ValueActionFactory<>("DESede3-CFB64")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_DES_EDE3_OFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_des_ede3_ofb") + .shouldBeDetectedAs(new ValueActionFactory<>("DESede3-OFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // DESX + private static final IDetectionRule EVP_DESX_CBC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_desx_cbc") + .shouldBeDetectedAs(new ValueActionFactory<>("DESX-CBC")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Blowfish + // ==================================================================== + + private static final IDetectionRule EVP_BF_ECB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_bf_ecb") + .shouldBeDetectedAs(new ValueActionFactory<>("BLOWFISH-ECB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_BF_CBC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_bf_cbc") + .shouldBeDetectedAs(new ValueActionFactory<>("BLOWFISH-CBC")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_BF_CFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_bf_cfb") + .shouldBeDetectedAs(new ValueActionFactory<>("BLOWFISH-CFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_BF_CFB64 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_bf_cfb64") + .shouldBeDetectedAs(new ValueActionFactory<>("BLOWFISH-CFB64")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_BF_OFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_bf_ofb") + .shouldBeDetectedAs(new ValueActionFactory<>("BLOWFISH-OFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // CAST5 + // ==================================================================== + + private static final IDetectionRule EVP_CAST5_ECB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_cast5_ecb") + .shouldBeDetectedAs(new ValueActionFactory<>("CAST5-ECB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAST5_CBC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_cast5_cbc") + .shouldBeDetectedAs(new ValueActionFactory<>("CAST5-CBC")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAST5_CFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_cast5_cfb") + .shouldBeDetectedAs(new ValueActionFactory<>("CAST5-CFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAST5_CFB64 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_cast5_cfb64") + .shouldBeDetectedAs(new ValueActionFactory<>("CAST5-CFB64")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CAST5_OFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_cast5_ofb") + .shouldBeDetectedAs(new ValueActionFactory<>("CAST5-OFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // RC2 + // ==================================================================== + + private static final IDetectionRule EVP_RC2_ECB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_rc2_ecb") + .shouldBeDetectedAs(new ValueActionFactory<>("RC2-ECB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_RC2_CBC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_rc2_cbc") + .shouldBeDetectedAs(new ValueActionFactory<>("RC2-CBC")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_RC2_CFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_rc2_cfb") + .shouldBeDetectedAs(new ValueActionFactory<>("RC2-CFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_RC2_CFB64 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_rc2_cfb64") + .shouldBeDetectedAs(new ValueActionFactory<>("RC2-CFB64")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_RC2_OFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_rc2_ofb") + .shouldBeDetectedAs(new ValueActionFactory<>("RC2-OFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_RC2_40_CBC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_rc2_40_cbc") + .shouldBeDetectedAs(new ValueActionFactory<>("RC2-40-CBC")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_RC2_64_CBC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_rc2_64_cbc") + .shouldBeDetectedAs(new ValueActionFactory<>("RC2-64-CBC")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // RC4 (Stream Cipher) + // ==================================================================== + + private static final IDetectionRule EVP_RC4 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_rc4") + .shouldBeDetectedAs(new ValueActionFactory<>("RC4")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_RC4_40 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_rc4_40") + .shouldBeDetectedAs(new ValueActionFactory<>("RC4-40")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_RC4_HMAC_MD5 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_rc4_hmac_md5") + .shouldBeDetectedAs(new ValueActionFactory<>("RC4-HMAC-MD5")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // RC5 + // ==================================================================== + + private static final IDetectionRule EVP_RC5_32_12_16_ECB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_rc5_32_12_16_ecb") + .shouldBeDetectedAs(new ValueActionFactory<>("RC5-ECB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_RC5_32_12_16_CBC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_rc5_32_12_16_cbc") + .shouldBeDetectedAs(new ValueActionFactory<>("RC5-CBC")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_RC5_32_12_16_CFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_rc5_32_12_16_cfb") + .shouldBeDetectedAs(new ValueActionFactory<>("RC5-CFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_RC5_32_12_16_CFB64 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_rc5_32_12_16_cfb64") + .shouldBeDetectedAs(new ValueActionFactory<>("RC5-CFB64")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_RC5_32_12_16_OFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_rc5_32_12_16_ofb") + .shouldBeDetectedAs(new ValueActionFactory<>("RC5-OFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // IDEA + // ==================================================================== + + private static final IDetectionRule EVP_IDEA_ECB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_idea_ecb") + .shouldBeDetectedAs(new ValueActionFactory<>("IDEA-ECB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_IDEA_CBC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_idea_cbc") + .shouldBeDetectedAs(new ValueActionFactory<>("IDEA-CBC")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_IDEA_CFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_idea_cfb") + .shouldBeDetectedAs(new ValueActionFactory<>("IDEA-CFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_IDEA_CFB64 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_idea_cfb64") + .shouldBeDetectedAs(new ValueActionFactory<>("IDEA-CFB64")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_IDEA_OFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_idea_ofb") + .shouldBeDetectedAs(new ValueActionFactory<>("IDEA-OFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // SEED (Korean National Standard) + // ==================================================================== + + private static final IDetectionRule EVP_SEED_ECB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_seed_ecb") + .shouldBeDetectedAs(new ValueActionFactory<>("SEED-ECB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_SEED_CBC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_seed_cbc") + .shouldBeDetectedAs(new ValueActionFactory<>("SEED-CBC")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_SEED_CFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_seed_cfb") + .shouldBeDetectedAs(new ValueActionFactory<>("SEED-CFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_SEED_CFB128 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_seed_cfb128") + .shouldBeDetectedAs(new ValueActionFactory<>("SEED-CFB128")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_SEED_OFB = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_seed_ofb") + .shouldBeDetectedAs(new ValueActionFactory<>("SEED-OFB")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // ChaCha20 + // ==================================================================== + + private static final IDetectionRule EVP_CHACHA20 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_chacha20") + .shouldBeDetectedAs(new ValueActionFactory<>("ChaCha20")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_CHACHA20_POLY1305 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_chacha20_poly1305") + .shouldBeDetectedAs(new ValueActionFactory<>("ChaCha20-Poly1305")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // AES CBC-HMAC Combined Mode - TLS Encrypt-then-MAC + // ==================================================================== + + private static final IDetectionRule EVP_AES_128_CBC_HMAC_SHA1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_128_cbc_hmac_sha1") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-CBC-HMAC-SHA1")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_256_CBC_HMAC_SHA1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_256_cbc_hmac_sha1") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-CBC-HMAC-SHA1")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_128_CBC_HMAC_SHA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_128_cbc_hmac_sha256") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-CBC-HMAC-SHA256")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_AES_256_CBC_HMAC_SHA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_aes_256_cbc_hmac_sha256") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-CBC-HMAC-SHA256")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // SM2 Asymmetric Encryption (via EVP_PKEY API) + // Note: Unlike other rules in this file, SM2 uses EVP_PKEY_encrypt/decrypt + // rather than EVP_CIPHER API, as it's an asymmetric operation + // ==================================================================== + + private static final IDetectionRule SM2_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("SM2-PKE")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SM2_DECRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_decrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("SM2-PKE")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // NULL Cipher + // ==================================================================== + + private static final IDetectionRule EVP_ENC_NULL = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_enc_null") + .shouldBeDetectedAs(new ValueActionFactory<>("NULL")) + .withoutParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private OpenSSLEvpCipher() { + // nothing + } + + @Nonnull + public static List> rules() { + return List.of( + // AES-128 + EVP_AES_128_CBC, + EVP_AES_128_ECB, + EVP_AES_128_GCM, + EVP_AES_128_CTR, + EVP_AES_128_CCM, + EVP_AES_128_CFB, + EVP_AES_128_CFB1, + EVP_AES_128_CFB8, + EVP_AES_128_CFB128, + EVP_AES_128_OFB, + EVP_AES_128_XTS, + EVP_AES_128_OCB, + EVP_AES_128_WRAP, + EVP_AES_128_WRAP_PAD, + // AES-192 + EVP_AES_192_CBC, + EVP_AES_192_ECB, + EVP_AES_192_GCM, + EVP_AES_192_CTR, + EVP_AES_192_CCM, + EVP_AES_192_CFB, + EVP_AES_192_CFB1, + EVP_AES_192_CFB8, + EVP_AES_192_CFB128, + EVP_AES_192_OFB, + EVP_AES_192_OCB, + EVP_AES_192_WRAP, + EVP_AES_192_WRAP_PAD, + // AES-256 + EVP_AES_256_CBC, + EVP_AES_256_ECB, + EVP_AES_256_GCM, + EVP_AES_256_CTR, + EVP_AES_256_CCM, + EVP_AES_256_CFB, + EVP_AES_256_CFB1, + EVP_AES_256_CFB8, + EVP_AES_256_CFB128, + EVP_AES_256_OFB, + EVP_AES_256_XTS, + EVP_AES_256_OCB, + EVP_AES_256_WRAP, + EVP_AES_256_WRAP_PAD, + // Camellia-128 + EVP_CAMELLIA_128_ECB, + EVP_CAMELLIA_128_CBC, + EVP_CAMELLIA_128_CFB, + EVP_CAMELLIA_128_CFB1, + EVP_CAMELLIA_128_CFB8, + EVP_CAMELLIA_128_CFB128, + EVP_CAMELLIA_128_OFB, + EVP_CAMELLIA_128_CTR, + // Camellia-192 + EVP_CAMELLIA_192_ECB, + EVP_CAMELLIA_192_CBC, + EVP_CAMELLIA_192_CFB, + EVP_CAMELLIA_192_CFB1, + EVP_CAMELLIA_192_CFB8, + EVP_CAMELLIA_192_CFB128, + EVP_CAMELLIA_192_OFB, + EVP_CAMELLIA_192_CTR, + // Camellia-256 + EVP_CAMELLIA_256_ECB, + EVP_CAMELLIA_256_CBC, + EVP_CAMELLIA_256_CFB, + EVP_CAMELLIA_256_CFB1, + EVP_CAMELLIA_256_CFB8, + EVP_CAMELLIA_256_CFB128, + EVP_CAMELLIA_256_OFB, + EVP_CAMELLIA_256_CTR, + // ARIA-128 + EVP_ARIA_128_ECB, + EVP_ARIA_128_CBC, + EVP_ARIA_128_CFB, + EVP_ARIA_128_CFB1, + EVP_ARIA_128_CFB8, + EVP_ARIA_128_CFB128, + EVP_ARIA_128_OFB, + EVP_ARIA_128_CTR, + EVP_ARIA_128_GCM, + EVP_ARIA_128_CCM, + // ARIA-192 + EVP_ARIA_192_ECB, + EVP_ARIA_192_CBC, + EVP_ARIA_192_CFB, + EVP_ARIA_192_CFB1, + EVP_ARIA_192_CFB8, + EVP_ARIA_192_CFB128, + EVP_ARIA_192_OFB, + EVP_ARIA_192_CTR, + EVP_ARIA_192_GCM, + EVP_ARIA_192_CCM, + // ARIA-256 + EVP_ARIA_256_ECB, + EVP_ARIA_256_CBC, + EVP_ARIA_256_CFB, + EVP_ARIA_256_CFB1, + EVP_ARIA_256_CFB8, + EVP_ARIA_256_CFB128, + EVP_ARIA_256_OFB, + EVP_ARIA_256_CTR, + EVP_ARIA_256_GCM, + EVP_ARIA_256_CCM, + // SM4 + EVP_SM4_ECB, + EVP_SM4_CBC, + EVP_SM4_CFB, + EVP_SM4_CFB128, + EVP_SM4_OFB, + EVP_SM4_CTR, + EVP_SM4_GCM, + EVP_SM4_CCM, + EVP_SM4_XTS, + // DES/3DES + EVP_DES_CBC, + EVP_DES_ECB, + EVP_DES_CFB, + EVP_DES_CFB1, + EVP_DES_CFB8, + EVP_DES_CFB64, + EVP_DES_OFB, + EVP_DES_EDE, + EVP_DES_EDE_ECB, + EVP_DES_EDE_CBC, + EVP_DES_EDE_CFB64, + EVP_DES_EDE_OFB, + EVP_DES_EDE3, + EVP_DES_EDE3_ECB, + EVP_DES_EDE3_CBC, + EVP_DES_EDE3_CFB1, + EVP_DES_EDE3_CFB8, + EVP_DES_EDE3_CFB64, + EVP_DES_EDE3_OFB, + EVP_DESX_CBC, + // Blowfish + EVP_BF_ECB, + EVP_BF_CBC, + EVP_BF_CFB, + EVP_BF_CFB64, + EVP_BF_OFB, + // CAST5 + EVP_CAST5_ECB, + EVP_CAST5_CBC, + EVP_CAST5_CFB, + EVP_CAST5_CFB64, + EVP_CAST5_OFB, + // RC2 + EVP_RC2_ECB, + EVP_RC2_CBC, + EVP_RC2_CFB, + EVP_RC2_CFB64, + EVP_RC2_OFB, + EVP_RC2_40_CBC, + EVP_RC2_64_CBC, + // RC4 + EVP_RC4, + EVP_RC4_40, + EVP_RC4_HMAC_MD5, + // RC5 + EVP_RC5_32_12_16_ECB, + EVP_RC5_32_12_16_CBC, + EVP_RC5_32_12_16_CFB, + EVP_RC5_32_12_16_CFB64, + EVP_RC5_32_12_16_OFB, + // IDEA + EVP_IDEA_ECB, + EVP_IDEA_CBC, + EVP_IDEA_CFB, + EVP_IDEA_CFB64, + EVP_IDEA_OFB, + // SEED + EVP_SEED_ECB, + EVP_SEED_CBC, + EVP_SEED_CFB, + EVP_SEED_CFB128, + EVP_SEED_OFB, + // ChaCha20 + EVP_CHACHA20, + EVP_CHACHA20_POLY1305, + // AES CBC-HMAC + EVP_AES_128_CBC_HMAC_SHA1, + EVP_AES_256_CBC_HMAC_SHA1, + EVP_AES_128_CBC_HMAC_SHA256, + EVP_AES_256_CBC_HMAC_SHA256, + // SM2 Asymmetric Encryption + SM2_ENCRYPT, + SM2_DECRYPT, + // NULL Cipher + EVP_ENC_NULL); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/cipher/OpenSSLEvpCipherFetch.java b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/cipher/OpenSSLEvpCipherFetch.java new file mode 100644 index 000000000..99fdffad6 --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/cipher/OpenSSLEvpCipherFetch.java @@ -0,0 +1,519 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.openssl.cipher; + +import com.ibm.engine.model.context.CipherContext; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.List; +import javax.annotation.Nonnull; + +/** + * Detection rules for OpenSSL provider-only cipher modes accessible via EVP_CIPHER_fetch. + * + *

These cipher modes don't have convenience EVP_* functions and must be accessed through the + * provider API using string identifiers. Covers modern AEAD modes (AES-SIV, AES-GCM-SIV), key + * wrapping variants, and encrypt-then-MAC constructions. + */ +@SuppressWarnings("java:S1192") +public final class OpenSSLEvpCipherFetch { + + private static final String BUNDLE = "OpenSSL"; + + // ==================================================================== + // AES-SIV - Synthetic IV Mode (RFC 5297) + // ==================================================================== + + private static final IDetectionRule AES_128_SIV = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-SIV")) + .withMethodParameter("*") + .withMethodParameter("\"AES-128-SIV\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_192_SIV = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-192-SIV")) + .withMethodParameter("*") + .withMethodParameter("\"AES-192-SIV\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_256_SIV = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-SIV")) + .withMethodParameter("*") + .withMethodParameter("\"AES-256-SIV\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // AES-GCM-SIV - Nonce-Misuse Resistant AEAD (RFC 8452) + // ==================================================================== + + private static final IDetectionRule AES_128_GCM_SIV = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-GCM-SIV")) + .withMethodParameter("*") + .withMethodParameter("\"AES-128-GCM-SIV\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_192_GCM_SIV = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-192-GCM-SIV")) + .withMethodParameter("*") + .withMethodParameter("\"AES-192-GCM-SIV\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_256_GCM_SIV = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-GCM-SIV")) + .withMethodParameter("*") + .withMethodParameter("\"AES-256-GCM-SIV\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // AES CBC-CTS - Ciphertext Stealing Mode + // ==================================================================== + + private static final IDetectionRule AES_128_CBC_CTS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-CBC-CTS")) + .withMethodParameter("*") + .withMethodParameter("\"AES-128-CBC-CTS\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_192_CBC_CTS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-192-CBC-CTS")) + .withMethodParameter("*") + .withMethodParameter("\"AES-192-CBC-CTS\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_256_CBC_CTS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-CBC-CTS")) + .withMethodParameter("*") + .withMethodParameter("\"AES-256-CBC-CTS\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // AES WRAP-INV - Inverted Key Wrap (RFC 3394) + // ==================================================================== + + private static final IDetectionRule AES_128_WRAP_INV = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-WRAP-INV")) + .withMethodParameter("*") + .withMethodParameter("\"AES-128-WRAP-INV\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_192_WRAP_INV = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-192-WRAP-INV")) + .withMethodParameter("*") + .withMethodParameter("\"AES-192-WRAP-INV\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_256_WRAP_INV = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-WRAP-INV")) + .withMethodParameter("*") + .withMethodParameter("\"AES-256-WRAP-INV\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // AES WRAP-PAD-INV - Inverted Padded Key Wrap (RFC 5649) + // ==================================================================== + + private static final IDetectionRule AES_128_WRAP_PAD_INV = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-WRAP-PAD-INV")) + .withMethodParameter("*") + .withMethodParameter("\"AES-128-WRAP-PAD-INV\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_192_WRAP_PAD_INV = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-192-WRAP-PAD-INV")) + .withMethodParameter("*") + .withMethodParameter("\"AES-192-WRAP-PAD-INV\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_256_WRAP_PAD_INV = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-WRAP-PAD-INV")) + .withMethodParameter("*") + .withMethodParameter("\"AES-256-WRAP-PAD-INV\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // AES ETM - Encrypt-Then-MAC Variants (3 key sizes × 3 hash variants) + // ==================================================================== + + private static final IDetectionRule AES_128_CBC_HMAC_SHA1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-CBC-HMAC-SHA1")) + .withMethodParameter("*") + .withMethodParameter("\"AES-128-CBC-HMAC-SHA1\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_128_CBC_HMAC_SHA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-CBC-HMAC-SHA256")) + .withMethodParameter("*") + .withMethodParameter("\"AES-128-CBC-HMAC-SHA256\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_192_CBC_HMAC_SHA1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-192-CBC-HMAC-SHA1")) + .withMethodParameter("*") + .withMethodParameter("\"AES-192-CBC-HMAC-SHA1\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_192_CBC_HMAC_SHA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-192-CBC-HMAC-SHA256")) + .withMethodParameter("*") + .withMethodParameter("\"AES-192-CBC-HMAC-SHA256\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_256_CBC_HMAC_SHA1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-CBC-HMAC-SHA1")) + .withMethodParameter("*") + .withMethodParameter("\"AES-256-CBC-HMAC-SHA1\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_256_CBC_HMAC_SHA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-CBC-HMAC-SHA256")) + .withMethodParameter("*") + .withMethodParameter("\"AES-256-CBC-HMAC-SHA256\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // AES ETM - Encrypt-then-MAC for TLS (RFC 7366) + // ==================================================================== + + private static final IDetectionRule AES_128_CBC_HMAC_SHA1_ETM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-CBC-HMAC-SHA1-ETM")) + .withMethodParameter("*") + .withMethodParameter("\"AES-128-CBC-HMAC-SHA1-ETM\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_192_CBC_HMAC_SHA1_ETM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-192-CBC-HMAC-SHA1-ETM")) + .withMethodParameter("*") + .withMethodParameter("\"AES-192-CBC-HMAC-SHA1-ETM\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_256_CBC_HMAC_SHA1_ETM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-CBC-HMAC-SHA1-ETM")) + .withMethodParameter("*") + .withMethodParameter("\"AES-256-CBC-HMAC-SHA1-ETM\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_128_CBC_HMAC_SHA256_ETM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-CBC-HMAC-SHA256-ETM")) + .withMethodParameter("*") + .withMethodParameter("\"AES-128-CBC-HMAC-SHA256-ETM\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_192_CBC_HMAC_SHA256_ETM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-192-CBC-HMAC-SHA256-ETM")) + .withMethodParameter("*") + .withMethodParameter("\"AES-192-CBC-HMAC-SHA256-ETM\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_256_CBC_HMAC_SHA256_ETM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-CBC-HMAC-SHA256-ETM")) + .withMethodParameter("*") + .withMethodParameter("\"AES-256-CBC-HMAC-SHA256-ETM\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_128_CBC_HMAC_SHA512_ETM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-128-CBC-HMAC-SHA512-ETM")) + .withMethodParameter("*") + .withMethodParameter("\"AES-128-CBC-HMAC-SHA512-ETM\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_192_CBC_HMAC_SHA512_ETM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-192-CBC-HMAC-SHA512-ETM")) + .withMethodParameter("*") + .withMethodParameter("\"AES-192-CBC-HMAC-SHA512-ETM\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_256_CBC_HMAC_SHA512_ETM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-256-CBC-HMAC-SHA512-ETM")) + .withMethodParameter("*") + .withMethodParameter("\"AES-256-CBC-HMAC-SHA512-ETM\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Camellia CBC-CTS - Ciphertext Stealing Mode + // ==================================================================== + + private static final IDetectionRule CAMELLIA_128_CBC_CTS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-128-CBC-CTS")) + .withMethodParameter("*") + .withMethodParameter("\"CAMELLIA-128-CBC-CTS\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule CAMELLIA_192_CBC_CTS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-192-CBC-CTS")) + .withMethodParameter("*") + .withMethodParameter("\"CAMELLIA-192-CBC-CTS\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule CAMELLIA_256_CBC_CTS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_CIPHER_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("CAMELLIA-256-CBC-CTS")) + .withMethodParameter("*") + .withMethodParameter("\"CAMELLIA-256-CBC-CTS\"") + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private OpenSSLEvpCipherFetch() { + // nothing + } + + @Nonnull + public static List> rules() { + return List.of( + // AES-SIV + AES_128_SIV, + AES_192_SIV, + AES_256_SIV, + // AES-GCM-SIV + AES_128_GCM_SIV, + AES_192_GCM_SIV, + AES_256_GCM_SIV, + // AES CBC-CTS + AES_128_CBC_CTS, + AES_192_CBC_CTS, + AES_256_CBC_CTS, + // AES WRAP-INV + AES_128_WRAP_INV, + AES_192_WRAP_INV, + AES_256_WRAP_INV, + // AES WRAP-PAD-INV + AES_128_WRAP_PAD_INV, + AES_192_WRAP_PAD_INV, + AES_256_WRAP_PAD_INV, + // AES CBC-HMAC (non-ETM) + AES_128_CBC_HMAC_SHA1, + AES_128_CBC_HMAC_SHA256, + AES_192_CBC_HMAC_SHA1, + AES_192_CBC_HMAC_SHA256, + AES_256_CBC_HMAC_SHA1, + AES_256_CBC_HMAC_SHA256, + // AES ETM (Encrypt-then-MAC) + AES_128_CBC_HMAC_SHA1_ETM, + AES_192_CBC_HMAC_SHA1_ETM, + AES_256_CBC_HMAC_SHA1_ETM, + AES_128_CBC_HMAC_SHA256_ETM, + AES_192_CBC_HMAC_SHA256_ETM, + AES_256_CBC_HMAC_SHA256_ETM, + AES_128_CBC_HMAC_SHA512_ETM, + AES_192_CBC_HMAC_SHA512_ETM, + AES_256_CBC_HMAC_SHA512_ETM, + // Camellia CBC-CTS + CAMELLIA_128_CBC_CTS, + CAMELLIA_192_CBC_CTS, + CAMELLIA_256_CBC_CTS); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/digest/OpenSSLEvpMessageDigest.java b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/digest/OpenSSLEvpMessageDigest.java new file mode 100644 index 000000000..e2338ac06 --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/digest/OpenSSLEvpMessageDigest.java @@ -0,0 +1,391 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.openssl.digest; + +import com.ibm.engine.model.context.DigestContext; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.List; +import javax.annotation.Nonnull; + +/** + * Detection rules for OpenSSL EVP message digest algorithm specifiers. + * + *

These rules detect calls to OpenSSL functions that return EVP_MD pointers, identifying the + * specific hash algorithm being used. Each function (e.g., {@code EVP_sha256()}) maps to a known + * digest algorithm name. + * + *

Covers MD2, MD4, MD5, SHA-1, SHA-2, SHA-3, SHAKE, RIPEMD, Whirlpool, BLAKE2, SM3, and other + * hash functions supported by OpenSSL. + */ +@SuppressWarnings("java:S1192") +public final class OpenSSLEvpMessageDigest { + + private static final String BUNDLE = "OpenSSL"; + + // ==================================================================== + // MD Family + // ==================================================================== + + private static final IDetectionRule EVP_MD2 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_md2") + .shouldBeDetectedAs(new ValueActionFactory<>("MD2")) + .withoutParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MD4 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_md4") + .shouldBeDetectedAs(new ValueActionFactory<>("MD4")) + .withoutParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MD5 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_md5") + .shouldBeDetectedAs(new ValueActionFactory<>("MD5")) + .withoutParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MDC2 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_mdc2") + .shouldBeDetectedAs(new ValueActionFactory<>("MDC2")) + .withoutParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // SHA-1 + // ==================================================================== + + private static final IDetectionRule EVP_SHA1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_sha1") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA-1")) + .withoutParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // SHA-2 Family + // ==================================================================== + + private static final IDetectionRule EVP_SHA224 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_sha224") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA-224")) + .withoutParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_SHA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_sha256") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA-256")) + .withoutParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_SHA384 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_sha384") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA-384")) + .withoutParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_SHA512 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_sha512") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA-512")) + .withoutParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_SHA512_224 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_sha512_224") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA-512/224")) + .withoutParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_SHA512_256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_sha512_256") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA-512/256")) + .withoutParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // SHA-3 Family + // ==================================================================== + + private static final IDetectionRule EVP_SHA3_224 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_sha3_224") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA3-224")) + .withoutParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_SHA3_256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_sha3_256") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA3-256")) + .withoutParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_SHA3_384 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_sha3_384") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA3-384")) + .withoutParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_SHA3_512 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_sha3_512") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA3-512")) + .withoutParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // SHAKE (Extendable-Output Functions) + // ==================================================================== + + private static final IDetectionRule EVP_SHAKE128 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_shake128") + .shouldBeDetectedAs(new ValueActionFactory<>("SHAKE128")) + .withoutParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_SHAKE256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_shake256") + .shouldBeDetectedAs(new ValueActionFactory<>("SHAKE256")) + .withoutParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // RIPEMD + // ==================================================================== + + private static final IDetectionRule EVP_RIPEMD160 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_ripemd160") + .shouldBeDetectedAs(new ValueActionFactory<>("RIPEMD160")) + .withoutParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Whirlpool + // ==================================================================== + + private static final IDetectionRule EVP_WHIRLPOOL = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_whirlpool") + .shouldBeDetectedAs(new ValueActionFactory<>("WHIRLPOOL")) + .withoutParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // BLAKE2 + // ==================================================================== + + private static final IDetectionRule EVP_BLAKE2B512 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_blake2b512") + .shouldBeDetectedAs(new ValueActionFactory<>("BLAKE2B-512")) + .withoutParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_BLAKE2S256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_blake2s256") + .shouldBeDetectedAs(new ValueActionFactory<>("BLAKE2S-256")) + .withoutParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // SM3 (Chinese National Standard) + // ==================================================================== + + private static final IDetectionRule EVP_SM3 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_sm3") + .shouldBeDetectedAs(new ValueActionFactory<>("SM3")) + .withoutParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Combined and Special Digests + // ==================================================================== + + private static final IDetectionRule EVP_MD5_SHA1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_md5_sha1") + .shouldBeDetectedAs(new ValueActionFactory<>("MD5-SHA1")) + .withoutParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MD_NULL = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_md_null") + .shouldBeDetectedAs(new ValueActionFactory<>("NULL")) + .withoutParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private OpenSSLEvpMessageDigest() { + // nothing + } + + @Nonnull + public static List> rules() { + return List.of( + // MD Family + EVP_MD2, + EVP_MD4, + EVP_MD5, + EVP_MDC2, + // SHA-1 + EVP_SHA1, + // SHA-2 + EVP_SHA224, + EVP_SHA256, + EVP_SHA384, + EVP_SHA512, + EVP_SHA512_224, + EVP_SHA512_256, + // SHA-3 + EVP_SHA3_224, + EVP_SHA3_256, + EVP_SHA3_384, + EVP_SHA3_512, + // SHAKE + EVP_SHAKE128, + EVP_SHAKE256, + // RIPEMD + EVP_RIPEMD160, + // Whirlpool + EVP_WHIRLPOOL, + // BLAKE2 + EVP_BLAKE2B512, + EVP_BLAKE2S256, + // SM3 + EVP_SM3, + // Combined/Special + EVP_MD5_SHA1, + EVP_MD_NULL); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/kdf/OpenSSLEvpKdf.java b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/kdf/OpenSSLEvpKdf.java new file mode 100644 index 000000000..f82507124 --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/kdf/OpenSSLEvpKdf.java @@ -0,0 +1,715 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.openssl.kdf; + +import com.ibm.engine.model.context.KeyDerivationFunctionContext; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.List; +import javax.annotation.Nonnull; + +/** + * Detection rules for OpenSSL Key Derivation Functions (KDFs). + * + *

These rules detect KDF usage through the EVP_KDF API introduced in OpenSSL 3.0. Covers PBKDF2, + * HKDF, Scrypt, TLS PRF, X963KDF, KBKDF, Argon2, and other KDFs. + */ +@SuppressWarnings("java:S1192") +public final class OpenSSLEvpKdf { + + private static final String BUNDLE = "OpenSSL"; + + // ==================================================================== + // PBKDF2 - Password-Based Key Derivation Function 2 + // ==================================================================== + + private static final IDetectionRule PBKDF2_HMAC_SHA1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("PBKDF2-HMAC-SHA1")) + .withMethodParameter("*") + .withMethodParameter("\"PBKDF2\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule PBKDF2_HMAC_SHA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("PBKDF2-HMAC-SHA256")) + .withMethodParameter("*") + .withMethodParameter("\"PBKDF2\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule PBKDF2_HMAC_SHA384 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("PBKDF2-HMAC-SHA384")) + .withMethodParameter("*") + .withMethodParameter("\"PBKDF2\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule PBKDF2_HMAC_SHA512 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("PBKDF2-HMAC-SHA512")) + .withMethodParameter("*") + .withMethodParameter("\"PBKDF2\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // HKDF - HMAC-based Key Derivation Function + // ==================================================================== + + private static final IDetectionRule HKDF_SHA1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HKDF-SHA1")) + .withMethodParameter("*") + .withMethodParameter("\"HKDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule HKDF_SHA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HKDF-SHA256")) + .withMethodParameter("*") + .withMethodParameter("\"HKDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule HKDF_SHA384 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HKDF-SHA384")) + .withMethodParameter("*") + .withMethodParameter("\"HKDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule HKDF_SHA512 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HKDF-SHA512")) + .withMethodParameter("*") + .withMethodParameter("\"HKDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule HKDF_SHA3_256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HKDF-SHA3-256")) + .withMethodParameter("*") + .withMethodParameter("\"HKDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Scrypt + // ==================================================================== + + private static final IDetectionRule SCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("SCRYPT")) + .withMethodParameter("*") + .withMethodParameter("\"SCRYPT\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // TLS1-PRF - TLS 1.0/1.1/1.2 Pseudo-Random Function + // ==================================================================== + + private static final IDetectionRule TLS1_PRF_MD5_SHA1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("TLS1-PRF-MD5-SHA1")) + .withMethodParameter("*") + .withMethodParameter("\"TLS1-PRF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule TLS1_PRF_SHA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("TLS1-PRF-SHA256")) + .withMethodParameter("*") + .withMethodParameter("\"TLS1-PRF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule TLS1_PRF_SHA384 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("TLS1-PRF-SHA384")) + .withMethodParameter("*") + .withMethodParameter("\"TLS1-PRF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule TLS1_PRF_SHA512 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("TLS1-PRF-SHA512")) + .withMethodParameter("*") + .withMethodParameter("\"TLS1-PRF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // TLS13-KDF - TLS 1.3 Key Derivation Function + // ==================================================================== + + private static final IDetectionRule TLS13_KDF_SHA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("TLS13-KDF-SHA256")) + .withMethodParameter("*") + .withMethodParameter("\"TLS13-KDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule TLS13_KDF_SHA384 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("TLS13-KDF-SHA384")) + .withMethodParameter("*") + .withMethodParameter("\"TLS13-KDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule TLS13_KDF_SHA512 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("TLS13-KDF-SHA512")) + .withMethodParameter("*") + .withMethodParameter("\"TLS13-KDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // X963KDF - ANSI X9.63 Key Derivation Function + // ==================================================================== + + private static final IDetectionRule X963KDF_SHA1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("X963KDF-SHA1")) + .withMethodParameter("*") + .withMethodParameter("\"X963KDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule X963KDF_SHA224 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("X963KDF-SHA224")) + .withMethodParameter("*") + .withMethodParameter("\"X963KDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule X963KDF_SHA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("X963KDF-SHA256")) + .withMethodParameter("*") + .withMethodParameter("\"X963KDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule X963KDF_SHA384 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("X963KDF-SHA384")) + .withMethodParameter("*") + .withMethodParameter("\"X963KDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule X963KDF_SHA512 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("X963KDF-SHA512")) + .withMethodParameter("*") + .withMethodParameter("\"X963KDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // KBKDF - Key-Based Key Derivation Function (NIST SP 800-108) + // ==================================================================== + + private static final IDetectionRule KBKDF_HMAC_SHA1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("KBKDF-HMAC-SHA1")) + .withMethodParameter("*") + .withMethodParameter("\"KBKDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule KBKDF_HMAC_SHA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("KBKDF-HMAC-SHA256")) + .withMethodParameter("*") + .withMethodParameter("\"KBKDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule KBKDF_HMAC_SHA384 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("KBKDF-HMAC-SHA384")) + .withMethodParameter("*") + .withMethodParameter("\"KBKDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule KBKDF_HMAC_SHA512 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("KBKDF-HMAC-SHA512")) + .withMethodParameter("*") + .withMethodParameter("\"KBKDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule KBKDF_CMAC_AES128 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("KBKDF-CMAC-AES128")) + .withMethodParameter("*") + .withMethodParameter("\"KBKDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule KBKDF_CMAC_AES256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("KBKDF-CMAC-AES256")) + .withMethodParameter("*") + .withMethodParameter("\"KBKDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // SSHKDF - SSH Key Derivation Function + // ==================================================================== + + private static final IDetectionRule SSHKDF_SHA1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("SSHKDF-SHA1")) + .withMethodParameter("*") + .withMethodParameter("\"SSHKDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SSHKDF_SHA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("SSHKDF-SHA256")) + .withMethodParameter("*") + .withMethodParameter("\"SSHKDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Argon2 - Memory-hard password hashing and KDF + // ==================================================================== + + private static final IDetectionRule ARGON2D = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("ARGON2D")) + .withMethodParameter("*") + .withMethodParameter("\"ARGON2D\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ARGON2I = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("ARGON2I")) + .withMethodParameter("*") + .withMethodParameter("\"ARGON2I\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ARGON2ID = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("ARGON2ID")) + .withMethodParameter("*") + .withMethodParameter("\"ARGON2ID\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // KRB5KDF - Kerberos 5 Key Derivation Function + // ==================================================================== + + private static final IDetectionRule KRB5KDF = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("KRB5KDF")) + .withMethodParameter("*") + .withMethodParameter("\"KRB5KDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // X942KDF - X9.42 Key Derivation Function + // ==================================================================== + + private static final IDetectionRule X942KDF_SHA1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("X942KDF-SHA1")) + .withMethodParameter("*") + .withMethodParameter("\"X942KDF-ASN1\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule X942KDF_SHA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("X942KDF-SHA256")) + .withMethodParameter("*") + .withMethodParameter("\"X942KDF-ASN1\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule X942KDF_CONCAT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("X942KDF-CONCAT")) + .withMethodParameter("*") + .withMethodParameter("\"X942KDF-CONCAT\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // SSKDF - Single Step Key Derivation Function (NIST SP 800-56C) + // ==================================================================== + + private static final IDetectionRule SSKDF = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("SSKDF")) + .withMethodParameter("*") + .withMethodParameter("\"SSKDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // HMAC-DRBG-KDF - HMAC-based DRBG as KDF (NIST SP 800-90A) + // ==================================================================== + + private static final IDetectionRule HMAC_DRBG_KDF = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC-DRBG-KDF")) + .withMethodParameter("*") + .withMethodParameter("\"HMAC-DRBG-KDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // PKCS12KDF - PKCS#12 Key Derivation Function + // ==================================================================== + + private static final IDetectionRule PKCS12KDF = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("PKCS12KDF")) + .withMethodParameter("*") + .withMethodParameter("\"PKCS12KDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // PVKKDF - Microsoft PVK Key Derivation Function (Legacy) + // ==================================================================== + + private static final IDetectionRule PVKKDF = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_KDF_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("PVKKDF")) + .withMethodParameter("*") + .withMethodParameter("\"PVKKDF\"") + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // PBKDF1 - Password-Based Key Derivation Function 1 (legacy) + // ==================================================================== + + private static final IDetectionRule PBKDF1_MD5 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("PKCS5_PBKDF1_MD5") + .shouldBeDetectedAs(new ValueActionFactory<>("PBKDF1-MD5")) + .withAnyParameters() + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule PBKDF1_SHA1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("PKCS5_PBKDF1_SHA1") + .shouldBeDetectedAs(new ValueActionFactory<>("PBKDF1-SHA1")) + .withAnyParameters() + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Legacy PBKDF2 functions + // ==================================================================== + + private static final IDetectionRule PKCS5_PBKDF2_HMAC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("PKCS5_PBKDF2_HMAC") + .shouldBeDetectedAs(new ValueActionFactory<>("PBKDF2-HMAC")) + .withAnyParameters() + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule PKCS5_PBKDF2_HMAC_SHA1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("PKCS5_PBKDF2_HMAC_SHA1") + .shouldBeDetectedAs(new ValueActionFactory<>("PBKDF2-HMAC-SHA1")) + .withAnyParameters() + .buildForContext(new KeyDerivationFunctionContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private OpenSSLEvpKdf() { + // nothing + } + + @Nonnull + public static List> rules() { + return List.of( + // PBKDF2 + PBKDF2_HMAC_SHA1, + PBKDF2_HMAC_SHA256, + PBKDF2_HMAC_SHA384, + PBKDF2_HMAC_SHA512, + // HKDF + HKDF_SHA1, + HKDF_SHA256, + HKDF_SHA384, + HKDF_SHA512, + HKDF_SHA3_256, + // Scrypt + SCRYPT, + // TLS1-PRF + TLS1_PRF_MD5_SHA1, + TLS1_PRF_SHA256, + TLS1_PRF_SHA384, + TLS1_PRF_SHA512, + // TLS13-KDF + TLS13_KDF_SHA256, + TLS13_KDF_SHA384, + TLS13_KDF_SHA512, + // X963KDF + X963KDF_SHA1, + X963KDF_SHA224, + X963KDF_SHA256, + X963KDF_SHA384, + X963KDF_SHA512, + // KBKDF + KBKDF_HMAC_SHA1, + KBKDF_HMAC_SHA256, + KBKDF_HMAC_SHA384, + KBKDF_HMAC_SHA512, + KBKDF_CMAC_AES128, + KBKDF_CMAC_AES256, + // SSHKDF + SSHKDF_SHA1, + SSHKDF_SHA256, + // Argon2 + ARGON2D, + ARGON2I, + ARGON2ID, + // KRB5KDF + KRB5KDF, + // X942KDF + X942KDF_SHA1, + X942KDF_SHA256, + X942KDF_CONCAT, + // SSKDF + SSKDF, + // HMAC-DRBG-KDF + HMAC_DRBG_KDF, + // PKCS12KDF + PKCS12KDF, + // PVKKDF + PVKKDF, + // PBKDF1 (legacy) + PBKDF1_MD5, + PBKDF1_SHA1, + // Legacy PBKDF2 + PKCS5_PBKDF2_HMAC, + PKCS5_PBKDF2_HMAC_SHA1); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/keyagreement/OpenSSLEvpKeyAgreement.java b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/keyagreement/OpenSSLEvpKeyAgreement.java new file mode 100644 index 000000000..9cf20c788 --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/keyagreement/OpenSSLEvpKeyAgreement.java @@ -0,0 +1,456 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.openssl.keyagreement; + +import com.ibm.engine.model.context.KeyAgreementContext; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.List; +import javax.annotation.Nonnull; + +/** + * Detection rules for OpenSSL key agreement operations. + * + *

These rules detect key agreement/exchange operations through EVP_PKEY_derive and related + * functions. Covers Diffie-Hellman (DH), Elliptic Curve Diffie-Hellman (ECDH), X25519/X448, + * post-quantum ML-KEM (Kyber), and SM2. + */ +@SuppressWarnings("java:S1192") +public final class OpenSSLEvpKeyAgreement { + + private static final String BUNDLE = "OpenSSL"; + + // ==================================================================== + // Diffie-Hellman (DH) + // ==================================================================== + + private static final IDetectionRule DH_DERIVE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_derive") + .shouldBeDetectedAs(new ValueActionFactory<>("DH")) + .withAnyParameters() + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DH_2048 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_id") + .shouldBeDetectedAs(new ValueActionFactory<>("DH-2048")) + .withMethodParameter("EVP_PKEY_DH") + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DH_3072 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_id") + .shouldBeDetectedAs(new ValueActionFactory<>("DH-3072")) + .withMethodParameter("EVP_PKEY_DH") + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DH_4096 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_id") + .shouldBeDetectedAs(new ValueActionFactory<>("DH-4096")) + .withMethodParameter("EVP_PKEY_DH") + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Elliptic Curve Diffie-Hellman (ECDH) + // ==================================================================== + + private static final IDetectionRule ECDH_DERIVE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_derive") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDH")) + .withAnyParameters() + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ECDH_P256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_id") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDH-P256")) + .withMethodParameter("EVP_PKEY_EC") + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ECDH_P384 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_id") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDH-P384")) + .withMethodParameter("EVP_PKEY_EC") + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ECDH_P521 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_id") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDH-P521")) + .withMethodParameter("EVP_PKEY_EC") + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ECDH_SECP256K1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_id") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDH-SECP256K1")) + .withMethodParameter("EVP_PKEY_EC") + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ECDH_BRAINPOOLP256R1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_id") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDH-BRAINPOOLP256R1")) + .withMethodParameter("EVP_PKEY_EC") + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ECDH_BRAINPOOLP384R1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_id") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDH-BRAINPOOLP384R1")) + .withMethodParameter("EVP_PKEY_EC") + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ECDH_BRAINPOOLP512R1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_id") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDH-BRAINPOOLP512R1")) + .withMethodParameter("EVP_PKEY_EC") + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // X25519 and X448 - Modern Curve25519/Curve448 key exchange + // ==================================================================== + + private static final IDetectionRule X25519_DERIVE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_derive") + .shouldBeDetectedAs(new ValueActionFactory<>("X25519")) + .withAnyParameters() + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule X25519_CTX = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_id") + .shouldBeDetectedAs(new ValueActionFactory<>("X25519")) + .withMethodParameter("EVP_PKEY_X25519") + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule X448_DERIVE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_derive") + .shouldBeDetectedAs(new ValueActionFactory<>("X448")) + .withAnyParameters() + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule X448_CTX = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_id") + .shouldBeDetectedAs(new ValueActionFactory<>("X448")) + .withMethodParameter("EVP_PKEY_X448") + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // ML-KEM (Kyber) - Post-Quantum Key Encapsulation Mechanism + // ==================================================================== + + private static final IDetectionRule ML_KEM_512_ENCAPS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_encapsulate") + .shouldBeDetectedAs(new ValueActionFactory<>("ML-KEM-512")) + .withAnyParameters() + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ML_KEM_512_DECAPS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_decapsulate") + .shouldBeDetectedAs(new ValueActionFactory<>("ML-KEM-512")) + .withAnyParameters() + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ML_KEM_768_ENCAPS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_encapsulate") + .shouldBeDetectedAs(new ValueActionFactory<>("ML-KEM-768")) + .withAnyParameters() + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ML_KEM_768_DECAPS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_decapsulate") + .shouldBeDetectedAs(new ValueActionFactory<>("ML-KEM-768")) + .withAnyParameters() + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ML_KEM_1024_ENCAPS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_encapsulate") + .shouldBeDetectedAs(new ValueActionFactory<>("ML-KEM-1024")) + .withAnyParameters() + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ML_KEM_1024_DECAPS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_decapsulate") + .shouldBeDetectedAs(new ValueActionFactory<>("ML-KEM-1024")) + .withAnyParameters() + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Hybrid Post-Quantum KEMs (PQC + Classical) + // ==================================================================== + + // X25519MLKEM768 - X25519 + ML-KEM-768 (TLS group 0x11EC) + private static final IDetectionRule X25519MLKEM768_ENCAPS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_encapsulate") + .shouldBeDetectedAs(new ValueActionFactory<>("X25519MLKEM768")) + .withAnyParameters() + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule X25519MLKEM768_DECAPS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_decapsulate") + .shouldBeDetectedAs(new ValueActionFactory<>("X25519MLKEM768")) + .withAnyParameters() + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // X448MLKEM1024 - X448 + ML-KEM-1024 (TLS group 0x11EE) + private static final IDetectionRule X448MLKEM1024_ENCAPS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_encapsulate") + .shouldBeDetectedAs(new ValueActionFactory<>("X448MLKEM1024")) + .withAnyParameters() + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule X448MLKEM1024_DECAPS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_decapsulate") + .shouldBeDetectedAs(new ValueActionFactory<>("X448MLKEM1024")) + .withAnyParameters() + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // SecP256r1MLKEM768 - ECDH P-256 + ML-KEM-768 (TLS group 0x11EB) + private static final IDetectionRule SECP256R1MLKEM768_ENCAPS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_encapsulate") + .shouldBeDetectedAs(new ValueActionFactory<>("SecP256r1MLKEM768")) + .withAnyParameters() + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SECP256R1MLKEM768_DECAPS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_decapsulate") + .shouldBeDetectedAs(new ValueActionFactory<>("SecP256r1MLKEM768")) + .withAnyParameters() + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // SecP384r1MLKEM1024 - ECDH P-384 + ML-KEM-1024 (TLS group 0x11ED) + private static final IDetectionRule SECP384R1MLKEM1024_ENCAPS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_encapsulate") + .shouldBeDetectedAs(new ValueActionFactory<>("SecP384r1MLKEM1024")) + .withAnyParameters() + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SECP384R1MLKEM1024_DECAPS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_decapsulate") + .shouldBeDetectedAs(new ValueActionFactory<>("SecP384r1MLKEM1024")) + .withAnyParameters() + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // SM2 Key Exchange + // ==================================================================== + + private static final IDetectionRule SM2_DERIVE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_derive") + .shouldBeDetectedAs(new ValueActionFactory<>("SM2")) + .withAnyParameters() + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private OpenSSLEvpKeyAgreement() { + // nothing + } + + @Nonnull + public static List> rules() { + return List.of( + // DH + DH_DERIVE, + DH_2048, + DH_3072, + DH_4096, + // ECDH + ECDH_DERIVE, + ECDH_P256, + ECDH_P384, + ECDH_P521, + ECDH_SECP256K1, + ECDH_BRAINPOOLP256R1, + ECDH_BRAINPOOLP384R1, + ECDH_BRAINPOOLP512R1, + // X25519/X448 + X25519_DERIVE, + X25519_CTX, + X448_DERIVE, + X448_CTX, + // ML-KEM (Post-Quantum) + ML_KEM_512_ENCAPS, + ML_KEM_512_DECAPS, + ML_KEM_768_ENCAPS, + ML_KEM_768_DECAPS, + ML_KEM_1024_ENCAPS, + ML_KEM_1024_DECAPS, + // Hybrid PQC KEMs + X25519MLKEM768_ENCAPS, + X25519MLKEM768_DECAPS, + X448MLKEM1024_ENCAPS, + X448MLKEM1024_DECAPS, + SECP256R1MLKEM768_ENCAPS, + SECP256R1MLKEM768_DECAPS, + SECP384R1MLKEM1024_ENCAPS, + SECP384R1MLKEM1024_DECAPS, + // SM2 + SM2_DERIVE); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/keygen/OpenSSLEvpKeyGen.java b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/keygen/OpenSSLEvpKeyGen.java new file mode 100644 index 000000000..6dc216c9c --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/keygen/OpenSSLEvpKeyGen.java @@ -0,0 +1,680 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.openssl.keygen; + +import com.ibm.engine.model.context.KeyContext; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.List; +import javax.annotation.Nonnull; + +@SuppressWarnings("java:S1192") +public final class OpenSSLEvpKeyGen { + + private static final String BUNDLE = "OpenSSL"; + + // ==================================================================== + // RSA Key Generation + // ==================================================================== + + private static final IDetectionRule EVP_PKEY_CTX_NEW_RSA = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_id") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_PKEY_CTX_NEW_RSA_PSS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_id") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-PSS")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_RSA_KEYGEN_BITS_2048 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_set_rsa_keygen_bits") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-2048")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_RSA_KEYGEN_BITS_3072 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_set_rsa_keygen_bits") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-3072")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_RSA_KEYGEN_BITS_4096 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_set_rsa_keygen_bits") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-4096")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // DSA Key Generation + // ==================================================================== + + private static final IDetectionRule EVP_PKEY_CTX_NEW_DSA = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_id") + .shouldBeDetectedAs(new ValueActionFactory<>("DSA")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_DSA_PARAMGEN_BITS_2048 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_set_dsa_paramgen_bits") + .shouldBeDetectedAs(new ValueActionFactory<>("DSA-2048")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_DSA_PARAMGEN_BITS_3072 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_set_dsa_paramgen_bits") + .shouldBeDetectedAs(new ValueActionFactory<>("DSA-3072")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // EC Key Generation + // ==================================================================== + + private static final IDetectionRule EVP_PKEY_CTX_NEW_EC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_id") + .shouldBeDetectedAs(new ValueActionFactory<>("EC")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_EC_CURVE_P256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_set_ec_paramgen_curve_nid") + .shouldBeDetectedAs(new ValueActionFactory<>("EC-P256")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_EC_CURVE_P384 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_set_ec_paramgen_curve_nid") + .shouldBeDetectedAs(new ValueActionFactory<>("EC-P384")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_EC_CURVE_P521 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_set_ec_paramgen_curve_nid") + .shouldBeDetectedAs(new ValueActionFactory<>("EC-P521")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_EC_CURVE_SECP256K1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_set_ec_paramgen_curve_nid") + .shouldBeDetectedAs(new ValueActionFactory<>("EC-SECP256K1")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_EC_CURVE_BP256R1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_set_ec_paramgen_curve_nid") + .shouldBeDetectedAs(new ValueActionFactory<>("EC-BRAINPOOLP256R1")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_EC_CURVE_BP384R1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_set_ec_paramgen_curve_nid") + .shouldBeDetectedAs(new ValueActionFactory<>("EC-BRAINPOOLP384R1")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_EC_CURVE_BP512R1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_set_ec_paramgen_curve_nid") + .shouldBeDetectedAs(new ValueActionFactory<>("EC-BRAINPOOLP512R1")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // DH Key Generation + // ==================================================================== + + private static final IDetectionRule EVP_PKEY_CTX_NEW_DH = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_id") + .shouldBeDetectedAs(new ValueActionFactory<>("DH")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_DH_PARAMGEN_2048 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_set_dh_paramgen_prime_len") + .shouldBeDetectedAs(new ValueActionFactory<>("DH-2048")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_DH_PARAMGEN_4096 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_set_dh_paramgen_prime_len") + .shouldBeDetectedAs(new ValueActionFactory<>("DH-4096")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // EdDSA Key Generation + // ==================================================================== + + private static final IDetectionRule EVP_PKEY_CTX_NEW_ED25519 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_id") + .shouldBeDetectedAs(new ValueActionFactory<>("ED25519")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_PKEY_CTX_NEW_ED448 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_id") + .shouldBeDetectedAs(new ValueActionFactory<>("ED448")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // X25519/X448 Key Generation + // ==================================================================== + + private static final IDetectionRule EVP_PKEY_CTX_NEW_X25519 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_id") + .shouldBeDetectedAs(new ValueActionFactory<>("X25519")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_PKEY_CTX_NEW_X448 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_id") + .shouldBeDetectedAs(new ValueActionFactory<>("X448")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Post-Quantum Key Generation - ML-KEM (Kyber) + // ==================================================================== + + private static final IDetectionRule EVP_PKEY_CTX_NEW_MLKEM512 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_from_name") + .shouldBeDetectedAs(new ValueActionFactory<>("ML-KEM-512")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_PKEY_CTX_NEW_MLKEM768 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_from_name") + .shouldBeDetectedAs(new ValueActionFactory<>("ML-KEM-768")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_PKEY_CTX_NEW_MLKEM1024 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_from_name") + .shouldBeDetectedAs(new ValueActionFactory<>("ML-KEM-1024")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Hybrid Post-Quantum KEMs (PQC + Classical) + // ==================================================================== + + private static final IDetectionRule EVP_PKEY_CTX_NEW_X25519MLKEM768 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_from_name") + .shouldBeDetectedAs(new ValueActionFactory<>("X25519MLKEM768")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_PKEY_CTX_NEW_X448MLKEM1024 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_from_name") + .shouldBeDetectedAs(new ValueActionFactory<>("X448MLKEM1024")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_PKEY_CTX_NEW_SECP256R1MLKEM768 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_from_name") + .shouldBeDetectedAs(new ValueActionFactory<>("SecP256r1MLKEM768")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_PKEY_CTX_NEW_SECP384R1MLKEM1024 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_from_name") + .shouldBeDetectedAs(new ValueActionFactory<>("SecP384r1MLKEM1024")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Post-Quantum Key Generation - ML-DSA + // ==================================================================== + + private static final IDetectionRule EVP_PKEY_CTX_NEW_MLDSA44 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_from_name") + .shouldBeDetectedAs(new ValueActionFactory<>("ML-DSA-44")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_PKEY_CTX_NEW_MLDSA65 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_from_name") + .shouldBeDetectedAs(new ValueActionFactory<>("ML-DSA-65")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_PKEY_CTX_NEW_MLDSA87 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_from_name") + .shouldBeDetectedAs(new ValueActionFactory<>("ML-DSA-87")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Post-Quantum Key Generation - SLH-DSA + // ==================================================================== + + private static final IDetectionRule EVP_PKEY_CTX_NEW_SLH_DSA_SHA2_128F = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_from_name") + .shouldBeDetectedAs(new ValueActionFactory<>("SLH-DSA-SHA2-128F")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_PKEY_CTX_NEW_SLH_DSA_SHA2_128S = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_from_name") + .shouldBeDetectedAs(new ValueActionFactory<>("SLH-DSA-SHA2-128S")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_PKEY_CTX_NEW_SLH_DSA_SHAKE_128F = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_from_name") + .shouldBeDetectedAs(new ValueActionFactory<>("SLH-DSA-SHAKE-128F")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_PKEY_CTX_NEW_SLH_DSA_SHA2_192F = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_from_name") + .shouldBeDetectedAs(new ValueActionFactory<>("SLH-DSA-SHA2-192F")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_PKEY_CTX_NEW_SLH_DSA_SHAKE_128S = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_from_name") + .shouldBeDetectedAs(new ValueActionFactory<>("SLH-DSA-SHAKE-128S")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_PKEY_CTX_NEW_SLH_DSA_SHA2_192S = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_from_name") + .shouldBeDetectedAs(new ValueActionFactory<>("SLH-DSA-SHA2-192S")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_PKEY_CTX_NEW_SLH_DSA_SHAKE_192F = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_from_name") + .shouldBeDetectedAs(new ValueActionFactory<>("SLH-DSA-SHAKE-192F")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_PKEY_CTX_NEW_SLH_DSA_SHAKE_192S = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_from_name") + .shouldBeDetectedAs(new ValueActionFactory<>("SLH-DSA-SHAKE-192S")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_PKEY_CTX_NEW_SLH_DSA_SHA2_256F = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_from_name") + .shouldBeDetectedAs(new ValueActionFactory<>("SLH-DSA-SHA2-256F")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_PKEY_CTX_NEW_SLH_DSA_SHA2_256S = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_from_name") + .shouldBeDetectedAs(new ValueActionFactory<>("SLH-DSA-SHA2-256S")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_PKEY_CTX_NEW_SLH_DSA_SHAKE_256F = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_from_name") + .shouldBeDetectedAs(new ValueActionFactory<>("SLH-DSA-SHAKE-256F")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_PKEY_CTX_NEW_SLH_DSA_SHAKE_256S = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_from_name") + .shouldBeDetectedAs(new ValueActionFactory<>("SLH-DSA-SHAKE-256S")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // EVP_PKEY_keygen (generic keygen detection) + // ==================================================================== + + private static final IDetectionRule EVP_PKEY_KEYGEN = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_keygen") + .shouldBeDetectedAs(new ValueActionFactory<>("KEYGEN")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_PKEY_KEYGEN_INIT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_keygen_init") + .shouldBeDetectedAs(new ValueActionFactory<>("KEYGEN-INIT")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // SM2 + // ==================================================================== + + private static final IDetectionRule EVP_PKEY_CTX_NEW_SM2 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_new_from_name") + .shouldBeDetectedAs(new ValueActionFactory<>("SM2")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private OpenSSLEvpKeyGen() { + // nothing + } + + @Nonnull + public static List> rules() { + return List.of( + // RSA + EVP_PKEY_CTX_NEW_RSA, + EVP_PKEY_CTX_NEW_RSA_PSS, + EVP_RSA_KEYGEN_BITS_2048, + EVP_RSA_KEYGEN_BITS_3072, + EVP_RSA_KEYGEN_BITS_4096, + // DSA + EVP_PKEY_CTX_NEW_DSA, + EVP_DSA_PARAMGEN_BITS_2048, + EVP_DSA_PARAMGEN_BITS_3072, + // EC + EVP_PKEY_CTX_NEW_EC, + EVP_EC_CURVE_P256, + EVP_EC_CURVE_P384, + EVP_EC_CURVE_P521, + EVP_EC_CURVE_SECP256K1, + EVP_EC_CURVE_BP256R1, + EVP_EC_CURVE_BP384R1, + EVP_EC_CURVE_BP512R1, + // DH + EVP_PKEY_CTX_NEW_DH, + EVP_DH_PARAMGEN_2048, + EVP_DH_PARAMGEN_4096, + // EdDSA + EVP_PKEY_CTX_NEW_ED25519, + EVP_PKEY_CTX_NEW_ED448, + // X25519/X448 + EVP_PKEY_CTX_NEW_X25519, + EVP_PKEY_CTX_NEW_X448, + // ML-KEM + EVP_PKEY_CTX_NEW_MLKEM512, + EVP_PKEY_CTX_NEW_MLKEM768, + EVP_PKEY_CTX_NEW_MLKEM1024, + // Hybrid PQC KEMs + EVP_PKEY_CTX_NEW_X25519MLKEM768, + EVP_PKEY_CTX_NEW_X448MLKEM1024, + EVP_PKEY_CTX_NEW_SECP256R1MLKEM768, + EVP_PKEY_CTX_NEW_SECP384R1MLKEM1024, + // ML-DSA + EVP_PKEY_CTX_NEW_MLDSA44, + EVP_PKEY_CTX_NEW_MLDSA65, + EVP_PKEY_CTX_NEW_MLDSA87, + // SLH-DSA + EVP_PKEY_CTX_NEW_SLH_DSA_SHA2_128F, + EVP_PKEY_CTX_NEW_SLH_DSA_SHA2_128S, + EVP_PKEY_CTX_NEW_SLH_DSA_SHAKE_128F, + EVP_PKEY_CTX_NEW_SLH_DSA_SHAKE_128S, + EVP_PKEY_CTX_NEW_SLH_DSA_SHA2_192F, + EVP_PKEY_CTX_NEW_SLH_DSA_SHA2_192S, + EVP_PKEY_CTX_NEW_SLH_DSA_SHAKE_192F, + EVP_PKEY_CTX_NEW_SLH_DSA_SHAKE_192S, + EVP_PKEY_CTX_NEW_SLH_DSA_SHA2_256F, + EVP_PKEY_CTX_NEW_SLH_DSA_SHA2_256S, + EVP_PKEY_CTX_NEW_SLH_DSA_SHAKE_256F, + EVP_PKEY_CTX_NEW_SLH_DSA_SHAKE_256S, + // Generic keygen + // SM2 + EVP_PKEY_CTX_NEW_SM2, + // Generic keygen + EVP_PKEY_KEYGEN, + EVP_PKEY_KEYGEN_INIT); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/legacy/OpenSSLLegacyCipher.java b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/legacy/OpenSSLLegacyCipher.java new file mode 100644 index 000000000..20137eb6e --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/legacy/OpenSSLLegacyCipher.java @@ -0,0 +1,607 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.openssl.legacy; + +import com.ibm.engine.model.context.CipherContext; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.List; +import javax.annotation.Nonnull; + +/** + * Detection rules for OpenSSL legacy cipher APIs. + * + *

These rules detect direct cipher operations using the legacy (pre-EVP) APIs. These APIs are + * deprecated but still widely used in existing codebases. + * + *

Covers: AES, DES, 3DES, Blowfish, RC4, RC2, CAST, IDEA + */ +@SuppressWarnings("java:S1192") +public final class OpenSSLLegacyCipher { + + private static final String BUNDLE = "OpenSSL"; + + // ==================================================================== + // Legacy AES functions + // ==================================================================== + + private static final IDetectionRule AES_SET_ENCRYPT_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("AES_set_encrypt_key") + .shouldBeDetectedAs(new ValueActionFactory<>("AES")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_SET_DECRYPT_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("AES_set_decrypt_key") + .shouldBeDetectedAs(new ValueActionFactory<>("AES")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("AES_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-ECB")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_DECRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("AES_decrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-ECB")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_ECB_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("AES_ecb_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-ECB")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_CBC_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("AES_cbc_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-CBC")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_CFB128_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("AES_cfb128_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-CFB128")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_OFB128_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("AES_ofb128_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-OFB")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_CTR128_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("AES_ctr128_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-CTR")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_IGE_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("AES_ige_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-IGE")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Legacy DES functions + // ==================================================================== + + private static final IDetectionRule DES_SET_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DES_set_key", "DES_set_key_checked", "DES_set_key_unchecked") + .shouldBeDetectedAs(new ValueActionFactory<>("DES")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DES_ECB_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DES_ecb_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("DES-ECB")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DES_CBC_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DES_ncbc_encrypt", "DES_cbc_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("DES-CBC")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DES_CFB_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DES_cfb64_encrypt", "DES_cfb_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("DES-CFB")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DES_OFB_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DES_ofb64_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("DES-OFB")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DES_EDE3_CBC_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DES_ede3_cbc_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("3DES-CBC")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DES_EDE3_ECB_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DES_ecb3_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("3DES-ECB")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DES_EDE3_CFB_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DES_ede3_cfb64_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("3DES-CFB")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Legacy Blowfish functions + // ==================================================================== + + private static final IDetectionRule BF_SET_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("BF_set_key") + .shouldBeDetectedAs(new ValueActionFactory<>("BLOWFISH")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule BF_ECB_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("BF_ecb_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("BLOWFISH-ECB")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule BF_CBC_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("BF_cbc_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("BLOWFISH-CBC")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule BF_CFB64_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("BF_cfb64_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("BLOWFISH-CFB")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule BF_OFB64_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("BF_ofb64_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("BLOWFISH-OFB")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Legacy RC4 functions + // ==================================================================== + + private static final IDetectionRule RC4_SET_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RC4_set_key") + .shouldBeDetectedAs(new ValueActionFactory<>("RC4")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RC4 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RC4") + .shouldBeDetectedAs(new ValueActionFactory<>("RC4")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Legacy RC2 functions + // ==================================================================== + + private static final IDetectionRule RC2_SET_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RC2_set_key") + .shouldBeDetectedAs(new ValueActionFactory<>("RC2")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RC2_ECB_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RC2_ecb_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("RC2-ECB")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RC2_CBC_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RC2_cbc_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("RC2-CBC")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RC2_CFB64_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RC2_cfb64_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("RC2-CFB")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RC2_OFB64_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RC2_ofb64_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("RC2-OFB")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Legacy CAST functions + // ==================================================================== + + private static final IDetectionRule CAST_SET_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("CAST_set_key") + .shouldBeDetectedAs(new ValueActionFactory<>("CAST5")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule CAST_ECB_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("CAST_ecb_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("CAST5-ECB")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule CAST_CBC_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("CAST_cbc_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("CAST5-CBC")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule CAST_CFB64_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("CAST_cfb64_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("CAST5-CFB")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule CAST_OFB64_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("CAST_ofb64_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("CAST5-OFB")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Legacy IDEA functions + // ==================================================================== + + private static final IDetectionRule IDEA_SET_ENCRYPT_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("IDEA_set_encrypt_key") + .shouldBeDetectedAs(new ValueActionFactory<>("IDEA")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule IDEA_SET_DECRYPT_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("IDEA_set_decrypt_key") + .shouldBeDetectedAs(new ValueActionFactory<>("IDEA")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule IDEA_ECB_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("IDEA_ecb_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("IDEA-ECB")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule IDEA_CBC_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("IDEA_cbc_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("IDEA-CBC")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule IDEA_CFB64_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("IDEA_cfb64_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("IDEA-CFB")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule IDEA_OFB64_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("IDEA_ofb64_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("IDEA-OFB")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Legacy AES Key Wrap functions + // ==================================================================== + + private static final IDetectionRule AES_WRAP_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("AES_wrap_key") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-WRAP")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule AES_UNWRAP_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("AES_unwrap_key") + .shouldBeDetectedAs(new ValueActionFactory<>("AES-WRAP")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private OpenSSLLegacyCipher() { + // nothing + } + + @Nonnull + public static List> rules() { + return List.of( + // AES + AES_SET_ENCRYPT_KEY, + AES_SET_DECRYPT_KEY, + AES_ENCRYPT, + AES_DECRYPT, + AES_ECB_ENCRYPT, + AES_CBC_ENCRYPT, + AES_CFB128_ENCRYPT, + AES_OFB128_ENCRYPT, + AES_CTR128_ENCRYPT, + AES_IGE_ENCRYPT, + // DES + DES_SET_KEY, + DES_ECB_ENCRYPT, + DES_CBC_ENCRYPT, + DES_CFB_ENCRYPT, + DES_OFB_ENCRYPT, + DES_EDE3_CBC_ENCRYPT, + DES_EDE3_ECB_ENCRYPT, + DES_EDE3_CFB_ENCRYPT, + // Blowfish + BF_SET_KEY, + BF_ECB_ENCRYPT, + BF_CBC_ENCRYPT, + BF_CFB64_ENCRYPT, + BF_OFB64_ENCRYPT, + // RC4 + RC4_SET_KEY, + RC4, + // RC2 + RC2_SET_KEY, + RC2_ECB_ENCRYPT, + RC2_CBC_ENCRYPT, + RC2_CFB64_ENCRYPT, + RC2_OFB64_ENCRYPT, + // CAST + CAST_SET_KEY, + CAST_ECB_ENCRYPT, + CAST_CBC_ENCRYPT, + CAST_CFB64_ENCRYPT, + CAST_OFB64_ENCRYPT, + // IDEA + IDEA_SET_ENCRYPT_KEY, + IDEA_SET_DECRYPT_KEY, + IDEA_ECB_ENCRYPT, + IDEA_CBC_ENCRYPT, + IDEA_CFB64_ENCRYPT, + IDEA_OFB64_ENCRYPT, + // AES Key Wrap + AES_WRAP_KEY, + AES_UNWRAP_KEY); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/legacy/OpenSSLLegacyDh.java b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/legacy/OpenSSLLegacyDh.java new file mode 100644 index 000000000..8bf63b5d3 --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/legacy/OpenSSLLegacyDh.java @@ -0,0 +1,252 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.openssl.legacy; + +import com.ibm.engine.model.context.KeyAgreementContext; +import com.ibm.engine.model.context.KeyContext; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.List; +import javax.annotation.Nonnull; + +/** + * Detection rules for OpenSSL legacy DH (Diffie-Hellman) APIs. + * + *

These rules detect direct DH operations using the legacy (pre-EVP) APIs from dh.h. These APIs + * are deprecated but still widely used in existing codebases. + * + *

Covers: Key/Parameter Generation, Key Agreement, Predefined Groups (RFC 5114), Size/Info + */ +@SuppressWarnings("java:S1192") +public final class OpenSSLLegacyDh { + + private static final String BUNDLE = "OpenSSL"; + + // ==================================================================== + // Key/Parameter Generation functions + // ==================================================================== + + private static final IDetectionRule DH_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DH_new") + .shouldBeDetectedAs(new ValueActionFactory<>("DH")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DH_GENERATE_PARAMETERS_EX = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DH_generate_parameters_ex") + .shouldBeDetectedAs(new ValueActionFactory<>("DH")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DH_GENERATE_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DH_generate_key") + .shouldBeDetectedAs(new ValueActionFactory<>("DH")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DH_CHECK = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DH_check") + .shouldBeDetectedAs(new ValueActionFactory<>("DH")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DH_CHECK_PARAMS_EX = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DH_check_params_ex") + .shouldBeDetectedAs(new ValueActionFactory<>("DH")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DH_CHECK_EX = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DH_check_ex") + .shouldBeDetectedAs(new ValueActionFactory<>("DH")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DH_CHECK_PUB_KEY_EX = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DH_check_pub_key_ex") + .shouldBeDetectedAs(new ValueActionFactory<>("DH")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Key Agreement functions + // ==================================================================== + + private static final IDetectionRule DH_COMPUTE_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DH_compute_key") + .shouldBeDetectedAs(new ValueActionFactory<>("DH")) + .withAnyParameters() + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DH_COMPUTE_KEY_PADDED = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DH_compute_key_padded") + .shouldBeDetectedAs(new ValueActionFactory<>("DH")) + .withAnyParameters() + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Predefined Groups (RFC 5114) functions + // ==================================================================== + + private static final IDetectionRule DH_GET_1024_160 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DH_get_1024_160") + .shouldBeDetectedAs(new ValueActionFactory<>("DH-1024-160")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DH_GET_2048_224 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DH_get_2048_224") + .shouldBeDetectedAs(new ValueActionFactory<>("DH-2048-224")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DH_GET_2048_256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DH_get_2048_256") + .shouldBeDetectedAs(new ValueActionFactory<>("DH-2048-256")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Size/Info functions + // ==================================================================== + + private static final IDetectionRule DH_SIZE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DH_size") + .shouldBeDetectedAs(new ValueActionFactory<>("DH")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DH_BITS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DH_bits") + .shouldBeDetectedAs(new ValueActionFactory<>("DH")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DH_SECURITY_BITS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DH_security_bits") + .shouldBeDetectedAs(new ValueActionFactory<>("DH")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private OpenSSLLegacyDh() { + // nothing + } + + @Nonnull + public static List> rules() { + return List.of( + // Key/Parameter Generation + DH_NEW, + DH_GENERATE_PARAMETERS_EX, + DH_GENERATE_KEY, + DH_CHECK, + DH_CHECK_PARAMS_EX, + DH_CHECK_EX, + DH_CHECK_PUB_KEY_EX, + // Key Agreement + DH_COMPUTE_KEY, + DH_COMPUTE_KEY_PADDED, + // Predefined Groups (RFC 5114) + DH_GET_1024_160, + DH_GET_2048_224, + DH_GET_2048_256, + // Size/Info + DH_SIZE, + DH_BITS, + DH_SECURITY_BITS); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/legacy/OpenSSLLegacyDigest.java b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/legacy/OpenSSLLegacyDigest.java new file mode 100644 index 000000000..00e1237c5 --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/legacy/OpenSSLLegacyDigest.java @@ -0,0 +1,422 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.openssl.legacy; + +import com.ibm.engine.model.context.DigestContext; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.List; +import javax.annotation.Nonnull; + +/** + * Detection rules for OpenSSL legacy digest/hash APIs. + * + *

These rules detect direct hash operations using the legacy (pre-EVP) APIs. These APIs are + * deprecated but still widely used in existing codebases. + * + *

Covers: MD5, SHA-1, SHA-2 family (SHA-224, SHA-256, SHA-384, SHA-512), RIPEMD-160 + */ +@SuppressWarnings("java:S1192") +public final class OpenSSLLegacyDigest { + + private static final String BUNDLE = "OpenSSL"; + + // ==================================================================== + // Legacy MD5 functions + // ==================================================================== + + private static final IDetectionRule MD5_INIT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("MD5_Init") + .shouldBeDetectedAs(new ValueActionFactory<>("MD5")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule MD5_UPDATE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("MD5_Update") + .shouldBeDetectedAs(new ValueActionFactory<>("MD5")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule MD5_FINAL = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("MD5_Final") + .shouldBeDetectedAs(new ValueActionFactory<>("MD5")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule MD5 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("MD5") + .shouldBeDetectedAs(new ValueActionFactory<>("MD5")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Legacy SHA-1 functions + // ==================================================================== + + private static final IDetectionRule SHA1_INIT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SHA1_Init") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA1")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SHA1_UPDATE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SHA1_Update") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA1")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SHA1_FINAL = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SHA1_Final") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA1")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SHA1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SHA1") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA1")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Legacy SHA-224 functions + // ==================================================================== + + private static final IDetectionRule SHA224_INIT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SHA224_Init") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA224")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SHA224_UPDATE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SHA224_Update") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA224")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SHA224_FINAL = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SHA224_Final") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA224")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SHA224 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SHA224") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA224")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Legacy SHA-256 functions + // ==================================================================== + + private static final IDetectionRule SHA256_INIT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SHA256_Init") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA256")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SHA256_UPDATE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SHA256_Update") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA256")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SHA256_FINAL = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SHA256_Final") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA256")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SHA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SHA256") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA256")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Legacy SHA-384 functions + // ==================================================================== + + private static final IDetectionRule SHA384_INIT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SHA384_Init") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA384")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SHA384_UPDATE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SHA384_Update") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA384")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SHA384_FINAL = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SHA384_Final") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA384")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SHA384 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SHA384") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA384")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Legacy SHA-512 functions + // ==================================================================== + + private static final IDetectionRule SHA512_INIT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SHA512_Init") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA512")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SHA512_UPDATE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SHA512_Update") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA512")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SHA512_FINAL = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SHA512_Final") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA512")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SHA512 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SHA512") + .shouldBeDetectedAs(new ValueActionFactory<>("SHA512")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Legacy RIPEMD-160 functions + // ==================================================================== + + private static final IDetectionRule RIPEMD160_INIT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RIPEMD160_Init") + .shouldBeDetectedAs(new ValueActionFactory<>("RIPEMD160")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RIPEMD160_UPDATE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RIPEMD160_Update") + .shouldBeDetectedAs(new ValueActionFactory<>("RIPEMD160")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RIPEMD160_FINAL = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RIPEMD160_Final") + .shouldBeDetectedAs(new ValueActionFactory<>("RIPEMD160")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RIPEMD160 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RIPEMD160") + .shouldBeDetectedAs(new ValueActionFactory<>("RIPEMD160")) + .withAnyParameters() + .buildForContext(new DigestContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private OpenSSLLegacyDigest() { + // nothing + } + + @Nonnull + public static List> rules() { + return List.of( + // MD5 + MD5_INIT, + MD5_UPDATE, + MD5_FINAL, + MD5, + // SHA-1 + SHA1_INIT, + SHA1_UPDATE, + SHA1_FINAL, + SHA1, + // SHA-224 + SHA224_INIT, + SHA224_UPDATE, + SHA224_FINAL, + SHA224, + // SHA-256 + SHA256_INIT, + SHA256_UPDATE, + SHA256_FINAL, + SHA256, + // SHA-384 + SHA384_INIT, + SHA384_UPDATE, + SHA384_FINAL, + SHA384, + // SHA-512 + SHA512_INIT, + SHA512_UPDATE, + SHA512_FINAL, + SHA512, + // RIPEMD-160 + RIPEMD160_INIT, + RIPEMD160_UPDATE, + RIPEMD160_FINAL, + RIPEMD160); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/legacy/OpenSSLLegacyDsa.java b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/legacy/OpenSSLLegacyDsa.java new file mode 100644 index 000000000..21bf02a70 --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/legacy/OpenSSLLegacyDsa.java @@ -0,0 +1,216 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.openssl.legacy; + +import com.ibm.engine.model.context.KeyContext; +import com.ibm.engine.model.context.SignatureContext; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.List; +import javax.annotation.Nonnull; + +/** + * Detection rules for OpenSSL legacy DSA APIs. + * + *

These rules detect direct DSA operations using the legacy (pre-EVP) APIs from dsa.h. These + * APIs are deprecated but still widely used in existing codebases. + * + *

Covers: key generation, signing, verification, size/utility, and conversion functions. + */ +@SuppressWarnings("java:S1192") +public final class OpenSSLLegacyDsa { + + private static final String BUNDLE = "OpenSSL"; + + // ==================================================================== + // Key Generation functions + // ==================================================================== + + private static final IDetectionRule DSA_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DSA_new") + .shouldBeDetectedAs(new ValueActionFactory<>("DSA")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DSA_GENERATE_PARAMETERS_EX = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DSA_generate_parameters_ex") + .shouldBeDetectedAs(new ValueActionFactory<>("DSA")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DSA_GENERATE_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DSA_generate_key") + .shouldBeDetectedAs(new ValueActionFactory<>("DSA")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Signature functions + // ==================================================================== + + private static final IDetectionRule DSA_SIGN = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DSA_sign") + .shouldBeDetectedAs(new ValueActionFactory<>("DSA-SIGN")) + .withAnyParameters() + .buildForContext(new SignatureContext(SignatureContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DSA_SIGN_SETUP = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DSA_sign_setup") + .shouldBeDetectedAs(new ValueActionFactory<>("DSA-SIGN")) + .withAnyParameters() + .buildForContext(new SignatureContext(SignatureContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DSA_VERIFY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DSA_verify") + .shouldBeDetectedAs(new ValueActionFactory<>("DSA-VERIFY")) + .withAnyParameters() + .buildForContext(new SignatureContext(SignatureContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DSA_DO_SIGN = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DSA_do_sign") + .shouldBeDetectedAs(new ValueActionFactory<>("DSA-SIGN")) + .withAnyParameters() + .buildForContext(new SignatureContext(SignatureContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DSA_DO_VERIFY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DSA_do_verify") + .shouldBeDetectedAs(new ValueActionFactory<>("DSA-VERIFY")) + .withAnyParameters() + .buildForContext(new SignatureContext(SignatureContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Size/Utility functions + // ==================================================================== + + private static final IDetectionRule DSA_SIZE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DSA_size") + .shouldBeDetectedAs(new ValueActionFactory<>("DSA")) + .withAnyParameters() + .buildForContext(new SignatureContext(SignatureContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DSA_BITS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DSA_bits") + .shouldBeDetectedAs(new ValueActionFactory<>("DSA")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DSA_SECURITY_BITS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DSA_security_bits") + .shouldBeDetectedAs(new ValueActionFactory<>("DSA")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Conversion functions + // ==================================================================== + + private static final IDetectionRule DSA_DUP_DH = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DSA_dup_DH") + .shouldBeDetectedAs(new ValueActionFactory<>("DSA-DH")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private OpenSSLLegacyDsa() { + // nothing + } + + @Nonnull + public static List> rules() { + return List.of( + // Key Generation + DSA_NEW, + DSA_GENERATE_PARAMETERS_EX, + DSA_GENERATE_KEY, + // Signatures + DSA_SIGN, + DSA_SIGN_SETUP, + DSA_VERIFY, + DSA_DO_SIGN, + DSA_DO_VERIFY, + // Size/Utility + DSA_SIZE, + DSA_BITS, + DSA_SECURITY_BITS, + // Conversion + DSA_DUP_DH); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/legacy/OpenSSLLegacyEc.java b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/legacy/OpenSSLLegacyEc.java new file mode 100644 index 000000000..d3102b8f2 --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/legacy/OpenSSLLegacyEc.java @@ -0,0 +1,319 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.openssl.legacy; + +import com.ibm.engine.model.context.KeyAgreementContext; +import com.ibm.engine.model.context.KeyContext; +import com.ibm.engine.model.context.SignatureContext; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.List; +import javax.annotation.Nonnull; + +/** + * Detection rules for OpenSSL legacy EC APIs. + * + *

These rules detect direct EC operations using the legacy (pre-EVP) APIs from ec.h. These APIs + * are deprecated but still widely used in existing codebases. + * + *

Covers: EC key management, ECDSA signatures, ECDH key agreement, EC group/curve, EC point + * operations + */ +@SuppressWarnings("java:S1192") +public final class OpenSSLLegacyEc { + + private static final String BUNDLE = "OpenSSL"; + + // ==================================================================== + // EC Key Management functions + // ==================================================================== + + private static final IDetectionRule EC_KEY_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EC_KEY_new") + .shouldBeDetectedAs(new ValueActionFactory<>("EC")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EC_KEY_NEW_BY_CURVE_NAME = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EC_KEY_new_by_curve_name") + .shouldBeDetectedAs(new ValueActionFactory<>("EC")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EC_KEY_GENERATE_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EC_KEY_generate_key") + .shouldBeDetectedAs(new ValueActionFactory<>("EC")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EC_KEY_CHECK_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EC_KEY_check_key") + .shouldBeDetectedAs(new ValueActionFactory<>("EC")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EC_KEY_SET_PUBLIC_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EC_KEY_set_public_key") + .shouldBeDetectedAs(new ValueActionFactory<>("EC")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EC_KEY_SET_PRIVATE_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EC_KEY_set_private_key") + .shouldBeDetectedAs(new ValueActionFactory<>("EC")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // ECDSA Signature functions + // ==================================================================== + + private static final IDetectionRule ECDSA_SIGN = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("ECDSA_sign") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDSA-SIGN")) + .withAnyParameters() + .buildForContext(new SignatureContext(SignatureContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ECDSA_VERIFY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("ECDSA_verify") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDSA-VERIFY")) + .withAnyParameters() + .buildForContext(new SignatureContext(SignatureContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ECDSA_DO_SIGN = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("ECDSA_do_sign") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDSA-SIGN")) + .withAnyParameters() + .buildForContext(new SignatureContext(SignatureContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ECDSA_DO_VERIFY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("ECDSA_do_verify") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDSA-VERIFY")) + .withAnyParameters() + .buildForContext(new SignatureContext(SignatureContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ECDSA_SIGN_SETUP = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("ECDSA_sign_setup") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDSA-SIGN")) + .withAnyParameters() + .buildForContext(new SignatureContext(SignatureContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ECDSA_SIGN_EX = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("ECDSA_sign_ex") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDSA-SIGN")) + .withAnyParameters() + .buildForContext(new SignatureContext(SignatureContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ECDSA_DO_SIGN_EX = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("ECDSA_do_sign_ex") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDSA-SIGN")) + .withAnyParameters() + .buildForContext(new SignatureContext(SignatureContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ECDSA_SIZE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("ECDSA_size") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDSA")) + .withAnyParameters() + .buildForContext(new SignatureContext(SignatureContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // ECDH Key Agreement functions + // ==================================================================== + + private static final IDetectionRule ECDH_COMPUTE_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("ECDH_compute_key") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDH")) + .withAnyParameters() + .buildForContext(new KeyAgreementContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // EC Group/Curve functions + // ==================================================================== + + private static final IDetectionRule EC_GROUP_NEW_BY_CURVE_NAME = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EC_GROUP_new_by_curve_name") + .shouldBeDetectedAs(new ValueActionFactory<>("EC")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EC_GROUP_NEW_CURVE_GFP = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EC_GROUP_new_curve_GFp") + .shouldBeDetectedAs(new ValueActionFactory<>("EC-GFP")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EC_GROUP_NEW_CURVE_GF2M = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EC_GROUP_new_curve_GF2m") + .shouldBeDetectedAs(new ValueActionFactory<>("EC-GF2M")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // EC Point Operation functions + // ==================================================================== + + private static final IDetectionRule EC_POINT_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EC_POINT_new") + .shouldBeDetectedAs(new ValueActionFactory<>("EC")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EC_POINT_MUL = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EC_POINT_mul") + .shouldBeDetectedAs(new ValueActionFactory<>("EC")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private OpenSSLLegacyEc() { + // nothing + } + + @Nonnull + public static List> rules() { + return List.of( + // EC Key Management + EC_KEY_NEW, + EC_KEY_NEW_BY_CURVE_NAME, + EC_KEY_GENERATE_KEY, + EC_KEY_CHECK_KEY, + EC_KEY_SET_PUBLIC_KEY, + EC_KEY_SET_PRIVATE_KEY, + // ECDSA Signatures + ECDSA_SIGN, + ECDSA_VERIFY, + ECDSA_DO_SIGN, + ECDSA_DO_VERIFY, + ECDSA_SIGN_SETUP, + ECDSA_SIGN_EX, + ECDSA_DO_SIGN_EX, + ECDSA_SIZE, + // ECDH Key Agreement + ECDH_COMPUTE_KEY, + // EC Group/Curve + EC_GROUP_NEW_BY_CURVE_NAME, + EC_GROUP_NEW_CURVE_GFP, + EC_GROUP_NEW_CURVE_GF2M, + // EC Point Operations + EC_POINT_NEW, + EC_POINT_MUL); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/legacy/OpenSSLLegacyMac.java b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/legacy/OpenSSLLegacyMac.java new file mode 100644 index 000000000..73094a59e --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/legacy/OpenSSLLegacyMac.java @@ -0,0 +1,258 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.openssl.legacy; + +import com.ibm.engine.model.context.MacContext; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.List; +import javax.annotation.Nonnull; + +/** + * Detection rules for OpenSSL legacy MAC (Message Authentication Code) APIs. + * + *

These rules detect MAC operations using the legacy (pre-EVP) APIs. These APIs are deprecated + * but still widely used in existing codebases. + * + *

Covers: HMAC, CMAC + */ +@SuppressWarnings("java:S1192") +public final class OpenSSLLegacyMac { + + private static final String BUNDLE = "OpenSSL"; + + // ==================================================================== + // Legacy HMAC functions + // ==================================================================== + + private static final IDetectionRule HMAC_CTX_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("HMAC_CTX_new") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC")) + .withoutParameters() + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule HMAC_CTX_RESET = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("HMAC_CTX_reset") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC")) + .withAnyParameters() + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule HMAC_CTX_COPY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("HMAC_CTX_copy") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC")) + .withAnyParameters() + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule HMAC_INIT_EX = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("HMAC_Init_ex") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC")) + .withAnyParameters() + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule HMAC_INIT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("HMAC_Init") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC")) + .withAnyParameters() + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule HMAC_UPDATE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("HMAC_Update") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC")) + .withAnyParameters() + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule HMAC_FINAL = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("HMAC_Final") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC")) + .withAnyParameters() + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule HMAC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("HMAC") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC")) + .withAnyParameters() + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Legacy CMAC functions + // ==================================================================== + + private static final IDetectionRule CMAC_CTX_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("CMAC_CTX_new") + .shouldBeDetectedAs(new ValueActionFactory<>("CMAC")) + .withAnyParameters() + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule CMAC_INIT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("CMAC_Init") + .shouldBeDetectedAs(new ValueActionFactory<>("CMAC")) + .withAnyParameters() + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule CMAC_UPDATE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("CMAC_Update") + .shouldBeDetectedAs(new ValueActionFactory<>("CMAC")) + .withAnyParameters() + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule CMAC_FINAL = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("CMAC_Final") + .shouldBeDetectedAs(new ValueActionFactory<>("CMAC")) + .withAnyParameters() + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule CMAC_RESUME = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("CMAC_resume") + .shouldBeDetectedAs(new ValueActionFactory<>("CMAC")) + .withAnyParameters() + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Legacy Poly1305 functions + // ==================================================================== + + private static final IDetectionRule POLY1305_INIT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("Poly1305_Init") + .shouldBeDetectedAs(new ValueActionFactory<>("POLY1305")) + .withAnyParameters() + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule POLY1305_UPDATE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("Poly1305_Update") + .shouldBeDetectedAs(new ValueActionFactory<>("POLY1305")) + .withAnyParameters() + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule POLY1305_FINAL = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("Poly1305_Final") + .shouldBeDetectedAs(new ValueActionFactory<>("POLY1305")) + .withAnyParameters() + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private OpenSSLLegacyMac() { + // nothing + } + + @Nonnull + public static List> rules() { + return List.of( + // HMAC + HMAC_CTX_NEW, + HMAC_CTX_RESET, + HMAC_CTX_COPY, + HMAC_INIT_EX, + HMAC_INIT, + HMAC_UPDATE, + HMAC_FINAL, + HMAC, + // CMAC + CMAC_CTX_NEW, + CMAC_INIT, + CMAC_UPDATE, + CMAC_FINAL, + CMAC_RESUME, + // Poly1305 + POLY1305_INIT, + POLY1305_UPDATE, + POLY1305_FINAL); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/legacy/OpenSSLLegacyRsa.java b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/legacy/OpenSSLLegacyRsa.java new file mode 100644 index 000000000..d32a7719a --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/legacy/OpenSSLLegacyRsa.java @@ -0,0 +1,316 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.openssl.legacy; + +import com.ibm.engine.model.context.CipherContext; +import com.ibm.engine.model.context.KeyContext; +import com.ibm.engine.model.context.SignatureContext; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.List; +import javax.annotation.Nonnull; + +/** + * Detection rules for OpenSSL legacy RSA Direct API functions (from rsa.h). + * + *

These rules detect RSA operations using the legacy (pre-EVP) APIs. These APIs are deprecated + * but still widely used in existing codebases. + * + *

Covers: RSA key management, encryption/decryption, signing/verification, PSS, OAEP + */ +@SuppressWarnings("java:S1192") +public final class OpenSSLLegacyRsa { + + private static final String BUNDLE = "OpenSSL"; + + // ==================================================================== + // Key Management + // ==================================================================== + + private static final IDetectionRule RSA_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RSA_new") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RSA_GENERATE_KEY_EX = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RSA_generate_key_ex") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RSA_GENERATE_MULTI_PRIME_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RSA_generate_multi_prime_key") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Encryption + // ==================================================================== + + private static final IDetectionRule RSA_PUBLIC_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RSA_public_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-ENCRYPT")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RSA_PRIVATE_DECRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RSA_private_decrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-DECRYPT")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Signatures + // ==================================================================== + + private static final IDetectionRule RSA_SIGN = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RSA_sign") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-SIGN")) + .withAnyParameters() + .buildForContext(new SignatureContext(SignatureContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RSA_VERIFY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RSA_verify") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-VERIFY")) + .withAnyParameters() + .buildForContext(new SignatureContext(SignatureContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RSA_SIGN_ASN1_OCTET_STRING = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RSA_sign_ASN1_OCTET_STRING") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-SIGN")) + .withAnyParameters() + .buildForContext(new SignatureContext(SignatureContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RSA_VERIFY_ASN1_OCTET_STRING = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RSA_verify_ASN1_OCTET_STRING") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-VERIFY")) + .withAnyParameters() + .buildForContext(new SignatureContext(SignatureContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Reverse operations (legacy) + // ==================================================================== + + private static final IDetectionRule RSA_PRIVATE_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RSA_private_encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-SIGN")) + .withAnyParameters() + .buildForContext(new SignatureContext(SignatureContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RSA_PUBLIC_DECRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RSA_public_decrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-VERIFY")) + .withAnyParameters() + .buildForContext(new SignatureContext(SignatureContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Key validation + // ==================================================================== + + private static final IDetectionRule RSA_CHECK_KEY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RSA_check_key") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RSA_CHECK_KEY_EX = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RSA_check_key_ex") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA")) + .withAnyParameters() + .buildForContext(new KeyContext(KeyContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // PSS + // ==================================================================== + + private static final IDetectionRule RSA_PADDING_ADD_PKCS1_PSS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RSA_padding_add_PKCS1_PSS") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-PSS")) + .withAnyParameters() + .buildForContext(new SignatureContext(SignatureContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RSA_PADDING_ADD_PKCS1_PSS_MGF1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RSA_padding_add_PKCS1_PSS_mgf1") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-PSS")) + .withAnyParameters() + .buildForContext(new SignatureContext(SignatureContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RSA_VERIFY_PKCS1_PSS = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RSA_verify_PKCS1_PSS") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-PSS")) + .withAnyParameters() + .buildForContext(new SignatureContext(SignatureContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RSA_VERIFY_PKCS1_PSS_MGF1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RSA_verify_PKCS1_PSS_mgf1") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-PSS")) + .withAnyParameters() + .buildForContext(new SignatureContext(SignatureContext.Kind.NONE)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // OAEP + // ==================================================================== + + private static final IDetectionRule RSA_PADDING_ADD_PKCS1_OAEP = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RSA_padding_add_PKCS1_OAEP") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-OAEP")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RSA_PADDING_ADD_PKCS1_OAEP_MGF1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RSA_padding_add_PKCS1_OAEP_mgf1") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-OAEP")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private OpenSSLLegacyRsa() { + // nothing + } + + @Nonnull + public static List> rules() { + return List.of( + // Key Management + RSA_NEW, + RSA_GENERATE_KEY_EX, + RSA_GENERATE_MULTI_PRIME_KEY, + // Encryption + RSA_PUBLIC_ENCRYPT, + RSA_PRIVATE_DECRYPT, + // Signatures + RSA_SIGN, + RSA_VERIFY, + RSA_SIGN_ASN1_OCTET_STRING, + RSA_VERIFY_ASN1_OCTET_STRING, + // Reverse operations (legacy) + RSA_PRIVATE_ENCRYPT, + RSA_PUBLIC_DECRYPT, + // Key validation + RSA_CHECK_KEY, + RSA_CHECK_KEY_EX, + // PSS + RSA_PADDING_ADD_PKCS1_PSS, + RSA_PADDING_ADD_PKCS1_PSS_MGF1, + RSA_VERIFY_PKCS1_PSS, + RSA_VERIFY_PKCS1_PSS_MGF1, + // OAEP + RSA_PADDING_ADD_PKCS1_OAEP, + RSA_PADDING_ADD_PKCS1_OAEP_MGF1); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/mac/OpenSSLEvpMac.java b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/mac/OpenSSLEvpMac.java new file mode 100644 index 000000000..6229c8a37 --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/mac/OpenSSLEvpMac.java @@ -0,0 +1,567 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.openssl.mac; + +import com.ibm.engine.model.context.MacContext; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.List; +import javax.annotation.Nonnull; + +/** + * Detection rules for OpenSSL EVP MAC (Message Authentication Code) algorithms. + * + *

These rules detect calls to OpenSSL MAC functions using the EVP_MAC API. OpenSSL 3.x uses + * EVP_MAC_fetch() to obtain MAC algorithms like HMAC, CMAC, GMAC, Poly1305, etc. + * + *

Covers HMAC (with various digests), CMAC, GMAC, Poly1305, SipHash, KMAC, and BLAKE2 MAC. + */ +@SuppressWarnings("java:S1192") +public final class OpenSSLEvpMac { + + private static final String BUNDLE = "OpenSSL"; + + // ==================================================================== + // HMAC (Hash-based Message Authentication Code) + // ==================================================================== + + private static final IDetectionRule EVP_MAC_HMAC_MD5 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC-MD5")) + .withMethodParameter("*") + .withMethodParameter("\"HMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_HMAC_SHA1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC-SHA1")) + .withMethodParameter("*") + .withMethodParameter("\"HMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_HMAC_SHA224 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC-SHA224")) + .withMethodParameter("*") + .withMethodParameter("\"HMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_HMAC_SHA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC-SHA256")) + .withMethodParameter("*") + .withMethodParameter("\"HMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_HMAC_SHA384 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC-SHA384")) + .withMethodParameter("*") + .withMethodParameter("\"HMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_HMAC_SHA512 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC-SHA512")) + .withMethodParameter("*") + .withMethodParameter("\"HMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_HMAC_SHA3_224 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC-SHA3-224")) + .withMethodParameter("*") + .withMethodParameter("\"HMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_HMAC_SHA3_256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC-SHA3-256")) + .withMethodParameter("*") + .withMethodParameter("\"HMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_HMAC_SHA3_384 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC-SHA3-384")) + .withMethodParameter("*") + .withMethodParameter("\"HMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_HMAC_SHA3_512 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC-SHA3-512")) + .withMethodParameter("*") + .withMethodParameter("\"HMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_HMAC_SHA512_224 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC-SHA512/224")) + .withMethodParameter("*") + .withMethodParameter("\"HMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_HMAC_SHA512_256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC-SHA512/256")) + .withMethodParameter("*") + .withMethodParameter("\"HMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_HMAC_RIPEMD160 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC-RIPEMD160")) + .withMethodParameter("*") + .withMethodParameter("\"HMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_HMAC_BLAKE2B = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC-BLAKE2B")) + .withMethodParameter("*") + .withMethodParameter("\"HMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_HMAC_BLAKE2S = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC-BLAKE2S")) + .withMethodParameter("*") + .withMethodParameter("\"HMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_HMAC_SM3 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC-SM3")) + .withMethodParameter("*") + .withMethodParameter("\"HMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // CMAC (Cipher-based Message Authentication Code) + // ==================================================================== + + private static final IDetectionRule EVP_MAC_CMAC_AES128 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("CMAC-AES-128")) + .withMethodParameter("*") + .withMethodParameter("\"CMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_CMAC_AES192 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("CMAC-AES-192")) + .withMethodParameter("*") + .withMethodParameter("\"CMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_CMAC_AES256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("CMAC-AES-256")) + .withMethodParameter("*") + .withMethodParameter("\"CMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_CMAC_3DES = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("CMAC-3DES")) + .withMethodParameter("*") + .withMethodParameter("\"CMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_CMAC_CAMELLIA128 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("CMAC-CAMELLIA-128")) + .withMethodParameter("*") + .withMethodParameter("\"CMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_CMAC_CAMELLIA192 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("CMAC-CAMELLIA-192")) + .withMethodParameter("*") + .withMethodParameter("\"CMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_CMAC_CAMELLIA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("CMAC-CAMELLIA-256")) + .withMethodParameter("*") + .withMethodParameter("\"CMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_CMAC_ARIA128 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("CMAC-ARIA-128")) + .withMethodParameter("*") + .withMethodParameter("\"CMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_CMAC_ARIA192 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("CMAC-ARIA-192")) + .withMethodParameter("*") + .withMethodParameter("\"CMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_CMAC_ARIA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("CMAC-ARIA-256")) + .withMethodParameter("*") + .withMethodParameter("\"CMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_CMAC_SM4 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("CMAC-SM4")) + .withMethodParameter("*") + .withMethodParameter("\"CMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // GMAC (Galois Message Authentication Code) + // ==================================================================== + + private static final IDetectionRule EVP_MAC_GMAC_AES128 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("GMAC-AES-128")) + .withMethodParameter("*") + .withMethodParameter("\"GMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_GMAC_AES192 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("GMAC-AES-192")) + .withMethodParameter("*") + .withMethodParameter("\"GMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_GMAC_AES256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("GMAC-AES-256")) + .withMethodParameter("*") + .withMethodParameter("\"GMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Poly1305 + // ==================================================================== + + private static final IDetectionRule EVP_MAC_POLY1305 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("POLY1305")) + .withMethodParameter("*") + .withMethodParameter("\"Poly1305\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // SipHash + // ==================================================================== + + private static final IDetectionRule EVP_MAC_SIPHASH_2_4 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("SIPHASH-2-4")) + .withMethodParameter("*") + .withMethodParameter("\"SipHash\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_SIPHASH_4_8 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("SIPHASH-4-8")) + .withMethodParameter("*") + .withMethodParameter("\"SipHash\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // KMAC (Keccak Message Authentication Code) + // ==================================================================== + + private static final IDetectionRule EVP_MAC_KMAC128 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("KMAC128")) + .withMethodParameter("*") + .withMethodParameter("\"KMAC128\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_KMAC256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("KMAC256")) + .withMethodParameter("*") + .withMethodParameter("\"KMAC256\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // BLAKE2 MAC + // ==================================================================== + + private static final IDetectionRule EVP_MAC_BLAKE2BMAC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("BLAKE2BMAC")) + .withMethodParameter("*") + .withMethodParameter("\"BLAKE2BMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule EVP_MAC_BLAKE2SMAC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_MAC_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("BLAKE2SMAC")) + .withMethodParameter("*") + .withMethodParameter("\"BLAKE2SMAC\"") + .buildForContext(new MacContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private OpenSSLEvpMac() { + // nothing + } + + @Nonnull + public static List> rules() { + return List.of( + // HMAC + EVP_MAC_HMAC_MD5, + EVP_MAC_HMAC_SHA1, + EVP_MAC_HMAC_SHA224, + EVP_MAC_HMAC_SHA256, + EVP_MAC_HMAC_SHA384, + EVP_MAC_HMAC_SHA512, + EVP_MAC_HMAC_SHA512_224, + EVP_MAC_HMAC_SHA512_256, + EVP_MAC_HMAC_SHA3_224, + EVP_MAC_HMAC_SHA3_256, + EVP_MAC_HMAC_SHA3_384, + EVP_MAC_HMAC_SHA3_512, + EVP_MAC_HMAC_RIPEMD160, + EVP_MAC_HMAC_BLAKE2B, + EVP_MAC_HMAC_BLAKE2S, + EVP_MAC_HMAC_SM3, + // CMAC + EVP_MAC_CMAC_AES128, + EVP_MAC_CMAC_AES192, + EVP_MAC_CMAC_AES256, + EVP_MAC_CMAC_3DES, + EVP_MAC_CMAC_CAMELLIA128, + EVP_MAC_CMAC_CAMELLIA192, + EVP_MAC_CMAC_CAMELLIA256, + EVP_MAC_CMAC_ARIA128, + EVP_MAC_CMAC_ARIA192, + EVP_MAC_CMAC_ARIA256, + EVP_MAC_CMAC_SM4, + // GMAC + EVP_MAC_GMAC_AES128, + EVP_MAC_GMAC_AES192, + EVP_MAC_GMAC_AES256, + // Poly1305 + EVP_MAC_POLY1305, + // SipHash + EVP_MAC_SIPHASH_2_4, + EVP_MAC_SIPHASH_4_8, + // KMAC + EVP_MAC_KMAC128, + EVP_MAC_KMAC256, + // BLAKE2 MAC + EVP_MAC_BLAKE2BMAC, + EVP_MAC_BLAKE2SMAC); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/rand/OpenSSLRand.java b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/rand/OpenSSLRand.java new file mode 100644 index 000000000..969344c4e --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/rand/OpenSSLRand.java @@ -0,0 +1,333 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.openssl.rand; + +import com.ibm.engine.model.context.PRNGContext; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.List; +import javax.annotation.Nonnull; + +/** + * Detection rules for OpenSSL random number generation. + * + *

These rules detect random number generation through the RAND API and EVP_RAND API. Covers + * basic RAND_bytes operations and Deterministic Random Bit Generators (DRBG) using CTR, HASH, and + * HMAC modes. + */ +@SuppressWarnings("java:S1192") +public final class OpenSSLRand { + + private static final String BUNDLE = "OpenSSL"; + + // ==================================================================== + // Legacy RAND API + // ==================================================================== + + private static final IDetectionRule RAND_BYTES = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RAND_bytes") + .shouldBeDetectedAs(new ValueActionFactory<>("RAND")) + .withAnyParameters() + .buildForContext(new PRNGContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RAND_PRIV_BYTES = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RAND_priv_bytes") + .shouldBeDetectedAs(new ValueActionFactory<>("RAND")) + .withAnyParameters() + .buildForContext(new PRNGContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RAND_PSEUDO_BYTES = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RAND_pseudo_bytes") + .shouldBeDetectedAs(new ValueActionFactory<>("RAND-PSEUDO")) + .withAnyParameters() + .buildForContext(new PRNGContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // EVP_RAND API - CTR-DRBG (Counter mode DRBG) + // ==================================================================== + + private static final IDetectionRule CTR_DRBG_AES128 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_RAND_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("CTR-DRBG-AES128")) + .withMethodParameter("*") + .withMethodParameter("\"CTR-DRBG\"") + .buildForContext(new PRNGContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule CTR_DRBG_AES192 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_RAND_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("CTR-DRBG-AES192")) + .withMethodParameter("*") + .withMethodParameter("\"CTR-DRBG\"") + .buildForContext(new PRNGContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule CTR_DRBG_AES256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_RAND_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("CTR-DRBG-AES256")) + .withMethodParameter("*") + .withMethodParameter("\"CTR-DRBG\"") + .buildForContext(new PRNGContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // EVP_RAND API - HASH-DRBG (Hash-based DRBG) + // ==================================================================== + + private static final IDetectionRule HASH_DRBG_SHA1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_RAND_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HASH-DRBG-SHA1")) + .withMethodParameter("*") + .withMethodParameter("\"HASH-DRBG\"") + .buildForContext(new PRNGContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule HASH_DRBG_SHA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_RAND_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HASH-DRBG-SHA256")) + .withMethodParameter("*") + .withMethodParameter("\"HASH-DRBG\"") + .buildForContext(new PRNGContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule HASH_DRBG_SHA384 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_RAND_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HASH-DRBG-SHA384")) + .withMethodParameter("*") + .withMethodParameter("\"HASH-DRBG\"") + .buildForContext(new PRNGContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule HASH_DRBG_SHA512 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_RAND_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HASH-DRBG-SHA512")) + .withMethodParameter("*") + .withMethodParameter("\"HASH-DRBG\"") + .buildForContext(new PRNGContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // EVP_RAND API - HMAC-DRBG (HMAC-based DRBG) + // ==================================================================== + + private static final IDetectionRule HMAC_DRBG_SHA1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_RAND_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC-DRBG-SHA1")) + .withMethodParameter("*") + .withMethodParameter("\"HMAC-DRBG\"") + .buildForContext(new PRNGContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule HMAC_DRBG_SHA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_RAND_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC-DRBG-SHA256")) + .withMethodParameter("*") + .withMethodParameter("\"HMAC-DRBG\"") + .buildForContext(new PRNGContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule HMAC_DRBG_SHA384 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_RAND_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC-DRBG-SHA384")) + .withMethodParameter("*") + .withMethodParameter("\"HMAC-DRBG\"") + .buildForContext(new PRNGContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule HMAC_DRBG_SHA512 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_RAND_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("HMAC-DRBG-SHA512")) + .withMethodParameter("*") + .withMethodParameter("\"HMAC-DRBG\"") + .buildForContext(new PRNGContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // EVP_RAND API - Entropy Sources + // ==================================================================== + + private static final IDetectionRule SEED_SRC = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_RAND_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("SEED-SRC")) + .withMethodParameter("*") + .withMethodParameter("\"SEED-SRC\"") + .buildForContext(new PRNGContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule JITTER = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_RAND_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("JITTER")) + .withMethodParameter("*") + .withMethodParameter("\"JITTER\"") + .buildForContext(new PRNGContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule TEST_RAND = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_RAND_fetch") + .shouldBeDetectedAs(new ValueActionFactory<>("TEST-RAND")) + .withMethodParameter("*") + .withMethodParameter("\"TEST-RAND\"") + .buildForContext(new PRNGContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Legacy RAND Entropy Seeding + // ==================================================================== + + private static final IDetectionRule RAND_SEED = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RAND_seed") + .shouldBeDetectedAs(new ValueActionFactory<>("RAND-SEED")) + .withAnyParameters() + .buildForContext(new PRNGContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RAND_ADD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RAND_add") + .shouldBeDetectedAs(new ValueActionFactory<>("RAND-ADD")) + .withAnyParameters() + .buildForContext(new PRNGContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RAND_POLL = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("RAND_poll") + .shouldBeDetectedAs(new ValueActionFactory<>("RAND-POLL")) + .withoutParameters() + .buildForContext(new PRNGContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private OpenSSLRand() { + // nothing + } + + @Nonnull + public static List> rules() { + return List.of( + // Legacy RAND API + RAND_BYTES, + RAND_PRIV_BYTES, + RAND_PSEUDO_BYTES, + RAND_SEED, + RAND_ADD, + RAND_POLL, + // CTR-DRBG + CTR_DRBG_AES128, + CTR_DRBG_AES192, + CTR_DRBG_AES256, + // HASH-DRBG + HASH_DRBG_SHA1, + HASH_DRBG_SHA256, + HASH_DRBG_SHA384, + HASH_DRBG_SHA512, + // HMAC-DRBG + HMAC_DRBG_SHA1, + HMAC_DRBG_SHA256, + HMAC_DRBG_SHA384, + HMAC_DRBG_SHA512, + // Entropy Sources + SEED_SRC, + JITTER, + TEST_RAND); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/signature/OpenSSLEvpSignature.java b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/signature/OpenSSLEvpSignature.java new file mode 100644 index 000000000..ed5e364d6 --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/signature/OpenSSLEvpSignature.java @@ -0,0 +1,560 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.openssl.signature; + +import com.ibm.engine.model.context.SignatureContext; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.List; +import javax.annotation.Nonnull; + +/** + * Detection rules for OpenSSL signature operations. + * + *

These rules detect signature algorithm usage through EVP_DigestSign/Verify operations and + * EVP_PKEY operations that specify signature algorithms. + * + *

Covers RSA (PKCS#1 v1.5, PSS), DSA, ECDSA, EdDSA, post-quantum (ML-DSA, SLH-DSA), and SM2 + * signatures. + */ +@SuppressWarnings("java:S1192") +public final class OpenSSLEvpSignature { + + private static final String BUNDLE = "OpenSSL"; + + // ==================================================================== + // RSA Signatures - PKCS#1 v1.5 + // ==================================================================== + + private static final IDetectionRule RSA_PKCS1_SHA1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_DigestSignInit", "EVP_DigestVerifyInit") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-SHA1")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RSA_PKCS1_SHA224 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_DigestSignInit", "EVP_DigestVerifyInit") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-SHA224")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RSA_PKCS1_SHA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_DigestSignInit", "EVP_DigestVerifyInit") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-SHA256")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RSA_PKCS1_SHA384 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_DigestSignInit", "EVP_DigestVerifyInit") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-SHA384")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RSA_PKCS1_SHA512 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_DigestSignInit", "EVP_DigestVerifyInit") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-SHA512")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // RSA Signatures - PSS + // ==================================================================== + + private static final IDetectionRule RSA_PSS_SHA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_set_rsa_padding") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-PSS-SHA256")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RSA_PSS_SHA384 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_set_rsa_padding") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-PSS-SHA384")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule RSA_PSS_SHA512 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_CTX_set_rsa_padding") + .shouldBeDetectedAs(new ValueActionFactory<>("RSA-PSS-SHA512")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // DSA Signatures + // ==================================================================== + + private static final IDetectionRule DSA_SHA1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_DigestSignInit", "EVP_DigestVerifyInit") + .shouldBeDetectedAs(new ValueActionFactory<>("DSA-SHA1")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DSA_SHA224 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_DigestSignInit", "EVP_DigestVerifyInit") + .shouldBeDetectedAs(new ValueActionFactory<>("DSA-SHA224")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DSA_SHA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_DigestSignInit", "EVP_DigestVerifyInit") + .shouldBeDetectedAs(new ValueActionFactory<>("DSA-SHA256")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DSA_SHA384 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_DigestSignInit", "EVP_DigestVerifyInit") + .shouldBeDetectedAs(new ValueActionFactory<>("DSA-SHA384")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DSA_SHA512 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_DigestSignInit", "EVP_DigestVerifyInit") + .shouldBeDetectedAs(new ValueActionFactory<>("DSA-SHA512")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // ECDSA Signatures + // ==================================================================== + + private static final IDetectionRule ECDSA_SHA1 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_DigestSignInit", "EVP_DigestVerifyInit") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDSA-SHA1")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ECDSA_SHA224 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_DigestSignInit", "EVP_DigestVerifyInit") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDSA-SHA224")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ECDSA_SHA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_DigestSignInit", "EVP_DigestVerifyInit") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDSA-SHA256")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ECDSA_SHA384 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_DigestSignInit", "EVP_DigestVerifyInit") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDSA-SHA384")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ECDSA_SHA512 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_DigestSignInit", "EVP_DigestVerifyInit") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDSA-SHA512")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ECDSA_SHA3_256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_DigestSignInit", "EVP_DigestVerifyInit") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDSA-SHA3-256")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ECDSA_SHA3_384 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_DigestSignInit", "EVP_DigestVerifyInit") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDSA-SHA3-384")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ECDSA_SHA3_512 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_DigestSignInit", "EVP_DigestVerifyInit") + .shouldBeDetectedAs(new ValueActionFactory<>("ECDSA-SHA3-512")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // EdDSA Signatures + // ==================================================================== + + private static final IDetectionRule ED25519 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_DigestSign", "EVP_DigestVerify") + .shouldBeDetectedAs(new ValueActionFactory<>("ED25519")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ED448 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_DigestSign", "EVP_DigestVerify") + .shouldBeDetectedAs(new ValueActionFactory<>("ED448")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Post-Quantum Signatures - ML-DSA + // ==================================================================== + + private static final IDetectionRule ML_DSA_44 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_sign", "EVP_PKEY_verify") + .shouldBeDetectedAs(new ValueActionFactory<>("ML-DSA-44")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ML_DSA_65 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_sign", "EVP_PKEY_verify") + .shouldBeDetectedAs(new ValueActionFactory<>("ML-DSA-65")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule ML_DSA_87 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_sign", "EVP_PKEY_verify") + .shouldBeDetectedAs(new ValueActionFactory<>("ML-DSA-87")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Post-Quantum Signatures - SLH-DSA + // ==================================================================== + + private static final IDetectionRule SLH_DSA_SHA2_128F = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_sign", "EVP_PKEY_verify") + .shouldBeDetectedAs(new ValueActionFactory<>("SLH-DSA-SHA2-128F")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SLH_DSA_SHA2_128S = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_sign", "EVP_PKEY_verify") + .shouldBeDetectedAs(new ValueActionFactory<>("SLH-DSA-SHA2-128S")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SLH_DSA_SHAKE_128F = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_sign", "EVP_PKEY_verify") + .shouldBeDetectedAs(new ValueActionFactory<>("SLH-DSA-SHAKE-128F")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SLH_DSA_SHAKE_128S = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_sign", "EVP_PKEY_verify") + .shouldBeDetectedAs(new ValueActionFactory<>("SLH-DSA-SHAKE-128S")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SLH_DSA_SHA2_192F = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_sign", "EVP_PKEY_verify") + .shouldBeDetectedAs(new ValueActionFactory<>("SLH-DSA-SHA2-192F")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SLH_DSA_SHA2_192S = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_sign", "EVP_PKEY_verify") + .shouldBeDetectedAs(new ValueActionFactory<>("SLH-DSA-SHA2-192S")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SLH_DSA_SHAKE_192F = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_sign", "EVP_PKEY_verify") + .shouldBeDetectedAs(new ValueActionFactory<>("SLH-DSA-SHAKE-192F")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SLH_DSA_SHAKE_192S = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_sign", "EVP_PKEY_verify") + .shouldBeDetectedAs(new ValueActionFactory<>("SLH-DSA-SHAKE-192S")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SLH_DSA_SHA2_256F = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_sign", "EVP_PKEY_verify") + .shouldBeDetectedAs(new ValueActionFactory<>("SLH-DSA-SHA2-256F")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SLH_DSA_SHA2_256S = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_sign", "EVP_PKEY_verify") + .shouldBeDetectedAs(new ValueActionFactory<>("SLH-DSA-SHA2-256S")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SLH_DSA_SHAKE_256F = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_sign", "EVP_PKEY_verify") + .shouldBeDetectedAs(new ValueActionFactory<>("SLH-DSA-SHAKE-256F")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SLH_DSA_SHAKE_256S = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_PKEY_sign", "EVP_PKEY_verify") + .shouldBeDetectedAs(new ValueActionFactory<>("SLH-DSA-SHAKE-256S")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // SM2 Signature + // ==================================================================== + + private static final IDetectionRule SM2 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("EVP_DigestSignInit", "EVP_DigestVerifyInit") + .shouldBeDetectedAs(new ValueActionFactory<>("SM2")) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private OpenSSLEvpSignature() { + // nothing + } + + @Nonnull + public static List> rules() { + return List.of( + // RSA PKCS#1 v1.5 + RSA_PKCS1_SHA1, + RSA_PKCS1_SHA224, + RSA_PKCS1_SHA256, + RSA_PKCS1_SHA384, + RSA_PKCS1_SHA512, + // RSA-PSS + RSA_PSS_SHA256, + RSA_PSS_SHA384, + RSA_PSS_SHA512, + // DSA + DSA_SHA1, + DSA_SHA224, + DSA_SHA256, + DSA_SHA384, + DSA_SHA512, + // ECDSA + ECDSA_SHA1, + ECDSA_SHA224, + ECDSA_SHA256, + ECDSA_SHA384, + ECDSA_SHA512, + ECDSA_SHA3_256, + ECDSA_SHA3_384, + ECDSA_SHA3_512, + // EdDSA + ED25519, + ED448, + // ML-DSA (Post-Quantum) + ML_DSA_44, + ML_DSA_65, + ML_DSA_87, + // SLH-DSA (Post-Quantum) + SLH_DSA_SHA2_128F, + SLH_DSA_SHA2_128S, + SLH_DSA_SHAKE_128F, + SLH_DSA_SHAKE_128S, + SLH_DSA_SHA2_192F, + SLH_DSA_SHA2_192S, + SLH_DSA_SHAKE_192F, + SLH_DSA_SHAKE_192S, + SLH_DSA_SHA2_256F, + SLH_DSA_SHA2_256S, + SLH_DSA_SHAKE_256F, + SLH_DSA_SHAKE_256S, + // SM2 + SM2); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/ssl/OpenSSLLibssl.java b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/ssl/OpenSSLLibssl.java new file mode 100644 index 000000000..ec9d70e87 --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/ssl/OpenSSLLibssl.java @@ -0,0 +1,649 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.openssl.ssl; + +import com.ibm.engine.model.context.ProtocolContext; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.List; +import javax.annotation.Nonnull; + +/** + * Detection rules for OpenSSL libssl (SSL/TLS protocol) functions. + * + *

These rules detect usage of SSL/TLS protocol functions including protocol version selection, + * context creation, and cipher suite configuration. Covers TLS 1.0-1.3, DTLS 1.0-1.2, QUIC, and + * SSLv3. + */ +@SuppressWarnings("java:S1192") +public final class OpenSSLLibssl { + + private static final String BUNDLE = "OpenSSL"; + + // ==================================================================== + // TLS Generic (Version Negotiation) + // ==================================================================== + + private static final IDetectionRule TLS_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("TLS_method") + .shouldBeDetectedAs(new ValueActionFactory<>("TLS")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule TLS_CLIENT_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("TLS_client_method") + .shouldBeDetectedAs(new ValueActionFactory<>("TLS")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule TLS_SERVER_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("TLS_server_method") + .shouldBeDetectedAs(new ValueActionFactory<>("TLS")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // TLS 1.3 (RFC 8446) + // ==================================================================== + + private static final IDetectionRule TLSV1_3_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("TLSv1_3_method") + .shouldBeDetectedAs(new ValueActionFactory<>("TLSv1.3")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule TLSV1_3_CLIENT_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("TLSv1_3_client_method") + .shouldBeDetectedAs(new ValueActionFactory<>("TLSv1.3")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule TLSV1_3_SERVER_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("TLSv1_3_server_method") + .shouldBeDetectedAs(new ValueActionFactory<>("TLSv1.3")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // TLS 1.2 (RFC 5246) + // ==================================================================== + + private static final IDetectionRule TLSV1_2_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("TLSv1_2_method") + .shouldBeDetectedAs(new ValueActionFactory<>("TLSv1.2")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule TLSV1_2_CLIENT_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("TLSv1_2_client_method") + .shouldBeDetectedAs(new ValueActionFactory<>("TLSv1.2")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule TLSV1_2_SERVER_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("TLSv1_2_server_method") + .shouldBeDetectedAs(new ValueActionFactory<>("TLSv1.2")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // TLS 1.1 (Deprecated) + // ==================================================================== + + private static final IDetectionRule TLSV1_1_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("TLSv1_1_method") + .shouldBeDetectedAs(new ValueActionFactory<>("TLSv1.1")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule TLSV1_1_CLIENT_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("TLSv1_1_client_method") + .shouldBeDetectedAs(new ValueActionFactory<>("TLSv1.1")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule TLSV1_1_SERVER_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("TLSv1_1_server_method") + .shouldBeDetectedAs(new ValueActionFactory<>("TLSv1.1")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // TLS 1.0 (Deprecated) + // ==================================================================== + + private static final IDetectionRule TLSV1_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("TLSv1_method") + .shouldBeDetectedAs(new ValueActionFactory<>("TLSv1.0")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule TLSV1_CLIENT_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("TLSv1_client_method") + .shouldBeDetectedAs(new ValueActionFactory<>("TLSv1.0")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule TLSV1_SERVER_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("TLSv1_server_method") + .shouldBeDetectedAs(new ValueActionFactory<>("TLSv1.0")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // SSL 3.0 (Insecure - disabled by default) + // ==================================================================== + + private static final IDetectionRule SSLV3_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SSLv3_method") + .shouldBeDetectedAs(new ValueActionFactory<>("SSLv3.0")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SSLV3_CLIENT_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SSLv3_client_method") + .shouldBeDetectedAs(new ValueActionFactory<>("SSLv3.0")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SSLV3_SERVER_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SSLv3_server_method") + .shouldBeDetectedAs(new ValueActionFactory<>("SSLv3.0")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // DTLS Generic + // ==================================================================== + + private static final IDetectionRule DTLS_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DTLS_method") + .shouldBeDetectedAs(new ValueActionFactory<>("DTLS")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DTLS_CLIENT_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DTLS_client_method") + .shouldBeDetectedAs(new ValueActionFactory<>("DTLS")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DTLS_SERVER_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DTLS_server_method") + .shouldBeDetectedAs(new ValueActionFactory<>("DTLS")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // DTLS 1.2 (RFC 6347) + // ==================================================================== + + private static final IDetectionRule DTLSV1_2_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DTLSv1_2_method") + .shouldBeDetectedAs(new ValueActionFactory<>("DTLSv1.2")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DTLSV1_2_CLIENT_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DTLSv1_2_client_method") + .shouldBeDetectedAs(new ValueActionFactory<>("DTLSv1.2")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DTLSV1_2_SERVER_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DTLSv1_2_server_method") + .shouldBeDetectedAs(new ValueActionFactory<>("DTLSv1.2")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // DTLS 1.0 (Deprecated) + // ==================================================================== + + private static final IDetectionRule DTLSV1_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DTLSv1_method") + .shouldBeDetectedAs(new ValueActionFactory<>("DTLSv1.0")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DTLSV1_CLIENT_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DTLSv1_client_method") + .shouldBeDetectedAs(new ValueActionFactory<>("DTLSv1.0")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule DTLSV1_SERVER_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("DTLSv1_server_method") + .shouldBeDetectedAs(new ValueActionFactory<>("DTLSv1.0")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // QUIC (RFC 9000 - OpenSSL 3.2+) + // ==================================================================== + + private static final IDetectionRule OSSL_QUIC_CLIENT_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("OSSL_QUIC_client_method") + .shouldBeDetectedAs(new ValueActionFactory<>("QUIC")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule OSSL_QUIC_CLIENT_THREAD_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("OSSL_QUIC_client_thread_method") + .shouldBeDetectedAs(new ValueActionFactory<>("QUIC")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule OSSL_QUIC_SERVER_METHOD = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("OSSL_QUIC_server_method") + .shouldBeDetectedAs(new ValueActionFactory<>("QUIC")) + .withoutParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // SSL_CTX_new - Context creation (detects SSL/TLS usage) + // ==================================================================== + + private static final IDetectionRule SSL_CTX_NEW = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SSL_CTX_new") + .shouldBeDetectedAs(new ValueActionFactory<>("TLS")) + .withAnyParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Cipher Suite Configuration + // ==================================================================== + + private static final IDetectionRule SSL_CTX_SET_CIPHER_LIST = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SSL_CTX_set_cipher_list") + .shouldBeDetectedAs(new ValueActionFactory<>("TLS-CIPHER-CONFIG")) + .withAnyParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SSL_SET_CIPHER_LIST = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SSL_set_cipher_list") + .shouldBeDetectedAs(new ValueActionFactory<>("TLS-CIPHER-CONFIG")) + .withAnyParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SSL_CTX_SET_CIPHERSUITES = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SSL_CTX_set_ciphersuites") + .shouldBeDetectedAs(new ValueActionFactory<>("TLS1.3-CIPHER-CONFIG")) + .withAnyParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SSL_SET_CIPHERSUITES = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SSL_set_ciphersuites") + .shouldBeDetectedAs(new ValueActionFactory<>("TLS1.3-CIPHER-CONFIG")) + .withAnyParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // Protocol Version Configuration + // ==================================================================== + + /** + * Detects SSL_CTX_set_min_proto_version calls and extracts version parameter. + * + *

Uses {@link OpenSSLVersionDetectionFactory} to extract the version parameter value during + * detection phase (workaround for C++ detection engine parameter extraction limitations). + * + *

The factory creates {@link OpenSSLVersionValue} which uses {@link + * org.sonar.cxx.utils.CxxConstantUtils} to resolve constants like TLS1_2_VERSION (0x0303) to + * actual integer values, then maps them to version strings like "TLSv1.2". + */ + private static final IDetectionRule SSL_CTX_SET_MIN_PROTO_VERSION = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SSL_CTX_set_min_proto_version") + .shouldBeDetectedAs(new OpenSSLVersionDetectionFactory("MIN")) + .withAnyParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + /** + * Detects SSL_CTX_set_max_proto_version calls and extracts version parameter. + * + *

Uses {@link OpenSSLVersionDetectionFactory} to extract the version parameter value during + * detection phase (workaround for C++ detection engine parameter extraction limitations). + * + *

The factory creates {@link OpenSSLVersionValue} which uses {@link + * org.sonar.cxx.utils.CxxConstantUtils} to resolve constants like TLS1_3_VERSION (0x0304) to + * actual integer values, then maps them to version strings like "TLSv1.3". + */ + private static final IDetectionRule SSL_CTX_SET_MAX_PROTO_VERSION = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SSL_CTX_set_max_proto_version") + .shouldBeDetectedAs(new OpenSSLVersionDetectionFactory("MAX")) + .withAnyParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // SSL Connection Operations + // ==================================================================== + + private static final IDetectionRule SSL_CONNECT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SSL_connect") + .shouldBeDetectedAs(new ValueActionFactory<>("TLS")) + .withAnyParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SSL_ACCEPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SSL_accept") + .shouldBeDetectedAs(new ValueActionFactory<>("TLS")) + .withAnyParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SSL_DO_HANDSHAKE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SSL_do_handshake") + .shouldBeDetectedAs(new ValueActionFactory<>("TLS")) + .withAnyParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + // ==================================================================== + // TLS 1.3 Early Data (0-RTT) + // ==================================================================== + + private static final IDetectionRule SSL_WRITE_EARLY_DATA = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SSL_write_early_data") + .shouldBeDetectedAs(new ValueActionFactory<>("TLSv1.3-0RTT")) + .withAnyParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private static final IDetectionRule SSL_READ_EARLY_DATA = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("*") + .forMethods("SSL_read_early_data") + .shouldBeDetectedAs(new ValueActionFactory<>("TLSv1.3-0RTT")) + .withAnyParameters() + .buildForContext(new ProtocolContext(ProtocolContext.Kind.TLS)) + .inBundle(() -> BUNDLE) + .withoutDependingDetectionRules(); + + private OpenSSLLibssl() { + // nothing + } + + @Nonnull + public static List> rules() { + return List.of( + // TLS Generic + TLS_METHOD, + TLS_CLIENT_METHOD, + TLS_SERVER_METHOD, + // TLS 1.3 + TLSV1_3_METHOD, + TLSV1_3_CLIENT_METHOD, + TLSV1_3_SERVER_METHOD, + // TLS 1.2 + TLSV1_2_METHOD, + TLSV1_2_CLIENT_METHOD, + TLSV1_2_SERVER_METHOD, + // TLS 1.1 (Deprecated) + TLSV1_1_METHOD, + TLSV1_1_CLIENT_METHOD, + TLSV1_1_SERVER_METHOD, + // TLS 1.0 (Deprecated) + TLSV1_METHOD, + TLSV1_CLIENT_METHOD, + TLSV1_SERVER_METHOD, + // SSL 3.0 (Insecure) + SSLV3_METHOD, + SSLV3_CLIENT_METHOD, + SSLV3_SERVER_METHOD, + // DTLS Generic + DTLS_METHOD, + DTLS_CLIENT_METHOD, + DTLS_SERVER_METHOD, + // DTLS 1.2 + DTLSV1_2_METHOD, + DTLSV1_2_CLIENT_METHOD, + DTLSV1_2_SERVER_METHOD, + // DTLS 1.0 (Deprecated) + DTLSV1_METHOD, + DTLSV1_CLIENT_METHOD, + DTLSV1_SERVER_METHOD, + // QUIC + OSSL_QUIC_CLIENT_METHOD, + OSSL_QUIC_CLIENT_THREAD_METHOD, + OSSL_QUIC_SERVER_METHOD, + // SSL Context + SSL_CTX_NEW, + // Cipher Configuration + SSL_CTX_SET_CIPHER_LIST, + SSL_SET_CIPHER_LIST, + SSL_CTX_SET_CIPHERSUITES, + SSL_SET_CIPHERSUITES, + // Protocol Version Configuration + SSL_CTX_SET_MIN_PROTO_VERSION, + SSL_CTX_SET_MAX_PROTO_VERSION, + // Connection Operations + SSL_CONNECT, + SSL_ACCEPT, + SSL_DO_HANDSHAKE, + // TLS 1.3 Early Data + SSL_WRITE_EARLY_DATA, + SSL_READ_EARLY_DATA); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/ssl/OpenSSLVersionDetectionFactory.java b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/ssl/OpenSSLVersionDetectionFactory.java new file mode 100644 index 000000000..1d1dd925c --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/ssl/OpenSSLVersionDetectionFactory.java @@ -0,0 +1,50 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.openssl.ssl; + +import com.ibm.engine.model.IAction; +import com.ibm.engine.model.factory.IActionFactory; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.Optional; +import javax.annotation.Nonnull; + +/** + * Factory for creating OpenSSL version detection values. + * + *

This factory creates {@link OpenSSLVersionValue} instances which extract and resolve version + * parameters from SSL_CTX_set_min/max_proto_version function calls. + * + *

Used as a workaround for C++ detection engine limitations with parameter extraction via the + * builder API. + */ +public final class OpenSSLVersionDetectionFactory implements IActionFactory { + + @Nonnull private final String kind; // "MIN" or "MAX" + + public OpenSSLVersionDetectionFactory(@Nonnull String kind) { + this.kind = kind; + } + + @Nonnull + @Override + public Optional> apply(@Nonnull AstNode astNode) { + return Optional.of(new OpenSSLVersionValue(kind, astNode)); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/ssl/OpenSSLVersionValue.java b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/ssl/OpenSSLVersionValue.java new file mode 100644 index 000000000..c3f0dd3d9 --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/rules/detection/openssl/ssl/OpenSSLVersionValue.java @@ -0,0 +1,220 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.openssl.ssl; + +import com.ibm.engine.model.IAction; +import com.sonar.cxx.sslr.api.AstNode; +import com.sonar.cxx.sslr.api.GenericTokenType; +import java.util.List; +import java.util.Map; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.cxx.parser.CxxTokenType; +import org.sonar.cxx.utils.CxxAstNodeHelper; +import org.sonar.cxx.utils.CxxConstantUtils; + +/** + * Specialized IAction for OpenSSL protocol version detection. + * + *

Extracts the version parameter from SSL_CTX_set_min/max_proto_version calls by directly + * navigating the C++ AST structure and resolves it to a human-readable version string. + * + *

The sonar-cxx parser represents a call like {@code SSL_CTX_set_min_proto_version(ctx, 0x0303)} + * with a single argument node that has three children: {@code ctx} (IDENTIFIER), {@code ,} (COMMA), + * and {@code 0x0303} (NUMBER). This class extracts the third child (index 2) as the version + * parameter. + * + *

Supports: + * + *

    + *
  • Direct hex literals (e.g., {@code 0x0303} → "TLSv1.2") + *
  • Compile-time constants via CxxConstantUtils (e.g., resolved {@code const int} variables) + *
  • Well-known OpenSSL constant names (e.g., {@code TLS1_2_VERSION} → "TLSv1.2") when the + * preprocessor does not expand them + *
  • Fallback to generic markers for unresolvable expressions (e.g., runtime variables) + *
+ */ +public final class OpenSSLVersionValue implements IAction { + private static final Logger LOGGER = LoggerFactory.getLogger(OpenSSLVersionValue.class); + + /** + * Maps well-known OpenSSL version constant names to their version strings. These constants are + * defined in {@code openssl/tls1.h} and {@code openssl/ssl3.h}. When the sonar-cxx preprocessor + * cannot expand these macros (e.g., headers not on the include path), they appear as bare + * IDENTIFIERs in the AST and must be resolved by name. + */ + private static final Map OPENSSL_VERSION_CONSTANTS = + Map.ofEntries( + Map.entry("SSL3_VERSION", "SSLv3.0"), // 0x0300 + Map.entry("TLS1_VERSION", "TLSv1.0"), // 0x0301 + Map.entry("TLS1_1_VERSION", "TLSv1.1"), // 0x0302 + Map.entry("TLS1_2_VERSION", "TLSv1.2"), // 0x0303 + Map.entry("TLS1_3_VERSION", "TLSv1.3"), // 0x0304 + Map.entry("DTLS1_VERSION", "DTLSv1.0"), // 0xFEFF + Map.entry("DTLS1_2_VERSION", "DTLSv1.2"), // 0xFEFD + Map.entry("DTLS1_BAD_VER", "DTLSv1.0")); // 0x0100 + + @Nonnull private final String kind; // "MIN" or "MAX" + @Nonnull private final AstNode methodCallNode; + + public OpenSSLVersionValue(@Nonnull String kind, @Nonnull AstNode methodCallNode) { + this.kind = kind; + this.methodCallNode = methodCallNode; + } + + @Nonnull + @Override + public AstNode getLocation() { + return methodCallNode; + } + + @Nonnull + @Override + public String asString() { + try { + List arguments = CxxAstNodeHelper.getFunctionCallArguments(methodCallNode); + + // The sonar-cxx parser collapses all arguments into a single initializerList node. + // Children: [0]=ctx (IDENTIFIER), [1]=, (COMMA), [2]=0x0303 (NUMBER/IDENTIFIER) + if (!arguments.isEmpty()) { + AstNode argList = arguments.get(0); + if (argList.getNumberOfChildren() >= 3) { + AstNode versionParam = argList.getChildren().get(2); + String resolved = resolveVersionString(versionParam); + if (resolved != null) { + LOGGER.debug("Resolved {} version parameter → \"{}\"", kind, resolved); + return resolved; + } + } + } + } catch (Exception e) { + LOGGER.warn("Error extracting {} version parameter: {}", kind, e.getMessage()); + } + + // Fallback to generic marker when version cannot be resolved + return "TLS-" + kind + "-VERSION"; + } + + /** + * Resolves a version parameter AST node to a version string. + * + *

Resolution strategy (in order): + * + *

    + *
  1. If the node is a NUMBER literal, parse it and map to a version string + *
  2. If the node is an IDENTIFIER matching a well-known OpenSSL constant name, map it + * directly (handles the case where the preprocessor did not expand the macro) + *
  3. Try CxxConstantUtils to resolve const variables or enum constants + *
  4. Traverse through single-child wrapper nodes and retry at each level + *
+ * + * @param versionParam The AST node representing the version parameter + * @return The version string (e.g., "TLSv1.2"), or null if resolution fails + */ + @Nullable private String resolveVersionString(@Nonnull AstNode versionParam) { + AstNode current = versionParam; + while (current != null) { + // 1. Direct NUMBER literal (e.g., 0x0303) + if (current.is(CxxTokenType.NUMBER)) { + return resolveNumberToVersionString(current.getTokenValue()); + } + + // 2. Well-known OpenSSL constant name (e.g., TLS1_2_VERSION) + if (current.is(GenericTokenType.IDENTIFIER)) { + String constantName = current.getTokenValue(); + String versionString = OPENSSL_VERSION_CONSTANTS.get(constantName); + if (versionString != null) { + LOGGER.debug( + "Resolved {} version from OpenSSL constant name: {} → \"{}\"", + kind, + constantName, + versionString); + return versionString; + } + } + + // 3. Try CxxConstantUtils (handles const variables, enum constants, expressions) + Object result = CxxConstantUtils.resolveAsConstant(current); + if (result instanceof Number num) { + String versionString = mapVersionToString(num.intValue()); + if (versionString != null) { + return versionString; + } + LOGGER.warn("Unknown version value {} for {} version", num.intValue(), kind); + return null; + } + + // 4. Descend through single-child wrapper nodes + if (current.getNumberOfChildren() == 1) { + current = current.getFirstChild(); + } else { + break; + } + } + return null; + } + + /** + * Parses a C++ number literal string and maps it to a version string. + * + * @param tokenValue The raw token value (e.g., "0x0303", "771", "0x0303u") + * @return The version string, or null if the number is unknown + */ + @Nullable private static String resolveNumberToVersionString(@Nonnull String tokenValue) { + try { + int value; + if (tokenValue.length() > 1 + && tokenValue.charAt(0) == '0' + && (tokenValue.charAt(1) == 'x' || tokenValue.charAt(1) == 'X')) { + // Hex literal: f/F are valid hex digits, so only strip integer suffixes (u/l) + String hex = tokenValue.replaceAll("[uUlL]+$", "").substring(2); + value = Integer.parseInt(hex, 16); + } else { + // Decimal/octal literal: strip all type suffixes including float suffix (f/F) + String dec = tokenValue.replaceAll("[uUlLfF]+$", ""); + value = Integer.parseInt(dec); + } + return mapVersionToString(value); + } catch (NumberFormatException e) { + return null; + } + } + + /** + * Maps an OpenSSL version integer to a human-readable version string. + * + * @param versionValue The integer version value (e.g., 0x0303 = 771) + * @return The version string (e.g., "TLSv1.2"), or null if the value is unknown + */ + @Nullable private static String mapVersionToString(int versionValue) { + return switch (versionValue) { + case 768 -> "SSLv3.0"; // 0x0300 + case 769 -> "TLSv1.0"; // 0x0301 + case 770 -> "TLSv1.1"; // 0x0302 + case 771 -> "TLSv1.2"; // 0x0303 + case 772 -> "TLSv1.3"; // 0x0304 + case 65279 -> "DTLSv1.0"; // 0xFEFF + case 65277 -> "DTLSv1.2"; // 0xFEFD + default -> null; + }; + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/translation/CxxTranslationProcess.java b/cpp/src/main/java/com/ibm/plugin/translation/CxxTranslationProcess.java new file mode 100644 index 000000000..fee88e72e --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/translation/CxxTranslationProcess.java @@ -0,0 +1,83 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.translation; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.enricher.Enricher; +import com.ibm.mapper.ITranslationProcess; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.reorganizer.IReorganizerRule; +import com.ibm.mapper.reorganizer.Reorganizer; +import com.ibm.mapper.utils.Utils; +import com.ibm.plugin.translation.translator.CxxTranslator; +import com.sonar.cxx.sslr.api.AstNode; +import com.sonar.cxx.sslr.api.Grammar; +import java.util.List; +import javax.annotation.Nonnull; +import org.sonar.cxx.squidbridge.SquidAstVisitorContext; +import org.sonar.cxx.squidbridge.api.Symbol; +import org.sonar.cxx.squidbridge.checks.SquidCheck; + +/** + * C++ translation process for converting detection findings to the mapper model. + * + *

This class implements the three-phase translation pipeline: + * + *

    + *
  1. Translate: Convert detection values to mapper model nodes + *
  2. Reorganize: Apply reorganizer rules to normalize the tree structure + *
  3. Enrich: Add additional algorithm details from the enricher + *
+ */ +public final class CxxTranslationProcess + extends ITranslationProcess< + SquidCheck, AstNode, Symbol, SquidAstVisitorContext> { + + public CxxTranslationProcess(@Nonnull List reorganizerRules) { + super(reorganizerRules); + } + + @Override + @Nonnull + public List initiate( + @Nonnull + DetectionStore< + SquidCheck, + AstNode, + Symbol, + SquidAstVisitorContext> + rootDetectionStore) { + // 1. Translate + final CxxTranslator cxxTranslator = new CxxTranslator(); + final List translatedValues = cxxTranslator.translate(rootDetectionStore); + Utils.printNodeTree("translated ", translatedValues); + + // 2. Reorganize + final Reorganizer cxxReorganizer = new Reorganizer(reorganizerRules); + final List reorganizedValues = cxxReorganizer.reorganize(translatedValues); + Utils.printNodeTree("reorganised", reorganizedValues); + + // 3. Enrich + final List enrichedValues = Enricher.enrich(reorganizedValues).stream().toList(); + Utils.printNodeTree("enriched ", enrichedValues); + + return enrichedValues.stream().toList(); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/translation/reorganizer/CxxReorganizerRules.java b/cpp/src/main/java/com/ibm/plugin/translation/reorganizer/CxxReorganizerRules.java new file mode 100644 index 000000000..15f9d7801 --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/translation/reorganizer/CxxReorganizerRules.java @@ -0,0 +1,71 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.translation.reorganizer; + +import com.ibm.mapper.model.Signature; +import com.ibm.mapper.model.functionality.Sign; +import com.ibm.mapper.reorganizer.IReorganizerRule; +import com.ibm.mapper.reorganizer.rules.AeadBlockCipherReorganizer; +import com.ibm.mapper.reorganizer.rules.AsymmetricBlockCipherReorganizer; +import com.ibm.mapper.reorganizer.rules.BlockCipherReorganizer; +import com.ibm.mapper.reorganizer.rules.CipherParameterReorganizer; +import com.ibm.mapper.reorganizer.rules.CipherSuiteReorganizer; +import com.ibm.mapper.reorganizer.rules.KeyReorgenizer; +import com.ibm.mapper.reorganizer.rules.MacReorganizer; +import com.ibm.mapper.reorganizer.rules.SignatureReorganizer; +import java.util.List; +import javax.annotation.Nonnull; + +/** + * Reorganizer rules for C++ detection results. + * + *

This class provides the reorganizer rules used to normalize the translation tree structure. + * The rules are the same as used in the Java module, as they operate on the language-agnostic + * mapper model. + */ +public final class CxxReorganizerRules { + private CxxReorganizerRules() { + // private + } + + @Nonnull + public static List rules() { + return List.of( + AeadBlockCipherReorganizer.MERGE_AE_PARENT_AND_CHILD, + AeadBlockCipherReorganizer.MOVE_TAG_LENGTH_UNDER_MAC, + AsymmetricBlockCipherReorganizer.INVERT_DIGEST_AND_ITS_SIZE, + AsymmetricBlockCipherReorganizer.MERGE_PKE_PARENT_AND_CHILD, + BlockCipherReorganizer.MERGE_BLOCK_CIPHER_PARENT_AND_CHILD, + CipherParameterReorganizer.MOVE_KEY_LENGTH_UNDER_TAG_LENGTH_UP, + CipherParameterReorganizer.MOVE_NODES_UNDER_DECRYPT_UP, + CipherParameterReorganizer.MOVE_NODES_UNDER_ENCRYPT_UP, + CipherSuiteReorganizer.ADD_TLS_PROTOCOL_AS_PARENT_NODE, + MacReorganizer.MERGE_UNKNOWN_MAC_PARENT_AND_CIPHER_CHILD, + MacReorganizer.MOVE_SOME_MAC_CHILDREN_UNDER_BLOCKCIPHER, + MacReorganizer.MOVE_TAG_LENGTH_UNDER_MAC, + SignatureReorganizer.MERGE_UNKNOWN_SIGNATURE_PARENT_AND_CHILD, + SignatureReorganizer.moveNodesFromUnderFunctionalityUnderParent( + Sign.class, Signature.class), + SignatureReorganizer.MERGE_SIGNATURE_PARENT_AND_CHILD, + KeyReorgenizer.SPECIFY_KEY_TYPE_BY_LOOKING_AT_KEY_GENERATION, + KeyReorgenizer.MOVE_KEY_UNDER_ALGORITHM_AND_REPLACE_INNER_ALGORITHM, + KeyReorgenizer.PROPAGATE_KEY_LENGTH_TO_BLOCK_CIPHER); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/translation/translator/CxxTranslator.java b/cpp/src/main/java/com/ibm/plugin/translation/translator/CxxTranslator.java new file mode 100644 index 000000000..046d98422 --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/translation/translator/CxxTranslator.java @@ -0,0 +1,227 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.translation.translator; + +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.context.AlgorithmParameterContext; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.engine.model.context.DigestContext; +import com.ibm.engine.model.context.IDetectionContext; +import com.ibm.engine.model.context.KeyAgreementContext; +import com.ibm.engine.model.context.KeyContext; +import com.ibm.engine.model.context.KeyDerivationFunctionContext; +import com.ibm.engine.model.context.MacContext; +import com.ibm.engine.model.context.PRNGContext; +import com.ibm.engine.model.context.PrivateKeyContext; +import com.ibm.engine.model.context.ProtocolContext; +import com.ibm.engine.model.context.PublicKeyContext; +import com.ibm.engine.model.context.SecretKeyContext; +import com.ibm.engine.model.context.SignatureContext; +import com.ibm.engine.rule.IBundle; +import com.ibm.mapper.ITranslator; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.utils.DetectionLocation; +import com.ibm.plugin.translation.translator.contexts.CxxCipherContextTranslator; +import com.ibm.plugin.translation.translator.contexts.CxxDigestContextTranslator; +import com.ibm.plugin.translation.translator.contexts.CxxKeyAgreementContextTranslator; +import com.ibm.plugin.translation.translator.contexts.CxxKeyContextTranslator; +import com.ibm.plugin.translation.translator.contexts.CxxKeyDerivationFunctionContextTranslator; +import com.ibm.plugin.translation.translator.contexts.CxxMacContextTranslator; +import com.ibm.plugin.translation.translator.contexts.CxxPRNGContextTranslator; +import com.ibm.plugin.translation.translator.contexts.CxxProtocolContextTranslator; +import com.ibm.plugin.translation.translator.contexts.CxxSecretKeyContextTranslator; +import com.ibm.plugin.translation.translator.contexts.CxxSignatureContextTranslator; +import com.sonar.cxx.sslr.api.AstNode; +import com.sonar.cxx.sslr.api.Grammar; +import com.sonar.cxx.sslr.api.Token; +import java.util.List; +import java.util.Optional; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.sonar.cxx.parser.CxxGrammarImpl; +import org.sonar.cxx.squidbridge.SquidAstVisitorContext; +import org.sonar.cxx.squidbridge.api.Symbol; +import org.sonar.cxx.squidbridge.checks.SquidCheck; +import org.sonar.cxx.utils.CxxAstNodeHelper; + +/** + * C++ translator for converting detection findings to the mapper model. + * + *

This class extends the base {@link ITranslator} and provides C++-specific translation logic + * for various cryptographic detection contexts (cipher, key, digest, signature, etc.). + * + *

The translator delegates to context-specific translators based on the detection context type. + */ +public final class CxxTranslator + extends ITranslator< + SquidCheck, AstNode, Symbol, SquidAstVisitorContext> { + + public CxxTranslator() { + // nothing + } + + @Override + @Nonnull + public Optional translate( + @Nonnull final IBundle bundleIdentifier, + @Nonnull final IValue value, + @Nonnull final IDetectionContext detectionValueContext, + @Nonnull final String filePath) { + DetectionLocation detectionLocation = + getDetectionContextFrom(value.getLocation(), bundleIdentifier, filePath); + if (detectionLocation == null) { + return Optional.empty(); + } + + // cipher context + if (detectionValueContext.is(CipherContext.class)) { + CxxCipherContextTranslator cxxCipherContextTranslation = + new CxxCipherContextTranslator(); + return cxxCipherContextTranslation.translate( + bundleIdentifier, value, detectionValueContext, detectionLocation); + + // secret key context + } else if (detectionValueContext.is(SecretKeyContext.class)) { + CxxSecretKeyContextTranslator cxxSecretKeyContextTranslation = + new CxxSecretKeyContextTranslator(); + return cxxSecretKeyContextTranslation.translate( + bundleIdentifier, value, detectionValueContext, detectionLocation); + + // private- / public- / secret- / key context + } else if (detectionValueContext.is(KeyContext.class) + || detectionValueContext.is(PublicKeyContext.class) + || detectionValueContext.is(PrivateKeyContext.class) + || detectionValueContext.is(SecretKeyContext.class)) { + CxxKeyContextTranslator cxxKeyContextTranslation = new CxxKeyContextTranslator(); + return cxxKeyContextTranslation.translate( + bundleIdentifier, value, detectionValueContext, detectionLocation); + + // key agreement context + } else if (detectionValueContext.is(KeyAgreementContext.class)) { + CxxKeyAgreementContextTranslator cxxKeyAgreementContextTranslation = + new CxxKeyAgreementContextTranslator(); + return cxxKeyAgreementContextTranslation.translate( + bundleIdentifier, value, detectionValueContext, detectionLocation); + + // PRNG context + } else if (detectionValueContext.is(PRNGContext.class)) { + CxxPRNGContextTranslator cxxPRNGContextTranslation = new CxxPRNGContextTranslator(); + return cxxPRNGContextTranslation.translate( + bundleIdentifier, value, detectionValueContext, detectionLocation); + + // digest context + } else if (detectionValueContext.is(DigestContext.class)) { + CxxDigestContextTranslator cxxDigestContextTranslation = + new CxxDigestContextTranslator(); + return cxxDigestContextTranslation.translate( + bundleIdentifier, value, detectionValueContext, detectionLocation); + + // signature context + } else if (detectionValueContext.is(SignatureContext.class)) { + CxxSignatureContextTranslator cxxSignatureContextTranslation = + new CxxSignatureContextTranslator(); + return cxxSignatureContextTranslation.translate( + bundleIdentifier, value, detectionValueContext, detectionLocation); + + // mac context + } else if (detectionValueContext.is(MacContext.class)) { + CxxMacContextTranslator cxxMacContextTranslation = new CxxMacContextTranslator(); + return cxxMacContextTranslation.translate( + bundleIdentifier, value, detectionValueContext, detectionLocation); + + // key derivation function context + } else if (detectionValueContext.is(KeyDerivationFunctionContext.class)) { + CxxKeyDerivationFunctionContextTranslator cxxKdfContextTranslation = + new CxxKeyDerivationFunctionContextTranslator(); + return cxxKdfContextTranslation.translate( + bundleIdentifier, value, detectionValueContext, detectionLocation); + + // algorithm parameter context + } else if (detectionValueContext.is(AlgorithmParameterContext.class)) { + // TODO: Implement CxxAlgorithmParameterContextTranslator + return Optional.empty(); + + // protocol + } else if (detectionValueContext.is(ProtocolContext.class)) { + CxxProtocolContextTranslator cxxProtocolContextTranslation = + new CxxProtocolContextTranslator(); + return cxxProtocolContextTranslation.translate( + bundleIdentifier, value, detectionValueContext, detectionLocation); + } + return Optional.empty(); + } + + /** + * Gets a detection location from the specified AstNode location and file path. + * + *

This method extracts line number, column offset, and keywords from the AST node to create + * a DetectionLocation for reporting findings. + */ + @Override + @Nullable public DetectionLocation getDetectionContextFrom( + @Nonnull AstNode location, @Nonnull IBundle bundle, @Nonnull String filePath) { + Token token = location.getToken(); + if (token == null) { + return null; + } + + int lineNumber = token.getLine(); + int offset = token.getColumn(); + List keywords = extractKeywords(location); + + return new DetectionLocation(filePath, lineNumber, offset, keywords, bundle); + } + + /** + * Extracts keywords from the AST node for the detection location. + * + * @param node The AST node to extract keywords from + * @return List of keywords (function name, etc.) + */ + @Nonnull + private List extractKeywords(@Nonnull AstNode node) { + // Try to extract function name for function calls + if (node.is(CxxGrammarImpl.postfixExpression)) { + if (CxxAstNodeHelper.isFunctionCall(node)) { + String functionName = CxxAstNodeHelper.getFunctionCallName(node); + if (functionName != null) { + return List.of(functionName); + } + } + } else if (node.is(CxxGrammarImpl.newExpression)) { + // For new expressions, try to get the type name from the type specifier + AstNode typeSpecifier = node.getFirstDescendant(CxxGrammarImpl.typeSpecifier); + if (typeSpecifier != null) { + String typeName = CxxAstNodeHelper.getIdentifierName(typeSpecifier); + if (typeName != null) { + return List.of(typeName); + } + } + } + + // Fallback to token value + Token token = node.getToken(); + if (token != null) { + return List.of(token.getValue()); + } + + return List.of(); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxCipherContextTranslator.java b/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxCipherContextTranslator.java new file mode 100644 index 000000000..37a302e72 --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxCipherContextTranslator.java @@ -0,0 +1,1233 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.translation.translator.contexts; + +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.IDetectionContext; +import com.ibm.engine.rule.IBundle; +import com.ibm.mapper.IContextTranslation; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Mode; +import com.ibm.mapper.model.PublicKeyEncryption; +import com.ibm.mapper.model.algorithms.AES; +import com.ibm.mapper.model.algorithms.Aria; +import com.ibm.mapper.model.algorithms.Blowfish; +import com.ibm.mapper.model.algorithms.Camellia; +import com.ibm.mapper.model.algorithms.ChaCha20; +import com.ibm.mapper.model.algorithms.ChaCha20Poly1305; +import com.ibm.mapper.model.algorithms.DES; +import com.ibm.mapper.model.algorithms.DESede; +import com.ibm.mapper.model.algorithms.IDEA; +import com.ibm.mapper.model.algorithms.RC2; +import com.ibm.mapper.model.algorithms.RC4; +import com.ibm.mapper.model.algorithms.RC5; +import com.ibm.mapper.model.algorithms.SEED; +import com.ibm.mapper.model.algorithms.SM2; +import com.ibm.mapper.model.algorithms.SM4; +import com.ibm.mapper.model.algorithms.cast.CAST128; +import com.ibm.mapper.utils.DetectionLocation; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.Optional; +import javax.annotation.Nonnull; + +public final class CxxCipherContextTranslator implements IContextTranslation { + + @Override + public @Nonnull Optional translate( + @Nonnull IBundle bundleIdentifier, + @Nonnull IValue value, + @Nonnull IDetectionContext detectionContext, + @Nonnull DetectionLocation detectionLocation) { + + if (value instanceof ValueAction) { + return switch (value.asString().toUpperCase().trim()) { + + // ================================================================ + // AES (Advanced Encryption Standard) + // ================================================================ + + // AES-128 + case "AES-128-CBC" -> + Optional.of( + new AES( + 128, + new Mode("CBC", detectionLocation), + detectionLocation)); + case "AES-128-ECB" -> + Optional.of( + new AES( + 128, + new Mode("ECB", detectionLocation), + detectionLocation)); + case "AES-128-GCM" -> + Optional.of( + new AES( + 128, + new Mode("GCM", detectionLocation), + detectionLocation)); + case "AES-128-CTR" -> + Optional.of( + new AES( + 128, + new Mode("CTR", detectionLocation), + detectionLocation)); + case "AES-128-CCM" -> + Optional.of( + new AES( + 128, + new Mode("CCM", detectionLocation), + detectionLocation)); + case "AES-128-CFB" -> + Optional.of( + new AES( + 128, + new Mode("CFB", detectionLocation), + detectionLocation)); + case "AES-128-CFB1" -> + Optional.of( + new AES( + 128, + new Mode("CFB1", detectionLocation), + detectionLocation)); + case "AES-128-CFB8" -> + Optional.of( + new AES( + 128, + new Mode("CFB8", detectionLocation), + detectionLocation)); + case "AES-128-CFB128" -> + Optional.of( + new AES( + 128, + new Mode("CFB128", detectionLocation), + detectionLocation)); + case "AES-128-OFB" -> + Optional.of( + new AES( + 128, + new Mode("OFB", detectionLocation), + detectionLocation)); + case "AES-128-XTS" -> + Optional.of( + new AES( + 128, + new Mode("XTS", detectionLocation), + detectionLocation)); + case "AES-128-OCB" -> + Optional.of( + new AES( + 128, + new Mode("OCB", detectionLocation), + detectionLocation)); + case "AES-128-WRAP" -> + Optional.of( + new AES( + 128, + new Mode("WRAP", detectionLocation), + detectionLocation)); + case "AES-128-WRAP-PAD" -> + Optional.of( + new AES( + 128, + new Mode("WRAP-PAD", detectionLocation), + detectionLocation)); + + // AES-192 + case "AES-192-CBC" -> + Optional.of( + new AES( + 192, + new Mode("CBC", detectionLocation), + detectionLocation)); + case "AES-192-ECB" -> + Optional.of( + new AES( + 192, + new Mode("ECB", detectionLocation), + detectionLocation)); + case "AES-192-GCM" -> + Optional.of( + new AES( + 192, + new Mode("GCM", detectionLocation), + detectionLocation)); + case "AES-192-CFB" -> + Optional.of( + new AES( + 192, + new Mode("CFB", detectionLocation), + detectionLocation)); + case "AES-192-CFB1" -> + Optional.of( + new AES( + 192, + new Mode("CFB1", detectionLocation), + detectionLocation)); + case "AES-192-CFB8" -> + Optional.of( + new AES( + 192, + new Mode("CFB8", detectionLocation), + detectionLocation)); + case "AES-192-CFB128" -> + Optional.of( + new AES( + 192, + new Mode("CFB128", detectionLocation), + detectionLocation)); + case "AES-192-OFB" -> + Optional.of( + new AES( + 192, + new Mode("OFB", detectionLocation), + detectionLocation)); + case "AES-192-OCB" -> + Optional.of( + new AES( + 192, + new Mode("OCB", detectionLocation), + detectionLocation)); + case "AES-192-WRAP" -> + Optional.of( + new AES( + 192, + new Mode("WRAP", detectionLocation), + detectionLocation)); + case "AES-192-WRAP-PAD" -> + Optional.of( + new AES( + 192, + new Mode("WRAP-PAD", detectionLocation), + detectionLocation)); + case "AES-192-CTR" -> + Optional.of( + new AES( + 192, + new Mode("CTR", detectionLocation), + detectionLocation)); + case "AES-192-CCM" -> + Optional.of( + new AES( + 192, + new Mode("CCM", detectionLocation), + detectionLocation)); + + // AES-256 + case "AES-256-CBC" -> + Optional.of( + new AES( + 256, + new Mode("CBC", detectionLocation), + detectionLocation)); + case "AES-256-ECB" -> + Optional.of( + new AES( + 256, + new Mode("ECB", detectionLocation), + detectionLocation)); + case "AES-256-GCM" -> + Optional.of( + new AES( + 256, + new Mode("GCM", detectionLocation), + detectionLocation)); + case "AES-256-CTR" -> + Optional.of( + new AES( + 256, + new Mode("CTR", detectionLocation), + detectionLocation)); + case "AES-256-CCM" -> + Optional.of( + new AES( + 256, + new Mode("CCM", detectionLocation), + detectionLocation)); + case "AES-256-CFB" -> + Optional.of( + new AES( + 256, + new Mode("CFB", detectionLocation), + detectionLocation)); + case "AES-256-CFB1" -> + Optional.of( + new AES( + 256, + new Mode("CFB1", detectionLocation), + detectionLocation)); + case "AES-256-CFB8" -> + Optional.of( + new AES( + 256, + new Mode("CFB8", detectionLocation), + detectionLocation)); + case "AES-256-CFB128" -> + Optional.of( + new AES( + 256, + new Mode("CFB128", detectionLocation), + detectionLocation)); + case "AES-256-OFB" -> + Optional.of( + new AES( + 256, + new Mode("OFB", detectionLocation), + detectionLocation)); + case "AES-256-XTS" -> + Optional.of( + new AES( + 256, + new Mode("XTS", detectionLocation), + detectionLocation)); + case "AES-256-OCB" -> + Optional.of( + new AES( + 256, + new Mode("OCB", detectionLocation), + detectionLocation)); + case "AES-256-WRAP" -> + Optional.of( + new AES( + 256, + new Mode("WRAP", detectionLocation), + detectionLocation)); + case "AES-256-WRAP-PAD" -> + Optional.of( + new AES( + 256, + new Mode("WRAP-PAD", detectionLocation), + detectionLocation)); + + // Provider-only AES modes (no EVP_* convenience functions) + case "AES-128-SIV" -> + Optional.of( + new AES( + 128, + new Mode("SIV", detectionLocation), + detectionLocation)); + case "AES-192-SIV" -> + Optional.of( + new AES( + 192, + new Mode("SIV", detectionLocation), + detectionLocation)); + case "AES-256-SIV" -> + Optional.of( + new AES( + 256, + new Mode("SIV", detectionLocation), + detectionLocation)); + case "AES-128-GCM-SIV" -> + Optional.of( + new AES( + 128, + new Mode("GCM-SIV", detectionLocation), + detectionLocation)); + case "AES-192-GCM-SIV" -> + Optional.of( + new AES( + 192, + new Mode("GCM-SIV", detectionLocation), + detectionLocation)); + case "AES-256-GCM-SIV" -> + Optional.of( + new AES( + 256, + new Mode("GCM-SIV", detectionLocation), + detectionLocation)); + case "AES-128-CBC-CTS" -> + Optional.of( + new AES( + 128, + new Mode("CBC-CTS", detectionLocation), + detectionLocation)); + case "AES-192-CBC-CTS" -> + Optional.of( + new AES( + 192, + new Mode("CBC-CTS", detectionLocation), + detectionLocation)); + case "AES-256-CBC-CTS" -> + Optional.of( + new AES( + 256, + new Mode("CBC-CTS", detectionLocation), + detectionLocation)); + case "AES-128-WRAP-INV" -> + Optional.of( + new AES( + 128, + new Mode("WRAP-INV", detectionLocation), + detectionLocation)); + case "AES-192-WRAP-INV" -> + Optional.of( + new AES( + 192, + new Mode("WRAP-INV", detectionLocation), + detectionLocation)); + case "AES-256-WRAP-INV" -> + Optional.of( + new AES( + 256, + new Mode("WRAP-INV", detectionLocation), + detectionLocation)); + case "AES-128-WRAP-PAD-INV" -> + Optional.of( + new AES( + 128, + new Mode("WRAP-PAD-INV", detectionLocation), + detectionLocation)); + case "AES-192-WRAP-PAD-INV" -> + Optional.of( + new AES( + 192, + new Mode("WRAP-PAD-INV", detectionLocation), + detectionLocation)); + case "AES-256-WRAP-PAD-INV" -> + Optional.of( + new AES( + 256, + new Mode("WRAP-PAD-INV", detectionLocation), + detectionLocation)); + case "AES-128-CBC-HMAC-SHA1" -> + Optional.of( + new AES( + 128, + new Mode("CBC-HMAC-SHA1", detectionLocation), + detectionLocation)); + case "AES-128-CBC-HMAC-SHA256" -> + Optional.of( + new AES( + 128, + new Mode("CBC-HMAC-SHA256", detectionLocation), + detectionLocation)); + case "AES-192-CBC-HMAC-SHA1" -> + Optional.of( + new AES( + 192, + new Mode("CBC-HMAC-SHA1", detectionLocation), + detectionLocation)); + case "AES-192-CBC-HMAC-SHA256" -> + Optional.of( + new AES( + 192, + new Mode("CBC-HMAC-SHA256", detectionLocation), + detectionLocation)); + case "AES-256-CBC-HMAC-SHA1" -> + Optional.of( + new AES( + 256, + new Mode("CBC-HMAC-SHA1", detectionLocation), + detectionLocation)); + case "AES-256-CBC-HMAC-SHA256" -> + Optional.of( + new AES( + 256, + new Mode("CBC-HMAC-SHA256", detectionLocation), + detectionLocation)); + + // Provider-only AES ETM (Encrypt-then-MAC) modes + case "AES-128-CBC-HMAC-SHA1-ETM" -> + Optional.of( + new AES( + 128, + new Mode("CBC-HMAC-SHA1-ETM", detectionLocation), + detectionLocation)); + case "AES-192-CBC-HMAC-SHA1-ETM" -> + Optional.of( + new AES( + 192, + new Mode("CBC-HMAC-SHA1-ETM", detectionLocation), + detectionLocation)); + case "AES-256-CBC-HMAC-SHA1-ETM" -> + Optional.of( + new AES( + 256, + new Mode("CBC-HMAC-SHA1-ETM", detectionLocation), + detectionLocation)); + case "AES-128-CBC-HMAC-SHA256-ETM" -> + Optional.of( + new AES( + 128, + new Mode("CBC-HMAC-SHA256-ETM", detectionLocation), + detectionLocation)); + case "AES-192-CBC-HMAC-SHA256-ETM" -> + Optional.of( + new AES( + 192, + new Mode("CBC-HMAC-SHA256-ETM", detectionLocation), + detectionLocation)); + case "AES-256-CBC-HMAC-SHA256-ETM" -> + Optional.of( + new AES( + 256, + new Mode("CBC-HMAC-SHA256-ETM", detectionLocation), + detectionLocation)); + case "AES-128-CBC-HMAC-SHA512-ETM" -> + Optional.of( + new AES( + 128, + new Mode("CBC-HMAC-SHA512-ETM", detectionLocation), + detectionLocation)); + case "AES-192-CBC-HMAC-SHA512-ETM" -> + Optional.of( + new AES( + 192, + new Mode("CBC-HMAC-SHA512-ETM", detectionLocation), + detectionLocation)); + case "AES-256-CBC-HMAC-SHA512-ETM" -> + Optional.of( + new AES( + 256, + new Mode("CBC-HMAC-SHA512-ETM", detectionLocation), + detectionLocation)); + + // ================================================================ + // Camellia + // ================================================================ + + // Camellia-128 + case "CAMELLIA-128-ECB" -> + Optional.of( + new Camellia( + 128, + new Mode("ECB", detectionLocation), + detectionLocation)); + case "CAMELLIA-128-CBC" -> + Optional.of( + new Camellia( + 128, + new Mode("CBC", detectionLocation), + detectionLocation)); + case "CAMELLIA-128-CFB" -> + Optional.of( + new Camellia( + 128, + new Mode("CFB", detectionLocation), + detectionLocation)); + case "CAMELLIA-128-CFB1" -> + Optional.of( + new Camellia( + 128, + new Mode("CFB1", detectionLocation), + detectionLocation)); + case "CAMELLIA-128-CFB8" -> + Optional.of( + new Camellia( + 128, + new Mode("CFB8", detectionLocation), + detectionLocation)); + case "CAMELLIA-128-CFB128" -> + Optional.of( + new Camellia( + 128, + new Mode("CFB128", detectionLocation), + detectionLocation)); + case "CAMELLIA-128-OFB" -> + Optional.of( + new Camellia( + 128, + new Mode("OFB", detectionLocation), + detectionLocation)); + case "CAMELLIA-128-CTR" -> + Optional.of( + new Camellia( + 128, + new Mode("CTR", detectionLocation), + detectionLocation)); + case "CAMELLIA-128-GCM" -> + Optional.of( + new Camellia( + 128, + new Mode("GCM", detectionLocation), + detectionLocation)); + case "CAMELLIA-128-CCM" -> + Optional.of( + new Camellia( + 128, + new Mode("CCM", detectionLocation), + detectionLocation)); + + // Camellia-192 + case "CAMELLIA-192-ECB" -> + Optional.of( + new Camellia( + 192, + new Mode("ECB", detectionLocation), + detectionLocation)); + case "CAMELLIA-192-CBC" -> + Optional.of( + new Camellia( + 192, + new Mode("CBC", detectionLocation), + detectionLocation)); + case "CAMELLIA-192-CFB" -> + Optional.of( + new Camellia( + 192, + new Mode("CFB", detectionLocation), + detectionLocation)); + case "CAMELLIA-192-CFB1" -> + Optional.of( + new Camellia( + 192, + new Mode("CFB1", detectionLocation), + detectionLocation)); + case "CAMELLIA-192-CFB8" -> + Optional.of( + new Camellia( + 192, + new Mode("CFB8", detectionLocation), + detectionLocation)); + case "CAMELLIA-192-CFB128" -> + Optional.of( + new Camellia( + 192, + new Mode("CFB128", detectionLocation), + detectionLocation)); + case "CAMELLIA-192-OFB" -> + Optional.of( + new Camellia( + 192, + new Mode("OFB", detectionLocation), + detectionLocation)); + case "CAMELLIA-192-CTR" -> + Optional.of( + new Camellia( + 192, + new Mode("CTR", detectionLocation), + detectionLocation)); + case "CAMELLIA-192-GCM" -> + Optional.of( + new Camellia( + 192, + new Mode("GCM", detectionLocation), + detectionLocation)); + case "CAMELLIA-192-CCM" -> + Optional.of( + new Camellia( + 192, + new Mode("CCM", detectionLocation), + detectionLocation)); + + // Camellia-256 + case "CAMELLIA-256-ECB" -> + Optional.of( + new Camellia( + 256, + new Mode("ECB", detectionLocation), + detectionLocation)); + case "CAMELLIA-256-CBC" -> + Optional.of( + new Camellia( + 256, + new Mode("CBC", detectionLocation), + detectionLocation)); + case "CAMELLIA-256-CFB" -> + Optional.of( + new Camellia( + 256, + new Mode("CFB", detectionLocation), + detectionLocation)); + case "CAMELLIA-256-CFB1" -> + Optional.of( + new Camellia( + 256, + new Mode("CFB1", detectionLocation), + detectionLocation)); + case "CAMELLIA-256-CFB8" -> + Optional.of( + new Camellia( + 256, + new Mode("CFB8", detectionLocation), + detectionLocation)); + case "CAMELLIA-256-CFB128" -> + Optional.of( + new Camellia( + 256, + new Mode("CFB128", detectionLocation), + detectionLocation)); + case "CAMELLIA-256-OFB" -> + Optional.of( + new Camellia( + 256, + new Mode("OFB", detectionLocation), + detectionLocation)); + case "CAMELLIA-256-CTR" -> + Optional.of( + new Camellia( + 256, + new Mode("CTR", detectionLocation), + detectionLocation)); + case "CAMELLIA-256-GCM" -> + Optional.of( + new Camellia( + 256, + new Mode("GCM", detectionLocation), + detectionLocation)); + case "CAMELLIA-256-CCM" -> + Optional.of( + new Camellia( + 256, + new Mode("CCM", detectionLocation), + detectionLocation)); + + // Provider-only Camellia modes + case "CAMELLIA-128-CBC-CTS" -> + Optional.of( + new Camellia( + 128, + new Mode("CBC-CTS", detectionLocation), + detectionLocation)); + case "CAMELLIA-192-CBC-CTS" -> + Optional.of( + new Camellia( + 192, + new Mode("CBC-CTS", detectionLocation), + detectionLocation)); + case "CAMELLIA-256-CBC-CTS" -> + Optional.of( + new Camellia( + 256, + new Mode("CBC-CTS", detectionLocation), + detectionLocation)); + + // ================================================================ + // ARIA + // ================================================================ + + // ARIA-128 + case "ARIA-128-ECB" -> + Optional.of( + new Aria( + 128, + new Mode("ECB", detectionLocation), + detectionLocation)); + case "ARIA-128-CBC" -> + Optional.of( + new Aria( + 128, + new Mode("CBC", detectionLocation), + detectionLocation)); + case "ARIA-128-CFB" -> + Optional.of( + new Aria( + 128, + new Mode("CFB", detectionLocation), + detectionLocation)); + case "ARIA-128-CFB1" -> + Optional.of( + new Aria( + 128, + new Mode("CFB1", detectionLocation), + detectionLocation)); + case "ARIA-128-CFB8" -> + Optional.of( + new Aria( + 128, + new Mode("CFB8", detectionLocation), + detectionLocation)); + case "ARIA-128-CFB128" -> + Optional.of( + new Aria( + 128, + new Mode("CFB128", detectionLocation), + detectionLocation)); + case "ARIA-128-OFB" -> + Optional.of( + new Aria( + 128, + new Mode("OFB", detectionLocation), + detectionLocation)); + case "ARIA-128-CTR" -> + Optional.of( + new Aria( + 128, + new Mode("CTR", detectionLocation), + detectionLocation)); + case "ARIA-128-GCM" -> + Optional.of( + new Aria( + 128, + new Mode("GCM", detectionLocation), + detectionLocation)); + case "ARIA-128-CCM" -> + Optional.of( + new Aria( + 128, + new Mode("CCM", detectionLocation), + detectionLocation)); + + // ARIA-192 + case "ARIA-192-ECB" -> + Optional.of( + new Aria( + 192, + new Mode("ECB", detectionLocation), + detectionLocation)); + case "ARIA-192-CBC" -> + Optional.of( + new Aria( + 192, + new Mode("CBC", detectionLocation), + detectionLocation)); + case "ARIA-192-CFB" -> + Optional.of( + new Aria( + 192, + new Mode("CFB", detectionLocation), + detectionLocation)); + case "ARIA-192-CFB1" -> + Optional.of( + new Aria( + 192, + new Mode("CFB1", detectionLocation), + detectionLocation)); + case "ARIA-192-CFB8" -> + Optional.of( + new Aria( + 192, + new Mode("CFB8", detectionLocation), + detectionLocation)); + case "ARIA-192-CFB128" -> + Optional.of( + new Aria( + 192, + new Mode("CFB128", detectionLocation), + detectionLocation)); + case "ARIA-192-OFB" -> + Optional.of( + new Aria( + 192, + new Mode("OFB", detectionLocation), + detectionLocation)); + case "ARIA-192-CTR" -> + Optional.of( + new Aria( + 192, + new Mode("CTR", detectionLocation), + detectionLocation)); + case "ARIA-192-GCM" -> + Optional.of( + new Aria( + 192, + new Mode("GCM", detectionLocation), + detectionLocation)); + case "ARIA-192-CCM" -> + Optional.of( + new Aria( + 192, + new Mode("CCM", detectionLocation), + detectionLocation)); + + // ARIA-256 + case "ARIA-256-ECB" -> + Optional.of( + new Aria( + 256, + new Mode("ECB", detectionLocation), + detectionLocation)); + case "ARIA-256-CBC" -> + Optional.of( + new Aria( + 256, + new Mode("CBC", detectionLocation), + detectionLocation)); + case "ARIA-256-CFB" -> + Optional.of( + new Aria( + 256, + new Mode("CFB", detectionLocation), + detectionLocation)); + case "ARIA-256-CFB1" -> + Optional.of( + new Aria( + 256, + new Mode("CFB1", detectionLocation), + detectionLocation)); + case "ARIA-256-CFB8" -> + Optional.of( + new Aria( + 256, + new Mode("CFB8", detectionLocation), + detectionLocation)); + case "ARIA-256-CFB128" -> + Optional.of( + new Aria( + 256, + new Mode("CFB128", detectionLocation), + detectionLocation)); + case "ARIA-256-OFB" -> + Optional.of( + new Aria( + 256, + new Mode("OFB", detectionLocation), + detectionLocation)); + case "ARIA-256-CTR" -> + Optional.of( + new Aria( + 256, + new Mode("CTR", detectionLocation), + detectionLocation)); + case "ARIA-256-GCM" -> + Optional.of( + new Aria( + 256, + new Mode("GCM", detectionLocation), + detectionLocation)); + case "ARIA-256-CCM" -> + Optional.of( + new Aria( + 256, + new Mode("CCM", detectionLocation), + detectionLocation)); + + // ================================================================ + // SM4 (Chinese National Standard) + // ================================================================ + + case "SM4-ECB" -> + Optional.of(new SM4(new Mode("ECB", detectionLocation), detectionLocation)); + case "SM4-CBC" -> + Optional.of(new SM4(new Mode("CBC", detectionLocation), detectionLocation)); + case "SM4-CFB" -> + Optional.of(new SM4(new Mode("CFB", detectionLocation), detectionLocation)); + case "SM4-CFB128" -> + Optional.of( + new SM4(new Mode("CFB128", detectionLocation), detectionLocation)); + case "SM4-OFB" -> + Optional.of(new SM4(new Mode("OFB", detectionLocation), detectionLocation)); + case "SM4-CTR" -> + Optional.of(new SM4(new Mode("CTR", detectionLocation), detectionLocation)); + case "SM4-GCM" -> + Optional.of(new SM4(new Mode("GCM", detectionLocation), detectionLocation)); + case "SM4-CCM" -> + Optional.of(new SM4(new Mode("CCM", detectionLocation), detectionLocation)); + case "SM4-XTS" -> + Optional.of(new SM4(new Mode("XTS", detectionLocation), detectionLocation)); + + // ================================================================ + // DES / 3DES + // ================================================================ + + case "DES-CBC" -> + Optional.of(new DES(new Mode("CBC", detectionLocation), detectionLocation)); + case "DES-ECB" -> + Optional.of(new DES(new Mode("ECB", detectionLocation), detectionLocation)); + case "DES-CFB" -> + Optional.of(new DES(new Mode("CFB", detectionLocation), detectionLocation)); + case "DES-CFB1" -> + Optional.of( + new DES(new Mode("CFB1", detectionLocation), detectionLocation)); + case "DES-CFB8" -> + Optional.of( + new DES(new Mode("CFB8", detectionLocation), detectionLocation)); + case "DES-CFB64" -> + Optional.of( + new DES(new Mode("CFB64", detectionLocation), detectionLocation)); + case "DES-OFB" -> + Optional.of(new DES(new Mode("OFB", detectionLocation), detectionLocation)); + + // DESX (DES with pre/post XOR whitening) + case "DESX-CBC" -> + Optional.of(new DES(new Mode("CBC", detectionLocation), detectionLocation)); + + // DESede (2-key Triple-DES, 112-bit effective key strength) + case "DESEDE" -> Optional.of(new DESede(112, detectionLocation)); + case "DESEDE-ECB" -> + Optional.of( + new DESede( + 112, + new Mode("ECB", detectionLocation), + detectionLocation)); + case "DESEDE-CBC" -> + Optional.of( + new DESede( + 112, + new Mode("CBC", detectionLocation), + detectionLocation)); + case "DESEDE-CFB64" -> + Optional.of( + new DESede( + 112, + new Mode("CFB64", detectionLocation), + detectionLocation)); + case "DESEDE-OFB" -> + Optional.of( + new DESede( + 112, + new Mode("OFB", detectionLocation), + detectionLocation)); + + // DESede3 (3-key Triple-DES, 168-bit effective key strength) + case "DESEDE3" -> Optional.of(new DESede(168, detectionLocation)); + case "DESEDE3-ECB" -> + Optional.of( + new DESede( + 168, + new Mode("ECB", detectionLocation), + detectionLocation)); + case "DESEDE3-CBC" -> + Optional.of( + new DESede( + 168, + new Mode("CBC", detectionLocation), + detectionLocation)); + case "DESEDE3-CFB1" -> + Optional.of( + new DESede( + 168, + new Mode("CFB1", detectionLocation), + detectionLocation)); + case "DESEDE3-CFB8" -> + Optional.of( + new DESede( + 168, + new Mode("CFB8", detectionLocation), + detectionLocation)); + case "DESEDE3-CFB64" -> + Optional.of( + new DESede( + 168, + new Mode("CFB64", detectionLocation), + detectionLocation)); + case "DESEDE3-OFB" -> + Optional.of( + new DESede( + 168, + new Mode("OFB", detectionLocation), + detectionLocation)); + + // ================================================================ + // Blowfish + // ================================================================ + + case "BLOWFISH-ECB" -> + Optional.of( + new Blowfish( + 128, + new Mode("ECB", detectionLocation), + detectionLocation)); + case "BLOWFISH-CBC" -> + Optional.of( + new Blowfish( + 128, + new Mode("CBC", detectionLocation), + detectionLocation)); + case "BLOWFISH-CFB" -> + Optional.of( + new Blowfish( + 128, + new Mode("CFB", detectionLocation), + detectionLocation)); + case "BLOWFISH-CFB64" -> + Optional.of( + new Blowfish( + 128, + new Mode("CFB64", detectionLocation), + detectionLocation)); + case "BLOWFISH-OFB" -> + Optional.of( + new Blowfish( + 128, + new Mode("OFB", detectionLocation), + detectionLocation)); + + // ================================================================ + // CAST5 (CAST-128) + // ================================================================ + + case "CAST5-ECB" -> + Optional.of( + new CAST128( + 128, + new Mode("ECB", detectionLocation), + detectionLocation)); + case "CAST5-CBC" -> + Optional.of( + new CAST128( + 128, + new Mode("CBC", detectionLocation), + detectionLocation)); + case "CAST5-CFB" -> + Optional.of( + new CAST128( + 128, + new Mode("CFB", detectionLocation), + detectionLocation)); + case "CAST5-CFB64" -> + Optional.of( + new CAST128( + 128, + new Mode("CFB64", detectionLocation), + detectionLocation)); + case "CAST5-OFB" -> + Optional.of( + new CAST128( + 128, + new Mode("OFB", detectionLocation), + detectionLocation)); + + // ================================================================ + // RC2 + // ================================================================ + + case "RC2-ECB" -> + Optional.of( + new RC2( + 128, + new Mode("ECB", detectionLocation), + detectionLocation)); + case "RC2-CBC" -> + Optional.of( + new RC2( + 128, + new Mode("CBC", detectionLocation), + detectionLocation)); + case "RC2-CFB" -> + Optional.of( + new RC2( + 128, + new Mode("CFB", detectionLocation), + detectionLocation)); + case "RC2-CFB64" -> + Optional.of( + new RC2( + 128, + new Mode("CFB64", detectionLocation), + detectionLocation)); + case "RC2-OFB" -> + Optional.of( + new RC2( + 128, + new Mode("OFB", detectionLocation), + detectionLocation)); + case "RC2-40-CBC" -> + Optional.of( + new RC2(40, new Mode("CBC", detectionLocation), detectionLocation)); + case "RC2-64-CBC" -> + Optional.of( + new RC2(64, new Mode("CBC", detectionLocation), detectionLocation)); + + // ================================================================ + // RC4 (Stream Cipher) + // ================================================================ + + case "RC4" -> Optional.of(new RC4(detectionLocation)); + case "RC4-40" -> Optional.of(new RC4(40, detectionLocation)); + case "RC4-HMAC-MD5" -> Optional.of(new RC4(detectionLocation)); + + // ================================================================ + // RC5 + // ================================================================ + + case "RC5-ECB" -> + Optional.of( + new RC5( + 128, + new Mode("ECB", detectionLocation), + detectionLocation)); + case "RC5-CBC" -> + Optional.of( + new RC5( + 128, + new Mode("CBC", detectionLocation), + detectionLocation)); + case "RC5-CFB" -> + Optional.of( + new RC5( + 128, + new Mode("CFB", detectionLocation), + detectionLocation)); + case "RC5-CFB64" -> + Optional.of( + new RC5( + 128, + new Mode("CFB64", detectionLocation), + detectionLocation)); + case "RC5-OFB" -> + Optional.of( + new RC5( + 128, + new Mode("OFB", detectionLocation), + detectionLocation)); + + // ================================================================ + // IDEA + // ================================================================ + + case "IDEA-ECB" -> + Optional.of( + new IDEA(new Mode("ECB", detectionLocation), detectionLocation)); + case "IDEA-CBC" -> + Optional.of( + new IDEA(new Mode("CBC", detectionLocation), detectionLocation)); + case "IDEA-CFB" -> + Optional.of( + new IDEA(new Mode("CFB", detectionLocation), detectionLocation)); + case "IDEA-CFB64" -> + Optional.of( + new IDEA(new Mode("CFB64", detectionLocation), detectionLocation)); + case "IDEA-OFB" -> + Optional.of( + new IDEA(new Mode("OFB", detectionLocation), detectionLocation)); + + // ================================================================ + // SEED (Korean National Standard) + // ================================================================ + + case "SEED-ECB" -> + Optional.of( + new SEED(new Mode("ECB", detectionLocation), detectionLocation)); + case "SEED-CBC" -> + Optional.of( + new SEED(new Mode("CBC", detectionLocation), detectionLocation)); + case "SEED-CFB" -> + Optional.of( + new SEED(new Mode("CFB", detectionLocation), detectionLocation)); + case "SEED-CFB128" -> + Optional.of( + new SEED(new Mode("CFB128", detectionLocation), detectionLocation)); + case "SEED-OFB" -> + Optional.of( + new SEED(new Mode("OFB", detectionLocation), detectionLocation)); + + // ================================================================ + // ChaCha20 + // ================================================================ + + case "CHACHA20" -> Optional.of(new ChaCha20(detectionLocation)); + case "CHACHA20-POLY1305" -> Optional.of(new ChaCha20Poly1305(detectionLocation)); + + // ================================================================ + // SM2 Public Key Encryption + // ================================================================ + + case "SM2-PKE" -> + Optional.of(new SM2(PublicKeyEncryption.class, new SM2(detectionLocation))); + + default -> Optional.empty(); + }; + } + + return Optional.empty(); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxDigestContextTranslator.java b/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxDigestContextTranslator.java new file mode 100644 index 000000000..8384a76ba --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxDigestContextTranslator.java @@ -0,0 +1,120 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.translation.translator.contexts; + +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.IDetectionContext; +import com.ibm.engine.rule.IBundle; +import com.ibm.mapper.IContextTranslation; +import com.ibm.mapper.model.Algorithm; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.algorithms.MD2; +import com.ibm.mapper.model.algorithms.MD4; +import com.ibm.mapper.model.algorithms.MD5; +import com.ibm.mapper.model.algorithms.RIPEMD; +import com.ibm.mapper.model.algorithms.SHA; +import com.ibm.mapper.model.algorithms.SHA2; +import com.ibm.mapper.model.algorithms.SHA3; +import com.ibm.mapper.model.algorithms.SM3; +import com.ibm.mapper.model.algorithms.Whirlpool; +import com.ibm.mapper.model.algorithms.blake.BLAKE2b; +import com.ibm.mapper.model.algorithms.blake.BLAKE2s; +import com.ibm.mapper.model.algorithms.shake.SHAKE; +import com.ibm.mapper.utils.DetectionLocation; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.Optional; +import javax.annotation.Nonnull; + +public final class CxxDigestContextTranslator implements IContextTranslation { + + @Override + public @Nonnull Optional translate( + @Nonnull IBundle bundleIdentifier, + @Nonnull IValue value, + @Nonnull IDetectionContext detectionContext, + @Nonnull DetectionLocation detectionLocation) { + + if (value instanceof ValueAction) { + return switch (value.asString().toUpperCase().trim()) { + // MD Family + case "MD2" -> Optional.of(new MD2(detectionLocation)); + case "MD4" -> Optional.of(new MD4(detectionLocation)); + case "MD5" -> Optional.of(new MD5(detectionLocation)); + // MDC2 (ISO/IEC 10118-2) is a hash function built on DES, not MD5 + case "MDC2" -> + Optional.of(new Algorithm("MDC2", MessageDigest.class, detectionLocation)); + + // SHA-1 + case "SHA-1" -> Optional.of(new SHA(detectionLocation)); + + // SHA-2 + case "SHA-224" -> Optional.of(new SHA2(224, detectionLocation)); + case "SHA-256" -> Optional.of(new SHA2(256, detectionLocation)); + case "SHA-384" -> Optional.of(new SHA2(384, detectionLocation)); + case "SHA-512" -> Optional.of(new SHA2(512, detectionLocation)); + case "SHA-512/224" -> + Optional.of( + new SHA2(224, new SHA2(512, detectionLocation), detectionLocation)); + case "SHA-512/256" -> + Optional.of( + new SHA2(256, new SHA2(512, detectionLocation), detectionLocation)); + + // SHA-3 + case "SHA3-224" -> Optional.of(new SHA3(224, detectionLocation)); + case "SHA3-256" -> Optional.of(new SHA3(256, detectionLocation)); + case "SHA3-384" -> Optional.of(new SHA3(384, detectionLocation)); + case "SHA3-512" -> Optional.of(new SHA3(512, detectionLocation)); + + // SHAKE (Extendable-Output Functions) + case "SHAKE128" -> Optional.of(new SHAKE(128, detectionLocation)); + case "SHAKE256" -> Optional.of(new SHAKE(256, detectionLocation)); + + // RIPEMD + case "RIPEMD160" -> Optional.of(new RIPEMD(160, detectionLocation)); + + // Whirlpool + case "WHIRLPOOL" -> Optional.of(new Whirlpool(detectionLocation)); + + // BLAKE2 + case "BLAKE2B-512" -> Optional.of(new BLAKE2b(512, false, detectionLocation)); + case "BLAKE2S-256" -> Optional.of(new BLAKE2s(256, false, detectionLocation)); + + // SM3 + case "SM3" -> Optional.of(new SM3(detectionLocation)); + + // Combined/Special digests + case "MD5-SHA1" -> { + // Combined MD5+SHA1 for TLS 1.0 (concatenated output: 128-bit MD5 + 160-bit + // SHA-1) + yield Optional.of( + new MD5(detectionLocation)); // Primary algorithm, may need composite + // handling + } + case "NULL" -> Optional.empty(); // NULL digest - no actual hashing + + default -> Optional.empty(); + }; + } + + return Optional.empty(); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxKeyAgreementContextTranslator.java b/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxKeyAgreementContextTranslator.java new file mode 100644 index 000000000..d6fe02ba2 --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxKeyAgreementContextTranslator.java @@ -0,0 +1,126 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.translation.translator.contexts; + +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.IDetectionContext; +import com.ibm.engine.rule.IBundle; +import com.ibm.mapper.IContextTranslation; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.KeyAgreement; +import com.ibm.mapper.model.algorithms.DH; +import com.ibm.mapper.model.algorithms.ECDH; +import com.ibm.mapper.model.algorithms.MLKEM; +import com.ibm.mapper.model.algorithms.SM2; +import com.ibm.mapper.model.algorithms.SecP256r1MLKEM768; +import com.ibm.mapper.model.algorithms.SecP384r1MLKEM1024; +import com.ibm.mapper.model.algorithms.X25519; +import com.ibm.mapper.model.algorithms.X25519MLKEM768; +import com.ibm.mapper.model.algorithms.X448; +import com.ibm.mapper.model.algorithms.X448MLKEM1024; +import com.ibm.mapper.utils.DetectionLocation; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.Optional; +import javax.annotation.Nonnull; + +/** + * Translator for C++ key agreement detection contexts. + * + *

This translator handles the translation of key agreement-related detection values (Diffie- + * Hellman, ECDH, X25519/X448, ML-KEM, SM2) to the mapper model nodes. + */ +public final class CxxKeyAgreementContextTranslator implements IContextTranslation { + + @Override + public @Nonnull Optional translate( + @Nonnull IBundle bundleIdentifier, + @Nonnull IValue value, + @Nonnull IDetectionContext detectionContext, + @Nonnull DetectionLocation detectionLocation) { + + if (value instanceof ValueAction) { + String algorithmName = value.asString().toUpperCase().trim(); + + // DH (Diffie-Hellman) + if (algorithmName.equals("DH")) { + return Optional.of(new DH(KeyAgreement.class, detectionLocation)); + } + if (algorithmName.equals("DH-2048")) { + return Optional.of(new DH(KeyAgreement.class, detectionLocation)); + } + if (algorithmName.equals("DH-3072")) { + return Optional.of(new DH(KeyAgreement.class, detectionLocation)); + } + if (algorithmName.equals("DH-4096")) { + return Optional.of(new DH(KeyAgreement.class, detectionLocation)); + } + + // ECDH (Elliptic Curve Diffie-Hellman) + if (algorithmName.equals("ECDH")) { + return Optional.of(new ECDH(detectionLocation)); + } + if (algorithmName.startsWith("ECDH-")) { + // ECDH-P256, ECDH-P384, ECDH-P521, ECDH-SECP256K1 + return Optional.of(new ECDH(detectionLocation)); + } + + // X25519 and X448 + if (algorithmName.equals("X25519")) { + return Optional.of(new X25519(detectionLocation)); + } + if (algorithmName.equals("X448")) { + return Optional.of(new X448(detectionLocation)); + } + + // ML-KEM (Kyber) - Post-Quantum Key Encapsulation Mechanism + if (algorithmName.equals("ML-KEM-512")) { + return Optional.of(new MLKEM(512, detectionLocation)); + } + if (algorithmName.equals("ML-KEM-768")) { + return Optional.of(new MLKEM(768, detectionLocation)); + } + if (algorithmName.equals("ML-KEM-1024")) { + return Optional.of(new MLKEM(1024, detectionLocation)); + } + + // Hybrid Post-Quantum KEMs (PQC + Classical) + if (algorithmName.equals("X25519MLKEM768")) { + return Optional.of(new X25519MLKEM768(detectionLocation)); + } + if (algorithmName.equals("X448MLKEM1024")) { + return Optional.of(new X448MLKEM1024(detectionLocation)); + } + if (algorithmName.equals("SECP256R1MLKEM768")) { + return Optional.of(new SecP256r1MLKEM768(detectionLocation)); + } + if (algorithmName.equals("SECP384R1MLKEM1024")) { + return Optional.of(new SecP384r1MLKEM1024(detectionLocation)); + } + + // SM2 Key Exchange + if (algorithmName.equals("SM2")) { + return Optional.of(new SM2(detectionLocation)); + } + } + + return Optional.empty(); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxKeyContextTranslator.java b/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxKeyContextTranslator.java new file mode 100644 index 000000000..7c7a7effa --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxKeyContextTranslator.java @@ -0,0 +1,142 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.translation.translator.contexts; + +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.IDetectionContext; +import com.ibm.engine.rule.IBundle; +import com.ibm.mapper.IContextTranslation; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.PublicKeyEncryption; +import com.ibm.mapper.model.algorithms.DH; +import com.ibm.mapper.model.algorithms.DSA; +import com.ibm.mapper.model.algorithms.ECDSA; +import com.ibm.mapper.model.algorithms.Ed25519; +import com.ibm.mapper.model.algorithms.Ed448; +import com.ibm.mapper.model.algorithms.MLDSA; +import com.ibm.mapper.model.algorithms.MLKEM; +import com.ibm.mapper.model.algorithms.RSA; +import com.ibm.mapper.model.algorithms.SLHDSA; +import com.ibm.mapper.model.algorithms.SecP256r1MLKEM768; +import com.ibm.mapper.model.algorithms.SecP384r1MLKEM1024; +import com.ibm.mapper.model.algorithms.X25519; +import com.ibm.mapper.model.algorithms.X25519MLKEM768; +import com.ibm.mapper.model.algorithms.X448; +import com.ibm.mapper.model.algorithms.X448MLKEM1024; +import com.ibm.mapper.utils.DetectionLocation; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.Optional; +import javax.annotation.Nonnull; + +/** + * Translator for C++ key detection contexts. + * + *

This translator handles the translation of key-related detection values (public keys, private + * keys, secret keys) to the mapper model nodes. + */ +public final class CxxKeyContextTranslator implements IContextTranslation { + + @Override + public @Nonnull Optional translate( + @Nonnull IBundle bundleIdentifier, + @Nonnull IValue value, + @Nonnull IDetectionContext detectionContext, + @Nonnull DetectionLocation detectionLocation) { + + if (value instanceof ValueAction) { + return switch (value.asString().toUpperCase().trim()) { + // RSA + case "RSA" -> Optional.of(new RSA(detectionLocation)); + case "RSA-PSS" -> Optional.of(new RSA(detectionLocation)); + case "RSA-2048" -> Optional.of(new RSA(2048, detectionLocation)); + case "RSA-3072" -> Optional.of(new RSA(3072, detectionLocation)); + case "RSA-4096" -> Optional.of(new RSA(4096, detectionLocation)); + + // DSA + case "DSA" -> Optional.of(new DSA(detectionLocation)); + case "DSA-2048" -> Optional.of(new DSA(detectionLocation)); + case "DSA-3072" -> Optional.of(new DSA(detectionLocation)); + + // EC + case "EC" -> Optional.of(new ECDSA(detectionLocation)); + case "EC-P256" -> Optional.of(new ECDSA(detectionLocation)); + case "EC-P384" -> Optional.of(new ECDSA(detectionLocation)); + case "EC-P521" -> Optional.of(new ECDSA(detectionLocation)); + case "EC-SECP256K1" -> Optional.of(new ECDSA(detectionLocation)); + case "EC-BRAINPOOLP256R1" -> Optional.of(new ECDSA(detectionLocation)); + case "EC-BRAINPOOLP384R1" -> Optional.of(new ECDSA(detectionLocation)); + case "EC-BRAINPOOLP512R1" -> Optional.of(new ECDSA(detectionLocation)); + + // DH + case "DH" -> Optional.of(new DH(detectionLocation)); + case "DH-2048" -> Optional.of(new DH(PublicKeyEncryption.class, detectionLocation)); + case "DH-4096" -> Optional.of(new DH(PublicKeyEncryption.class, detectionLocation)); + + // EdDSA + case "ED25519" -> Optional.of(new Ed25519(detectionLocation)); + case "ED448" -> Optional.of(new Ed448(detectionLocation)); + + // X25519/X448 + case "X25519" -> Optional.of(new X25519(detectionLocation)); + case "X448" -> Optional.of(new X448(detectionLocation)); + + // ML-KEM (Post-Quantum) + case "ML-KEM-512" -> Optional.of(new MLKEM(512, detectionLocation)); + case "ML-KEM-768" -> Optional.of(new MLKEM(768, detectionLocation)); + case "ML-KEM-1024" -> Optional.of(new MLKEM(1024, detectionLocation)); + + // ML-DSA (Post-Quantum) + case "ML-DSA-44" -> Optional.of(new MLDSA(2, detectionLocation)); + case "ML-DSA-65" -> Optional.of(new MLDSA(3, detectionLocation)); + case "ML-DSA-87" -> Optional.of(new MLDSA(5, detectionLocation)); + + // SLH-DSA (Post-Quantum) + case "SLH-DSA-SHA2-128F", + "SLH-DSA-SHA2-128S", + "SLH-DSA-SHAKE-128F", + "SLH-DSA-SHAKE-128S", + "SLH-DSA-SHA2-192F", + "SLH-DSA-SHA2-192S", + "SLH-DSA-SHAKE-192F", + "SLH-DSA-SHAKE-192S", + "SLH-DSA-SHA2-256F", + "SLH-DSA-SHA2-256S", + "SLH-DSA-SHAKE-256F", + "SLH-DSA-SHAKE-256S" -> + Optional.of(new SLHDSA(detectionLocation)); + + // Hybrid Post-Quantum KEMs (PQC + Classical) + case "X25519MLKEM768" -> Optional.of(new X25519MLKEM768(detectionLocation)); + case "X448MLKEM1024" -> Optional.of(new X448MLKEM1024(detectionLocation)); + case "SECP256R1MLKEM768" -> Optional.of(new SecP256r1MLKEM768(detectionLocation)); + case "SECP384R1MLKEM1024" -> Optional.of(new SecP384r1MLKEM1024(detectionLocation)); + + // SM2 + case "SM2" -> + Optional.of(new com.ibm.mapper.model.algorithms.SM2(detectionLocation)); + + default -> Optional.empty(); + }; + } + + return Optional.empty(); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxKeyDerivationFunctionContextTranslator.java b/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxKeyDerivationFunctionContextTranslator.java new file mode 100644 index 000000000..4913622fa --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxKeyDerivationFunctionContextTranslator.java @@ -0,0 +1,197 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.translation.translator.contexts; + +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.IDetectionContext; +import com.ibm.engine.rule.IBundle; +import com.ibm.mapper.IContextTranslation; +import com.ibm.mapper.model.Algorithm; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.KeyDerivationFunction; +import com.ibm.mapper.model.PasswordBasedKeyDerivationFunction; +import com.ibm.mapper.model.algorithms.AES; +import com.ibm.mapper.model.algorithms.ANSIX942; +import com.ibm.mapper.model.algorithms.ANSIX963; +import com.ibm.mapper.model.algorithms.CMAC; +import com.ibm.mapper.model.algorithms.ConcatenationKDF; +import com.ibm.mapper.model.algorithms.HKDF; +import com.ibm.mapper.model.algorithms.HMAC; +import com.ibm.mapper.model.algorithms.KDFCounter; +import com.ibm.mapper.model.algorithms.MD5; +import com.ibm.mapper.model.algorithms.PBKDF1; +import com.ibm.mapper.model.algorithms.PBKDF2; +import com.ibm.mapper.model.algorithms.SHA; +import com.ibm.mapper.model.algorithms.SHA2; +import com.ibm.mapper.model.algorithms.SHA3; +import com.ibm.mapper.model.algorithms.Scrypt; +import com.ibm.mapper.utils.DetectionLocation; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.Optional; +import javax.annotation.Nonnull; + +public final class CxxKeyDerivationFunctionContextTranslator + implements IContextTranslation { + + @Override + public @Nonnull Optional translate( + @Nonnull IBundle bundleIdentifier, + @Nonnull IValue value, + @Nonnull IDetectionContext detectionContext, + @Nonnull DetectionLocation detectionLocation) { + + if (value instanceof ValueAction) { + return switch (value.asString().toUpperCase().trim()) { + // PBKDF2 + case "PBKDF2-HMAC-SHA1" -> Optional.of(new PBKDF2(new SHA(detectionLocation))); + case "PBKDF2-HMAC-SHA256" -> + Optional.of(new PBKDF2(new SHA2(256, detectionLocation))); + case "PBKDF2-HMAC-SHA384" -> + Optional.of(new PBKDF2(new SHA2(384, detectionLocation))); + case "PBKDF2-HMAC-SHA512" -> + Optional.of(new PBKDF2(new SHA2(512, detectionLocation))); + case "PBKDF2-HMAC-SHA3-256" -> + Optional.of(new PBKDF2(new SHA3(256, detectionLocation))); + case "PBKDF2-HMAC-SHA3-512" -> + Optional.of(new PBKDF2(new SHA3(512, detectionLocation))); + case "PBKDF2-HMAC-SM3", "PBKDF2-HMAC-MD5" -> + Optional.of(new PBKDF2(detectionLocation)); + + // HKDF + case "HKDF-SHA1" -> Optional.of(new HKDF(new SHA(detectionLocation))); + case "HKDF-SHA256" -> Optional.of(new HKDF(new SHA2(256, detectionLocation))); + case "HKDF-SHA384" -> Optional.of(new HKDF(new SHA2(384, detectionLocation))); + case "HKDF-SHA512" -> Optional.of(new HKDF(new SHA2(512, detectionLocation))); + case "HKDF-SHA3-256" -> Optional.of(new HKDF(new SHA3(256, detectionLocation))); + + // Scrypt + case "SCRYPT" -> Optional.of(new Scrypt(detectionLocation)); + + // TLS PRF + case "TLS1-PRF-MD5-SHA1", "TLS1-PRF-SHA256", "TLS1-PRF-SHA384", "TLS1-PRF-SHA512" -> + Optional.of(new PBKDF2(detectionLocation)); + + // TLS 1.3 KDF + case "TLS13-KDF-SHA256" -> Optional.of(new HKDF(new SHA2(256, detectionLocation))); + case "TLS13-KDF-SHA384" -> Optional.of(new HKDF(new SHA2(384, detectionLocation))); + case "TLS13-KDF-SHA512" -> Optional.of(new HKDF(new SHA2(512, detectionLocation))); + + // X963KDF + case "X963KDF-SHA1" -> Optional.of(new ANSIX963(new SHA(detectionLocation))); + case "X963KDF-SHA224" -> + Optional.of(new ANSIX963(new SHA2(224, detectionLocation))); + case "X963KDF-SHA256" -> + Optional.of(new ANSIX963(new SHA2(256, detectionLocation))); + case "X963KDF-SHA384" -> + Optional.of(new ANSIX963(new SHA2(384, detectionLocation))); + case "X963KDF-SHA512" -> + Optional.of(new ANSIX963(new SHA2(512, detectionLocation))); + + // KBKDF (SP 800-108 Key-Based KDF) — counter mode with HMAC or CMAC + case "KBKDF-HMAC-SHA1" -> + Optional.of(new KDFCounter(new HMAC(new SHA(detectionLocation)))); + case "KBKDF-HMAC-SHA256" -> + Optional.of(new KDFCounter(new HMAC(new SHA2(256, detectionLocation)))); + case "KBKDF-HMAC-SHA384" -> + Optional.of(new KDFCounter(new HMAC(new SHA2(384, detectionLocation)))); + case "KBKDF-HMAC-SHA512" -> + Optional.of(new KDFCounter(new HMAC(new SHA2(512, detectionLocation)))); + case "KBKDF-CMAC-AES128" -> + Optional.of(new KDFCounter(new CMAC(new AES(128, detectionLocation)))); + case "KBKDF-CMAC-AES256" -> + Optional.of(new KDFCounter(new CMAC(new AES(256, detectionLocation)))); + + // X942KDF (ANSI X9.42 Key Derivation) + case "X942KDF-SHA256", "X942KDF-SHA512", "X942KDF-SHA1", "X942KDF-CONCAT" -> + Optional.of(new ANSIX942(detectionLocation)); + + // SSKDF (Single-step KDF / ConcatenationKDF) + case "SSKDF", "SSKDF-SHA256", "SSKDF-SHA512" -> + Optional.of(new ConcatenationKDF(detectionLocation)); + + // SSHKDF + case "SSHKDF-SHA1", "SSHKDF-SHA256", "SSHKDF-SHA512" -> + Optional.of(new PBKDF2(detectionLocation)); + + // KRB5KDF (Kerberos Key Derivation Function) + case "KRB5KDF" -> + Optional.of( + new Algorithm( + "KRB5KDF", KeyDerivationFunction.class, detectionLocation)); + + // Argon2 (password-based KDF / memory-hard) + case "ARGON2D" -> + Optional.of( + new Algorithm( + "Argon2d", + PasswordBasedKeyDerivationFunction.class, + detectionLocation)); + case "ARGON2I" -> + Optional.of( + new Algorithm( + "Argon2i", + PasswordBasedKeyDerivationFunction.class, + detectionLocation)); + case "ARGON2ID" -> + Optional.of( + new Algorithm( + "Argon2id", + PasswordBasedKeyDerivationFunction.class, + detectionLocation)); + + // PKCS12KDF (PKCS#12 password-based key derivation) + case "PKCS12KDF" -> + Optional.of( + new Algorithm( + "PKCS12KDF", + PasswordBasedKeyDerivationFunction.class, + detectionLocation)); + + // PVKKDF (Microsoft PVK file key derivation) + case "PVKKDF" -> + Optional.of( + new Algorithm( + "PVKKDF", + PasswordBasedKeyDerivationFunction.class, + detectionLocation)); + + // PBKDF1 (legacy, PKCS#5 v1.5) + case "PBKDF1-MD5" -> Optional.of(new PBKDF1(new MD5(detectionLocation))); + case "PBKDF1-SHA1" -> Optional.of(new PBKDF1(new SHA(detectionLocation))); + + // PBKDF2-HMAC (bare, without explicit digest) + case "PBKDF2-HMAC" -> Optional.of(new PBKDF2(detectionLocation)); + + // HMAC-DRBG-KDF + case "HMAC-DRBG-KDF" -> + Optional.of( + new Algorithm( + "HMAC-DRBG-KDF", + KeyDerivationFunction.class, + detectionLocation)); + + default -> Optional.empty(); + }; + } + + return Optional.empty(); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxMacContextTranslator.java b/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxMacContextTranslator.java new file mode 100644 index 000000000..13ad5d6ff --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxMacContextTranslator.java @@ -0,0 +1,145 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.translation.translator.contexts; + +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.IDetectionContext; +import com.ibm.engine.rule.IBundle; +import com.ibm.mapper.IContextTranslation; +import com.ibm.mapper.model.Algorithm; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Mac; +import com.ibm.mapper.model.algorithms.AES; +import com.ibm.mapper.model.algorithms.Aria; +import com.ibm.mapper.model.algorithms.CMAC; +import com.ibm.mapper.model.algorithms.Camellia; +import com.ibm.mapper.model.algorithms.DESede; +import com.ibm.mapper.model.algorithms.HMAC; +import com.ibm.mapper.model.algorithms.KMAC; +import com.ibm.mapper.model.algorithms.MD5; +import com.ibm.mapper.model.algorithms.Poly1305; +import com.ibm.mapper.model.algorithms.RIPEMD; +import com.ibm.mapper.model.algorithms.SHA; +import com.ibm.mapper.model.algorithms.SHA2; +import com.ibm.mapper.model.algorithms.SHA3; +import com.ibm.mapper.model.algorithms.SM3; +import com.ibm.mapper.model.algorithms.SM4; +import com.ibm.mapper.model.algorithms.SipHash; +import com.ibm.mapper.model.algorithms.blake.BLAKE2b; +import com.ibm.mapper.model.algorithms.blake.BLAKE2s; +import com.ibm.mapper.utils.DetectionLocation; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.Optional; +import javax.annotation.Nonnull; + +/** + * Translator for C++ MAC detection contexts. + * + *

This translator handles the translation of MAC-related detection values to the mapper model + * nodes. Supports HMAC, CMAC, GMAC, Poly1305, SipHash, KMAC, and BLAKE2 MAC variants. + */ +public final class CxxMacContextTranslator implements IContextTranslation { + + @Override + public @Nonnull Optional translate( + @Nonnull IBundle bundleIdentifier, + @Nonnull IValue value, + @Nonnull IDetectionContext detectionContext, + @Nonnull DetectionLocation detectionLocation) { + + if (value instanceof ValueAction) { + return switch (value.asString().toUpperCase().trim()) { + // HMAC variants + case "HMAC-MD5" -> Optional.of(new HMAC(new MD5(detectionLocation))); + case "HMAC-SHA1" -> Optional.of(new HMAC(new SHA(detectionLocation))); + case "HMAC-SHA224" -> Optional.of(new HMAC(new SHA2(224, detectionLocation))); + case "HMAC-SHA256" -> Optional.of(new HMAC(new SHA2(256, detectionLocation))); + case "HMAC-SHA384" -> Optional.of(new HMAC(new SHA2(384, detectionLocation))); + case "HMAC-SHA512" -> Optional.of(new HMAC(new SHA2(512, detectionLocation))); + // SHA-512/224 and SHA-512/256 are truncated variants of SHA-512 + case "HMAC-SHA512/224" -> Optional.of(new HMAC(new SHA2(224, detectionLocation))); + case "HMAC-SHA512/256" -> Optional.of(new HMAC(new SHA2(256, detectionLocation))); + case "HMAC-SHA3-224" -> Optional.of(new HMAC(new SHA3(224, detectionLocation))); + case "HMAC-SHA3-256" -> Optional.of(new HMAC(new SHA3(256, detectionLocation))); + case "HMAC-SHA3-384" -> Optional.of(new HMAC(new SHA3(384, detectionLocation))); + case "HMAC-SHA3-512" -> Optional.of(new HMAC(new SHA3(512, detectionLocation))); + case "HMAC-RIPEMD160" -> Optional.of(new HMAC(new RIPEMD(160, detectionLocation))); + case "HMAC-BLAKE2B" -> + Optional.of(new HMAC(new BLAKE2b(512, false, detectionLocation))); + case "HMAC-BLAKE2S" -> + Optional.of(new HMAC(new BLAKE2s(256, false, detectionLocation))); + case "HMAC-SM3" -> Optional.of(new HMAC(new SM3(detectionLocation))); + + // CMAC variants + case "CMAC-AES-128" -> Optional.of(new CMAC(new AES(128, detectionLocation))); + case "CMAC-AES-192" -> Optional.of(new CMAC(new AES(192, detectionLocation))); + case "CMAC-AES-256" -> Optional.of(new CMAC(new AES(256, detectionLocation))); + case "CMAC-3DES" -> Optional.of(new CMAC(new DESede(168, detectionLocation))); + case "CMAC-CAMELLIA-128" -> + Optional.of(new CMAC(new Camellia(128, detectionLocation))); + case "CMAC-CAMELLIA-192" -> + Optional.of(new CMAC(new Camellia(192, detectionLocation))); + case "CMAC-CAMELLIA-256" -> + Optional.of(new CMAC(new Camellia(256, detectionLocation))); + case "CMAC-ARIA-128" -> Optional.of(new CMAC(new Aria(128, detectionLocation))); + case "CMAC-ARIA-192" -> Optional.of(new CMAC(new Aria(192, detectionLocation))); + case "CMAC-ARIA-256" -> Optional.of(new CMAC(new Aria(256, detectionLocation))); + case "CMAC-SM4" -> Optional.of(new CMAC(new SM4(detectionLocation))); + + // GMAC variants (Galois MAC — AES-GCM authentication-only mode) + case "GMAC-AES-128" -> { + Algorithm gmac = new Algorithm("GMAC", Mac.class, detectionLocation); + gmac.put(new AES(128, detectionLocation)); + yield Optional.of(gmac); + } + case "GMAC-AES-192" -> { + Algorithm gmac = new Algorithm("GMAC", Mac.class, detectionLocation); + gmac.put(new AES(192, detectionLocation)); + yield Optional.of(gmac); + } + case "GMAC-AES-256" -> { + Algorithm gmac = new Algorithm("GMAC", Mac.class, detectionLocation); + gmac.put(new AES(256, detectionLocation)); + yield Optional.of(gmac); + } + + // Poly1305 + case "POLY1305" -> Optional.of(new Poly1305(detectionLocation)); + + // SipHash + case "SIPHASH-2-4" -> Optional.of(new SipHash(detectionLocation)); + case "SIPHASH-4-8" -> Optional.of(new SipHash(detectionLocation)); + + // KMAC + case "KMAC128" -> Optional.of(new KMAC(128, detectionLocation)); + case "KMAC256" -> Optional.of(new KMAC(256, detectionLocation)); + + // BLAKE2 MAC + case "BLAKE2BMAC" -> Optional.of(new BLAKE2b(512, false, detectionLocation)); + case "BLAKE2SMAC" -> Optional.of(new BLAKE2s(256, false, detectionLocation)); + + default -> Optional.empty(); + }; + } + + return Optional.empty(); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxPRNGContextTranslator.java b/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxPRNGContextTranslator.java new file mode 100644 index 000000000..cd60b1d92 --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxPRNGContextTranslator.java @@ -0,0 +1,159 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.translation.translator.contexts; + +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.IDetectionContext; +import com.ibm.engine.rule.IBundle; +import com.ibm.mapper.IContextTranslation; +import com.ibm.mapper.model.Algorithm; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.PseudorandomNumberGenerator; +import com.ibm.mapper.model.algorithms.AES; +import com.ibm.mapper.model.algorithms.SHA; +import com.ibm.mapper.model.algorithms.SHA2; +import com.ibm.mapper.utils.DetectionLocation; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.Optional; +import javax.annotation.Nonnull; + +/** + * Translator for C++ PRNG (Pseudo-Random Number Generator) detection contexts. + * + *

This translator handles the translation of PRNG-related detection values (RAND, DRBG variants) + * to the mapper model nodes. + */ +public final class CxxPRNGContextTranslator implements IContextTranslation { + + @Override + public @Nonnull Optional translate( + @Nonnull IBundle bundleIdentifier, + @Nonnull IValue value, + @Nonnull IDetectionContext detectionContext, + @Nonnull DetectionLocation detectionLocation) { + + if (value instanceof ValueAction) { + return switch (value.asString().toUpperCase().trim()) { + // Basic RAND operations + case "RAND" -> + Optional.of( + new Algorithm( + "RAND", + PseudorandomNumberGenerator.class, + detectionLocation)); + case "RAND-PSEUDO" -> + Optional.of( + new Algorithm( + "RAND-PSEUDO", + PseudorandomNumberGenerator.class, + detectionLocation)); + + // CTR-DRBG (Counter mode DRBG) - AES-based + case "CTR-DRBG-AES128" -> + Optional.of( + new AES( + PseudorandomNumberGenerator.class, + new AES(128, detectionLocation))); + case "CTR-DRBG-AES192" -> + Optional.of( + new AES( + PseudorandomNumberGenerator.class, + new AES(192, detectionLocation))); + case "CTR-DRBG-AES256" -> + Optional.of( + new AES( + PseudorandomNumberGenerator.class, + new AES(256, detectionLocation))); + + // HASH-DRBG (Hash-based DRBG) + case "HASH-DRBG-SHA1" -> + Optional.of( + new SHA( + PseudorandomNumberGenerator.class, + new SHA(detectionLocation))); + case "HASH-DRBG-SHA256" -> + Optional.of( + new SHA2( + PseudorandomNumberGenerator.class, + new SHA2(256, detectionLocation))); + case "HASH-DRBG-SHA384" -> + Optional.of( + new SHA2( + PseudorandomNumberGenerator.class, + new SHA2(384, detectionLocation))); + case "HASH-DRBG-SHA512" -> + Optional.of( + new SHA2( + PseudorandomNumberGenerator.class, + new SHA2(512, detectionLocation))); + + // HMAC-DRBG (HMAC-based DRBG) - use same hash-based approach + case "HMAC-DRBG-SHA1" -> + Optional.of( + new SHA( + PseudorandomNumberGenerator.class, + new SHA(detectionLocation))); + case "HMAC-DRBG-SHA256" -> + Optional.of( + new SHA2( + PseudorandomNumberGenerator.class, + new SHA2(256, detectionLocation))); + case "HMAC-DRBG-SHA384" -> + Optional.of( + new SHA2( + PseudorandomNumberGenerator.class, + new SHA2(384, detectionLocation))); + case "HMAC-DRBG-SHA512" -> + Optional.of( + new SHA2( + PseudorandomNumberGenerator.class, + new SHA2(512, detectionLocation))); + + // Entropy sources (OpenSSL provider-based) + case "SEED-SRC" -> + Optional.of( + new Algorithm( + "SEED-SRC", + PseudorandomNumberGenerator.class, + detectionLocation)); + case "JITTER" -> + Optional.of( + new Algorithm( + "JITTER", + PseudorandomNumberGenerator.class, + detectionLocation)); + case "TEST-RAND" -> + Optional.of( + new Algorithm( + "TEST-RAND", + PseudorandomNumberGenerator.class, + detectionLocation)); + + // Entropy seeding operations (not distinct algorithms — yield empty) + case "RAND-SEED", "RAND-ADD", "RAND-POLL" -> Optional.empty(); + + default -> Optional.empty(); + }; + } + + return Optional.empty(); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxProtocolContextTranslator.java b/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxProtocolContextTranslator.java new file mode 100644 index 000000000..0152ac0d8 --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxProtocolContextTranslator.java @@ -0,0 +1,129 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.translation.translator.contexts; + +import com.ibm.engine.model.CipherSuite; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.IDetectionContext; +import com.ibm.engine.model.context.ProtocolContext; +import com.ibm.engine.rule.IBundle; +import com.ibm.mapper.IContextTranslation; +import com.ibm.mapper.mapper.ssl.CipherSuiteMapper; +import com.ibm.mapper.mapper.ssl.SSLVersionMapper; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Protocol; +import com.ibm.mapper.model.Unknown; +import com.ibm.mapper.model.Version; +import com.ibm.mapper.model.protocol.TLS; +import com.ibm.mapper.utils.DetectionLocation; +import com.ibm.plugin.rules.detection.openssl.ssl.OpenSSLVersionValue; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.Optional; +import javax.annotation.Nonnull; + +/** + * Translates OpenSSL libssl protocol contexts to CBOM model nodes. + * + *

Handles SSL/TLS protocol detection including version strings (TLS 1.2, TLS 1.3, DTLS, QUIC, + * etc.) and cipher suite configurations. + */ +public final class CxxProtocolContextTranslator implements IContextTranslation { + + @Nonnull + @Override + public Optional translate( + @Nonnull IBundle bundleIdentifier, + @Nonnull IValue value, + @Nonnull IDetectionContext detectionContext, + @Nonnull DetectionLocation detectionLocation) { + if (!bundleIdentifier.getIdentifier().equals("OpenSSL")) { + return Optional.empty(); + } + + final ProtocolContext.Kind kind = ((ProtocolContext) detectionContext).kind(); + + // Handle OpenSSLVersionValue (custom value type with parameter extraction) + if (value instanceof OpenSSLVersionValue versionValue) { + final String versionString = versionValue.asString(); + if (kind == ProtocolContext.Kind.TLS) { + final SSLVersionMapper sslVersionMapper = new SSLVersionMapper(); + final Optional parsedVersion = + sslVersionMapper.parse(versionString, detectionLocation); + if (parsedVersion.isPresent()) { + return Optional.of(new TLS(parsedVersion.get())); + } + // Fallback to generic protocol if parsing fails + return Optional.of(new Protocol(versionString, detectionLocation)); + } + return Optional.of(new Protocol(versionString, detectionLocation)); + } + + if (value instanceof com.ibm.engine.model.Protocol protocol) { + return switch (kind) { + case TLS -> + Optional.of(protocol) + .map( + p -> { + final SSLVersionMapper sslVersionMapper = + new SSLVersionMapper(); + return sslVersionMapper + .parse(p.asString(), detectionLocation) + .map(TLS::new) + .orElse(new TLS(detectionLocation)); + }); + default -> + Optional.of(protocol) + .map(p -> new Protocol(p.asString(), detectionLocation)); + }; + } else if (value instanceof CipherSuite cipherSuite) { + return switch (kind) { + case TLS -> + new CipherSuiteMapper() + .parse(cipherSuite.get(), detectionLocation) + .map(n -> n); + default -> + Optional.of(cipherSuite) + .map( + suite -> + new com.ibm.mapper.model.CipherSuite( + suite.asString(), detectionLocation)); + }; + } else if (value instanceof ValueAction valueAction) { + // Handle ValueAction instances from ValueActionFactory + final String stringValue = valueAction.asString(); + if (kind == ProtocolContext.Kind.TLS) { + // Try to parse as SSL version first + final SSLVersionMapper sslVersionMapper = new SSLVersionMapper(); + final Optional parsedVersion = + sslVersionMapper.parse(stringValue, detectionLocation); + if (parsedVersion.isPresent()) { + return Optional.of(new TLS(parsedVersion.get())); + } + // If not a version string, treat as generic protocol + return Optional.of(new Protocol(stringValue, detectionLocation)); + } + // For non-TLS protocols, create generic Protocol node + return Optional.of(new Protocol(stringValue, detectionLocation)); + } + + return Optional.of(new Unknown(detectionLocation)); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxSecretKeyContextTranslator.java b/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxSecretKeyContextTranslator.java new file mode 100644 index 000000000..3df18fabb --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxSecretKeyContextTranslator.java @@ -0,0 +1,55 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.translation.translator.contexts; + +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.context.IDetectionContext; +import com.ibm.engine.rule.IBundle; +import com.ibm.mapper.IContextTranslation; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.utils.DetectionLocation; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.Optional; +import javax.annotation.Nonnull; + +/** + * Translator for C++ secret key detection contexts. + * + *

This translator handles the translation of secret key-related detection values to the mapper + * model nodes. + */ +public final class CxxSecretKeyContextTranslator implements IContextTranslation { + + public CxxSecretKeyContextTranslator() { + // nothing + } + + @Override + @Nonnull + public Optional translate( + @Nonnull IBundle bundleIdentifier, + @Nonnull IValue value, + @Nonnull IDetectionContext detectionValueContext, + @Nonnull DetectionLocation detectionLocation) { + // TODO: Implement secret key context translation based on detection value type + // This will be expanded when OpenSSL/other library detection rules are added + return Optional.empty(); + } +} diff --git a/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxSignatureContextTranslator.java b/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxSignatureContextTranslator.java new file mode 100644 index 000000000..c9ac9946b --- /dev/null +++ b/cpp/src/main/java/com/ibm/plugin/translation/translator/contexts/CxxSignatureContextTranslator.java @@ -0,0 +1,163 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.translation.translator.contexts; + +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.IDetectionContext; +import com.ibm.engine.rule.IBundle; +import com.ibm.mapper.IContextTranslation; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.Signature; +import com.ibm.mapper.model.algorithms.DSA; +import com.ibm.mapper.model.algorithms.ECDSA; +import com.ibm.mapper.model.algorithms.EdDSA; +import com.ibm.mapper.model.algorithms.MLDSA; +import com.ibm.mapper.model.algorithms.RSA; +import com.ibm.mapper.model.algorithms.RSAssaPSS; +import com.ibm.mapper.model.algorithms.SHA; +import com.ibm.mapper.model.algorithms.SHA2; +import com.ibm.mapper.model.algorithms.SHA3; +import com.ibm.mapper.model.algorithms.SLHDSA; +import com.ibm.mapper.model.algorithms.SM2; +import com.ibm.mapper.utils.DetectionLocation; +import com.sonar.cxx.sslr.api.AstNode; +import java.util.Optional; +import javax.annotation.Nonnull; + +/** + * Translator for C++ signature detection contexts. + * + *

This translator handles the translation of signature-related detection values to the mapper + * model nodes. Supports RSA, DSA, ECDSA, EdDSA, post-quantum, and SM2 signatures. + */ +public final class CxxSignatureContextTranslator implements IContextTranslation { + + @Override + public @Nonnull Optional translate( + @Nonnull IBundle bundleIdentifier, + @Nonnull IValue value, + @Nonnull IDetectionContext detectionContext, + @Nonnull DetectionLocation detectionLocation) { + + if (value instanceof ValueAction) { + String algorithmName = value.asString().toUpperCase().trim(); + + // RSA-PSS Signatures (PKCS#1 v2.1 / RSASSA-PSS) — must check before generic RSA- + if (algorithmName.startsWith("RSA-PSS-")) { + RSAssaPSS rsapss = new RSAssaPSS(detectionLocation); + if (algorithmName.contains("SHA256")) { + rsapss.put(new SHA2(256, detectionLocation)); + } else if (algorithmName.contains("SHA384")) { + rsapss.put(new SHA2(384, detectionLocation)); + } else if (algorithmName.contains("SHA512")) { + rsapss.put(new SHA2(512, detectionLocation)); + } else if (algorithmName.contains("SHA1")) { + rsapss.put(new SHA(detectionLocation)); + } + return Optional.of(rsapss); + } + + // RSA Signatures (PKCS#1 v1.5) + if (algorithmName.startsWith("RSA-")) { + RSA rsa = new RSA(Signature.class, detectionLocation); + if (algorithmName.contains("SHA1")) { + rsa.put(new SHA(detectionLocation)); + } else if (algorithmName.contains("SHA224")) { + rsa.put(new SHA2(224, detectionLocation)); + } else if (algorithmName.contains("SHA256")) { + rsa.put(new SHA2(256, detectionLocation)); + } else if (algorithmName.contains("SHA384")) { + rsa.put(new SHA2(384, detectionLocation)); + } else if (algorithmName.contains("SHA512")) { + rsa.put(new SHA2(512, detectionLocation)); + } + return Optional.of(rsa); + } + + // DSA Signatures + if (algorithmName.startsWith("DSA-")) { + if (algorithmName.contains("SHA1")) { + return Optional.of(new DSA(new SHA(detectionLocation))); + } else if (algorithmName.contains("SHA224")) { + return Optional.of(new DSA(new SHA2(224, detectionLocation))); + } else if (algorithmName.contains("SHA256")) { + return Optional.of(new DSA(new SHA2(256, detectionLocation))); + } else if (algorithmName.contains("SHA384")) { + return Optional.of(new DSA(new SHA2(384, detectionLocation))); + } else if (algorithmName.contains("SHA512")) { + return Optional.of(new DSA(new SHA2(512, detectionLocation))); + } + return Optional.of(new DSA(detectionLocation)); + } + + // ECDSA Signatures + if (algorithmName.startsWith("ECDSA-")) { + ECDSA ecdsa = new ECDSA(detectionLocation); + if (algorithmName.contains("SHA1")) { + ecdsa.put(new SHA(detectionLocation)); + } else if (algorithmName.contains("SHA3-256")) { + ecdsa.put(new SHA3(256, detectionLocation)); + } else if (algorithmName.contains("SHA3-384")) { + ecdsa.put(new SHA3(384, detectionLocation)); + } else if (algorithmName.contains("SHA3-512")) { + ecdsa.put(new SHA3(512, detectionLocation)); + } else if (algorithmName.contains("SHA224")) { + ecdsa.put(new SHA2(224, detectionLocation)); + } else if (algorithmName.contains("SHA256")) { + ecdsa.put(new SHA2(256, detectionLocation)); + } else if (algorithmName.contains("SHA384")) { + ecdsa.put(new SHA2(384, detectionLocation)); + } else if (algorithmName.contains("SHA512")) { + ecdsa.put(new SHA2(512, detectionLocation)); + } + return Optional.of(ecdsa); + } + + // EdDSA Signatures + if (algorithmName.equals("ED25519") || algorithmName.equals("ED448")) { + return Optional.of(new EdDSA(detectionLocation)); + } + + // Post-Quantum: ML-DSA + if (algorithmName.startsWith("ML-DSA-")) { + if (algorithmName.equals("ML-DSA-44")) { + return Optional.of(new MLDSA(2, detectionLocation)); + } else if (algorithmName.equals("ML-DSA-65")) { + return Optional.of(new MLDSA(3, detectionLocation)); + } else if (algorithmName.equals("ML-DSA-87")) { + return Optional.of(new MLDSA(5, detectionLocation)); + } + } + + // Post-Quantum: SLH-DSA + if (algorithmName.startsWith("SLH-DSA-")) { + return Optional.of(new SLHDSA(detectionLocation)); + } + + // SM2 + if (algorithmName.equals("SM2")) { + return Optional.of(new SM2(detectionLocation)); + } + } + + return Optional.empty(); + } +} diff --git a/cpp/src/main/resources/org/sonar/l10n/cpp/rules/cpp/Inventory.html b/cpp/src/main/resources/org/sonar/l10n/cpp/rules/cpp/Inventory.html new file mode 100644 index 000000000..6df507b88 --- /dev/null +++ b/cpp/src/main/resources/org/sonar/l10n/cpp/rules/cpp/Inventory.html @@ -0,0 +1,10 @@ +

Cryptography Usage: Be careful

+ +

Cryptography is a critical component of modern digital security, protecting sensitive data and communications + from unauthorized access. However, implementing cryptographic systems correctly is notoriously challenging, + even for experienced developers. Therefore, caution is necessary when writing code related to + cryptography.

+ +

It is important that you read the documentation for the cryptographic library you are using and strictly + adhere to the specified implementation guidelines.

+ diff --git a/cpp/src/main/resources/org/sonar/l10n/cpp/rules/cpp/Inventory.json b/cpp/src/main/resources/org/sonar/l10n/cpp/rules/cpp/Inventory.json new file mode 100644 index 000000000..5fbf60599 --- /dev/null +++ b/cpp/src/main/resources/org/sonar/l10n/cpp/rules/cpp/Inventory.json @@ -0,0 +1,19 @@ +{ + "title": "Cryptographic Inventory (CBOM)", + "type": "CODE_SMELL", + "code": { + "impacts": { + "SECURITY": "INFO" + }, + "attribute": "TRUSTWORTHY" + }, + "status": "ready", + "tags": [ + "cryptography", + "cbom", + "cwe" + ], + "defaultSeverity": "Minor", + "scope": "Main", + "sqKey": "Inventory" +} diff --git a/cpp/src/test/java/com/ibm/plugin/CxxVerifier.java b/cpp/src/test/java/com/ibm/plugin/CxxVerifier.java new file mode 100644 index 000000000..b5329a1a1 --- /dev/null +++ b/cpp/src/test/java/com/ibm/plugin/CxxVerifier.java @@ -0,0 +1,89 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin; + +import com.sonar.cxx.sslr.api.Grammar; +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import javax.annotation.Nonnull; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.internal.TestInputFileBuilder; +import org.sonar.cxx.CxxAstScanner; +import org.sonar.cxx.squidbridge.SquidAstVisitor; + +/** + * Test verifier for C++ detection rules. + * + *

Scans a C++ test file using {@link CxxAstScanner} and invokes the provided check (typically a + * {@link TestBase} instance) which intercepts detection findings and calls {@code asserts()}. + */ +public final class CxxVerifier { + + private static final String TEST_FILES_BASE = "src/test/files/"; + + private CxxVerifier() { + // utility class + } + + /** + * Verifies a C++ test file by scanning it with the given check. + * + * @param relativePath Path to the test file relative to {@code src/test/files/} + * @param check The check (detection rule) to apply + */ + public static void verify( + @Nonnull String relativePath, @Nonnull SquidAstVisitor check) { + verify(relativePath, check, StandardCharsets.UTF_8); + } + + /** + * Verifies a C++ test file by scanning it with the given check and specified charset. + * + * @param relativePath Path to the test file relative to {@code src/test/files/} + * @param check The check (detection rule) to apply + * @param charset The character set of the test file + */ + public static void verify( + @Nonnull String relativePath, + @Nonnull SquidAstVisitor check, + @Nonnull Charset charset) { + String fullPath = TEST_FILES_BASE + relativePath; + File file = new File(fullPath); + if (!file.isFile()) { + throw new IllegalArgumentException("Test file not found: " + file.getAbsolutePath()); + } + + try { + String content = new String(java.nio.file.Files.readAllBytes(file.toPath()), charset); + InputFile inputFile = + TestInputFileBuilder.create("", fullPath) + .setCharset(charset) + .setProjectBaseDir(Path.of(".")) + .setContents(content) + .build(); + CxxAstScanner.scanSingleInputFile(inputFile, check); + } catch (IOException e) { + throw new IllegalStateException("Failed to read test file: " + fullPath, e); + } + } +} diff --git a/cpp/src/test/java/com/ibm/plugin/TestBase.java b/cpp/src/test/java/com/ibm/plugin/TestBase.java new file mode 100644 index 000000000..dbfe4e877 --- /dev/null +++ b/cpp/src/test/java/com/ibm/plugin/TestBase.java @@ -0,0 +1,164 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.detection.Finding; +import com.ibm.engine.model.IValue; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.utils.DetectionStoreLogger; +import com.ibm.mapper.model.INode; +import com.ibm.plugin.rules.CxxInventoryRule; +import com.ibm.plugin.rules.detection.CxxDetectionRules; +import com.sonar.cxx.sslr.api.AstNode; +import com.sonar.cxx.sslr.api.Grammar; +import java.util.List; +import java.util.Optional; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.junit.jupiter.api.BeforeEach; +import org.sonar.cxx.squidbridge.SquidAstVisitorContext; +import org.sonar.cxx.squidbridge.api.Symbol; +import org.sonar.cxx.squidbridge.checks.SquidCheck; + +public abstract class TestBase extends CxxInventoryRule { + + @Nonnull + private final DetectionStoreLogger< + SquidCheck, AstNode, Symbol, SquidAstVisitorContext> + detectionStoreLogger = new DetectionStoreLogger<>(); + + private int findingId = 0; + + public TestBase(@Nonnull List> detectionRules) { + super(detectionRules); + } + + public TestBase() { + super(CxxDetectionRules.rules()); + } + + @BeforeEach + public void resetState() { + CxxAggregator.reset(); + } + + @Override + public void update( + @Nonnull + Finding< + SquidCheck, + AstNode, + Symbol, + SquidAstVisitorContext> + finding) { + final DetectionStore< + SquidCheck, AstNode, Symbol, SquidAstVisitorContext> + detectionStore = finding.detectionStore(); + detectionStoreLogger.print(detectionStore); + + final List nodes = cxxTranslationProcess.initiate(detectionStore); + asserts(findingId, detectionStore, nodes); + findingId++; + // report + this.report(finding.getMarkerTree(), nodes) + .forEach( + issue -> + finding.detectionStore() + .getScanContext() + .reportIssue(this, issue.tree(), issue.message())); + } + + public abstract void asserts( + int findingId, + @Nonnull + DetectionStore< + SquidCheck, + AstNode, + Symbol, + SquidAstVisitorContext> + detectionStore, + @Nonnull List nodes); + + @Nullable public DetectionStore, AstNode, Symbol, SquidAstVisitorContext> + getStoreOfValueType( + @Nonnull final Class valueType, + @Nonnull + List< + DetectionStore< + SquidCheck, + AstNode, + Symbol, + SquidAstVisitorContext>> + detectionStores) { + Optional< + DetectionStore< + SquidCheck, + AstNode, + Symbol, + SquidAstVisitorContext>> + relevantStore = + detectionStores.stream() + .filter( + store -> + store.getDetectionValues().stream() + .anyMatch( + value -> + value.getClass() + .equals(valueType))) + .findFirst(); + return relevantStore.orElseGet( + () -> + detectionStores.stream() + .map( + store -> + Optional.ofNullable( + getStoreOfValueType( + valueType, store.getChildren()))) + .filter(Optional::isPresent) + .map(Optional::get) + .findFirst() + .orElse(null)); + } + + @Nullable public List< + DetectionStore< + SquidCheck, + AstNode, + Symbol, + SquidAstVisitorContext>> + getStoresOfValueType( + @Nonnull final Class valueType, + @Nonnull + List< + DetectionStore< + SquidCheck, + AstNode, + Symbol, + SquidAstVisitorContext>> + detectionStores) { + return detectionStores.stream() + .filter( + store -> + store.getDetectionValues().stream() + .anyMatch(value -> value.getClass().equals(valueType))) + .toList(); + } +} diff --git a/engine/pom.xml b/engine/pom.xml index 20acc80fd..895801166 100644 --- a/engine/pom.xml +++ b/engine/pom.xml @@ -29,6 +29,11 @@ antlr4-runtime 4.13.1 + + com.github.SonarOpenCommunity.sonar-cxx + cxx-squid + ${sonar.cxx.version} + diff --git a/engine/src/main/java/com/ibm/engine/language/LanguageSupporter.java b/engine/src/main/java/com/ibm/engine/language/LanguageSupporter.java index c5a82a55a..82ea14791 100644 --- a/engine/src/main/java/com/ibm/engine/language/LanguageSupporter.java +++ b/engine/src/main/java/com/ibm/engine/language/LanguageSupporter.java @@ -24,11 +24,16 @@ import com.ibm.engine.language.csharp.CSharpScanContext; import com.ibm.engine.language.csharp.CSharpSymbol; import com.ibm.engine.language.csharp.tree.CSharpTree; +import com.ibm.engine.language.cxx.CxxLanguageSupport; import com.ibm.engine.language.go.GoLanguageSupport; import com.ibm.engine.language.go.GoScanContext; import com.ibm.engine.language.java.JavaLanguageSupport; import com.ibm.engine.language.python.PythonLanguageSupport; +import com.sonar.cxx.sslr.api.AstNode; +import com.sonar.cxx.sslr.api.Grammar; import javax.annotation.Nonnull; +import org.sonar.cxx.squidbridge.SquidAstVisitorContext; +import org.sonar.cxx.squidbridge.checks.SquidCheck; import org.sonar.go.symbols.Symbol; import org.sonar.plugins.go.api.Tree; import org.sonar.plugins.go.api.checks.GoCheck; @@ -73,4 +78,14 @@ public static ILanguageSupport goLanguageS csharpLanguageSupporter() { return new CSharpLanguageSupport(); } + + @Nonnull + public static ILanguageSupport< + SquidCheck, + AstNode, + org.sonar.cxx.squidbridge.api.Symbol, + SquidAstVisitorContext> + cxxLanguageSupporter() { + return new CxxLanguageSupport(); + } } diff --git a/engine/src/main/java/com/ibm/engine/language/cxx/CxxBaseMethodVisitor.java b/engine/src/main/java/com/ibm/engine/language/cxx/CxxBaseMethodVisitor.java new file mode 100644 index 000000000..d7774c20d --- /dev/null +++ b/engine/src/main/java/com/ibm/engine/language/cxx/CxxBaseMethodVisitor.java @@ -0,0 +1,87 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.engine.language.cxx; + +import com.ibm.engine.detection.IBaseMethodVisitor; +import com.ibm.engine.detection.IDetectionEngine; +import com.ibm.engine.detection.TraceSymbol; +import com.sonar.cxx.sslr.api.AstNode; +import com.sonar.cxx.sslr.api.AstNodeType; +import javax.annotation.Nonnull; +import org.sonar.cxx.parser.CxxGrammarImpl; +import org.sonar.cxx.squidbridge.api.AstNodeTraversal; +import org.sonar.cxx.squidbridge.api.Symbol; +import org.sonar.cxx.utils.CxxAstNodeHelper; + +public class CxxBaseMethodVisitor implements IBaseMethodVisitor { + @Nonnull private final TraceSymbol traceSymbol; + @Nonnull private final IDetectionEngine detectionEngine; + + private static final AstNodeType[] DETECTION_NODE_TYPES = { + CxxGrammarImpl.postfixExpression, CxxGrammarImpl.newExpression, CxxGrammarImpl.enumSpecifier + }; + + public CxxBaseMethodVisitor( + @Nonnull TraceSymbol traceSymbol, + @Nonnull IDetectionEngine detectionEngine) { + this.traceSymbol = traceSymbol; + this.detectionEngine = detectionEngine; + } + + @Override + public void visitMethodDefinition(@Nonnull AstNode method) { + if (method.is(CxxGrammarImpl.functionDefinition)) { + AstNode functionBody = CxxAstNodeHelper.getFunctionDefinitionBody(method); + if (functionBody != null) { + traverseAndDetect(functionBody); + } + } else if (method.is(CxxGrammarImpl.translationUnit)) { + traverseAndDetect(method); + } + } + + private void traverseAndDetect(@Nonnull AstNode root) { + AstNodeTraversal.traverse(root, DETECTION_NODE_TYPES, this::visitNode); + } + + private void visitNode(@Nonnull AstNode node) { + if (node.is(CxxGrammarImpl.postfixExpression)) { + visitPostfixExpression(node); + } else if (node.is(CxxGrammarImpl.newExpression)) { + visitNewExpression(node); + } else if (node.is(CxxGrammarImpl.enumSpecifier)) { + visitEnumSpecifier(node); + } + } + + private void visitPostfixExpression(@Nonnull AstNode node) { + if (CxxAstNodeHelper.isFunctionCall(node)) { + detectionEngine.run(traceSymbol, node); + } + } + + private void visitNewExpression(@Nonnull AstNode node) { + detectionEngine.run(traceSymbol, node); + } + + private void visitEnumSpecifier(@Nonnull AstNode node) { + detectionEngine.run(traceSymbol, node); + } +} diff --git a/engine/src/main/java/com/ibm/engine/language/cxx/CxxDetectionEngine.java b/engine/src/main/java/com/ibm/engine/language/cxx/CxxDetectionEngine.java new file mode 100644 index 000000000..b854e4fa0 --- /dev/null +++ b/engine/src/main/java/com/ibm/engine/language/cxx/CxxDetectionEngine.java @@ -0,0 +1,446 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.engine.language.cxx; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.detection.DetectionStoreWithHook; +import com.ibm.engine.detection.Handler; +import com.ibm.engine.detection.IDetectionEngine; +import com.ibm.engine.detection.MatchContext; +import com.ibm.engine.detection.MethodDetection; +import com.ibm.engine.detection.ResolvedValue; +import com.ibm.engine.detection.TraceSymbol; +import com.ibm.engine.detection.ValueDetection; +import com.ibm.engine.hooks.MethodInvocationHookWithParameterResolvement; +import com.ibm.engine.hooks.MethodInvocationHookWithReturnResolvement; +import com.ibm.engine.model.factory.IValueFactory; +import com.ibm.engine.rule.DetectableParameter; +import com.ibm.engine.rule.DetectionRule; +import com.ibm.engine.rule.MethodDetectionRule; +import com.ibm.engine.rule.Parameter; +import com.sonar.cxx.sslr.api.AstNode; +import com.sonar.cxx.sslr.api.Grammar; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.sonar.cxx.parser.CxxGrammarImpl; +import org.sonar.cxx.squidbridge.SquidAstVisitorContext; +import org.sonar.cxx.squidbridge.api.AstNodeSymbolExtension; +import org.sonar.cxx.squidbridge.api.Symbol; +import org.sonar.cxx.squidbridge.checks.SquidCheck; +import org.sonar.cxx.utils.CxxAstNodeHelper; + +public class CxxDetectionEngine implements IDetectionEngine { + @Nonnull + private final DetectionStore< + SquidCheck, AstNode, Symbol, SquidAstVisitorContext> + detectionStore; + + @Nonnull + private final Handler, AstNode, Symbol, SquidAstVisitorContext> + handler; + + public CxxDetectionEngine( + @Nonnull + DetectionStore< + SquidCheck, + AstNode, + Symbol, + SquidAstVisitorContext> + detectionStore, + @Nonnull + Handler< + SquidCheck, + AstNode, + Symbol, + SquidAstVisitorContext> + handler) { + this.detectionStore = detectionStore; + this.handler = handler; + } + + @Override + public void run(@Nonnull AstNode tree) { + run(TraceSymbol.createStart(), tree); + } + + @Override + public void run(@Nonnull TraceSymbol traceSymbol, @Nonnull AstNode tree) { + if (CxxAstNodeHelper.isFunctionCall(tree)) { + handler.addCallToCallStack(tree, detectionStore.getScanContext()); + if (detectionStore + .getDetectionRule() + .match(tree, handler.getLanguageSupport().translation())) { + this.analyseExpression(traceSymbol, tree); + } + } else if (CxxAstNodeHelper.isConstructorCall(tree)) { + if (detectionStore + .getDetectionRule() + .match(tree, handler.getLanguageSupport().translation())) { + this.analyseExpression(traceSymbol, tree); + } + } else if (tree.is(CxxGrammarImpl.enumSpecifier)) { + handler.addCallToCallStack(tree, detectionStore.getScanContext()); + } + } + + @Nullable @Override + public AstNode extractArgumentFromMethodCaller( + @Nonnull AstNode methodDefinition, + @Nonnull AstNode methodInvocation, + @Nonnull AstNode methodParameterIdentifier) { + if (!methodDefinition.is(CxxGrammarImpl.functionDefinition)) { + return null; + } + + List defParams = + CxxAstNodeHelper.getFunctionDefinitionParameters(methodDefinition); + List callArgs; + + if (CxxAstNodeHelper.isFunctionCall(methodInvocation)) { + callArgs = CxxAstNodeHelper.getFunctionCallArguments(methodInvocation); + } else if (CxxAstNodeHelper.isConstructorCall(methodInvocation)) { + AstNode newInitializer = methodInvocation.getFirstChild(CxxGrammarImpl.newInitializer); + if (newInitializer != null) { + AstNode expressionList = + newInitializer.getFirstDescendant(CxxGrammarImpl.expressionList); + if (expressionList != null) { + callArgs = expressionList.getChildren(); + } else { + callArgs = Collections.emptyList(); + } + } else { + callArgs = Collections.emptyList(); + } + } else { + return null; + } + + if (defParams.size() != callArgs.size()) { + return null; + } + + final MatchContext matchContext = + MatchContext.build(false, detectionStore.getDetectionRule()); + Optional targetVarIdOptional = + handler.getLanguageSupport() + .translation() + .resolveIdentifierAsString(matchContext, methodParameterIdentifier); + + if (targetVarIdOptional.isEmpty()) { + return null; + } + final String targetVarId = targetVarIdOptional.get(); + + for (int i = 0; i < defParams.size(); i++) { + AstNode paramDecl = defParams.get(i); + String paramName = CxxAstNodeHelper.getIdentifierName(paramDecl); + if (paramName != null && paramName.equals(targetVarId)) { + return callArgs.get(i); + } + } + return null; + } + + @Nonnull + @Override + public List> resolveValuesInInnerScope( + @Nonnull Class clazz, + @Nonnull AstNode expression, + @Nullable IValueFactory valueFactory) { + return CxxSemantic.resolveValues( + clazz, expression, new LinkedList<>(), valueFactory, false, this); + } + + @Override + public void resolveValuesInOuterScope( + @Nonnull AstNode expression, @Nonnull Parameter parameter) { + Optional optionalMethodNode = + handler.getLanguageSupport().getEnclosingMethod(expression); + if (optionalMethodNode.isEmpty()) { + return; + } + AstNode methodNode = optionalMethodNode.get(); + + List> resolvedValues = + CxxSemantic.resolveValues( + Object.class, expression, new LinkedList<>(), null, true, this); + + if (resolvedValues.size() != 1) { + return; + } + final AstNode resolvedParameter = resolvedValues.get(0).tree(); + + createAMethodHook(methodNode, resolvedParameter, parameter); + } + + private void createAMethodHook( + @Nonnull AstNode methodNode, + @Nullable AstNode methodParameter, + @Nonnull Parameter detectableParameter) { + final MatchContext matchContext = + MatchContext.build(true, detectionStore.getDetectionRule()); + + if (methodParameter == null) { + MethodInvocationHookWithReturnResolvement< + SquidCheck, + AstNode, + Symbol, + SquidAstVisitorContext> + methodInvocationHookWithReturnResolvement = + new MethodInvocationHookWithReturnResolvement<>( + methodNode, detectableParameter, matchContext); + if (this.detectionStore + instanceof + final DetectionStoreWithHook< + SquidCheck, + AstNode, + Symbol, + SquidAstVisitorContext> + detectionStoreWithHook) { + detectionStoreWithHook.onSuccessiveHook(methodInvocationHookWithReturnResolvement); + } else { + handler.addHookToHookRepository(methodInvocationHookWithReturnResolvement); + detectionStore.onNewHookRegistration(methodInvocationHookWithReturnResolvement); + } + return; + } + + MethodInvocationHookWithParameterResolvement< + SquidCheck, AstNode, Symbol, SquidAstVisitorContext> + methodInvocationHookWithParameterResolvement = + new MethodInvocationHookWithParameterResolvement<>( + methodNode, methodParameter, detectableParameter, matchContext); + if (this.detectionStore + instanceof + final DetectionStoreWithHook< + SquidCheck, + AstNode, + Symbol, + SquidAstVisitorContext> + detectionStoreWithHook) { + detectionStoreWithHook.onSuccessiveHook(methodInvocationHookWithParameterResolvement); + } else { + handler.addHookToHookRepository(methodInvocationHookWithParameterResolvement); + detectionStore.onNewHookRegistration(methodInvocationHookWithParameterResolvement); + } + } + + @Override + public void resolveMethodReturnValues( + @Nonnull Class clazz, + @Nonnull AstNode methodDefinition, + @Nonnull Parameter parameter) { + throw new UnsupportedOperationException("Unimplemented method 'resolveMethodReturnValues'"); + } + + @Nullable @Override + public ResolvedValue resolveEnumValue( + @Nonnull Class clazz, + @Nonnull AstNode enumClassDefinition, + @Nonnull LinkedList selections) { + throw new UnsupportedOperationException("Unimplemented method 'resolveEnumValue'"); + } + + @Nonnull + @Override + public Optional> getAssignedSymbol(@Nonnull AstNode expression) { + Symbol symbol = CxxAstNodeHelper.getAssignedSymbol(expression); + if (symbol != null) { + return Optional.of(TraceSymbol.createFrom(symbol)); + } + return Optional.empty(); + } + + @Nonnull + @Override + public Optional> getMethodInvocationParameterSymbol( + @Nonnull AstNode methodInvocation, @Nonnull Parameter parameter) { + if (CxxAstNodeHelper.isFunctionCall(methodInvocation)) { + List arguments = CxxAstNodeHelper.getFunctionCallArguments(methodInvocation); + return getTraceSymbol(parameter, arguments); + } + return Optional.empty(); + } + + @Nonnull + @Override + public Optional> getNewClassParameterSymbol( + @Nonnull AstNode newClass, @Nonnull Parameter parameter) { + if (CxxAstNodeHelper.isConstructorCall(newClass)) { + AstNode newInitializer = newClass.getFirstChild(CxxGrammarImpl.newInitializer); + if (newInitializer != null) { + AstNode expressionList = + newInitializer.getFirstDescendant(CxxGrammarImpl.expressionList); + if (expressionList != null) { + return getTraceSymbol(parameter, expressionList.getChildren()); + } + } + } + return Optional.empty(); + } + + @Nonnull + private Optional> getTraceSymbol( + @Nonnull Parameter parameter, @Nonnull List arguments) { + if (parameter.getIndex() >= arguments.size()) { + return Optional.of(TraceSymbol.createWithStateDifferent()); + } + AstNode arg = arguments.get(parameter.getIndex()); + Symbol symbol = AstNodeSymbolExtension.getSymbol(arg); + if (symbol != null && !symbol.isUnknown()) { + return Optional.of(TraceSymbol.createFrom(symbol)); + } + return Optional.of(TraceSymbol.createWithStateNoSymbol()); + } + + @Override + public boolean isInvocationOnVariable( + @Nonnull AstNode methodInvocation, @Nonnull TraceSymbol variableSymbol) { + if (!CxxAstNodeHelper.isFunctionCall(methodInvocation)) { + return false; + } + if (!variableSymbol.is(TraceSymbol.State.SYMBOL)) { + return false; + } + Symbol variable = variableSymbol.getSymbol(); + if (variable == null) { + return false; + } + return CxxAstNodeHelper.isInvocationOnVariable(methodInvocation, variable, true); + } + + @Override + public boolean isInitForVariable( + @Nonnull AstNode newClass, @Nonnull TraceSymbol variableSymbol) { + if (!variableSymbol.is(TraceSymbol.State.SYMBOL)) { + return false; + } + Symbol variable = variableSymbol.getSymbol(); + Optional> symbolOptional = getAssignedSymbol(newClass); + if (symbolOptional.isEmpty()) { + return false; + } + TraceSymbol traceSymbol = symbolOptional.get(); + Symbol symbol = traceSymbol.getSymbol(); + if (symbol == null || variable == null) { + return false; + } + return symbol.name().equals(variable.name()); + } + + private void analyseExpression( + @Nonnull TraceSymbol traceSymbol, @Nonnull AstNode expressionNode) { + if (detectionStore.getDetectionRule().is(MethodDetectionRule.class)) { + MethodDetection methodDetection = new MethodDetection<>(expressionNode, null); + detectionStore.onReceivingNewDetection(methodDetection); + return; + } + + DetectionRule detectionRule = + (DetectionRule) detectionStore.getDetectionRule(); + if (detectionRule.actionFactory() != null) { + MethodDetection methodDetection = new MethodDetection<>(expressionNode, null); + detectionStore.onReceivingNewDetection(methodDetection); + } + + List arguments; + if (CxxAstNodeHelper.isFunctionCall(expressionNode)) { + arguments = CxxAstNodeHelper.getFunctionCallArguments(expressionNode); + } else if (CxxAstNodeHelper.isConstructorCall(expressionNode)) { + AstNode newInitializer = expressionNode.getFirstChild(CxxGrammarImpl.newInitializer); + if (newInitializer != null) { + AstNode expressionList = + newInitializer.getFirstDescendant(CxxGrammarImpl.expressionList); + if (expressionList != null) { + arguments = expressionList.getChildren(); + } else { + arguments = Collections.emptyList(); + } + } else { + arguments = Collections.emptyList(); + } + } else { + return; + } + + boolean isInvocation = + isInvocationOnVariable(expressionNode, traceSymbol) + || isInitForVariable(expressionNode, traceSymbol); + + int index = 0; + for (Parameter parameter : detectionRule.parameters()) { + if (!checkCurrentIndexState( + index, arguments, isInvocation, traceSymbol, expressionNode)) { + index++; + continue; + } + + AstNode expression = arguments.get(index); + + if (parameter.is(DetectableParameter.class)) { + DetectableParameter detectableParameter = + (DetectableParameter) parameter; + List> resolvedValues = + resolveValuesInInnerScope( + Object.class, expression, detectableParameter.getiValueFactory()); + if (resolvedValues.isEmpty()) { + resolveValuesInOuterScope(expression, detectableParameter); + } else { + resolvedValues.stream() + .map( + resolvedValue -> + new ValueDetection<>( + resolvedValue, + detectableParameter, + expressionNode, + expressionNode)) + .forEach(detectionStore::onReceivingNewDetection); + } + } else if (!parameter.getDetectionRules().isEmpty()) { + detectionStore.onDetectedDependingParameter( + parameter, expression, DetectionStore.Scope.EXPRESSION); + } + + index++; + } + } + + private boolean checkCurrentIndexState( + int index, + List arguments, + boolean isInvocation, + @Nonnull TraceSymbol traceSymbol, + @Nonnull AstNode expressionNode) { + if (arguments.size() <= index) { + return false; + } + + Optional assignedSymbol = + getAssignedSymbol(expressionNode).map(TraceSymbol::getSymbol); + + return !(traceSymbol.is(TraceSymbol.State.DIFFERENT) + || (traceSymbol.is(TraceSymbol.State.SYMBOL) && !isInvocation) + || (traceSymbol.is(TraceSymbol.State.NO_SYMBOL) && assignedSymbol.isPresent())); + } +} diff --git a/engine/src/main/java/com/ibm/engine/language/cxx/CxxLanguageSupport.java b/engine/src/main/java/com/ibm/engine/language/cxx/CxxLanguageSupport.java new file mode 100644 index 000000000..dc9080e3b --- /dev/null +++ b/engine/src/main/java/com/ibm/engine/language/cxx/CxxLanguageSupport.java @@ -0,0 +1,157 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.engine.language.cxx; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.detection.EnumMatcher; +import com.ibm.engine.detection.Handler; +import com.ibm.engine.detection.IBaseMethodVisitorFactory; +import com.ibm.engine.detection.IDetectionEngine; +import com.ibm.engine.detection.MatchContext; +import com.ibm.engine.detection.MethodMatcher; +import com.ibm.engine.executive.DetectionExecutive; +import com.ibm.engine.language.ILanguageSupport; +import com.ibm.engine.language.ILanguageTranslation; +import com.ibm.engine.language.IScanContext; +import com.ibm.engine.rule.IDetectionRule; +import com.sonar.cxx.sslr.api.AstNode; +import com.sonar.cxx.sslr.api.Grammar; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.cxx.parser.CxxGrammarImpl; +import org.sonar.cxx.squidbridge.SquidAstVisitorContext; +import org.sonar.cxx.squidbridge.api.Symbol; +import org.sonar.cxx.squidbridge.checks.SquidCheck; +import org.sonar.cxx.utils.CxxAstNodeHelper; + +public final class CxxLanguageSupport + implements ILanguageSupport< + SquidCheck, AstNode, Symbol, SquidAstVisitorContext> { + private static final Logger LOGGER = LoggerFactory.getLogger(CxxLanguageSupport.class); + + @Nonnull + private final Handler, AstNode, Symbol, SquidAstVisitorContext> + handler; + + public CxxLanguageSupport() { + this.handler = new Handler<>(this); + } + + @Nonnull + @Override + public ILanguageTranslation translation() { + return new CxxLanguageTranslation(); + } + + @Nonnull + @Override + public DetectionExecutive< + SquidCheck, AstNode, Symbol, SquidAstVisitorContext> + createDetectionExecutive( + @Nonnull AstNode tree, + @Nonnull IDetectionRule detectionRule, + @Nonnull IScanContext, AstNode> scanContext) { + return new DetectionExecutive<>(tree, detectionRule, scanContext, this.handler); + } + + @Nonnull + @Override + public IDetectionEngine createDetectionEngineInstance( + @Nonnull + DetectionStore< + SquidCheck, + AstNode, + Symbol, + SquidAstVisitorContext> + detectionStore) { + return new CxxDetectionEngine(detectionStore, this.handler); + } + + @Nonnull + @Override + public IBaseMethodVisitorFactory getBaseMethodVisitorFactory() { + return CxxBaseMethodVisitor::new; + } + + @Nonnull + @Override + public Optional getEnclosingMethod(@Nonnull AstNode expression) { + AstNode enclosingFunction = CxxAstNodeHelper.getEnclosingFunction(expression); + return Optional.ofNullable(enclosingFunction); + } + + @Nullable @Override + public MethodMatcher createMethodMatcherBasedOn(@Nonnull AstNode methodDefinition) { + if (!methodDefinition.is(CxxGrammarImpl.functionDefinition)) { + return null; + } + + try { + String functionName = CxxAstNodeHelper.getFunctionDefinitionName(methodDefinition); + if (functionName == null) { + return null; + } + + AstNode enclosingClass = CxxAstNodeHelper.getEnclosingClass(methodDefinition); + String invocationObjectName; + if (enclosingClass != null) { + String className = CxxAstNodeHelper.getIdentifierName(enclosingClass); + invocationObjectName = className != null ? className : ""; + } else { + invocationObjectName = ""; + } + + List parameters = + CxxAstNodeHelper.getFunctionDefinitionParameters(methodDefinition); + LinkedList parameterTypeList = new LinkedList<>(); + for (AstNode param : parameters) { + AstNode declSpecifierSeq = + param.getFirstChild(CxxGrammarImpl.parameterDeclSpecifierSeq); + if (declSpecifierSeq != null) { + StringBuilder sb = new StringBuilder(); + for (var token : declSpecifierSeq.getTokens()) { + sb.append(token.getValue()); + } + parameterTypeList.add(sb.toString().trim()); + } else { + parameterTypeList.add("*"); + } + } + + return new MethodMatcher<>(invocationObjectName, functionName, parameterTypeList); + } catch (Exception e) { + LOGGER.error(e.getLocalizedMessage()); + return null; + } + } + + @Nullable @Override + public EnumMatcher createSimpleEnumMatcherFor( + @Nonnull AstNode enumIdentifier, @Nonnull MatchContext matchContext) { + Optional enumIdentifierName = + translation().getEnumIdentifierName(matchContext, enumIdentifier); + return enumIdentifierName.>map(EnumMatcher::new).orElse(null); + } +} diff --git a/engine/src/main/java/com/ibm/engine/language/cxx/CxxLanguageTranslation.java b/engine/src/main/java/com/ibm/engine/language/cxx/CxxLanguageTranslation.java new file mode 100644 index 000000000..727386c83 --- /dev/null +++ b/engine/src/main/java/com/ibm/engine/language/cxx/CxxLanguageTranslation.java @@ -0,0 +1,305 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.engine.language.cxx; + +import com.ibm.engine.detection.IType; +import com.ibm.engine.detection.MatchContext; +import com.ibm.engine.language.ILanguageTranslation; +import com.sonar.cxx.sslr.api.AstNode; +import com.sonar.cxx.sslr.api.GenericTokenType; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import javax.annotation.Nonnull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.cxx.parser.CxxGrammarImpl; +import org.sonar.cxx.squidbridge.api.AstNodeSymbolExtension; +import org.sonar.cxx.squidbridge.api.AstNodeTypeExtension; +import org.sonar.cxx.squidbridge.api.Symbol; +import org.sonar.cxx.squidbridge.api.Type; +import org.sonar.cxx.utils.CxxAstNodeHelper; + +public class CxxLanguageTranslation implements ILanguageTranslation { + @Nonnull + private static final Logger LOGGER = LoggerFactory.getLogger(CxxLanguageTranslation.class); + + /** + * Synthetic type name used for standalone C/C++ function calls that have no object qualifier. + * Detection rules for C-style functions (e.g., OpenSSL's EVP_DigestInit_ex) should use {@code + * forObjectTypes("*")} to match any type, or {@code forObjectTypes("")} to match only + * standalone function calls. + */ + public static final String GLOBAL_SCOPE = ""; + + @Nonnull + @Override + public Optional getMethodName( + @Nonnull MatchContext matchContext, @Nonnull AstNode methodInvocation) { + if (CxxAstNodeHelper.isFunctionCall(methodInvocation)) { + String name = CxxAstNodeHelper.getFunctionCallName(methodInvocation); + if (name != null) { + return Optional.of(name); + } + } else if (CxxAstNodeHelper.isConstructorCall(methodInvocation)) { + return Optional.of(""); + } + return Optional.empty(); + } + + @Nonnull + @Override + public Optional getInvokedObjectTypeString( + @Nonnull MatchContext matchContext, @Nonnull AstNode methodInvocation) { + if (CxxAstNodeHelper.isMemberAccess(methodInvocation)) { + AstNode qualifier = CxxAstNodeHelper.getMemberAccessQualifier(methodInvocation); + if (qualifier != null) { + Type cxxType = AstNodeTypeExtension.getType(qualifier); + if (cxxType != null && !cxxType.isUnknown()) { + return Optional.of(createTypeFromCxxType(cxxType, matchContext)); + } + + Symbol symbol = AstNodeSymbolExtension.getSymbol(qualifier); + if (symbol != null && !symbol.isUnknown()) { + String fqn = symbol.fullyQualifiedName(); + if (fqn != null) { + return Optional.of(createTypeFromFqn(fqn, matchContext)); + } + } + + String identifierName = CxxAstNodeHelper.getIdentifierName(qualifier); + if (identifierName != null) { + return Optional.of(createTypeFromFqn(identifierName, matchContext)); + } + } + } else if (CxxAstNodeHelper.isConstructorCall(methodInvocation)) { + AstNode newTypeId = methodInvocation.getFirstChild(CxxGrammarImpl.newTypeId); + if (newTypeId != null) { + Type cxxType = AstNodeTypeExtension.getType(newTypeId); + if (cxxType != null && !cxxType.isUnknown()) { + return Optional.of(createTypeFromCxxType(cxxType, matchContext)); + } + + String typeName = extractTypeName(newTypeId); + if (typeName != null) { + return Optional.of(createTypeFromFqn(typeName, matchContext)); + } + } + } else if (CxxAstNodeHelper.isFunctionCall(methodInvocation)) { + // Standalone C/C++ function call (no member access qualifier). + // Return a synthetic global scope type so MethodMatcher.match() doesn't + // short-circuit on empty. Detection rules should use forObjectTypes("*"). + return Optional.of(createTypeFromFqn(GLOBAL_SCOPE, matchContext)); + } + return Optional.empty(); + } + + @Nonnull + @Override + public Optional getMethodReturnTypeString( + @Nonnull MatchContext matchContext, @Nonnull AstNode methodInvocation) { + if (CxxAstNodeHelper.isFunctionCall(methodInvocation)) { + Type cxxType = AstNodeTypeExtension.getType(methodInvocation); + if (cxxType != null && !cxxType.isUnknown()) { + return Optional.of(createTypeFromCxxType(cxxType, matchContext)); + } + + AstNode idExpr = methodInvocation.getFirstDescendant(CxxGrammarImpl.idExpression); + if (idExpr != null) { + Symbol symbol = AstNodeSymbolExtension.getSymbol(idExpr); + if (symbol != null + && symbol.isFunctionSymbol() + && symbol instanceof Symbol.FunctionSymbol funcSym) { + Type returnType = funcSym.returnType(); + if (returnType != null && !returnType.isUnknown()) { + return Optional.of(createTypeFromCxxType(returnType, matchContext)); + } + } + } + } + return Optional.empty(); + } + + @Nonnull + @Override + public List getMethodParameterTypes( + @Nonnull MatchContext matchContext, @Nonnull AstNode methodInvocation) { + List arguments; + + if (CxxAstNodeHelper.isFunctionCall(methodInvocation)) { + arguments = CxxAstNodeHelper.getFunctionCallArguments(methodInvocation); + } else if (CxxAstNodeHelper.isConstructorCall(methodInvocation)) { + AstNode newInitializer = methodInvocation.getFirstChild(CxxGrammarImpl.newInitializer); + if (newInitializer != null) { + AstNode expressionList = + newInitializer.getFirstDescendant(CxxGrammarImpl.expressionList); + if (expressionList != null) { + arguments = expressionList.getChildren(); + } else { + arguments = Collections.emptyList(); + } + } else { + arguments = Collections.emptyList(); + } + } else { + return Collections.emptyList(); + } + + if (arguments.isEmpty()) { + return Collections.emptyList(); + } + + List types = new ArrayList<>(); + List parameterMatchExactTypes = matchContext.parametersShouldMatchExactTypes(); + List matchMatrix = parameterMatchExactTypes; + + if (parameterMatchExactTypes.size() != arguments.size()) { + Boolean[] defaults = new Boolean[arguments.size()]; + java.util.Arrays.fill(defaults, Boolean.FALSE); + matchMatrix = java.util.Arrays.asList(defaults); + } + + for (int i = 0; i < arguments.size(); i++) { + AstNode argument = arguments.get(i); + boolean exactMatch = matchMatrix.get(i); + + Type argType = AstNodeTypeExtension.getType(argument); + if (argType != null && !argType.isUnknown()) { + types.add( + createTypeFromCxxType( + argType, + new MatchContext( + matchContext.isHookContext(), + exactMatch, + Collections.emptyList()))); + continue; + } + + Symbol argSymbol = AstNodeSymbolExtension.getSymbol(argument); + if (argSymbol != null && !argSymbol.isUnknown()) { + String fqn = argSymbol.fullyQualifiedName(); + if (fqn != null) { + types.add( + createTypeFromFqn( + fqn, + new MatchContext( + matchContext.isHookContext(), + exactMatch, + Collections.emptyList()))); + continue; + } + } + + types.add(createUnknownType()); + } + return types; + } + + @Nonnull + @Override + public Optional resolveIdentifierAsString( + @Nonnull MatchContext matchContext, @Nonnull AstNode identifier) { + if (identifier.is(GenericTokenType.IDENTIFIER)) { + return Optional.of(identifier.getTokenValue()); + } + String name = CxxAstNodeHelper.getIdentifierName(identifier); + if (name != null) { + return Optional.of(name); + } + return Optional.empty(); + } + + @Nonnull + @Override + public Optional getEnumIdentifierName( + @Nonnull MatchContext matchContext, @Nonnull AstNode enumIdentifier) { + if (enumIdentifier.is(GenericTokenType.IDENTIFIER)) { + return Optional.of(enumIdentifier.getTokenValue()); + } + String name = CxxAstNodeHelper.getIdentifierName(enumIdentifier); + if (name != null) { + return Optional.of(name); + } + return Optional.empty(); + } + + @Nonnull + @Override + public Optional getEnumClassName( + @Nonnull MatchContext matchContext, @Nonnull AstNode enumClass) { + if (enumClass.is(CxxGrammarImpl.enumSpecifier)) { + AstNode enumHead = enumClass.getFirstChild(CxxGrammarImpl.enumHead); + if (enumHead != null) { + AstNode enumHeadName = enumHead.getFirstChild(CxxGrammarImpl.enumHeadName); + if (enumHeadName != null) { + String name = CxxAstNodeHelper.getIdentifierName(enumHeadName); + if (name != null) { + return Optional.of(name); + } + } + } + } + return Optional.empty(); + } + + private IType createTypeFromCxxType(@Nonnull Type cxxType, @Nonnull MatchContext matchContext) { + return typeString -> { + if (matchContext.isHookContext() || matchContext.objectShouldMatchExactTypes()) { + return cxxType.is(typeString); + } + return cxxType.is(typeString) || cxxType.isSubtypeOf(typeString); + }; + } + + private IType createTypeFromFqn(@Nonnull String fqn, @Nonnull MatchContext matchContext) { + return typeString -> { + if (matchContext.isHookContext() || matchContext.objectShouldMatchExactTypes()) { + return fqn.equals(typeString); + } + return fqn.equals(typeString) + || fqn.endsWith("::" + typeString) + || typeString.endsWith("::" + fqn); + }; + } + + private IType createUnknownType() { + return typeString -> false; + } + + private String extractTypeName(AstNode typeNode) { + if (typeNode == null) { + return null; + } + AstNode typeSpecifierSeq = typeNode.getFirstDescendant(CxxGrammarImpl.typeSpecifierSeq); + if (typeSpecifierSeq != null) { + AstNode simpleTypeSpecifier = + typeSpecifierSeq.getFirstDescendant(CxxGrammarImpl.simpleTypeSpecifier); + if (simpleTypeSpecifier != null) { + StringBuilder sb = new StringBuilder(); + for (var token : simpleTypeSpecifier.getTokens()) { + sb.append(token.getValue()); + } + return sb.toString().trim(); + } + } + return CxxAstNodeHelper.getIdentifierName(typeNode); + } +} diff --git a/engine/src/main/java/com/ibm/engine/language/cxx/CxxScanContext.java b/engine/src/main/java/com/ibm/engine/language/cxx/CxxScanContext.java new file mode 100644 index 000000000..77ba737ca --- /dev/null +++ b/engine/src/main/java/com/ibm/engine/language/cxx/CxxScanContext.java @@ -0,0 +1,50 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.engine.language.cxx; + +import com.ibm.engine.language.IScanContext; +import com.sonar.cxx.sslr.api.AstNode; +import com.sonar.cxx.sslr.api.Grammar; +import javax.annotation.Nonnull; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.cxx.squidbridge.SquidAstVisitorContext; +import org.sonar.cxx.squidbridge.checks.SquidCheck; + +public record CxxScanContext(@Nonnull SquidAstVisitorContext cxxVisitorContext) + implements IScanContext, AstNode> { + + @Override + public void reportIssue( + @Nonnull SquidCheck currentRule, @Nonnull AstNode tree, @Nonnull String message) { + currentRule.addIssue(tree, message); + } + + @Nonnull + @Override + public InputFile getInputFile() { + return this.cxxVisitorContext.getInputFile(); + } + + @Nonnull + @Override + public String getFilePath() { + return this.cxxVisitorContext.getInputFile().uri().getPath(); + } +} diff --git a/engine/src/main/java/com/ibm/engine/language/cxx/CxxSemantic.java b/engine/src/main/java/com/ibm/engine/language/cxx/CxxSemantic.java new file mode 100644 index 000000000..3f59852da --- /dev/null +++ b/engine/src/main/java/com/ibm/engine/language/cxx/CxxSemantic.java @@ -0,0 +1,482 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.engine.language.cxx; + +import com.ibm.engine.detection.ResolvedValue; +import com.ibm.engine.model.factory.IValueFactory; +import com.sonar.cxx.sslr.api.AstNode; +import com.sonar.cxx.sslr.api.GenericTokenType; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.cxx.parser.CxxGrammarImpl; +import org.sonar.cxx.parser.CxxTokenType; +import org.sonar.cxx.utils.CxxAstNodeHelper; +import org.sonar.cxx.utils.CxxConstantUtils; + +public final class CxxSemantic { + private static final Logger LOGGER = LoggerFactory.getLogger(CxxSemantic.class); + + private CxxSemantic() { + // private + } + + @Nonnull + public static List> resolveValues( + @Nonnull Class clazz, + @Nonnull AstNode tree, + @Nonnull LinkedList selections, + @Nullable IValueFactory valueFactory, + boolean returnEnclosingParam, + @Nullable CxxDetectionEngine detectionEngine) { + return resolveValuesInternal( + clazz, tree, selections, valueFactory, returnEnclosingParam, detectionEngine, 0); + } + + @Nonnull + private static List> resolveValuesInternal( + @Nonnull Class clazz, + @Nonnull AstNode tree, + @Nonnull LinkedList selections, + @Nullable IValueFactory valueFactory, + boolean returnEnclosingParam, + @Nullable CxxDetectionEngine detectionEngine, + int depth) { + if (depth > 15) { + return Collections.emptyList(); + } + + if (tree.is(CxxTokenType.STRING)) { + return resolveStringLiteral(clazz, tree); + } else if (tree.is(CxxTokenType.NUMBER)) { + return resolveNumberLiteral(clazz, tree); + } else if (tree.is(CxxTokenType.CHARACTER)) { + return resolveCharLiteral(clazz, tree); + } else if (tree.is(GenericTokenType.IDENTIFIER)) { + return resolveIdentifier( + clazz, + tree, + selections, + valueFactory, + returnEnclosingParam, + detectionEngine, + depth); + } else if (tree.is(CxxGrammarImpl.primaryExpression)) { + return resolvePrimaryExpression( + clazz, + tree, + selections, + valueFactory, + returnEnclosingParam, + detectionEngine, + depth); + } else if (tree.is(CxxGrammarImpl.LITERAL)) { + return resolveLiteral( + clazz, + tree, + selections, + valueFactory, + returnEnclosingParam, + detectionEngine, + depth); + } else if (tree.is(CxxGrammarImpl.assignmentExpression)) { + return resolveAssignmentExpression( + clazz, + tree, + selections, + valueFactory, + returnEnclosingParam, + detectionEngine, + depth); + } else if (tree.is(CxxGrammarImpl.initializerClause)) { + return resolveInitializerClause( + clazz, + tree, + selections, + valueFactory, + returnEnclosingParam, + detectionEngine, + depth); + } else if (tree.is(CxxGrammarImpl.expression)) { + return resolveExpression( + clazz, + tree, + selections, + valueFactory, + returnEnclosingParam, + detectionEngine, + depth); + } else if (CxxAstNodeHelper.isFunctionCall(tree)) { + return resolveFunctionCall(clazz, tree, returnEnclosingParam, detectionEngine, depth); + } else { + AstNode firstChild = tree.getFirstChild(); + if (firstChild != null) { + return resolveValuesInternal( + clazz, + firstChild, + selections, + valueFactory, + returnEnclosingParam, + detectionEngine, + depth + 1); + } + } + + return Collections.emptyList(); + } + + @Nonnull + private static List> resolveStringLiteral( + @Nonnull Class clazz, @Nonnull AstNode tree) { + String value = tree.getTokenValue(); + if (value.startsWith("\"") && value.endsWith("\"") && value.length() >= 2) { + value = value.substring(1, value.length() - 1); + } else if (value.startsWith("L\"") && value.endsWith("\"") && value.length() >= 3) { + value = value.substring(2, value.length() - 1); + } else if (value.startsWith("u\"") && value.endsWith("\"") && value.length() >= 3) { + value = value.substring(2, value.length() - 1); + } else if (value.startsWith("U\"") && value.endsWith("\"") && value.length() >= 3) { + value = value.substring(2, value.length() - 1); + } else if (value.startsWith("u8\"") && value.endsWith("\"") && value.length() >= 4) { + value = value.substring(3, value.length() - 1); + } else if (value.startsWith("R\"") && value.endsWith("\"")) { + int parenOpen = value.indexOf('('); + int parenClose = value.lastIndexOf(')'); + if (parenOpen >= 0 && parenClose > parenOpen) { + value = value.substring(parenOpen + 1, parenClose); + } + } + Optional result = castValue(clazz, value); + return result.map(v -> List.of(new ResolvedValue<>(v, tree))) + .orElse(Collections.emptyList()); + } + + @Nonnull + private static List> resolveNumberLiteral( + @Nonnull Class clazz, @Nonnull AstNode tree) { + String value = tree.getTokenValue(); + value = value.replaceAll("[uUlLfF]", ""); + value = value.replace("'", ""); + + Object result; + try { + if (value.startsWith("0x") || value.startsWith("0X")) { + result = Integer.parseInt(value.substring(2), 16); + } else if (value.startsWith("0b") || value.startsWith("0B")) { + result = Integer.parseInt(value.substring(2), 2); + } else if (value.startsWith("0") && value.length() > 1 && !value.contains(".")) { + result = Integer.parseInt(value.substring(1), 8); + } else if (value.contains(".") || value.contains("e") || value.contains("E")) { + result = Double.parseDouble(value); + } else { + result = Integer.parseInt(value); + } + } catch (NumberFormatException e) { + result = value; + } + Optional castResult = castValue(clazz, result); + return castResult + .map(v -> List.of(new ResolvedValue<>(v, tree))) + .orElse(Collections.emptyList()); + } + + @Nonnull + private static List> resolveCharLiteral( + @Nonnull Class clazz, @Nonnull AstNode tree) { + String value = tree.getTokenValue(); + if (value.startsWith("'") && value.endsWith("'") && value.length() >= 3) { + value = value.substring(1, value.length() - 1); + } + Optional result = castValue(clazz, value); + return result.map(v -> List.of(new ResolvedValue<>(v, tree))) + .orElse(Collections.emptyList()); + } + + @Nonnull + private static List> resolveIdentifier( + @Nonnull Class clazz, + @Nonnull AstNode tree, + @Nonnull LinkedList selections, + @Nullable IValueFactory valueFactory, + boolean returnEnclosingParam, + @Nullable CxxDetectionEngine detectionEngine, + int depth) { + String name = tree.getTokenValue(); + if ("true".equals(name)) { + Optional result = castValue(clazz, Boolean.TRUE); + return result.map(v -> List.of(new ResolvedValue<>(v, tree))) + .orElse(Collections.emptyList()); + } else if ("false".equals(name)) { + Optional result = castValue(clazz, Boolean.FALSE); + return result.map(v -> List.of(new ResolvedValue<>(v, tree))) + .orElse(Collections.emptyList()); + } else if ("nullptr".equals(name)) { + Optional result = castValue(clazz, "nullptr"); + return result.map(v -> List.of(new ResolvedValue<>(v, tree))) + .orElse(Collections.emptyList()); + } + + // Try to resolve as compile-time constant using CxxConstantUtils + try { + Object constantValue = CxxConstantUtils.resolveAsConstant(tree); + if (constantValue != null) { + LOGGER.debug("Resolved identifier '{}' to constant value: {}", name, constantValue); + Optional result = castValue(clazz, constantValue); + if (result.isPresent()) { + return List.of(new ResolvedValue<>(result.get(), tree)); + } + } + } catch (Exception e) { + // If constant resolution fails, fall back to identifier name + LOGGER.debug("Could not resolve identifier '{}' as constant: {}", name, e.getMessage()); + } + + // Fallback to identifier name if not a constant + if (returnEnclosingParam) { + Optional result = castValue(clazz, name); + return result.map(v -> List.of(new ResolvedValue<>(v, tree))) + .orElse(Collections.emptyList()); + } + + Optional result = castValue(clazz, name); + return result.map(v -> List.of(new ResolvedValue<>(v, tree))) + .orElse(Collections.emptyList()); + } + + @Nonnull + private static List> resolvePrimaryExpression( + @Nonnull Class clazz, + @Nonnull AstNode tree, + @Nonnull LinkedList selections, + @Nullable IValueFactory valueFactory, + boolean returnEnclosingParam, + @Nullable CxxDetectionEngine detectionEngine, + int depth) { + AstNode literal = tree.getFirstChild(CxxGrammarImpl.LITERAL); + if (literal != null) { + return resolveLiteral( + clazz, + literal, + selections, + valueFactory, + returnEnclosingParam, + detectionEngine, + depth); + } + + AstNode idExpression = tree.getFirstChild(CxxGrammarImpl.idExpression); + if (idExpression != null) { + String identifierName = CxxAstNodeHelper.getIdentifierName(idExpression); + if (identifierName != null) { + Optional result = castValue(clazz, identifierName); + return result.map(v -> List.of(new ResolvedValue<>(v, tree))) + .orElse(Collections.emptyList()); + } + } + + AstNode firstChild = tree.getFirstChild(); + if (firstChild != null) { + return resolveValuesInternal( + clazz, + firstChild, + selections, + valueFactory, + returnEnclosingParam, + detectionEngine, + depth + 1); + } + + return Collections.emptyList(); + } + + @Nonnull + private static List> resolveLiteral( + @Nonnull Class clazz, + @Nonnull AstNode tree, + @Nonnull LinkedList selections, + @Nullable IValueFactory valueFactory, + boolean returnEnclosingParam, + @Nullable CxxDetectionEngine detectionEngine, + int depth) { + AstNode stringLiteral = tree.getFirstChild(CxxTokenType.STRING); + if (stringLiteral != null) { + return resolveStringLiteral(clazz, stringLiteral); + } + + AstNode numberLiteral = tree.getFirstChild(CxxTokenType.NUMBER); + if (numberLiteral != null) { + return resolveNumberLiteral(clazz, numberLiteral); + } + + AstNode charLiteral = tree.getFirstChild(CxxTokenType.CHARACTER); + if (charLiteral != null) { + return resolveCharLiteral(clazz, charLiteral); + } + + AstNode boolLiteral = tree.getFirstChild(CxxGrammarImpl.BOOL); + if (boolLiteral != null) { + String value = boolLiteral.getTokenValue(); + Boolean boolValue = "true".equals(value); + Optional result = castValue(clazz, boolValue); + return result.map(v -> List.of(new ResolvedValue<>(v, tree))) + .orElse(Collections.emptyList()); + } + + AstNode nullptrLiteral = tree.getFirstChild(CxxGrammarImpl.NULLPTR); + if (nullptrLiteral != null) { + Optional result = castValue(clazz, "nullptr"); + return result.map(v -> List.of(new ResolvedValue<>(v, tree))) + .orElse(Collections.emptyList()); + } + + AstNode firstChild = tree.getFirstChild(); + if (firstChild != null) { + return resolveValuesInternal( + clazz, + firstChild, + selections, + valueFactory, + returnEnclosingParam, + detectionEngine, + depth + 1); + } + + return Collections.emptyList(); + } + + @Nonnull + private static List> resolveAssignmentExpression( + @Nonnull Class clazz, + @Nonnull AstNode tree, + @Nonnull LinkedList selections, + @Nullable IValueFactory valueFactory, + boolean returnEnclosingParam, + @Nullable CxxDetectionEngine detectionEngine, + int depth) { + List children = tree.getChildren(); + if (!children.isEmpty()) { + AstNode lastChild = children.get(children.size() - 1); + return resolveValuesInternal( + clazz, + lastChild, + selections, + valueFactory, + returnEnclosingParam, + detectionEngine, + depth + 1); + } + return Collections.emptyList(); + } + + @Nonnull + private static List> resolveInitializerClause( + @Nonnull Class clazz, + @Nonnull AstNode tree, + @Nonnull LinkedList selections, + @Nullable IValueFactory valueFactory, + boolean returnEnclosingParam, + @Nullable CxxDetectionEngine detectionEngine, + int depth) { + AstNode assignmentExpression = tree.getFirstChild(CxxGrammarImpl.assignmentExpression); + if (assignmentExpression != null) { + return resolveAssignmentExpression( + clazz, + assignmentExpression, + selections, + valueFactory, + returnEnclosingParam, + detectionEngine, + depth); + } + AstNode firstChild = tree.getFirstChild(); + if (firstChild != null) { + return resolveValuesInternal( + clazz, + firstChild, + selections, + valueFactory, + returnEnclosingParam, + detectionEngine, + depth + 1); + } + return Collections.emptyList(); + } + + @Nonnull + private static List> resolveExpression( + @Nonnull Class clazz, + @Nonnull AstNode tree, + @Nonnull LinkedList selections, + @Nullable IValueFactory valueFactory, + boolean returnEnclosingParam, + @Nullable CxxDetectionEngine detectionEngine, + int depth) { + AstNode firstChild = tree.getFirstChild(); + if (firstChild != null) { + return resolveValuesInternal( + clazz, + firstChild, + selections, + valueFactory, + returnEnclosingParam, + detectionEngine, + depth + 1); + } + return Collections.emptyList(); + } + + @Nonnull + private static List> resolveFunctionCall( + @Nonnull Class clazz, + @Nonnull AstNode tree, + boolean returnEnclosingParam, + @Nullable CxxDetectionEngine detectionEngine, + int depth) { + String functionName = CxxAstNodeHelper.getFunctionCallName(tree); + if (functionName != null) { + Optional result = castValue(clazz, functionName); + return result.map(v -> List.of(new ResolvedValue<>(v, tree))) + .orElse(Collections.emptyList()); + } + return Collections.emptyList(); + } + + @Nonnull + private static Optional castValue(@Nonnull Class clazz, @Nullable Object value) { + if (value == null) { + return Optional.empty(); + } + try { + return Optional.of(clazz.cast(value)); + } catch (ClassCastException e) { + if (clazz == String.class) { + @SuppressWarnings("unchecked") + O stringValue = (O) value.toString(); + return Optional.of(stringValue); + } + return Optional.empty(); + } + } +} diff --git a/engine/src/main/java/com/ibm/engine/language/go/tree/CompositeLiteralWithBlockTree.java b/engine/src/main/java/com/ibm/engine/language/go/tree/CompositeLiteralWithBlockTree.java index 91daae336..2cbb24a53 100644 --- a/engine/src/main/java/com/ibm/engine/language/go/tree/CompositeLiteralWithBlockTree.java +++ b/engine/src/main/java/com/ibm/engine/language/go/tree/CompositeLiteralWithBlockTree.java @@ -23,7 +23,6 @@ import java.util.stream.Stream; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import org.checkerframework.checker.nullness.qual.NonNull; import org.sonar.go.impl.BaseTreeImpl; import org.sonar.plugins.go.api.BlockTree; import org.sonar.plugins.go.api.CompositeLiteralTree; @@ -66,7 +65,7 @@ public List identifiers() { } @Override - public @NonNull BlockTree blockTree() { + public @Nonnull BlockTree blockTree() { return blockTree; } diff --git a/engine/src/main/java/com/ibm/engine/language/go/tree/FunctionInvocationWIthIdentifiersTree.java b/engine/src/main/java/com/ibm/engine/language/go/tree/FunctionInvocationWIthIdentifiersTree.java index e73939f30..b04060d0c 100644 --- a/engine/src/main/java/com/ibm/engine/language/go/tree/FunctionInvocationWIthIdentifiersTree.java +++ b/engine/src/main/java/com/ibm/engine/language/go/tree/FunctionInvocationWIthIdentifiersTree.java @@ -24,7 +24,6 @@ import java.util.Optional; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import org.checkerframework.checker.nullness.qual.NonNull; import org.sonar.go.impl.FunctionInvocationTreeImpl; import org.sonar.plugins.go.api.BlockTree; import org.sonar.plugins.go.api.FunctionInvocationTree; @@ -54,7 +53,7 @@ public List identifiers() { } @Override - public @NonNull BlockTree blockTree() { + public @Nonnull BlockTree blockTree() { return blockTree; } } diff --git a/engine/src/main/java/com/ibm/engine/language/go/tree/IdentifierWithBlockTree.java b/engine/src/main/java/com/ibm/engine/language/go/tree/IdentifierWithBlockTree.java index 47b12dc31..0a09f59d4 100644 --- a/engine/src/main/java/com/ibm/engine/language/go/tree/IdentifierWithBlockTree.java +++ b/engine/src/main/java/com/ibm/engine/language/go/tree/IdentifierWithBlockTree.java @@ -21,7 +21,6 @@ import java.util.List; import javax.annotation.Nonnull; -import org.checkerframework.checker.nullness.qual.NonNull; import org.sonar.go.impl.BaseTreeImpl; import org.sonar.plugins.go.api.BlockTree; import org.sonar.plugins.go.api.IdentifierTree; @@ -54,7 +53,7 @@ public IdentifierTree identifierTree() { } @Override - public @NonNull BlockTree blockTree() { + public @Nonnull BlockTree blockTree() { return blockTree; } diff --git a/engine/src/main/java/com/ibm/engine/language/go/tree/TreeWithBlock.java b/engine/src/main/java/com/ibm/engine/language/go/tree/TreeWithBlock.java index 87e05c45e..2f36f1b32 100644 --- a/engine/src/main/java/com/ibm/engine/language/go/tree/TreeWithBlock.java +++ b/engine/src/main/java/com/ibm/engine/language/go/tree/TreeWithBlock.java @@ -21,7 +21,6 @@ import java.util.List; import javax.annotation.Nonnull; -import org.checkerframework.checker.nullness.qual.NonNull; import org.sonar.go.impl.BaseTreeImpl; import org.sonar.plugins.go.api.BlockTree; import org.sonar.plugins.go.api.Tree; @@ -42,7 +41,7 @@ public List children() { } @Override - public @NonNull BlockTree blockTree() { + public @Nonnull BlockTree blockTree() { return blockTree; } } diff --git a/mapper/src/main/java/com/ibm/mapper/mapper/bc/BcMessageSignerMapper.java b/mapper/src/main/java/com/ibm/mapper/mapper/bc/BcMessageSignerMapper.java index 1d953ff17..9b6570bbb 100644 --- a/mapper/src/main/java/com/ibm/mapper/mapper/bc/BcMessageSignerMapper.java +++ b/mapper/src/main/java/com/ibm/mapper/mapper/bc/BcMessageSignerMapper.java @@ -24,17 +24,17 @@ import com.ibm.mapper.model.INode; import com.ibm.mapper.model.Signature; import com.ibm.mapper.model.Unknown; -import com.ibm.mapper.model.algorithms.Dilithium; import com.ibm.mapper.model.algorithms.Falcon; import com.ibm.mapper.model.algorithms.GMSS; import com.ibm.mapper.model.algorithms.GeMSS; import com.ibm.mapper.model.algorithms.HSS; import com.ibm.mapper.model.algorithms.LMS; +import com.ibm.mapper.model.algorithms.MLDSA; import com.ibm.mapper.model.algorithms.Picnic; import com.ibm.mapper.model.algorithms.QTESLA; import com.ibm.mapper.model.algorithms.Rainbow; +import com.ibm.mapper.model.algorithms.SLHDSA; import com.ibm.mapper.model.algorithms.SPHINCS; -import com.ibm.mapper.model.algorithms.SPHINCSPlus; import com.ibm.mapper.model.algorithms.XMSS; import com.ibm.mapper.model.algorithms.XMSSMT; import com.ibm.mapper.utils.DetectionLocation; @@ -58,7 +58,7 @@ public Optional parse( private Optional map( @Nonnull String signerString, @Nonnull DetectionLocation detectionLocation) { return switch (signerString) { - case "DilithiumSigner" -> Optional.of(new Dilithium(detectionLocation)); + case "DilithiumSigner" -> Optional.of(new MLDSA(detectionLocation)); case "FalconSigner" -> Optional.of(new Falcon(detectionLocation)); case "GeMSSSigner" -> Optional.of(new GeMSS(detectionLocation)); case "GMSSSigner" -> Optional.of(new GMSS(detectionLocation)); @@ -67,7 +67,7 @@ private Optional map( case "PicnicSigner" -> Optional.of(new Picnic(detectionLocation)); case "QTESLASigner" -> Optional.of(new QTESLA(detectionLocation)); case "RainbowSigner" -> Optional.of(new Rainbow(detectionLocation)); - case "SPHINCSPlusSigner" -> Optional.of(new SPHINCSPlus(detectionLocation)); + case "SPHINCSPlusSigner" -> Optional.of(new SLHDSA(detectionLocation)); case "SPHINCS256Signer" -> Optional.of(new SPHINCS(256, detectionLocation)); /* StateAwareMessageSigner subinterface */ case "XMSSMTSigner" -> Optional.of(new XMSSMT(detectionLocation)); diff --git a/mapper/src/main/java/com/ibm/mapper/mapper/ssl/SSLVersionMapper.java b/mapper/src/main/java/com/ibm/mapper/mapper/ssl/SSLVersionMapper.java index 2baf9a8c4..85ccfcdf4 100644 --- a/mapper/src/main/java/com/ibm/mapper/mapper/ssl/SSLVersionMapper.java +++ b/mapper/src/main/java/com/ibm/mapper/mapper/ssl/SSLVersionMapper.java @@ -37,7 +37,7 @@ public Optional parse( return Optional.empty(); } - Pattern pattern = Pattern.compile("tlsv(\\d+(\\.\\d+)?)"); + Pattern pattern = Pattern.compile("^tlsv(\\d+(\\.\\d+)?)"); Matcher matcher = pattern.matcher(str.toLowerCase()); if (matcher.find()) { String number = matcher.group(1); diff --git a/mapper/src/main/java/com/ibm/mapper/model/algorithms/SLHDSA.java b/mapper/src/main/java/com/ibm/mapper/model/algorithms/SLHDSA.java new file mode 100644 index 000000000..0d94d8e2b --- /dev/null +++ b/mapper/src/main/java/com/ibm/mapper/model/algorithms/SLHDSA.java @@ -0,0 +1,91 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2025 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.mapper.model.algorithms; + +import com.ibm.mapper.model.Algorithm; +import com.ibm.mapper.model.INode; +import com.ibm.mapper.model.MessageDigest; +import com.ibm.mapper.model.ParameterSetIdentifier; +import com.ibm.mapper.model.Signature; +import com.ibm.mapper.utils.DetectionLocation; +import java.util.Optional; +import javax.annotation.Nonnull; + +/** + * + * + *

{@value #NAME}

+ * + *

+ * + *

Specification

+ * + *
    + *
  • https://csrc.nist.gov/pubs/fips/205/final + *
+ * + *

Other Names and Related Standards

+ * + *
    + *
  • Stateless Hash-Based Digital Signature + *
  • Standardized version of SPHINCS+ + *
+ */ +public class SLHDSA extends Algorithm implements Signature { + private static final String NAME = "SLH-DSA"; + + /** Returns a name of the form "SLH-DSA-XXX" where XXX is the parameter set identifer */ + @Override + @Nonnull + public String asString() { + StringBuilder builtName = + new StringBuilder( + this.hasChildOfType(MessageDigest.class) + .map(node -> node.asString() + "with" + this.name) + .orElse(this.name)); + Optional parameterSetIdentifier = this.hasChildOfType(ParameterSetIdentifier.class); + parameterSetIdentifier.ifPresent(node -> builtName.append("-").append(node.asString())); + return builtName.toString(); + } + + public SLHDSA(@Nonnull DetectionLocation detectionLocation) { + super(NAME, Signature.class, detectionLocation); + } + + public SLHDSA(@Nonnull MessageDigest preHash) { + this(preHash.getDetectionContext()); + this.put(preHash); + } + + public SLHDSA(int parameterSetIdentifier, @Nonnull DetectionLocation detectionLocation) { + this(detectionLocation); + this.put( + new ParameterSetIdentifier( + String.valueOf(parameterSetIdentifier), detectionLocation)); + } + + public SLHDSA(int parameterSetIdentifier, @Nonnull MessageDigest preHash) { + this(preHash.getDetectionContext()); + this.put(preHash); + this.put( + new ParameterSetIdentifier( + String.valueOf(parameterSetIdentifier), preHash.getDetectionContext())); + } +} diff --git a/mapper/src/main/java/com/ibm/mapper/model/algorithms/SecP256r1MLKEM768.java b/mapper/src/main/java/com/ibm/mapper/model/algorithms/SecP256r1MLKEM768.java new file mode 100644 index 000000000..6b5b3955f --- /dev/null +++ b/mapper/src/main/java/com/ibm/mapper/model/algorithms/SecP256r1MLKEM768.java @@ -0,0 +1,47 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.mapper.model.algorithms; + +import com.ibm.mapper.model.Algorithm; +import com.ibm.mapper.model.KeyEncapsulationMechanism; +import com.ibm.mapper.utils.DetectionLocation; +import javax.annotation.Nonnull; + +/** + * + * + *

{@value #NAME}

+ * + *

Hybrid post-quantum key encapsulation mechanism combining ECDH P-256 (secp256r1, NIST P-256) + * with ML-KEM-768 (post-quantum KEM). + * + *

TLS Named Group: 0x11EB + * + *

Also known as SecP256r1Kyber768Draft00 (earlier draft name). Provides quantum-safe key + * exchange for TLS 1.3. + */ +public final class SecP256r1MLKEM768 extends Algorithm implements KeyEncapsulationMechanism { + + private static final String NAME = "SecP256r1MLKEM768"; + + public SecP256r1MLKEM768(@Nonnull DetectionLocation detectionLocation) { + super(NAME, KeyEncapsulationMechanism.class, detectionLocation); + } +} diff --git a/mapper/src/main/java/com/ibm/mapper/model/algorithms/SecP384r1MLKEM1024.java b/mapper/src/main/java/com/ibm/mapper/model/algorithms/SecP384r1MLKEM1024.java new file mode 100644 index 000000000..e90bf4da5 --- /dev/null +++ b/mapper/src/main/java/com/ibm/mapper/model/algorithms/SecP384r1MLKEM1024.java @@ -0,0 +1,47 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.mapper.model.algorithms; + +import com.ibm.mapper.model.Algorithm; +import com.ibm.mapper.model.KeyEncapsulationMechanism; +import com.ibm.mapper.utils.DetectionLocation; +import javax.annotation.Nonnull; + +/** + * + * + *

{@value #NAME}

+ * + *

Hybrid post-quantum key encapsulation mechanism combining ECDH P-384 (secp384r1, NIST P-384) + * with ML-KEM-1024 (post-quantum KEM). + * + *

TLS Named Group: 0x11ED + * + *

Also known as SecP384r1Kyber1024Draft00 (earlier draft name). Provides high-security + * quantum-safe key exchange for TLS 1.3. + */ +public final class SecP384r1MLKEM1024 extends Algorithm implements KeyEncapsulationMechanism { + + private static final String NAME = "SecP384r1MLKEM1024"; + + public SecP384r1MLKEM1024(@Nonnull DetectionLocation detectionLocation) { + super(NAME, KeyEncapsulationMechanism.class, detectionLocation); + } +} diff --git a/mapper/src/main/java/com/ibm/mapper/model/algorithms/X25519MLKEM768.java b/mapper/src/main/java/com/ibm/mapper/model/algorithms/X25519MLKEM768.java new file mode 100644 index 000000000..261add14a --- /dev/null +++ b/mapper/src/main/java/com/ibm/mapper/model/algorithms/X25519MLKEM768.java @@ -0,0 +1,47 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.mapper.model.algorithms; + +import com.ibm.mapper.model.Algorithm; +import com.ibm.mapper.model.KeyEncapsulationMechanism; +import com.ibm.mapper.utils.DetectionLocation; +import javax.annotation.Nonnull; + +/** + * + * + *

{@value #NAME}

+ * + *

Hybrid post-quantum key encapsulation mechanism combining X25519 (Curve25519 elliptic curve + * Diffie-Hellman) with ML-KEM-768 (post-quantum KEM). + * + *

TLS Named Group: 0x11EC + * + *

Also known as X25519Kyber768Draft00 (earlier draft name). Provides quantum-safe key exchange + * for TLS 1.3. + */ +public final class X25519MLKEM768 extends Algorithm implements KeyEncapsulationMechanism { + + private static final String NAME = "X25519MLKEM768"; + + public X25519MLKEM768(@Nonnull DetectionLocation detectionLocation) { + super(NAME, KeyEncapsulationMechanism.class, detectionLocation); + } +} diff --git a/mapper/src/main/java/com/ibm/mapper/model/algorithms/X448MLKEM1024.java b/mapper/src/main/java/com/ibm/mapper/model/algorithms/X448MLKEM1024.java new file mode 100644 index 000000000..74c0b1915 --- /dev/null +++ b/mapper/src/main/java/com/ibm/mapper/model/algorithms/X448MLKEM1024.java @@ -0,0 +1,46 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.mapper.model.algorithms; + +import com.ibm.mapper.model.Algorithm; +import com.ibm.mapper.model.KeyEncapsulationMechanism; +import com.ibm.mapper.utils.DetectionLocation; +import javax.annotation.Nonnull; + +/** + * + * + *

{@value #NAME}

+ * + *

Hybrid post-quantum key encapsulation mechanism combining X448 (Curve448 elliptic curve + * Diffie-Hellman) with ML-KEM-1024 (post-quantum KEM). + * + *

TLS Named Group: 0x11EE + * + *

Provides high-security quantum-safe key exchange for TLS 1.3. + */ +public final class X448MLKEM1024 extends Algorithm implements KeyEncapsulationMechanism { + + private static final String NAME = "X448MLKEM1024"; + + public X448MLKEM1024(@Nonnull DetectionLocation detectionLocation) { + super(NAME, KeyEncapsulationMechanism.class, detectionLocation); + } +} diff --git a/mapper/src/test/java/com/ibm/mapper/mapper/ssl/SSLVersionMapperTest.java b/mapper/src/test/java/com/ibm/mapper/mapper/ssl/SSLVersionMapperTest.java index dd5207e03..2e2a14318 100644 --- a/mapper/src/test/java/com/ibm/mapper/mapper/ssl/SSLVersionMapperTest.java +++ b/mapper/src/test/java/com/ibm/mapper/mapper/ssl/SSLVersionMapperTest.java @@ -26,12 +26,12 @@ import com.ibm.mapper.utils.DetectionLocation; import java.util.List; import java.util.Optional; -import org.junit.Test; +import org.junit.jupiter.api.Test; public class SSLVersionMapperTest { @Test - public void test1() { + public void tlsv12IsParsedAsVersion1_2() { DetectionLocation testDetectionLocation = new DetectionLocation("testfile", 1, 1, List.of("test"), () -> "SSL"); @@ -44,7 +44,7 @@ public void test1() { } @Test - public void test2() { + public void tlsv1WithoutPatchIsParsedAsVersion1_0() { DetectionLocation testDetectionLocation = new DetectionLocation("testfile", 1, 1, List.of("test"), () -> "SSL"); @@ -57,7 +57,7 @@ public void test2() { } @Test - public void test3() { + public void tlsv13LowercaseIsParsedAsVersion1_3() { DetectionLocation testDetectionLocation = new DetectionLocation("testfile", 1, 1, List.of("test"), () -> "SSL"); @@ -68,4 +68,14 @@ public void test3() { assertThat(version.get().is(Version.class)).isTrue(); assertThat(version.get().asString()).isEqualTo("1.3"); } + + @Test + public void testDtlsVersionReturnsEmpty() { + DetectionLocation testDetectionLocation = + new DetectionLocation("testfile", 1, 1, List.of("test"), () -> "SSL"); + + final SSLVersionMapper mapper = new SSLVersionMapper(); + assertThat(mapper.parse("DTLSv1.2", testDetectionLocation)).isEmpty(); + assertThat(mapper.parse("DTLSv1.0", testDetectionLocation)).isEmpty(); + } } diff --git a/pom.xml b/pom.xml index a32d3c773..cb5572ad5 100644 --- a/pom.xml +++ b/pom.xml @@ -14,6 +14,7 @@ python go csharp + cpp engine output common @@ -37,8 +38,8 @@ - 17 - 17 + 21 + 21 UTF-8 2.9.1 @@ -51,10 +52,20 @@ 8.22.0.41895 5.16.0.29940 1.32.0.5128 + + + d04ca9d907b5d49b1f88785fa77dc6237b4351ad 1.28.0 + + + jitpack.io + https://jitpack.io + + + github @@ -132,6 +143,17 @@ sonar-go-plugin ${sonar.go.version} + + + com.github.SonarOpenCommunity.sonar-cxx + cxx-squid-bridge + ${sonar.cxx.version} + + + com.github.SonarOpenCommunity.sonar-cxx + cxx-squid + ${sonar.cxx.version} + diff --git a/sonar-cryptography-plugin/pom.xml b/sonar-cryptography-plugin/pom.xml index 9ac6bfe6a..a5f9396dc 100644 --- a/sonar-cryptography-plugin/pom.xml +++ b/sonar-cryptography-plugin/pom.xml @@ -47,6 +47,12 @@ 2.0.0-SNAPSHOT compile + + com.ibm + cpp + 2.0.0-SNAPSHOT + compile + @@ -71,7 +77,7 @@ Sonar Crypto Plugin com.ibm.plugin.CryptographyPlugin - java,jsp,py,ipynb,go,cs + java,jsp,py,ipynb,go,cs,cxx,cpp,c,h,hpp ${sonar.minVersion} true true diff --git a/sonar-cryptography-plugin/src/main/java/com/ibm/plugin/CryptographyPlugin.java b/sonar-cryptography-plugin/src/main/java/com/ibm/plugin/CryptographyPlugin.java index 415b5a011..7c04f444f 100644 --- a/sonar-cryptography-plugin/src/main/java/com/ibm/plugin/CryptographyPlugin.java +++ b/sonar-cryptography-plugin/src/main/java/com/ibm/plugin/CryptographyPlugin.java @@ -51,6 +51,9 @@ public void define(Context context) { // csharp CSharpScannerRuleDefinition.class, // Define C# rules CryptoCSharpSensor.class, // Custom sensor (sonar-csharp has no CheckRegistrar API) + // cpp + CxxScannerRuleDefinition.class, // Define C++ rules + CxxCheckRegistrar.class, // Register C++ rules by sonar-cxx sensor // general OutputFileJob.class); } diff --git a/sonar-cryptography-plugin/src/main/java/com/ibm/plugin/ScannerManager.java b/sonar-cryptography-plugin/src/main/java/com/ibm/plugin/ScannerManager.java index 7f8491b6f..039220269 100644 --- a/sonar-cryptography-plugin/src/main/java/com/ibm/plugin/ScannerManager.java +++ b/sonar-cryptography-plugin/src/main/java/com/ibm/plugin/ScannerManager.java @@ -67,6 +67,7 @@ private List getAggregatedNodes() { nodes.addAll(PythonAggregator.getDetectedNodes()); nodes.addAll(GoAggregator.getDetectedNodes()); nodes.addAll(CSharpAggregator.getDetectedNodes()); + nodes.addAll(CxxAggregator.getDetectedNodes()); return nodes; } @@ -75,5 +76,6 @@ public void reset() { PythonAggregator.reset(); GoAggregator.reset(); CSharpAggregator.reset(); + CxxAggregator.reset(); } } diff --git a/sonar-cryptography-plugin/src/test/java/com/ibm/plugin/PluginTest.java b/sonar-cryptography-plugin/src/test/java/com/ibm/plugin/PluginTest.java index d7a409553..67db06ea4 100644 --- a/sonar-cryptography-plugin/src/test/java/com/ibm/plugin/PluginTest.java +++ b/sonar-cryptography-plugin/src/test/java/com/ibm/plugin/PluginTest.java @@ -39,6 +39,6 @@ void testExtensions() { Plugin.Context context = new PluginContextImpl.Builder().setSonarRuntime(runtime).build(); CryptographyPlugin plugin = new CryptographyPlugin(); plugin.define(context); - Assertions.assertEquals(10, context.getExtensions().size()); + Assertions.assertEquals(12, context.getExtensions().size()); } }