mirror of
https://github.com/github/codeql.git
synced 2026-04-21 23:14:03 +02:00
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:
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user