Crypto: CtxFlow now uses an interface for additional steps. Add CTX step to handle paramgen. Remove redundant test. Overhaul of EVP update/initializer/final mechanics. Misc. updates for new API and refactoring EVPKeyGenOperation. Clean up of keygen_operaitons.ql.

This commit is contained in:
REDMOND\brodes
2025-06-09 15:07:00 -04:00
parent 98aae6a7bf
commit 4f2045bbdd
9 changed files with 266 additions and 143 deletions

View File

@@ -13,7 +13,9 @@ module CryptoInput implements InputSig<Language::Location> {
LocatableElement dfn_to_element(DataFlow::Node node) {
result = node.asExpr() or
result = node.asParameter() or
result = node.asVariable()
result = node.asVariable() or
result = node.asDefiningArgument()
// TODO: do we need asIndirectExpr()?
}
string locationToFileBaseNameAndLineNumberString(Location location) {

View File

@@ -23,7 +23,8 @@ class EVPPKeyAlgorithmConsumer extends PKeyValueConsumer {
or
this.(Call).getTarget().getName() in [
"EVP_PKEY_CTX_new_from_name", "EVP_PKEY_new_raw_private_key_ex",
"EVP_PKEY_new_raw_public_key_ex", "EVP_PKEY_CTX_ctrl", "EVP_PKEY_CTX_set_group_name"
"EVP_PKEY_new_raw_public_key_ex", "EVP_PKEY_CTX_ctrl", "EVP_PKEY_CTX_ctrl_uint64",
"EVP_PKEY_CTX_ctrl_str", "EVP_PKEY_CTX_set_group_name"
] and
valueArgNode.asExpr() = this.(Call).getArgument(1)
or

View File

@@ -28,7 +28,7 @@ import semmle.code.cpp.dataflow.new.DataFlow
* - EVP_MD_CTX
* - EVP_PKEY_CTX
*/
private class CtxType extends Type {
class CtxType extends Type {
CtxType() {
// It is possible for users to use the underlying type of the CTX variables
// these have a name matching 'evp_%ctx_%st
@@ -47,7 +47,7 @@ private class CtxType extends Type {
/**
* A pointer to a CtxType
*/
private class CtxPointerExpr extends Expr {
class CtxPointerExpr extends Expr {
CtxPointerExpr() {
this.getType() instanceof CtxType and
this.getType() instanceof PointerType
@@ -57,7 +57,7 @@ private class CtxPointerExpr extends Expr {
/**
* A call argument of type CtxPointerExpr.
*/
private class CtxPointerArgument extends CtxPointerExpr {
class CtxPointerArgument extends CtxPointerExpr {
CtxPointerArgument() { exists(Call c | c.getAnArgument() = this) }
Call getCall() { result.getAnArgument() = this }
@@ -83,32 +83,103 @@ private class CtxClearCall extends Call {
}
}
abstract private class CtxPassThroughCall extends Call {
abstract DataFlow::Node getNode1();
abstract DataFlow::Node getNode2();
}
/**
* A call whose target contains 'copy' and has an argument of type
* CtxPointerArgument.
*/
private class CtxCopyOutArgCall extends Call {
private class CtxCopyOutArgCall extends CtxPassThroughCall {
DataFlow::Node n1;
DataFlow::Node n2;
CtxCopyOutArgCall() {
this.getTarget().getName().toLowerCase().matches("%copy%") and
this.getAnArgument() instanceof CtxPointerArgument
n1.asExpr() = this.getAnArgument() and
n1.getType() instanceof CtxType and
n2.asDefiningArgument() = this.getAnArgument() and
n2.getType() instanceof CtxType and
n1.asDefiningArgument() != n2.asExpr()
}
override DataFlow::Node getNode1() { result = n1 }
override DataFlow::Node getNode2() { result = n2 }
}
/**
* A call whose target contains 'dup' and has an argument of type
* CtxPointerArgument.
*/
private class CtxCopyReturnCall extends Call, CtxPointerExpr {
private class CtxCopyReturnCall extends CtxPassThroughCall, CtxPointerExpr {
DataFlow::Node n1;
CtxCopyReturnCall() {
this.getTarget().getName().toLowerCase().matches("%dup%") and
this.getAnArgument() instanceof CtxPointerArgument
n1.asExpr() = this.getAnArgument() and
n1.getType() instanceof CtxType
}
override DataFlow::Node getNode1() { result = n1 }
override DataFlow::Node getNode2() { result.asExpr() = this }
}
/**
* A call to `EVP_PKEY_paramgen` acts as a kind of pass through.
* It's output pkey is eventually used in a new operation generating
* a fresh context pointer (e.g., `EVP_PKEY_CTX_new`).
* It is easier to model this as a pass through
* than to model the flow from the paramgen to the new key generation.
*/
private class CtxParamGenCall extends CtxPassThroughCall {
DataFlow::Node n1;
DataFlow::Node n2;
CtxParamGenCall() {
this.getTarget().getName() = "EVP_PKEY_paramgen" and
n1.asExpr() = this.getArgument(0) and
(
n2.asExpr() = this.getArgument(1)
or
n2.asDefiningArgument() = this.getArgument(1)
)
}
override DataFlow::Node getNode1() { result = n1 }
override DataFlow::Node getNode2() { result = n2 }
}
/**
* If the current node gets is an argument to a function
* that returns a pointer type, immediately flow through.
* NOTE: this passthrough is required if we allow
* intermediate steps to go into variables that are not a CTX type.
* See for example `CtxParamGenCall`.
*/
private class CallArgToCtxRet extends CtxPassThroughCall, CtxPointerExpr {
DataFlow::Node n1;
DataFlow::Node n2;
CallArgToCtxRet() {
this.getAnArgument() = n1.asExpr() and
n2.asExpr() = this
}
override DataFlow::Node getNode1() { result = n1 }
override DataFlow::Node getNode2() { result = n2 }
}
/**
* A source Ctx of interest is any argument or return of type CtxPointerExpr.
*/
private class CtxPointerSource extends CtxPointerExpr {
class CtxPointerSource extends CtxPointerExpr {
CtxPointerSource() {
this instanceof CtxPointerReturn or
this instanceof CtxPointerArgument
@@ -122,43 +193,31 @@ private class CtxPointerSource extends CtxPointerExpr {
}
/**
* Flow from any CtxPointerSource to any CtxPointerArgument.
* Flow from any CtxPointerSource to other CtxPointerSource.
*/
module OpenSSLCtxSourceToArgumentFlowConfig implements DataFlow::ConfigSig {
module OpenSSLCtxSourceToSourceFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { exists(CtxPointerSource s | s.asNode() = source) }
predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof CtxPointerArgument }
predicate isSink(DataFlow::Node sink) { exists(CtxPointerSource s | s.asNode() = sink) }
predicate isBarrier(DataFlow::Node node) {
exists(CtxClearCall c | c.getAnArgument() = node.asExpr())
}
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(CtxCopyOutArgCall c |
c.getAnArgument() = node1.asExpr() and
c.getAnArgument() = node2.asExpr() and
node1.asExpr() != node2.asExpr() and
node2.asExpr().getType() instanceof CtxType
)
or
exists(CtxCopyReturnCall c |
c.getAnArgument() = node1.asExpr() and
c = node2.asExpr() and
node1.asExpr() != node2.asExpr() and
node2.asExpr().getType() instanceof CtxType
)
exists(CtxPassThroughCall c | c.getNode1() = node1 and c.getNode2() = node2)
}
}
module OpenSSLCtxSourceToArgumentFlow = DataFlow::Global<OpenSSLCtxSourceToArgumentFlowConfig>;
module OpenSSLCtxSourceToArgumentFlow = DataFlow::Global<OpenSSLCtxSourceToSourceFlowConfig>;
/**
* Holds if there is a context flow from the source to the sink.
*/
predicate ctxArgOrRetFlowsToCtxArg(CtxPointerSource source, CtxPointerArgument sink) {
predicate ctxSrcToSrcFlow(CtxPointerSource source, CtxPointerSource sink) {
exists(DataFlow::Node a, DataFlow::Node b |
OpenSSLCtxSourceToArgumentFlow::flow(a, b) and
a = source.asNode() and
b.asExpr() = sink
b = sink.asNode()
)
}

View File

@@ -1,5 +1,5 @@
private import experimental.quantum.Language
private import experimental.quantum.OpenSSL.CtxFlow as CTXFlow
private import experimental.quantum.OpenSSL.CtxFlow
private import OpenSSLOperationBase
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
@@ -31,7 +31,11 @@ Crypto::KeyOperationSubtype intToCipherOperationSubtype(int i) {
}
// TODO: need to add key consumer
abstract class EVP_Cipher_Initializer extends EVPInitialize {
abstract class EVP_Cipher_Initializer extends EvpKeyOperationSubtypeInitializer,
EvpAlgorithmInitializer, EvpKeyInitializer, EvpIVInitializer
{
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
override Expr getAlgorithmArg() { result = this.(Call).getArgument(1) }
abstract Expr getOperationSubtypeArg();
@@ -94,13 +98,15 @@ class EVP_CipherInit_SKEY_Call extends EVP_EX2_Initializer {
override Expr getOperationSubtypeArg() { result = this.(Call).getArgument(5) }
}
class EVP_Cipher_Update_Call extends EVPUpdate {
class EVP_Cipher_Update_Call extends EvpUpdate {
EVP_Cipher_Update_Call() {
this.(Call).getTarget().getName() in [
"EVP_EncryptUpdate", "EVP_DecryptUpdate", "EVP_CipherUpdate"
]
}
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
override Expr getInputArg() { result = this.(Call).getArgument(3) }
override Expr getOutputArg() { result = this.(Call).getArgument(1) }
@@ -110,7 +116,7 @@ class EVP_Cipher_Update_Call extends EVPUpdate {
* see: https://docs.openssl.org/master/man3/EVP_EncryptInit/#synopsis
* Base configuration for all EVP cipher operations.
*/
abstract class EVP_Cipher_Operation extends EVPOperation, Crypto::KeyOperationInstance {
abstract class EVP_Cipher_Operation extends EvpOperation, Crypto::KeyOperationInstance {
override Expr getOutputArg() { result = this.(Call).getArgument(1) }
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
@@ -120,34 +126,38 @@ abstract class EVP_Cipher_Operation extends EVPOperation, Crypto::KeyOperationIn
result instanceof Crypto::TDecryptMode and
this.(Call).getTarget().getName().toLowerCase().matches("%decrypt%")
or
result = this.getInitCall().getKeyOperationSubtype() and
result = this.getInitCall().(EvpKeyOperationSubtypeInitializer).getKeyOperationSubtype() and
this.(Call).getTarget().getName().toLowerCase().matches("%cipher%")
}
override Crypto::ConsumerInputDataFlowNode getNonceConsumer() {
this.getInitCall().getIVArg() = result.asExpr()
this.getInitCall().(EvpIVInitializer).getIVArg() = result.asExpr()
}
override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
this.getInitCall().getKeyArg() = result.asExpr()
this.getInitCall().(EvpKeyInitializer).getKeyArg() = result.asExpr()
// todo: or track to the EVP_PKEY_CTX_new
}
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
result = EVPOperation.super.getOutputArtifact()
result = EvpOperation.super.getOutputArtifact()
}
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
result = EVPOperation.super.getInputConsumer()
result = EvpOperation.super.getInputConsumer()
}
}
class EVP_Cipher_Call extends EVPOperation, EVP_Cipher_Operation {
class EVP_Cipher_Call extends EvpOperation, EVP_Cipher_Operation {
EVP_Cipher_Call() { this.(Call).getTarget().getName() = "EVP_Cipher" }
override Expr getInputArg() { result = this.(Call).getArgument(2) }
override Expr getAlgorithmArg() { result = this.getInitCall().getAlgorithmArg() }
override Expr getAlgorithmArg() {
result = this.getInitCall().(EvpAlgorithmInitializer).getAlgorithmArg()
}
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
}
class EVP_Cipher_Final_Call extends EVPFinal, EVP_Cipher_Operation {
@@ -167,5 +177,9 @@ class EVP_Cipher_Final_Call extends EVPFinal, EVP_Cipher_Operation {
result = EVP_Cipher_Operation.super.getOutputArg()
}
override Expr getAlgorithmArg() { result = this.getInitCall().getAlgorithmArg() }
override Expr getAlgorithmArg() {
result = this.getInitCall().(EvpAlgorithmInitializer).getAlgorithmArg()
}
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
}

View File

@@ -3,11 +3,11 @@
*/
private import experimental.quantum.Language
private import experimental.quantum.OpenSSL.CtxFlow as CTXFlow
private import experimental.quantum.OpenSSL.CtxFlow
private import OpenSSLOperationBase
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
abstract class EVP_Hash_Initializer extends EVPInitialize { }
abstract class EVP_Hash_Initializer extends EvpAlgorithmInitializer { }
class EVP_DigestInit_Variant_Calls extends EVP_Hash_Initializer {
EVP_DigestInit_Variant_Calls() {
@@ -17,16 +17,20 @@ 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) }
}
class EVP_Digest_Update_Call extends EVPUpdate {
class EVP_Digest_Update_Call extends EvpUpdate {
EVP_Digest_Update_Call() { this.(Call).getTarget().getName() = "EVP_DigestUpdate" }
override Expr getInputArg() { result = this.(Call).getArgument(1) }
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
}
//https://docs.openssl.org/3.0/man3/EVP_DigestInit/#synopsis
class EVP_Q_Digest_Operation extends EVPOperation, Crypto::HashOperationInstance {
class EVP_Q_Digest_Operation extends EvpOperation, Crypto::HashOperationInstance {
EVP_Q_Digest_Operation() { this.(Call).getTarget().getName() = "EVP_Q_digest" }
override Expr getAlgorithmArg() { result = this.(Call).getArgument(1) }
@@ -42,19 +46,21 @@ class EVP_Q_Digest_Operation extends EVPOperation, Crypto::HashOperationInstance
override Expr getOutputArg() { result = this.(Call).getArgument(5) }
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
result = EVPOperation.super.getOutputArtifact()
result = EvpOperation.super.getOutputArtifact()
}
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
result = EVPOperation.super.getInputConsumer()
result = EvpOperation.super.getInputConsumer()
}
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
}
class EVP_Digest_Operation extends EVPOperation, Crypto::HashOperationInstance {
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 Expr getContextArg() { none() }
override CtxPointerSource getContextArg() { none() }
override Expr getAlgorithmArg() { result = this.(Call).getArgument(4) }
@@ -69,11 +75,11 @@ class EVP_Digest_Operation extends EVPOperation, Crypto::HashOperationInstance {
override Expr getOutputArg() { result = this.(Call).getArgument(2) }
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
result = EVPOperation.super.getOutputArtifact()
result = EvpOperation.super.getOutputArtifact()
}
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
result = EVPOperation.super.getInputConsumer()
result = EvpOperation.super.getInputConsumer()
}
}
@@ -84,6 +90,8 @@ class EVP_Digest_Final_Call extends EVPFinal, Crypto::HashOperationInstance {
]
}
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
override Expr getOutputArg() { result = this.(Call).getArgument(1) }
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
@@ -94,5 +102,7 @@ class EVP_Digest_Final_Call extends EVPFinal, Crypto::HashOperationInstance {
result = EVPFinal.super.getInputConsumer()
}
override Expr getAlgorithmArg() { result = this.getInitCall().getAlgorithmArg() }
override Expr getAlgorithmArg() {
result = this.getInitCall().(EvpAlgorithmInitializer).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 EVPInitialize {
class EVPKeyGenInitialize extends EvpAlgorithmInitializer {
EVPKeyGenInitialize() {
this.(Call).getTarget().getName() in [
"EVP_PKEY_keygen_init",
@@ -12,54 +12,88 @@ class EVPKeyGenInitialize extends EVPInitialize {
]
}
override Expr getAlgorithmArg() {
// The context argument encodes the algorithm
result = this.getContextArg()
}
/**
* The algorithm is encoded through the context argument.
*/
override Expr getAlgorithmArg() { result = this.getContextArg() }
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
}
// /**
// * All calls that can be tracked via ctx.
// * For example calls used to set parameters like a key size.
// */
// class EVPKeyGenUpdate extends Call {
// EVPKeyGenUpdate() {
// this.(Call).getTarget().getName() in [
// "EVP_PKEY_CTX_set_rsa_keygen_bits",
// // TODO: "EVP_PKEY_CTX_set_params"
// ]
// }
// /**
// * No input in our meaning.
// */
// override Expr getInputArg() { none() }
// /**
// * No output in our meaning.
// */
// override Expr getOutputArg() { none() }
// Expr getKeySizeArg() {
// this.(Call).getTarget().getName() = "EVP_PKEY_CTX_set_rsa_keygen_bits" and
// result = this.(Call).getArgument(1)
// }
// }
class EVPKeyGenOperation extends EVPOperation, Crypto::KeyGenerationOperationInstance {
/**
* A call to `EVP_PKEY_CTX_new` or `EVP_PKEY_CTX_new_from_pkey`.
* These calls initialize the context from a prior key.
* The key may be generated previously, or merely had it's
* parameters set (e.g., `EVP_PKEY_paramgen`).
* NOTE: for the case of `EVP_PKEY_paramgen`, these calls
* are encoded as context passthroughs, and any operation
* will get all associated initializers for teh paramgen
* at the final keygen operation automatically.
*/
class EVPNewKeyCtx extends EvpKeyInitializer {
Expr keyArg;
EVPNewKeyCtx() {
this.(Call).getTarget().getName() = "EVP_PKEY_CTX_new" and
keyArg = this.(Call).getArgument(0)
or
this.(Call).getTarget().getName() = "EVP_PKEY_CTX_new_from_pkey" and
keyArg = this.(Call).getArgument(1)
}
/**
* Context is returned
*/
override CtxPointerSource getContextArg() { result = this }
override Expr getKeyArg() { result = keyArg }
//TODO: do we specify the algorithm from the key as well?
}
/**
* A call to `EVP_PKEY_CTX_set_rsa_keygen_bits`.
* This sets the key size for RSA key generation.
*/
class EVPSetRSAKeyKeyBits extends EvpKeySizeInitializer {
EVPSetRSAKeyKeyBits() { this.(Call).getTarget().getName() = "EVP_PKEY_CTX_set_rsa_keygen_bits" }
override Expr getKeySizeArg() { result = this.(Call).getArgument(1) }
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
}
/**
* A call to `EVP_PKEY_CTX_set_dsa_paramgen_bits`.
* This sets the key size for DSA key generation.
*/
class EVPSetDSAKeyParamGenBits extends EvpKeySizeInitializer {
EVPSetDSAKeyParamGenBits() {
this.(Call).getTarget().getName() = "EVP_PKEY_CTX_set_dsa_paramgen_bits"
}
override Expr getKeySizeArg() { result = this.(Call).getArgument(1) }
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
}
class EVPKeyGenOperation extends EVPFinal, Crypto::KeyGenerationOperationInstance {
DataFlow::Node keyResultNode;
EVPKeyGenOperation() {
this.(Call).getTarget().getName() in ["EVP_RSA_gen", "EVP_PKEY_Q_keygen"] and
keyResultNode.asExpr() = this
or
this.(Call).getTarget().getName() in [
"EVP_PKEY_generate", "EVP_PKEY_keygen", "EVP_PKEY_paramgen"
] and
this.(Call).getTarget().getName() in ["EVP_PKEY_generate", "EVP_PKEY_keygen"] and
keyResultNode.asDefiningArgument() = this.(Call).getArgument(1)
}
override CtxPointerSource getContextArg() { 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().getAlgorithmArg()
result = this.getInitCall().(EvpAlgorithmInitializer).getAlgorithmArg()
}
override Crypto::KeyArtifactType getOutputKeyType() { result = Crypto::TAsymmetricKeyType() }
@@ -71,16 +105,16 @@ class EVPKeyGenOperation extends EVPOperation, Crypto::KeyGenerationOperationIns
override Crypto::ArtifactOutputDataFlowNode getOutputKeyArtifact() { result = keyResultNode }
override Crypto::ConsumerInputDataFlowNode getKeySizeConsumer() {
none()
// if this.(Call).getTarget().getName() = "EVP_PKEY_Q_keygen"
// then result = DataFlow::exprNode(this.(Call).getArgument(3)) // TODO: may be wrong for EC keys
// else
// if this.(Call).getTarget().getName() = "EVP_RSA_gen"
// then result = DataFlow::exprNode(this.(Call).getArgument(0))
// else result = DataFlow::exprNode(this.getUpdateCalls().(EVPKeyGenUpdate).getKeySizeArg())
}
override int getKeySizeFixed() {
none() // TODO
this.(Call).getTarget().getName() = "EVP_PKEY_Q_keygen" and
result = DataFlow::exprNode(this.(Call).getArgument(3)) and
// Arg 3 (0 based) is only a key size if the 'type' parameter is RSA, however,
// as a crude approximation, assume that if the type of the argument is not a derived type
// the argument must specify a key size (this is to avoid tracing if "rsa" is in the type parameter)
not this.(Call).getArgument(3).getType().getUnderlyingType() instanceof DerivedType
or
this.(Call).getTarget().getName() = "EVP_RSA_gen" and
result = DataFlow::exprNode(this.(Call).getArgument(0))
or
result = DataFlow::exprNode(this.getInitCall().(EvpKeySizeInitializer).getKeySizeArg())
}
}

View File

@@ -1,5 +1,5 @@
private import experimental.quantum.Language
private import experimental.quantum.OpenSSL.CtxFlow as CTXFlow
private import experimental.quantum.OpenSSL.CtxFlow
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
/**
@@ -25,48 +25,59 @@ abstract class OpenSSLOperation extends Crypto::OperationInstance instanceof Cal
}
/**
* A Call to initialization functions from the EVP API.
* A Call to an initialization function for an operation.
* These are not operations in the sense of Crypto::OperationInstance,
* but they are used to initialize the context for the operation.
* There may be multiple initialization calls for the same operation.
* Intended for use with EvPOperation.
*/
abstract class EVPInitialize extends Call {
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.
* This is assumed to be the same argument.
*/
Expr getContextArg() { result = this.(Call).getArgument(0) }
abstract CtxPointerSource getContextArg();
}
/**
* Gets the type of key operation, none if not applicable.
*/
Crypto::KeyOperationSubtype getKeyOperationSubtype() { none() }
abstract class EvpKeySizeInitializer extends EvpInitializer {
abstract Expr getKeySizeArg();
}
/**
* Explicitly specified algorithm or none if implicit (e.g., established by the key).
* None if not applicable.
*/
Expr getAlgorithmArg() { none() }
abstract class EvpKeyOperationSubtypeInitializer extends EvpInitializer {
abstract Crypto::KeyOperationSubtype getKeyOperationSubtype();
}
/**
* Gets the key for the operation, none if not applicable.
*/
Expr getKeyArg() { none() }
abstract class EvpAlgorithmInitializer extends EvpInitializer {
abstract Expr getAlgorithmArg();
}
/**
* Gets the IV/nonce, none if not applicable.
*/
Expr getIVArg() { none() }
abstract class EvpKeyInitializer extends EvpInitializer {
//, EvpAlgorithmInitializer {
abstract Expr getKeyArg();
// /**
// * Any key arg can potentially be traced to find the algorithm used to generate the key.
// */
// override Expr getAlgorithmArg(){
// }
}
abstract class EvpIVInitializer extends EvpInitializer {
abstract Expr getIVArg();
}
/**
* A Call to update functions from the EVP API.
* A Call to an "update" function.
* These are not operations in the sense of Crypto::OperationInstance,
* but they are used to update the context for the operation.
* but produce intermediate results for the operation that are later finalized
* (see EvpFinal).
* Intended for use with EvPOperation.
*/
abstract class EVPUpdate extends Call {
abstract class EvpUpdate extends Call {
/**
* Gets the context argument that ties together initialization, updates and/or final calls.
*/
Expr getContextArg() { result = this.(Call).getArgument(0) }
abstract CtxPointerSource getContextArg();
/**
* Update calls always have some input data like plaintext or message digest.
@@ -99,13 +110,13 @@ 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.
* Provides some default methods for Crypto::KeyOperationInstance class
* Provides some default methods for Crypto::KeyOperationInstance class.
*/
abstract class EVPOperation extends OpenSSLOperation {
abstract class EvpOperation extends OpenSSLOperation {
/**
* Gets the context argument that ties together initialization, updates and/or final calls.
*/
Expr getContextArg() { result = this.(Call).getArgument(0) }
abstract CtxPointerSource getContextArg();
/**
* Some input data like plaintext or message digest.
@@ -121,9 +132,7 @@ abstract class EVPOperation extends OpenSSLOperation {
/**
* Finds the initialization call, may be none.
*/
EVPInitialize getInitCall() {
CTXFlow::ctxArgOrRetFlowsToCtxArg(result.getContextArg(), this.getContextArg())
}
EvpInitializer getInitCall() { ctxSrcToSrcFlow(result.getContextArg(), this.getContextArg()) }
Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
result = DataFlow::exprNode(this.getOutputArg())
@@ -139,15 +148,16 @@ abstract class EVPOperation extends OpenSSLOperation {
/**
* An EVP final call,
* which is typicall usesed in an update/final pattern.
* which is typicall used in an update/final pattern.
* Final operations are typically identified by "final" in the name,
* e.g., "EVP_DigestFinal", "EVP_EncryptFinal", etc.
* however, this is not a strict rule.
*/
abstract class EVPFinal extends EVPOperation {
abstract class EVPFinal extends EvpOperation {
/**
* All update calls that were executed before this final call.
*/
EVPUpdate getUpdateCalls() {
CTXFlow::ctxArgOrRetFlowsToCtxArg(result.getContextArg(), this.getContextArg())
}
EvpUpdate getUpdateCalls() { ctxSrcToSrcFlow(result.getContextArg(), this.getContextArg()) }
/**
* Gets the input data provided to all update calls.

View File

@@ -1,7 +0,0 @@
import cpp
import experimental.quantum.Language
import experimental.quantum.OpenSSL.Operations.EVPKeyGenOperation
from EVPKeyGenOperation keyGen, Crypto::KeyArtifactNode key
where keyGen = key.asElement().(Crypto::KeyArtifactOutputInstance).getCreator()
select keyGen, key, key.getAKnownAlgorithm()

View File

@@ -1,6 +1,6 @@
import cpp
import experimental.quantum.Language
import experimental.quantum.OpenSSL.Operations.EVPKeyGenOperation
import experimental.quantum.OpenSSL.OpenSSL
from Crypto::KeyGenerationOperationInstance n //KeyGenerationOperationNode n
select n, n.getOutputKeyArtifact(), n.getKeyArtifactOutputInstance() // , n.getAnAlgorithmOrGenericSource()
from Crypto::KeyGenerationOperationNode n
select n, n.getOutputKeyArtifact(), n.getAnAlgorithmOrGenericSource()