diff --git a/config/identical-files.json b/config/identical-files.json index 0a5d037e226..26d1598ec53 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -580,5 +580,9 @@ "IncompleteMultiCharacterSanitization JS/Ruby": [ "javascript/ql/lib/semmle/javascript/security/IncompleteMultiCharacterSanitizationQuery.qll", "ruby/ql/lib/codeql/ruby/security/IncompleteMultiCharacterSanitizationQuery.qll" + ], + "EncryptionKeySizes Python/Java": [ + "python/ql/lib/semmle/python/security/internal/EncryptionKeySizes.qll", + "java/ql/lib/semmle/code/java/security/internal/EncryptionKeySizes.qll" ] } diff --git a/java/ql/lib/semmle/code/java/security/InsufficientKeySize.qll b/java/ql/lib/semmle/code/java/security/InsufficientKeySize.qll index e09bffca8e1..b156b594a70 100644 --- a/java/ql/lib/semmle/code/java/security/InsufficientKeySize.qll +++ b/java/ql/lib/semmle/code/java/security/InsufficientKeySize.qll @@ -2,6 +2,7 @@ private import semmle.code.java.security.Encryption private import semmle.code.java.dataflow.DataFlow +private import semmle.code.java.security.internal.EncryptionKeySizes /** A source for an insufficient key size. */ abstract class InsufficientKeySizeSource extends DataFlow::Node { @@ -21,39 +22,67 @@ private module Asymmetric { private module NonEllipticCurve { /** A source for an insufficient key size used in RSA, DSA, and DH algorithms. */ private class Source extends InsufficientKeySizeSource { - Source() { this.asExpr().(IntegerLiteral).getIntValue() < getMinKeySize() } + string algoName; - override predicate hasState(DataFlow::FlowState state) { state = getMinKeySize().toString() } + Source() { this.asExpr().(IntegerLiteral).getIntValue() < getMinKeySize(algoName) } + + override predicate hasState(DataFlow::FlowState state) { + state = getMinKeySize(algoName).toString() + } } /** A sink for an insufficient key size used in RSA, DSA, and DH algorithms. */ private class Sink extends InsufficientKeySizeSink { + string algoName; + Sink() { exists(KeyPairGenInit kpgInit, KeyPairGen kpg | - kpg.getAlgoName().matches(["RSA", "DSA", "DH"]) and + algoName in ["RSA", "DSA", "DH"] and + kpg.getAlgoName() = algoName and DataFlow::localExprFlow(kpg, kpgInit.getQualifier()) and this.asExpr() = kpgInit.getKeySizeArg() ) or - exists(Spec spec | this.asExpr() = spec.getKeySizeArg()) + exists(Spec spec | this.asExpr() = spec.getKeySizeArg() and algoName = spec.getAlgoName()) } - override predicate hasState(DataFlow::FlowState state) { state = getMinKeySize().toString() } + override predicate hasState(DataFlow::FlowState state) { + state = getMinKeySize(algoName).toString() + } } /** Returns the minimum recommended key size for RSA, DSA, and DH algorithms. */ - private int getMinKeySize() { result = 2048 } + private int getMinKeySize(string algoName) { + algoName = "RSA" and + result = minSecureKeySizeRsa() + or + algoName = "DSA" and + result = minSecureKeySizeDsa() + or + algoName = "DH" and + result = minSecureKeySizeDh() + } /** An instance of an RSA, DSA, or DH algorithm specification. */ private class Spec extends ClassInstanceExpr { + string algoName; + Spec() { - this.getConstructedType() instanceof RsaKeyGenParameterSpec or - this.getConstructedType() instanceof DsaGenParameterSpec or - this.getConstructedType() instanceof DhGenParameterSpec + this.getConstructedType() instanceof RsaKeyGenParameterSpec and + algoName = "RSA" + or + this.getConstructedType() instanceof DsaGenParameterSpec and + algoName = "DSA" + or + this.getConstructedType() instanceof DhGenParameterSpec and + algoName = "DH" } /** Gets the `keysize` argument of this instance. */ Argument getKeySizeArg() { result = this.getArgument(0) } + + /** Gets the algorithm name of this spec. */ + string getAlgoName() { result = algoName } } } @@ -87,7 +116,7 @@ private module Asymmetric { } /** Returns the minimum recommended key size for elliptic curve (EC) algorithms. */ - private int getMinKeySize() { result = 256 } + private int getMinKeySize() { result = minSecureKeySizeEcc() } /** Returns the key size from an EC algorithm's curve name string */ bindingset[algorithm] @@ -168,7 +197,7 @@ private module Symmetric { } /** Returns the minimum recommended key size for AES algorithms. */ - private int getMinKeySize() { result = 128 } + private int getMinKeySize() { result = minSecureKeySizeAes() } /** A call to the `init` method declared in `javax.crypto.KeyGenerator`. */ private class KeyGenInit extends MethodAccess { diff --git a/java/ql/lib/semmle/code/java/security/internal/EncryptionKeySizes.qll b/java/ql/lib/semmle/code/java/security/internal/EncryptionKeySizes.qll new file mode 100644 index 00000000000..46df3a3ca7b --- /dev/null +++ b/java/ql/lib/semmle/code/java/security/internal/EncryptionKeySizes.qll @@ -0,0 +1,21 @@ +/** + * INTERNAL: Do not use. + * + * Provides predicates for recommended encryption key sizes. + * Such that we can share this logic across our CodeQL analysis of different languages. + */ + +/** Returns the minimum recommended key size for RSA. */ +int minSecureKeySizeRsa() { result = 2048 } + +/** Returns the minimum recommended key size for DSA. */ +int minSecureKeySizeDsa() { result = 2048 } + +/** Returns the minimum recommended key size for DH. */ +int minSecureKeySizeDh() { result = 2048 } + +/** Returns the minimum recommended key size for elliptic curve cryptography. */ +int minSecureKeySizeEcc() { result = 256 } + +/** Returns the minimum recommended key size for AES. */ +int minSecureKeySizeAes() { result = 128 } diff --git a/python/ql/lib/semmle/python/Concepts.qll b/python/ql/lib/semmle/python/Concepts.qll index 861e4e7ca81..b4d2a64cb45 100644 --- a/python/ql/lib/semmle/python/Concepts.qll +++ b/python/ql/lib/semmle/python/Concepts.qll @@ -9,6 +9,7 @@ private import semmle.python.dataflow.new.DataFlow private import semmle.python.dataflow.new.RemoteFlowSources private import semmle.python.dataflow.new.TaintTracking private import semmle.python.Frameworks +private import semmle.python.security.internal.EncryptionKeySizes /** * A data-flow node that executes an operating system command, @@ -1141,21 +1142,21 @@ module Cryptography { abstract class RsaRange extends Range { final override string getName() { result = "RSA" } - final override int minimumSecureKeySize() { result = 2048 } + final override int minimumSecureKeySize() { result = minSecureKeySizeRsa() } } /** A data-flow node that generates a new DSA key-pair. */ abstract class DsaRange extends Range { final override string getName() { result = "DSA" } - final override int minimumSecureKeySize() { result = 2048 } + final override int minimumSecureKeySize() { result = minSecureKeySizeDsa() } } /** A data-flow node that generates a new ECC key-pair. */ abstract class EccRange extends Range { final override string getName() { result = "ECC" } - final override int minimumSecureKeySize() { result = 224 } + final override int minimumSecureKeySize() { result = minSecureKeySizeEcc() } } } } diff --git a/python/ql/lib/semmle/python/security/internal/EncryptionKeySizes.qll b/python/ql/lib/semmle/python/security/internal/EncryptionKeySizes.qll new file mode 100644 index 00000000000..46df3a3ca7b --- /dev/null +++ b/python/ql/lib/semmle/python/security/internal/EncryptionKeySizes.qll @@ -0,0 +1,21 @@ +/** + * INTERNAL: Do not use. + * + * Provides predicates for recommended encryption key sizes. + * Such that we can share this logic across our CodeQL analysis of different languages. + */ + +/** Returns the minimum recommended key size for RSA. */ +int minSecureKeySizeRsa() { result = 2048 } + +/** Returns the minimum recommended key size for DSA. */ +int minSecureKeySizeDsa() { result = 2048 } + +/** Returns the minimum recommended key size for DH. */ +int minSecureKeySizeDh() { result = 2048 } + +/** Returns the minimum recommended key size for elliptic curve cryptography. */ +int minSecureKeySizeEcc() { result = 256 } + +/** Returns the minimum recommended key size for AES. */ +int minSecureKeySizeAes() { result = 128 } diff --git a/python/ql/src/Security/CWE-326/WeakCryptoKey.qhelp b/python/ql/src/Security/CWE-326/WeakCryptoKey.qhelp index 8c6b578d12d..2bc138f86bb 100644 --- a/python/ql/src/Security/CWE-326/WeakCryptoKey.qhelp +++ b/python/ql/src/Security/CWE-326/WeakCryptoKey.qhelp @@ -11,13 +11,13 @@ As computational power increases, the ability to break ciphers grows and keys ne

The three main asymmetric key algorithms currently in use are Rivest–Shamir–Adleman (RSA) cryptography, Digital Signature Algorithm (DSA), and Elliptic-curve cryptography (ECC). With current technology, key sizes of 2048 bits for RSA and DSA, -or 224 bits for ECC, are regarded as unbreakable. +or 256 bits for ECC, are regarded as unbreakable.

-Increase the key size to the recommended amount or larger. For RSA or DSA this is at least 2048 bits, for ECC this is at least 224 bits. +Increase the key size to the recommended amount or larger. For RSA or DSA this is at least 2048 bits, for ECC this is at least 256 bits.

@@ -45,4 +45,3 @@ Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Len - diff --git a/python/ql/src/change-notes/2022-11-29-ecc-min-secure-keysize.md b/python/ql/src/change-notes/2022-11-29-ecc-min-secure-keysize.md new file mode 100644 index 00000000000..2fc0532d547 --- /dev/null +++ b/python/ql/src/change-notes/2022-11-29-ecc-min-secure-keysize.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Bumped the minimum keysize we consider secure for elliptic curve cryptography from 224 to 256 bits, following current best practices. This might effect results from the _Use of weak cryptographic key_ (`py/weak-crypto-key`) query. diff --git a/python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/WeakCryptoKey.expected b/python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/WeakCryptoKey.expected index dc50ddd7873..ea1f924045b 100644 --- a/python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/WeakCryptoKey.expected +++ b/python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/WeakCryptoKey.expected @@ -1,8 +1,8 @@ | weak_crypto.py:68:1:68:21 | ControlFlowNode for dsa_gen_key() | Creation of an DSA key uses $@ bits, which is below 2048 and considered breakable. | weak_crypto.py:16:12:16:15 | ControlFlowNode for IntegerLiteral | 1024 | -| weak_crypto.py:69:1:69:19 | ControlFlowNode for ec_gen_key() | Creation of an ECC key uses $@ bits, which is below 224 and considered breakable. | weak_crypto.py:22:11:22:22 | ControlFlowNode for Attribute | 163 | +| weak_crypto.py:69:1:69:19 | ControlFlowNode for ec_gen_key() | Creation of an ECC key uses $@ bits, which is below 256 and considered breakable. | weak_crypto.py:22:11:22:22 | ControlFlowNode for Attribute | 224 | | weak_crypto.py:70:1:70:28 | ControlFlowNode for rsa_gen_key() | Creation of an RSA key uses $@ bits, which is below 2048 and considered breakable. | weak_crypto.py:12:12:12:15 | ControlFlowNode for IntegerLiteral | 1024 | | weak_crypto.py:72:1:72:30 | ControlFlowNode for dsa_gen_key() | Creation of an DSA key uses $@ bits, which is below 2048 and considered breakable. | weak_crypto.py:16:12:16:15 | ControlFlowNode for IntegerLiteral | 1024 | -| weak_crypto.py:73:1:73:25 | ControlFlowNode for ec_gen_key() | Creation of an ECC key uses $@ bits, which is below 224 and considered breakable. | weak_crypto.py:22:11:22:22 | ControlFlowNode for Attribute | 163 | +| weak_crypto.py:73:1:73:25 | ControlFlowNode for ec_gen_key() | Creation of an ECC key uses $@ bits, which is below 256 and considered breakable. | weak_crypto.py:22:11:22:22 | ControlFlowNode for Attribute | 224 | | weak_crypto.py:74:1:74:37 | ControlFlowNode for rsa_gen_key() | Creation of an RSA key uses $@ bits, which is below 2048 and considered breakable. | weak_crypto.py:12:12:12:15 | ControlFlowNode for IntegerLiteral | 1024 | | weak_crypto.py:76:1:76:22 | ControlFlowNode for Attribute() | Creation of an DSA key uses $@ bits, which is below 2048 and considered breakable. | weak_crypto.py:16:12:16:15 | ControlFlowNode for IntegerLiteral | 1024 | | weak_crypto.py:77:1:77:22 | ControlFlowNode for Attribute() | Creation of an RSA key uses $@ bits, which is below 2048 and considered breakable. | weak_crypto.py:12:12:12:15 | ControlFlowNode for IntegerLiteral | 1024 | diff --git a/python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/weak_crypto.py b/python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/weak_crypto.py index de533254cfe..5ec929c7d09 100644 --- a/python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/weak_crypto.py +++ b/python/ql/test/query-tests/Security/CWE-326-WeakCryptoKey/weak_crypto.py @@ -19,8 +19,8 @@ DSA_STRONG = 3076 BIG = 10000 -EC_WEAK = ec.SECT163K1() # has key size of 163 -EC_OK = ec.SECP224R1() +EC_WEAK = ec.SECP224R1() +EC_OK = ec.SECP256R1() EC_STRONG = ec.SECP384R1() EC_BIG = ec.SECT571R1()