mirror of
https://github.com/github/codeql.git
synced 2026-04-30 19:26:02 +02:00
Crypto: Overhaul/refactor of EVPInitialzers. Update cipher operation to disallow null key and IV on initializers (typically do not represent an actual key or IV).
This commit is contained in:
19
cpp/ql/lib/experimental/quantum/OpenSSL/AvcFlow.qll
Normal file
19
cpp/ql/lib/experimental/quantum/OpenSSL/AvcFlow.qll
Normal file
@@ -0,0 +1,19 @@
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
|
||||
/**
|
||||
* Flows from algorithm values to operations, specific to OpenSSL
|
||||
*/
|
||||
module AvcToCallArgConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(OpenSSLAlgorithmValueConsumer c | c.getResultNode() = source)
|
||||
}
|
||||
|
||||
/**
|
||||
* Trace to any call accepting the algorithm.
|
||||
* NOTE: users must restrict this set to the operations they are interested in.
|
||||
*/
|
||||
predicate isSink(DataFlow::Node sink) { exists(Call c | c.getAnArgument() = sink.asExpr()) }
|
||||
}
|
||||
|
||||
module AvcToCallArgFlow = DataFlow::Global<AvcToCallArgConfig>;
|
||||
@@ -3,60 +3,31 @@ private import experimental.quantum.OpenSSL.CtxFlow
|
||||
private import OpenSSLOperationBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
|
||||
module EncValToInitEncArgConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source.asExpr().getValue().toInt() in [0, 1] }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(EVP_Cipher_Initializer initCall | sink.asExpr() = initCall.getOperationSubtypeArg())
|
||||
}
|
||||
}
|
||||
|
||||
module EncValToInitEncArgFlow = DataFlow::Global<EncValToInitEncArgConfig>;
|
||||
|
||||
int getEncConfigValue(Expr e) {
|
||||
exists(EVP_Cipher_Initializer initCall | e = initCall.getOperationSubtypeArg()) and
|
||||
exists(DataFlow::Node a, DataFlow::Node b |
|
||||
EncValToInitEncArgFlow::flow(a, b) and b.asExpr() = e and result = a.asExpr().getValue().toInt()
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[i]
|
||||
Crypto::KeyOperationSubtype intToCipherOperationSubtype(int i) {
|
||||
if i = 0
|
||||
then result instanceof Crypto::TEncryptMode
|
||||
else
|
||||
if i = 1
|
||||
then result instanceof Crypto::TDecryptMode
|
||||
else result instanceof Crypto::TUnknownKeyOperationMode
|
||||
}
|
||||
|
||||
// TODO: need to add key consumer
|
||||
abstract class EVP_Cipher_Initializer extends EvpKeyOperationSubtypeInitializer,
|
||||
EvpAlgorithmInitializer, EvpKeyInitializer, EvpIVInitializer
|
||||
EvpPrimaryAlgorithmInitializer, EvpKeyInitializer, EvpIVInitializer
|
||||
{
|
||||
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
|
||||
override Expr getAlgorithmArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
abstract Expr getOperationSubtypeArg();
|
||||
|
||||
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
|
||||
if this.(Call).getTarget().getName().toLowerCase().matches("%encrypt%")
|
||||
then result instanceof Crypto::TEncryptMode
|
||||
else
|
||||
if this.(Call).getTarget().getName().toLowerCase().matches("%decrypt%")
|
||||
then result instanceof Crypto::TDecryptMode
|
||||
else
|
||||
if exists(getEncConfigValue(this.getOperationSubtypeArg()))
|
||||
then result = intToCipherOperationSubtype(getEncConfigValue(this.getOperationSubtypeArg()))
|
||||
else result instanceof Crypto::TUnknownKeyOperationMode
|
||||
}
|
||||
}
|
||||
|
||||
abstract class EVP_EX_Initializer extends EVP_Cipher_Initializer {
|
||||
override Expr getKeyArg() { result = this.(Call).getArgument(3) }
|
||||
override Expr getKeyArg() {
|
||||
// Null key indicates the key is not actually set
|
||||
// This pattern can occur during a multi-step initialization
|
||||
// TODO/Note: not flowing 0 to the sink, assuming a direct use of NULL for now
|
||||
result = this.(Call).getArgument(3) and
|
||||
(exists(result.getValue()) implies result.getValue().toInt() != 0)
|
||||
}
|
||||
|
||||
override Expr getIVArg() { result = this.(Call).getArgument(4) }
|
||||
override Expr getIVArg() {
|
||||
// Null IV indicates the IV is not actually set
|
||||
// This occurs given that setting the IV sometimes requires first setting the IV size.
|
||||
// TODO/Note: not flowing 0 to the sink, assuming a direct use of NULL for now
|
||||
result = this.(Call).getArgument(4) and
|
||||
(exists(result.getValue()) implies result.getValue().toInt() != 0)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class EVP_EX2_Initializer extends EVP_Cipher_Initializer {
|
||||
@@ -65,19 +36,26 @@ abstract class EVP_EX2_Initializer extends EVP_Cipher_Initializer {
|
||||
override Expr getIVArg() { result = this.(Call).getArgument(3) }
|
||||
}
|
||||
|
||||
class EVP_Cipher_EX_Init_Call extends EVP_EX_Initializer {
|
||||
EVP_Cipher_EX_Init_Call() {
|
||||
class EvpCipherEXInitCall extends EVP_EX_Initializer {
|
||||
EvpCipherEXInitCall() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_EncryptInit_ex", "EVP_DecryptInit_ex", "EVP_CipherInit_ex"
|
||||
]
|
||||
}
|
||||
|
||||
override Expr getOperationSubtypeArg() {
|
||||
override Expr getKeyOperationSubtypeArg() {
|
||||
// NOTE: for EncryptInit and DecryptInit there is no subtype arg
|
||||
// the subtype is determined automatically by the initializer based on the operation name
|
||||
this.(Call).getTarget().getName().toLowerCase().matches("%cipherinit%") and
|
||||
result = this.(Call).getArgument(5)
|
||||
}
|
||||
}
|
||||
|
||||
// if this.(Call).getTarget().getName().toLowerCase().matches("%encrypt%")
|
||||
// then result instanceof Crypto::TEncryptMode
|
||||
// else
|
||||
// if this.(Call).getTarget().getName().toLowerCase().matches("%decrypt%")
|
||||
// then result instanceof Crypto::TDecryptMode
|
||||
class EVP_Cipher_EX2_or_Simple_Init_Call extends EVP_EX2_Initializer {
|
||||
EVP_Cipher_EX2_or_Simple_Init_Call() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
@@ -86,7 +64,7 @@ class EVP_Cipher_EX2_or_Simple_Init_Call extends EVP_EX2_Initializer {
|
||||
]
|
||||
}
|
||||
|
||||
override Expr getOperationSubtypeArg() {
|
||||
override Expr getKeyOperationSubtypeArg() {
|
||||
this.(Call).getTarget().getName().toLowerCase().matches("%cipherinit%") and
|
||||
result = this.(Call).getArgument(4)
|
||||
}
|
||||
@@ -95,7 +73,7 @@ class EVP_Cipher_EX2_or_Simple_Init_Call extends EVP_EX2_Initializer {
|
||||
class EVP_CipherInit_SKEY_Call extends EVP_EX2_Initializer {
|
||||
EVP_CipherInit_SKEY_Call() { this.(Call).getTarget().getName() in ["EVP_CipherInit_SKEY"] }
|
||||
|
||||
override Expr getOperationSubtypeArg() { result = this.(Call).getArgument(5) }
|
||||
override Expr getKeyOperationSubtypeArg() { result = this.(Call).getArgument(5) }
|
||||
}
|
||||
|
||||
class EVP_Cipher_Update_Call extends EvpUpdate {
|
||||
@@ -105,7 +83,7 @@ class EVP_Cipher_Update_Call extends EvpUpdate {
|
||||
]
|
||||
}
|
||||
|
||||
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
|
||||
override Expr getInputArg() { result = this.(Call).getArgument(3) }
|
||||
|
||||
@@ -154,10 +132,10 @@ class EVP_Cipher_Call extends EvpOperation, EVP_Cipher_Operation {
|
||||
override Expr getInputArg() { result = this.(Call).getArgument(2) }
|
||||
|
||||
override Expr getAlgorithmArg() {
|
||||
result = this.getInitCall().(EvpAlgorithmInitializer).getAlgorithmArg()
|
||||
result = this.getInitCall().(EvpPrimaryAlgorithmInitializer).getAlgorithmArg()
|
||||
}
|
||||
|
||||
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
class EVP_Cipher_Final_Call extends EVPFinal, EVP_Cipher_Operation {
|
||||
@@ -178,10 +156,10 @@ class EVP_Cipher_Final_Call extends EVPFinal, EVP_Cipher_Operation {
|
||||
}
|
||||
|
||||
override Expr getAlgorithmArg() {
|
||||
result = this.getInitCall().(EvpAlgorithmInitializer).getAlgorithmArg()
|
||||
result = this.getInitCall().(EvpPrimaryAlgorithmInitializer).getAlgorithmArg()
|
||||
}
|
||||
|
||||
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -195,9 +173,9 @@ class Evp_PKey_Cipher_Operation extends EVP_Cipher_Operation {
|
||||
|
||||
override Expr getInputArg() { result = this.(Call).getArgument(3) }
|
||||
|
||||
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
|
||||
override Expr getAlgorithmArg() {
|
||||
result = this.getInitCall().(EvpAlgorithmInitializer).getAlgorithmArg()
|
||||
result = this.getInitCall().(EvpPrimaryAlgorithmInitializer).getAlgorithmArg()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@ private import experimental.quantum.OpenSSL.CtxFlow
|
||||
private import OpenSSLOperationBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
|
||||
abstract class EVP_Hash_Initializer extends EvpAlgorithmInitializer { }
|
||||
|
||||
class EVP_DigestInit_Variant_Calls extends EVP_Hash_Initializer {
|
||||
class EVP_DigestInit_Variant_Calls extends EvpPrimaryAlgorithmInitializer {
|
||||
EVP_DigestInit_Variant_Calls() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_DigestInit", "EVP_DigestInit_ex", "EVP_DigestInit_ex2"
|
||||
@@ -18,7 +16,7 @@ class EVP_DigestInit_Variant_Calls extends EVP_Hash_Initializer {
|
||||
|
||||
override Expr getAlgorithmArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
class EVP_Digest_Update_Call extends EvpUpdate {
|
||||
@@ -26,7 +24,7 @@ class EVP_Digest_Update_Call extends EvpUpdate {
|
||||
|
||||
override Expr getInputArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
//https://docs.openssl.org/3.0/man3/EVP_DigestInit/#synopsis
|
||||
@@ -35,7 +33,7 @@ class EVP_Q_Digest_Operation extends EvpOperation, Crypto::HashOperationInstance
|
||||
|
||||
override Expr getAlgorithmArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
override EVP_Hash_Initializer getInitCall() {
|
||||
override EvpInitializer getInitCall() {
|
||||
// This variant of digest does not use an init
|
||||
// and even if it were used, the init would be ignored/undefined
|
||||
none()
|
||||
@@ -53,18 +51,18 @@ class EVP_Q_Digest_Operation extends EvpOperation, Crypto::HashOperationInstance
|
||||
result = EvpOperation.super.getInputConsumer()
|
||||
}
|
||||
|
||||
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
class EVP_Digest_Operation extends EvpOperation, Crypto::HashOperationInstance {
|
||||
EVP_Digest_Operation() { this.(Call).getTarget().getName() = "EVP_Digest" }
|
||||
|
||||
// There is no context argument for this function
|
||||
override CtxPointerSource getContextArg() { none() }
|
||||
override CtxPointerSource getContext() { none() }
|
||||
|
||||
override Expr getAlgorithmArg() { result = this.(Call).getArgument(4) }
|
||||
|
||||
override EVP_Hash_Initializer getInitCall() {
|
||||
override EvpPrimaryAlgorithmInitializer getInitCall() {
|
||||
// This variant of digest does not use an init
|
||||
// and even if it were used, the init would be ignored/undefined
|
||||
none()
|
||||
@@ -90,7 +88,7 @@ class EVP_Digest_Final_Call extends EVPFinal, Crypto::HashOperationInstance {
|
||||
]
|
||||
}
|
||||
|
||||
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
|
||||
override Expr getOutputArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
@@ -103,6 +101,6 @@ class EVP_Digest_Final_Call extends EVPFinal, Crypto::HashOperationInstance {
|
||||
}
|
||||
|
||||
override Expr getAlgorithmArg() {
|
||||
result = this.getInitCall().(EvpAlgorithmInitializer).getAlgorithmArg()
|
||||
result = this.getInitCall().(EvpPrimaryAlgorithmInitializer).getAlgorithmArg()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ private import OpenSSLOperationBase
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
private import semmle.code.cpp.dataflow.new.DataFlow
|
||||
|
||||
class EVPKeyGenInitialize extends EvpAlgorithmInitializer {
|
||||
class EVPKeyGenInitialize extends EvpPrimaryAlgorithmInitializer {
|
||||
EVPKeyGenInitialize() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_PKEY_keygen_init",
|
||||
@@ -14,10 +14,13 @@ class EVPKeyGenInitialize extends EvpAlgorithmInitializer {
|
||||
|
||||
/**
|
||||
* The algorithm is encoded through the context argument.
|
||||
* The context may be directly created from an algorithm consumer,
|
||||
* or from a new operation off of a prior key. Either way,
|
||||
* we will treat this argument as the algorithm argument.
|
||||
*/
|
||||
override Expr getAlgorithmArg() { result = this.getContextArg() }
|
||||
override Expr getAlgorithmArg() { result = this.getContext() }
|
||||
|
||||
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
class EVPKeyGenOperation extends EVPFinal, Crypto::KeyGenerationOperationInstance {
|
||||
@@ -31,13 +34,13 @@ class EVPKeyGenOperation extends EVPFinal, Crypto::KeyGenerationOperationInstanc
|
||||
keyResultNode.asDefiningArgument() = this.(Call).getArgument(1)
|
||||
}
|
||||
|
||||
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
|
||||
override Expr getAlgorithmArg() {
|
||||
this.(Call).getTarget().getName() = "EVP_PKEY_Q_keygen" and
|
||||
result = this.(Call).getArgument(0)
|
||||
or
|
||||
result = this.getInitCall().(EvpAlgorithmInitializer).getAlgorithmArg()
|
||||
result = this.getInitCall().(EvpPrimaryAlgorithmInitializer).getAlgorithmArg()
|
||||
}
|
||||
|
||||
override Crypto::KeyArtifactType getOutputKeyType() { result = Crypto::TAsymmetricKeyType() }
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/**
|
||||
* Initializers for EVP PKey
|
||||
* including https://docs.openssl.org/3.0/man3/EVP_PKEY_CTX_ctrl/
|
||||
* including:
|
||||
* https://docs.openssl.org/3.0/man3/EVP_PKEY_CTX_ctrl/
|
||||
* https://docs.openssl.org/3.0/man3/EVP_EncryptInit/#synopsis
|
||||
*/
|
||||
|
||||
import cpp
|
||||
@@ -31,26 +33,40 @@ class EVPNewKeyCtx extends EvpKeyInitializer {
|
||||
/**
|
||||
* Context is returned
|
||||
*/
|
||||
override CtxPointerSource getContextArg() { result = this }
|
||||
override CtxPointerSource getContext() { result = this }
|
||||
|
||||
override Expr getKeyArg() { result = keyArg }
|
||||
//TODO: do we specify the algorithm from the key as well?
|
||||
}
|
||||
|
||||
class EvpCtxSetAlgorithmInitializer extends EvpAlgorithmInitializer {
|
||||
EvpCtxSetAlgorithmInitializer() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_PKEY_CTX_set_signature_md", "EVP_PKEY_CTX_set_rsa_mgf1_md_name",
|
||||
"EVP_PKEY_CTX_set_rsa_mgf1_md", "EVP_PKEY_CTX_set_rsa_oaep_md_name",
|
||||
"EVP_PKEY_CTX_set_rsa_oaep_md", "EVP_PKEY_CTX_set_dsa_paramgen_md",
|
||||
"EVP_PKEY_CTX_set_dsa_paramgen_md_props", "EVP_PKEY_CTX_set_dh_kdf_md",
|
||||
"EVP_PKEY_CTX_set_ec_paramgen_curve_nid", "EVP_PKEY_CTX_set_ecdh_kdf_md"
|
||||
]
|
||||
/**
|
||||
* A call to "EVP_PKEY_CTX_set_ec_paramgen_curve_nid".
|
||||
* Note that this is a primary algorithm as the pattenr is to specify an "EC" context,
|
||||
* then set the specific curve later. Although the curve is set later, it is the primary
|
||||
* algorithm intended for an operation.
|
||||
*/
|
||||
class EvpCtxSetPrimaryAlgorithmInitializer extends EvpPrimaryAlgorithmInitializer {
|
||||
EvpCtxSetPrimaryAlgorithmInitializer() {
|
||||
this.(Call).getTarget().getName() = "EVP_PKEY_CTX_set_ec_paramgen_curve_nid"
|
||||
}
|
||||
|
||||
override Expr getAlgorithmArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
class EvpCtxSetHashAlgorithmInitializer extends EvpHashAlgorithmInitializer {
|
||||
EvpCtxSetHashAlgorithmInitializer() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_PKEY_CTX_set_signature_md", "EVP_PKEY_CTX_set_rsa_mgf1_md_name",
|
||||
"EVP_PKEY_CTX_set_rsa_mgf1_md", "EVP_PKEY_CTX_set_rsa_oaep_md_name",
|
||||
"EVP_PKEY_CTX_set_rsa_oaep_md", "EVP_PKEY_CTX_set_dsa_paramgen_md",
|
||||
"EVP_PKEY_CTX_set_dh_kdf_md", "EVP_PKEY_CTX_set_ecdh_kdf_md"
|
||||
]
|
||||
}
|
||||
|
||||
override Expr getHashAlgorithmArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
class EvpCtxSetKeySizeInitializer extends EvpKeySizeInitializer {
|
||||
@@ -58,7 +74,8 @@ class EvpCtxSetKeySizeInitializer extends EvpKeySizeInitializer {
|
||||
|
||||
EvpCtxSetKeySizeInitializer() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_PKEY_CTX_set_rsa_keygen_bits", "EVP_PKEY_CTX_set_dsa_paramgen_bits"
|
||||
"EVP_PKEY_CTX_set_rsa_keygen_bits", "EVP_PKEY_CTX_set_dsa_paramgen_bits",
|
||||
"EVP_CIPHER_CTX_set_key_length"
|
||||
] and
|
||||
arg = this.(Call).getArgument(1)
|
||||
or
|
||||
@@ -68,7 +85,7 @@ class EvpCtxSetKeySizeInitializer extends EvpKeySizeInitializer {
|
||||
|
||||
override Expr getKeySizeArg() { result = arg }
|
||||
|
||||
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
class EvpCtxSetKeyInitializer extends EvpKeyInitializer {
|
||||
@@ -76,17 +93,19 @@ class EvpCtxSetKeyInitializer extends EvpKeyInitializer {
|
||||
|
||||
override Expr getKeyArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
class EvpCtxSetPaddingInitializer extends EvpPaddingInitializer {
|
||||
EvpCtxSetPaddingInitializer() {
|
||||
this.(Call).getTarget().getName() = "EVP_PKEY_CTX_set_rsa_padding"
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_PKEY_CTX_set_rsa_padding", "EVP_CIPHER_CTX_set_padding"
|
||||
]
|
||||
}
|
||||
|
||||
override Expr getPaddingArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
class EvpCtxSetSaltLengthInitializer extends EvpSaltLengthInitializer {
|
||||
@@ -96,5 +115,5 @@ class EvpCtxSetSaltLengthInitializer extends EvpSaltLengthInitializer {
|
||||
|
||||
override Expr getSaltLengthArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
|
||||
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
private import experimental.quantum.Language
|
||||
private import experimental.quantum.OpenSSL.AvcFlow
|
||||
private import experimental.quantum.OpenSSL.CtxFlow
|
||||
private import experimental.quantum.OpenSSL.KeyFlow
|
||||
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
||||
@@ -7,6 +8,18 @@ private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgor
|
||||
// even if only importing the operation by itself.
|
||||
import EVPPKeyCtxInitializer
|
||||
|
||||
module EncValToInitEncArgConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source.asExpr().getValue().toInt() in [0, 1] }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(EvpKeyOperationSubtypeInitializer initCall |
|
||||
sink.asExpr() = initCall.getKeyOperationSubtypeArg()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module EncValToInitEncArgFlow = DataFlow::Global<EncValToInitEncArgConfig>;
|
||||
|
||||
/**
|
||||
* A class for all OpenSSL operations.
|
||||
*/
|
||||
@@ -24,7 +37,7 @@ abstract class OpenSSLOperation extends Crypto::OperationInstance instanceof Cal
|
||||
* Algorithm is specified in initialization call or is implicitly established by the key.
|
||||
*/
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
AlgGetterToArgFlow::flow(result.(OpenSSLAlgorithmValueConsumer).getResultNode(),
|
||||
AvcToCallArgFlow::flow(result.(OpenSSLAlgorithmValueConsumer).getResultNode(),
|
||||
DataFlow::exprNode(this.getAlgorithmArg()))
|
||||
}
|
||||
}
|
||||
@@ -38,29 +51,58 @@ abstract class OpenSSLOperation extends Crypto::OperationInstance instanceof Cal
|
||||
*/
|
||||
abstract class EvpInitializer extends Call {
|
||||
/**
|
||||
* Gets the context argument that ties together initialization, updates and/or final calls.
|
||||
* The context argument is the context coming into the initializer and is the output as well.
|
||||
* Gets the context argument or return that ties together initialization, updates and/or final calls.
|
||||
* The context is the context coming into the initializer and is the output as well.
|
||||
* This is assumed to be the same argument.
|
||||
*/
|
||||
abstract CtxPointerSource getContextArg();
|
||||
abstract CtxPointerSource getContext();
|
||||
}
|
||||
|
||||
abstract class EvpKeySizeInitializer extends EvpInitializer {
|
||||
abstract Expr getKeySizeArg();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlike many initializers, this returns the key operation subtype immediately, not the arg.
|
||||
* This is a design choice in the overall model, in that the model will not do any tracking
|
||||
* for the subtype argument in any automated fashion. Users are currently expected to find the
|
||||
* subtype argument manually and associate a type directly.
|
||||
*/
|
||||
abstract class EvpKeyOperationSubtypeInitializer extends EvpInitializer {
|
||||
abstract Crypto::KeyOperationSubtype getKeyOperationSubtype();
|
||||
abstract Expr getKeyOperationSubtypeArg();
|
||||
|
||||
private Crypto::KeyOperationSubtype intToCipherOperationSubtype(int i) {
|
||||
i = 0 and
|
||||
result instanceof Crypto::TEncryptMode
|
||||
or
|
||||
i = 1 and result instanceof Crypto::TDecryptMode
|
||||
}
|
||||
|
||||
Crypto::KeyOperationSubtype getKeyOperationSubtype() {
|
||||
exists(DataFlow::Node a, DataFlow::Node b |
|
||||
EncValToInitEncArgFlow::flow(a, b) and
|
||||
b.asExpr() = this.getKeyOperationSubtypeArg() and
|
||||
result = this.intToCipherOperationSubtype(a.asExpr().getValue().toInt())
|
||||
)
|
||||
or
|
||||
// Infer the subtype from the initialization call, and ignore the argument
|
||||
this.(Call).getTarget().getName().toLowerCase().matches("%encrypt%") and
|
||||
result instanceof Crypto::TEncryptMode
|
||||
or
|
||||
this.(Call).getTarget().getName().toLowerCase().matches("%decrypt%") and
|
||||
result instanceof Crypto::TDecryptMode
|
||||
}
|
||||
}
|
||||
|
||||
abstract class EvpAlgorithmInitializer extends EvpInitializer {
|
||||
/**
|
||||
* An primary algorithm initializer initializes the primary algorithm for a given operation.
|
||||
* For example, for a signing operation, the algorithm initializer may initialize algorithms
|
||||
* like RSA. Other algorithsm may be initialized on an operation, as part of a larger
|
||||
* operation/protocol. For example, hashing operations on signing operations; however,
|
||||
* these are not the primary algorithm. Any other algorithms initialized on an operation
|
||||
* require a specialized initializer, such as EvpHashAlgorithmInitializer.
|
||||
*/
|
||||
abstract class EvpPrimaryAlgorithmInitializer extends EvpInitializer {
|
||||
abstract Expr getAlgorithmArg();
|
||||
|
||||
Crypto::AlgorithmValueConsumer getAlgorithmValueConsumer() {
|
||||
AvcToCallArgFlow::flow(result.(OpenSSLAlgorithmValueConsumer).getResultNode(),
|
||||
DataFlow::exprNode(this.getAlgorithmArg()))
|
||||
}
|
||||
}
|
||||
|
||||
abstract class EvpKeyInitializer extends EvpInitializer {
|
||||
@@ -72,10 +114,10 @@ abstract class EvpKeyInitializer extends EvpInitializer {
|
||||
* the key. Extend any instance of key initializer provide initialization
|
||||
* of the algorithm and key size from the key.
|
||||
*/
|
||||
class EvpInitializerThroughKey extends EvpAlgorithmInitializer, EvpKeySizeInitializer instanceof EvpKeyInitializer
|
||||
class EvpInitializerThroughKey extends EvpPrimaryAlgorithmInitializer, EvpKeySizeInitializer instanceof EvpKeyInitializer
|
||||
{
|
||||
//TODO: charpred that traces from creation to key arg, grab creator
|
||||
override CtxPointerSource getContextArg() { result = EvpKeyInitializer.super.getContextArg() }
|
||||
override CtxPointerSource getContext() { result = EvpKeyInitializer.super.getContext() }
|
||||
|
||||
override Expr getAlgorithmArg() {
|
||||
result =
|
||||
@@ -109,6 +151,15 @@ abstract class EvpSaltLengthInitializer extends EvpInitializer {
|
||||
abstract Expr getSaltLengthArg();
|
||||
}
|
||||
|
||||
abstract class EvpHashAlgorithmInitializer extends EvpInitializer {
|
||||
abstract Expr getHashAlgorithmArg();
|
||||
|
||||
Crypto::AlgorithmValueConsumer getHashAlgorithmValueConsumer() {
|
||||
AvcToCallArgFlow::flow(result.(OpenSSLAlgorithmValueConsumer).getResultNode(),
|
||||
DataFlow::exprNode(this.getHashAlgorithmArg()))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Call to an "update" function.
|
||||
* These are not operations in the sense of Crypto::OperationInstance,
|
||||
@@ -120,7 +171,7 @@ abstract class EvpUpdate extends Call {
|
||||
/**
|
||||
* Gets the context argument that ties together initialization, updates and/or final calls.
|
||||
*/
|
||||
abstract CtxPointerSource getContextArg();
|
||||
abstract CtxPointerSource getContext();
|
||||
|
||||
/**
|
||||
* Update calls always have some input data like plaintext or message digest.
|
||||
@@ -133,23 +184,6 @@ abstract class EvpUpdate extends Call {
|
||||
Expr getOutputArg() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Flows from algorithm values to operations, specific to OpenSSL
|
||||
*/
|
||||
module AlgGetterToArgConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
exists(OpenSSLAlgorithmValueConsumer c | c.getResultNode() = source)
|
||||
}
|
||||
|
||||
/**
|
||||
* Trace to any call accepting the algorithm.
|
||||
* NOTE: users must restrict this set to the operations they are interested in.
|
||||
*/
|
||||
predicate isSink(DataFlow::Node sink) { exists(Call c | c.getAnArgument() = sink.asExpr()) }
|
||||
}
|
||||
|
||||
module AlgGetterToArgFlow = DataFlow::Global<AlgGetterToArgConfig>;
|
||||
|
||||
/**
|
||||
* The base class for all operations of the EVP API.
|
||||
* This captures one-shot APIs (with and without an initilizer call) and final calls.
|
||||
@@ -159,7 +193,7 @@ abstract class EvpOperation extends OpenSSLOperation {
|
||||
/**
|
||||
* Gets the context argument that ties together initialization, updates and/or final calls.
|
||||
*/
|
||||
abstract CtxPointerSource getContextArg();
|
||||
abstract CtxPointerSource getContext();
|
||||
|
||||
/**
|
||||
* Some input data like plaintext or message digest.
|
||||
@@ -175,7 +209,7 @@ abstract class EvpOperation extends OpenSSLOperation {
|
||||
/**
|
||||
* Finds the initialization call, may be none.
|
||||
*/
|
||||
EvpInitializer getInitCall() { ctxSrcToSrcFlow(result.getContextArg(), this.getContextArg()) }
|
||||
EvpInitializer getInitCall() { ctxSrcToSrcFlow(result.getContext(), this.getContext()) }
|
||||
|
||||
Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
|
||||
result = DataFlow::exprNode(this.getOutputArg())
|
||||
@@ -200,7 +234,7 @@ abstract class EVPFinal extends EvpOperation {
|
||||
/**
|
||||
* All update calls that were executed before this final call.
|
||||
*/
|
||||
EvpUpdate getUpdateCalls() { ctxSrcToSrcFlow(result.getContextArg(), this.getContextArg()) }
|
||||
EvpUpdate getUpdateCalls() { ctxSrcToSrcFlow(result.getContext(), this.getContext()) }
|
||||
|
||||
/**
|
||||
* Gets the input data provided to all update calls.
|
||||
@@ -214,3 +248,11 @@ abstract class EVPFinal extends EvpOperation {
|
||||
*/
|
||||
override Expr getOutputArg() { result = this.getUpdateCalls().getOutputArg() }
|
||||
}
|
||||
// Expr getAlgorithmArgFromContext(Expr contextArg) {
|
||||
// exists(EVPPKeyAlgorithmConsumer source |
|
||||
// result = source.getValueArgExpr() and
|
||||
// ctxFlowsToCtxArg(source.getResultNode().asExpr(), ctx)
|
||||
// )
|
||||
// or
|
||||
// result = getAlgorithmFromKey(getKeyFromCtx(ctx))
|
||||
// }
|
||||
|
||||
Reference in New Issue
Block a user