From cbaee937d0ab8962278be494e36eaad5ab24693f Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Fri, 8 Jan 2021 21:56:34 +0000 Subject: [PATCH] Optimize the query --- .../CWE/CWE-326/InsufficientKeySize.qhelp | 6 +- .../CWE/CWE-326/InsufficientKeySize.ql | 91 ++++++++----------- .../semmle/code/java/security/Encryption.qll | 14 ++- .../CWE-326/InsufficientKeySize.expected | 4 + .../security/CWE-326/InsufficientKeySize.java | 21 ++++- 5 files changed, 77 insertions(+), 59 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.qhelp b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.qhelp index 8de21f1c90a..10ec6adc9df 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.qhelp @@ -6,7 +6,7 @@ are vulnerable to brute force attack when too small a key size is used.

-

The key should be at least 2048-bit long when using RSA and DSA encryption, 224-bit long when using EC encryption, and 128-bit long when using +

The key should be at least 2048 bits long when using RSA and DSA encryption, 224 bits long when using EC encryption, and 128 bits long when using symmetric encryption.

@@ -24,10 +24,6 @@ symmetric encryption.

CWE. CWE-326: Inadequate Encryption Strength -
  • - C# implementation of CodeQL - codeql/csharp/ql/src/Security Features/InsufficientKeySize.ql -
  • \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql index 882d997f1b8..df265f267f7 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql @@ -11,16 +11,6 @@ import java import semmle.code.java.security.Encryption import semmle.code.java.dataflow.TaintTracking -/** The Java class `javax.crypto.KeyGenerator`. */ -class KeyGenerator extends RefType { - KeyGenerator() { this.hasQualifiedName("javax.crypto", "KeyGenerator") } -} - -/** The Java class `javax.crypto.KeyGenerator`. */ -class KeyPairGenerator extends RefType { - KeyPairGenerator() { this.hasQualifiedName("java.security", "KeyPairGenerator") } -} - /** The Java class `java.security.spec.ECGenParameterSpec`. */ class ECGenParameterSpec extends RefType { ECGenParameterSpec() { this.hasQualifiedName("java.security.spec", "ECGenParameterSpec") } @@ -42,9 +32,19 @@ class KeyPairGeneratorInitMethod extends Method { } } +/** Returns the key size in the EC algorithm string */ +bindingset[algorithm] +int getECKeySize(string algorithm) { + algorithm.matches("sec%") and // specification such as "secp256r1" + result = algorithm.regexpCapture("sec[p|t](\\d+)[a-zA-Z].*", 1).toInt() + or + algorithm.matches("X9.62%") and //specification such as "X9.62 prime192v2" + result = algorithm.regexpCapture("X9.62 .*[a-zA-Z](\\d+)[a-zA-Z].*", 1).toInt() +} + /** Taint configuration tracking flow from a key generator to a `init` method call. */ -class CryptoKeyGeneratorConfiguration extends TaintTracking::Configuration { - CryptoKeyGeneratorConfiguration() { this = "CryptoKeyGeneratorConfiguration" } +class KeyGeneratorInitConfiguration extends TaintTracking::Configuration { + KeyGeneratorInitConfiguration() { this = "KeyGeneratorInitConfiguration" } override predicate isSource(DataFlow::Node source) { exists(JavaxCryptoKeyGenerator jcg | jcg = source.asExpr()) @@ -59,8 +59,8 @@ class CryptoKeyGeneratorConfiguration extends TaintTracking::Configuration { } /** Taint configuration tracking flow from a keypair generator to a `initialize` method call. */ -class KeyPairGeneratorConfiguration extends TaintTracking::Configuration { - KeyPairGeneratorConfiguration() { this = "KeyPairGeneratorConfiguration" } +class KeyPairGeneratorInitConfiguration extends TaintTracking::Configuration { + KeyPairGeneratorInitConfiguration() { this = "KeyPairGeneratorInitConfiguration" } override predicate isSource(DataFlow::Node source) { exists(JavaSecurityKeyPairGenerator jkg | jkg = source.asExpr()) @@ -75,10 +75,10 @@ class KeyPairGeneratorConfiguration extends TaintTracking::Configuration { } /** Holds if an AES `KeyGenerator` is initialized with an insufficient key size. */ -predicate incorrectUseOfAES(MethodAccess ma, string msg) { +predicate hasShortAESKey(MethodAccess ma, string msg) { ma.getMethod() instanceof KeyGeneratorInitMethod and exists( - JavaxCryptoKeyGenerator jcg, CryptoKeyGeneratorConfiguration cc, DataFlow::PathNode source, + JavaxCryptoKeyGenerator jcg, KeyGeneratorInitConfiguration cc, DataFlow::PathNode source, DataFlow::PathNode dest | jcg.getAlgoSpec().(StringLiteral).getValue() = "AES" and @@ -90,66 +90,55 @@ predicate incorrectUseOfAES(MethodAccess ma, string msg) { msg = "Key size should be at least 128 bits for AES encryption." } -/** Holds if a DSA `KeyPairGenerator` is initialized with an insufficient key size. */ -predicate incorrectUseOfDSA(MethodAccess ma, string msg) { +/** Holds if an asymmetric `KeyPairGenerator` is initialized with an insufficient key size. */ +bindingset[type] +predicate hasShortAsymmetricKeyPair(MethodAccess ma, string msg, string type) { ma.getMethod() instanceof KeyPairGeneratorInitMethod and exists( - JavaSecurityKeyPairGenerator jpg, KeyPairGeneratorConfiguration kc, DataFlow::PathNode source, - DataFlow::PathNode dest + JavaSecurityKeyPairGenerator jpg, KeyPairGeneratorInitConfiguration kc, + DataFlow::PathNode source, DataFlow::PathNode dest | - jpg.getAlgoSpec().(StringLiteral).getValue() = "DSA" and + jpg.getAlgoSpec().(StringLiteral).getValue() = type and source.getNode().asExpr() = jpg and dest.getNode().asExpr() = ma.getQualifier() and kc.hasFlowPath(source, dest) ) and ma.getArgument(0).(IntegerLiteral).getIntValue() < 2048 and - msg = "Key size should be at least 2048 bits for DSA encryption." + msg = "Key size should be at least 2048 bits for " + type + " encryption." +} + +/** Holds if a DSA `KeyPairGenerator` is initialized with an insufficient key size. */ +predicate hasShortDSAKeyPair(MethodAccess ma, string msg) { + hasShortAsymmetricKeyPair(ma, msg, "DSA") } /** Holds if a RSA `KeyPairGenerator` is initialized with an insufficient key size. */ -predicate incorrectUseOfRSA(MethodAccess ma, string msg) { - ma.getMethod() instanceof KeyPairGeneratorInitMethod and - exists( - JavaSecurityKeyPairGenerator jpg, KeyPairGeneratorConfiguration kc, DataFlow::PathNode source, - DataFlow::PathNode dest - | - jpg.getAlgoSpec().(StringLiteral).getValue() = "RSA" and - source.getNode().asExpr() = jpg and - dest.getNode().asExpr() = ma.getQualifier() and - kc.hasFlowPath(source, dest) - ) and - ma.getArgument(0).(IntegerLiteral).getIntValue() < 2048 and - msg = "Key size should be at least 2048 bits for RSA encryption." +predicate hasShortRSAKeyPair(MethodAccess ma, string msg) { + hasShortAsymmetricKeyPair(ma, msg, "RSA") } /** Holds if an EC `KeyPairGenerator` is initialized with an insufficient key size. */ -predicate incorrectUseOfEC(MethodAccess ma, string msg) { +predicate hasShortECKeyPair(MethodAccess ma, string msg) { ma.getMethod() instanceof KeyPairGeneratorInitMethod and exists( - JavaSecurityKeyPairGenerator jpg, KeyPairGeneratorConfiguration kc, DataFlow::PathNode source, - DataFlow::PathNode dest, ClassInstanceExpr cie + JavaSecurityKeyPairGenerator jpg, KeyPairGeneratorInitConfiguration kc, + DataFlow::PathNode source, DataFlow::PathNode dest, ClassInstanceExpr cie | jpg.getAlgoSpec().(StringLiteral).getValue().matches("EC%") and //ECC variants such as ECDH and ECDSA source.getNode().asExpr() = jpg and dest.getNode().asExpr() = ma.getQualifier() and kc.hasFlowPath(source, dest) and - exists(VariableAssign va | - ma.getArgument(0).(VarAccess).getVariable() = va.getDestVar() and - va.getSource() = cie and - cie.getArgument(0) - .(StringLiteral) - .getRepresentedString() - .regexpCapture(".*[a-zA-Z]+([0-9]+)[a-zA-Z]+.*", 1) - .toInt() < 224 - ) + DataFlow::localExprFlow(cie, ma.getArgument(0)) and + ma.getArgument(0).getType() instanceof ECGenParameterSpec and + getECKeySize(cie.getArgument(0).(StringLiteral).getRepresentedString()) < 224 ) and msg = "Key size should be at least 224 bits for EC encryption." } from Expr e, string msg where - incorrectUseOfAES(e, msg) or - incorrectUseOfDSA(e, msg) or - incorrectUseOfRSA(e, msg) or - incorrectUseOfEC(e, msg) + hasShortAESKey(e, msg) or + hasShortDSAKeyPair(e, msg) or + hasShortRSAKeyPair(e, msg) or + hasShortECKeyPair(e, msg) select e, msg diff --git a/java/ql/src/semmle/code/java/security/Encryption.qll b/java/ql/src/semmle/code/java/security/Encryption.qll index b133fd3c523..9c10569d8c1 100644 --- a/java/ql/src/semmle/code/java/security/Encryption.qll +++ b/java/ql/src/semmle/code/java/security/Encryption.qll @@ -38,6 +38,16 @@ class HostnameVerifier extends RefType { HostnameVerifier() { hasQualifiedName("javax.net.ssl", "HostnameVerifier") } } +/** The Java class `javax.crypto.KeyGenerator`. */ +class KeyGenerator extends RefType { + KeyGenerator() { this.hasQualifiedName("javax.crypto", "KeyGenerator") } +} + +/** The Java class `java.security.KeyPairGenerator`. */ +class KeyPairGenerator extends RefType { + KeyPairGenerator() { this.hasQualifiedName("java.security", "KeyPairGenerator") } +} + /** The `verify` method of the class `javax.net.ssl.HostnameVerifier`. */ class HostnameVerifierVerify extends Method { HostnameVerifierVerify() { @@ -248,7 +258,7 @@ class JavaxCryptoSecretKey extends JavaxCryptoAlgoSpec { class JavaxCryptoKeyGenerator extends JavaxCryptoAlgoSpec { JavaxCryptoKeyGenerator() { exists(Method m | m.getAReference() = this | - m.getDeclaringType().getQualifiedName() = "javax.crypto.KeyGenerator" and + m.getDeclaringType() instanceof KeyGenerator and m.getName() = "getInstance" ) } @@ -309,7 +319,7 @@ class JavaSecuritySignature extends JavaSecurityAlgoSpec { class JavaSecurityKeyPairGenerator extends JavaxCryptoAlgoSpec { JavaSecurityKeyPairGenerator() { exists(Method m | m.getAReference() = this | - m.getDeclaringType().getQualifiedName() = "java.security.KeyPairGenerator" and + m.getDeclaringType() instanceof KeyPairGenerator and m.getName() = "getInstance" ) } diff --git a/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.expected b/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.expected index b47469aed5d..f350495d28f 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.expected @@ -2,3 +2,7 @@ | InsufficientKeySize.java:17:9:17:36 | initialize(...) | Key size should be at least 2048 bits for RSA encryption. | | InsufficientKeySize.java:25:9:25:36 | initialize(...) | Key size should be at least 2048 bits for DSA encryption. | | InsufficientKeySize.java:34:9:34:39 | initialize(...) | Key size should be at least 224 bits for EC encryption. | +| InsufficientKeySize.java:38:9:38:67 | initialize(...) | Key size should be at least 224 bits for EC encryption. | +| InsufficientKeySize.java:48:9:48:39 | initialize(...) | Key size should be at least 224 bits for EC encryption. | +| InsufficientKeySize.java:53:9:53:39 | initialize(...) | Key size should be at least 224 bits for EC encryption. | +| InsufficientKeySize.java:58:9:58:40 | initialize(...) | Key size should be at least 224 bits for EC encryption. | diff --git a/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.java b/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.java index 13f74b6fac3..80d49cdf5f1 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.java +++ b/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.java @@ -34,8 +34,27 @@ public class InsufficientKeySize { keyPairGen5.initialize(ecSpec1); KeyPairGenerator keyPairGen6 = KeyPairGenerator.getInstance("EC"); + // BAD: Key size is less than 224 + keyPairGen6.initialize(new ECGenParameterSpec("secp112r1")); + + KeyPairGenerator keyPairGen7 = KeyPairGenerator.getInstance("EC"); // GOOD: Key size is no less than 224 ECGenParameterSpec ecSpec2 = new ECGenParameterSpec("secp256r1"); - keyPairGen6.initialize(ecSpec2); + keyPairGen7.initialize(ecSpec2); + + KeyPairGenerator keyPairGen8 = KeyPairGenerator.getInstance("EC"); + // BAD: Key size is less than 224 + ECGenParameterSpec ecSpec3 = new ECGenParameterSpec("X9.62 prime192v2"); + keyPairGen8.initialize(ecSpec3); + + KeyPairGenerator keyPairGen9 = KeyPairGenerator.getInstance("EC"); + // BAD: Key size is less than 224 + ECGenParameterSpec ecSpec4 = new ECGenParameterSpec("X9.62 c2tnb191v3"); + keyPairGen9.initialize(ecSpec4); + + KeyPairGenerator keyPairGen10 = KeyPairGenerator.getInstance("EC"); + // BAD: Key size is less than 224 + ECGenParameterSpec ecSpec5 = new ECGenParameterSpec("sect163k1"); + keyPairGen10.initialize(ecSpec5); } }