diff --git a/java/ql/lib/semmle/code/java/security/RsaWithoutOaepQuery.qll b/java/ql/lib/semmle/code/java/security/RsaWithoutOaepQuery.qll new file mode 100644 index 000000000000..71cbb565e009 --- /dev/null +++ b/java/ql/lib/semmle/code/java/security/RsaWithoutOaepQuery.qll @@ -0,0 +1,23 @@ +/** Definitions for the RSA without OAEP query */ + +import java +import Encryption +import semmle.code.java.dataflow.DataFlow + +/** A configuration for finding RSA ciphers initialized without using OAEP padding. */ +class RsaWithoutOaepConfig extends DataFlow::Configuration { + RsaWithoutOaepConfig() { this = "RsaWithoutOaepConfig" } + + override predicate isSource(DataFlow::Node src) { + exists(CompileTimeConstantExpr specExpr, string spec | + specExpr.getStringValue() = spec and + specExpr = src.asExpr() and + spec.matches("RSA/%") and + not spec.matches("%OAEP%") + ) + } + + override predicate isSink(DataFlow::Node sink) { + exists(CryptoAlgoSpec cr | sink.asExpr() = cr.getAlgoSpec()) + } +} diff --git a/java/ql/src/Security/CWE/CWE-780/RsaWithoutOaep.java b/java/ql/src/Security/CWE/CWE-780/RsaWithoutOaep.java new file mode 100644 index 000000000000..34024a59f6e0 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-780/RsaWithoutOaep.java @@ -0,0 +1,7 @@ +// BAD: No padding scheme is used +Cipher rsa = Cipher.getInstance("RSA/ECB/NoPadding"); +... + +//GOOD: OAEP padding is used +Cipher rsa = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding"); +... \ No newline at end of file diff --git a/java/ql/src/Security/CWE/CWE-780/RsaWithoutOaep.qhelp b/java/ql/src/Security/CWE/CWE-780/RsaWithoutOaep.qhelp new file mode 100644 index 000000000000..03b0e0325207 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-780/RsaWithoutOaep.qhelp @@ -0,0 +1,27 @@ + + + + +

Cryptographic algorithms often use padding schemes to make the plaintext less predictable. The OAEP (Optimal Asymmetric Encryption Padding) scheme should be used with RSA encryption. + Using an outdated padding scheme such as PKCS1, or no padding at all, can weaken the encryption by making it vulnerable to a padding oracle attack. +

+
+ + +

Use the OAEP scheme when using RSA encryption.

+
+ + +

In the following example, the BAD case shows no padding being used, whereas the GOOD case shows an OAEP scheme being used.

+ +
+ + +
  • + Mobile Security Testing Guide. +
  • +
  • + The Padding Oracle Attack. +
  • +
    +
    diff --git a/java/ql/src/Security/CWE/CWE-780/RsaWithoutOaep.ql b/java/ql/src/Security/CWE/CWE-780/RsaWithoutOaep.ql new file mode 100644 index 000000000000..a5c8b954d277 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-780/RsaWithoutOaep.ql @@ -0,0 +1,20 @@ +/** + * @name Use of RSA algorithm without OAEP + * @description Using RSA encryption without OAEP padding can result in a padding oracle attack, leading to a weaker encryption. + * @kind path-problem + * @problem.severity warning + * @security-severity 7.5 + * @precision high + * @id java/rsa-without-oaep + * @tags security + * external/cwe/cwe-780 + */ + +import java +import semmle.code.java.security.RsaWithoutOaepQuery +import DataFlow::PathGraph + +from RsaWithoutOaepConfig conf, DataFlow::PathNode source, DataFlow::PathNode sink +where conf.hasFlowPath(source, sink) +select source, source, sink, + "This specification is used to initialize an RSA cipher without OAEP padding $@.", sink, "here" diff --git a/java/ql/src/change-notes/2022-08-05-rsa-without-oaep.md b/java/ql/src/change-notes/2022-08-05-rsa-without-oaep.md new file mode 100644 index 000000000000..06d71cbf8653 --- /dev/null +++ b/java/ql/src/change-notes/2022-08-05-rsa-without-oaep.md @@ -0,0 +1,4 @@ +--- +category: newQuery +--- +* A new query "Use of RSA algorithm without OAEP" (`java/rsa-without-oaep`) has been added. This query finds uses of RSA encryption that don't use the OAEP scheme. \ No newline at end of file diff --git a/java/ql/test/query-tests/security/CWE-780/RsaWithoutOaepTest.expected b/java/ql/test/query-tests/security/CWE-780/RsaWithoutOaepTest.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/java/ql/test/query-tests/security/CWE-780/RsaWithoutOaepTest.java b/java/ql/test/query-tests/security/CWE-780/RsaWithoutOaepTest.java new file mode 100644 index 000000000000..b8a1c73110c5 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-780/RsaWithoutOaepTest.java @@ -0,0 +1,17 @@ +import javax.crypto.Cipher; + +class RsaWithoutOaep { + public void test() throws Exception { + Cipher rsaBad = Cipher.getInstance("RSA/ECB/NoPadding"); // $hasTaintFlow + + Cipher rsaGood = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding"); + } + + public Cipher getCipher(String spec) throws Exception { + return Cipher.getInstance(spec); // $hasTaintFlow + } + + public void test2() throws Exception { + Cipher rsa = getCipher("RSA/ECB/NoPadding"); + } +} \ No newline at end of file diff --git a/java/ql/test/query-tests/security/CWE-780/RsaWithoutOaepTest.ql b/java/ql/test/query-tests/security/CWE-780/RsaWithoutOaepTest.ql new file mode 100644 index 000000000000..bf8e8cbae211 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-780/RsaWithoutOaepTest.ql @@ -0,0 +1,10 @@ +import java +import TestUtilities.InlineExpectationsTest +import TestUtilities.InlineFlowTest +import semmle.code.java.security.RsaWithoutOaepQuery + +class HasFlowTest extends InlineFlowTest { + override DataFlow::Configuration getTaintFlowConfig() { result instanceof RsaWithoutOaepConfig } + + override DataFlow::Configuration getValueFlowConfig() { none() } +}