C++: add initial insufficient key size query

This commit is contained in:
Robert Marsh
2022-02-10 14:53:40 -05:00
parent eb109828c0
commit dbe4770c7d
5 changed files with 128 additions and 0 deletions

View File

@@ -0,0 +1,36 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Using cryptographic algorithms with a small key size can leave data vulnerable to being decrypted.</p>
<p>Many cryptographic algorithms provided by cryptography libraries can be configured with key sizes that are
vulnerable to brute force attacks. Using such a key size means that an attacker may be able to easily decrypt the
encrypted data.</p>
</overview>
<recommendation>
<p>Ensure that you use a strong, modern cryptographic algorithm. Use at least AES-128 or RSA-2048.</p>
</recommendation>
<example>
</example>
<references>
<li>NIST, FIPS 140 Annex a: <a href="http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf">
Approved Security Functions</a>.</li>
<li>NIST, SP 800-131A: <a href="https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf">
Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths</a>.</li>
<!-- LocalWords: CWE
-->
</references>
</qhelp>

View File

@@ -0,0 +1,50 @@
/**
* @name Use of a cryptographic algorithm with insufficient key size
* @description Using cryptographic algorithms with too small a key size can
* allow an attacker to compromise security.
* @kind problem
* @problem.severity error
* @precision high
* @id cpp/insufficient-key-size
* @tags security
* external/cwe/cwe-326
*/
import cpp
import semmle.code.cpp.ir.dataflow.DataFlow
import semmle.code.cpp.ir.IR
int getMinimumKeyStrength(string func) {
func = "EVP_PKEY_CTX_set_dsa_paramgen_bits" and result = 2048
or
func = "EVP_PKEY_CTX_set_dh_paramgen_prime_len" and result = 2048
or
func = "EVP_PKEY_CTX_set_rsa_keygen_bits" and result = 2048
}
class KeyStrengthFlow extends DataFlow::Configuration {
KeyStrengthFlow() {
this = "KeyStrengthFlow"
}
override predicate isSource(DataFlow::Node node) {
node.asInstruction() instanceof IntegerConstantInstruction
}
override predicate isSink(DataFlow::Node node) {
exists(FunctionCall fc, string name|
node.asExpr() = fc.getArgument(1) and
fc.getTarget().hasGlobalName(name) and
exists(getMinimumKeyStrength(name))
)
}
}
from DataFlow::PathNode source, DataFlow::PathNode sink, KeyStrengthFlow conf, FunctionCall fc, string name, int bits
where
conf.hasFlowPath(source, sink) and
sink.getNode().asExpr() = fc.getArgument(1) and
fc.getTarget().hasGlobalName(name) and
bits = getMinimumKeyStrength(name) and
source.getNode().asInstruction().(ConstantValueInstruction).getValue().toInt() < bits
select fc, source, sink, "The key size $@ is insufficient for security", source, source.toString()

View File

@@ -0,0 +1,3 @@
| test.cpp:32:5:32:38 | call to EVP_PKEY_CTX_set_dsa_paramgen_bits | test.cpp:32:45:32:48 | 1024 | test.cpp:32:45:32:48 | 1024 | The key size $@ is insufficient for security | test.cpp:32:45:32:48 | 1024 | 1024 |
| test.cpp:33:5:33:42 | call to EVP_PKEY_CTX_set_dh_paramgen_prime_len | test.cpp:33:49:33:52 | 1024 | test.cpp:33:49:33:52 | 1024 | The key size $@ is insufficient for security | test.cpp:33:49:33:52 | 1024 | 1024 |
| test.cpp:35:5:35:36 | call to EVP_PKEY_CTX_set_rsa_keygen_bits | test.cpp:35:43:35:46 | 1024 | test.cpp:35:43:35:46 | 1024 | The key size $@ is insufficient for security | test.cpp:35:43:35:46 | 1024 | 1024 |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-326/InsufficientKeySize.ql

View File

@@ -0,0 +1,38 @@
typedef int EVP_CIPHER;
typedef int EVP_MD;
const EVP_CIPHER *EVP_aes_128_ctr();
const EVP_CIPHER *EVP_aes_192_ctr();
const EVP_CIPHER *EVP_aes_256_ctr();
const EVP_MD *EVP_sha224();
const EVP_MD *EVP_sha256();
const EVP_MD *EVP_sha384();
const EVP_MD *EVP_sha512();
class EVP_PKEY_CTX;
// int is a curve ID rather than a bit width
int EVP_PKEY_CTX_set_ec_paramgen_curve_nid(EVP_PKEY_CTX*, int);
int EVP_PKEY_CTX_set_dsa_paramgen_bits(EVP_PKEY_CTX*, int);
int EVP_PKEY_CTX_set_dh_paramgen_prime_len(EVP_PKEY_CTX*, int);
// RSA sets bits per-key rather than with parameters
int EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX*, int);
void test1(EVP_PKEY_CTX *ctx) {
EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx, 2048);
EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx, 2048);
// RSA sets bits per-key rather than with parameters
EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048);
// low key sizes
EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx, 1024);
EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx, 1024);
// RSA sets bits per-key rather than with parameters
EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 1024);
}