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:
REDMOND\brodes
2025-06-12 00:41:15 -04:00
parent 8f25380655
commit 20e2c7cefd
9 changed files with 186 additions and 141 deletions

View 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>;

View File

@@ -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()
}
}

View File

@@ -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()
}
}

View File

@@ -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() }

View File

@@ -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) }
}

View File

@@ -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))
// }