|
|
|
|
@@ -4,113 +4,63 @@
|
|
|
|
|
|
|
|
|
|
private import experimental.quantum.Language
|
|
|
|
|
private import OpenSSLOperationBase
|
|
|
|
|
private import experimental.quantum.OpenSSL.AvcFlow
|
|
|
|
|
private import experimental.quantum.OpenSSL.CtxFlow
|
|
|
|
|
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
|
|
|
|
private import experimental.quantum.OpenSSL.Operations.OpenSSLOperations
|
|
|
|
|
|
|
|
|
|
module OpenSSLKeyGenToArgConfig implements DataFlow::ConfigSig {
|
|
|
|
|
predicate isSource(DataFlow::Node source) {
|
|
|
|
|
exists(Crypto::KeyGenerationOperationInstance keygen | keygen.getOutputKeyArtifact() = source)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
predicate isSink(DataFlow::Node sink) { exists(Call c | c.getAnArgument() = sink.asExpr()) }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module OpenSSLKeyGenToArgFlow = TaintTracking::Global<OpenSSLKeyGenToArgConfig>;
|
|
|
|
|
|
|
|
|
|
// TODO: verification functions
|
|
|
|
|
class EVP_Signature_Initializer extends EVPInitialize {
|
|
|
|
|
EVP_Signature_Initializer() {
|
|
|
|
|
this.(Call).getTarget().getName() in [
|
|
|
|
|
"EVP_DigestSignInit", "EVP_DigestSignInit_ex", "EVP_SignInit", "EVP_SignInit_ex",
|
|
|
|
|
"EVP_PKEY_sign_init", "EVP_PKEY_sign_init_ex", "EVP_PKEY_sign_init_ex2",
|
|
|
|
|
"EVP_PKEY_sign_message_init"
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
class EvpSignatureDigestInitializer extends EvpHashAlgorithmInitializer {
|
|
|
|
|
Expr arg;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Gets the algorithm associated with this initialization by following
|
|
|
|
|
* where the algorithm is set through the context argument.
|
|
|
|
|
*/
|
|
|
|
|
Expr getAlgorithmArgFromCtx() {
|
|
|
|
|
// exists(EVPPKeyAlgorithmConsumer source, DataFlow::Node sink |
|
|
|
|
|
// result = source.getInputNode().asExpr() and
|
|
|
|
|
// sink.asExpr() = this.getContextArg() and
|
|
|
|
|
// OpenSSLCtxSourceToArgumentFlow::flow(source.getResultNode(), sink)
|
|
|
|
|
// )
|
|
|
|
|
// or
|
|
|
|
|
result = this.getAlgorithmArgFromKey(this.getKeyArgFromCtx())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Expr getAlgorithmArgFromKey(Expr keyArg) {
|
|
|
|
|
exists(Crypto::KeyGenerationOperationInstance keygen |
|
|
|
|
|
OpenSSLKeyGenToArgFlow::flow(keygen.getOutputKeyArtifact(), DataFlow::exprNode(keyArg)) and
|
|
|
|
|
result = keygen.(OpenSSLOperation).getAlgorithmArg()
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Gets the argument ingesting a key
|
|
|
|
|
* by tracing the context arg back to a context creation
|
|
|
|
|
*/
|
|
|
|
|
Expr getKeyArgFromCtx() {
|
|
|
|
|
exists(Call contextCreationCall |
|
|
|
|
|
ctxArgOrRetFlowsToCtxArg(contextCreationCall, this.getContextArg()) and
|
|
|
|
|
(
|
|
|
|
|
contextCreationCall.getTarget().getName() = "EVP_PKEY_CTX_new" and
|
|
|
|
|
result = contextCreationCall.getArgument(0)
|
|
|
|
|
or
|
|
|
|
|
contextCreationCall.getTarget().getName() = "EVP_PKEY_CTX_new_from_pkey" and
|
|
|
|
|
result = contextCreationCall.getArgument(1)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override Expr getAlgorithmArg() {
|
|
|
|
|
// explicit algorithm as argument
|
|
|
|
|
this.(Call).getTarget().getName() in ["EVP_PKEY_sign_init_ex2", "EVP_PKEY_sign_message_init"] and
|
|
|
|
|
result = this.(Call).getArgument(1)
|
|
|
|
|
// or
|
|
|
|
|
// // algorithm (and key) specified in the context
|
|
|
|
|
// this.(Call).getTarget().getName() in ["EVP_PKEY_sign_init", "EVP_PKEY_sign_init_ex"] and
|
|
|
|
|
// result = getAlgorithmArgFromCtx()
|
|
|
|
|
// or
|
|
|
|
|
// // algorithm specified by the key
|
|
|
|
|
// this.(Call).getTarget().getName() in ["EVP_DigestSignInit", "EVP_DigestSignInit_ex"] and
|
|
|
|
|
// result = getAlgorithmArgFromKey()
|
|
|
|
|
// // NOTE: for EVP_SignInit and EVP_SignInit_ex the algorithm is not specified
|
|
|
|
|
// // rather the algorithm is specified by the key used for signing later in a final call.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the key argument if there is one.
|
|
|
|
|
* If the key was provided via the context, we track it to the context.
|
|
|
|
|
*/
|
|
|
|
|
override Expr getKeyArg() {
|
|
|
|
|
this.(Call).getTarget().getName() = "EVP_DigestSignInit" and
|
|
|
|
|
result = this.(Call).getArgument(4)
|
|
|
|
|
EvpSignatureDigestInitializer() {
|
|
|
|
|
this.(Call).getTarget().getName() in ["EVP_DigestSignInit_ex", "EVP_DigestSignInit"] and
|
|
|
|
|
arg = this.(Call).getArgument(2)
|
|
|
|
|
or
|
|
|
|
|
this.(Call).getTarget().getName() = "EVP_DigestSignInit_ex" and
|
|
|
|
|
result = this.(Call).getArgument(5)
|
|
|
|
|
or
|
|
|
|
|
this.(Call).getTarget().getName().matches("EVP_PKEY_%") and
|
|
|
|
|
result = this.getKeyArgFromCtx()
|
|
|
|
|
this.(Call).getTarget().getName() in ["EVP_SignInit", "EVP_SignInit_ex"] and
|
|
|
|
|
arg = this.(Call).getArgument(1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Signing, verification or unknown.
|
|
|
|
|
*/
|
|
|
|
|
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
|
|
|
|
|
if this.(Call).getTarget().getName().toLowerCase().matches("%sign%")
|
|
|
|
|
then result instanceof Crypto::TSignMode
|
|
|
|
|
else
|
|
|
|
|
if this.(Call).getTarget().getName().toLowerCase().matches("%verify%")
|
|
|
|
|
then result instanceof Crypto::TVerifyMode
|
|
|
|
|
else result instanceof Crypto::TUnknownKeyOperationMode
|
|
|
|
|
}
|
|
|
|
|
override Expr getHashAlgorithmArg() { result = arg }
|
|
|
|
|
|
|
|
|
|
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class EVP_Signature_Update_Call extends EVPUpdate {
|
|
|
|
|
class EvpSignatureKeyInitializer extends EvpKeyInitializer {
|
|
|
|
|
Expr arg;
|
|
|
|
|
|
|
|
|
|
EvpSignatureKeyInitializer() {
|
|
|
|
|
this.(Call).getTarget().getName() = "EVP_DigestSignInit_ex" and
|
|
|
|
|
arg = this.(Call).getArgument(5)
|
|
|
|
|
or
|
|
|
|
|
this.(Call).getTarget().getName() = "EVP_DigestSignInit" and
|
|
|
|
|
arg = this.(Call).getArgument(4)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override Expr getKeyArg() { result = arg }
|
|
|
|
|
|
|
|
|
|
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class EvpSignaturePrimaryAlgorithmInitializer extends EvpPrimaryAlgorithmInitializer {
|
|
|
|
|
Expr arg;
|
|
|
|
|
|
|
|
|
|
EvpSignaturePrimaryAlgorithmInitializer() {
|
|
|
|
|
// signature algorithm
|
|
|
|
|
this.(Call).getTarget().getName() in ["EVP_PKEY_sign_init_ex2", "EVP_PKEY_sign_message_init"] and
|
|
|
|
|
arg = this.(Call).getArgument(1)
|
|
|
|
|
or
|
|
|
|
|
// configuration through the context argument
|
|
|
|
|
this.(Call).getTarget().getName() in ["EVP_PKEY_sign_init", "EVP_PKEY_sign_init_ex"] and
|
|
|
|
|
arg = this.getContext()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override Expr getAlgorithmArg() { result = arg }
|
|
|
|
|
|
|
|
|
|
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class EVP_Signature_Update_Call extends EvpUpdate {
|
|
|
|
|
EVP_Signature_Update_Call() {
|
|
|
|
|
this.(Call).getTarget().getName() in [
|
|
|
|
|
"EVP_DigestSignUpdate", "EVP_SignUpdate", "EVP_PKEY_sign_message_update"
|
|
|
|
|
@@ -121,6 +71,8 @@ class EVP_Signature_Update_Call extends EVPUpdate {
|
|
|
|
|
* Input is the message to sign.
|
|
|
|
|
*/
|
|
|
|
|
override Expr getInputArg() { result = this.(Call).getArgument(1) }
|
|
|
|
|
|
|
|
|
|
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -131,22 +83,37 @@ private Expr signatureOperationOutputArg(Call call) {
|
|
|
|
|
if call.getTarget().getName() = "EVP_SignFinal_ex"
|
|
|
|
|
then result = call.getArgument(2)
|
|
|
|
|
else result = call.getArgument(1)
|
|
|
|
|
////*******todo get rid of this predicate */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Base configuration for all EVP signature operations.
|
|
|
|
|
*/
|
|
|
|
|
abstract class EVP_Signature_Operation extends EVPOperation, Crypto::SignatureOperationInstance {
|
|
|
|
|
EVP_Signature_Operation() {
|
|
|
|
|
abstract class EvpSignatureOperation extends EvpOperation, Crypto::SignatureOperationInstance {
|
|
|
|
|
EvpSignatureOperation() {
|
|
|
|
|
this.(Call).getTarget().getName().matches("EVP_%") and
|
|
|
|
|
// NULL output argument means the call is to get the size of the signature and such call is not an operation
|
|
|
|
|
(
|
|
|
|
|
// ******TODO review logic
|
|
|
|
|
not exists(signatureOperationOutputArg(this).getValue())
|
|
|
|
|
or
|
|
|
|
|
signatureOperationOutputArg(this).getValue() != "0"
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Expr getHashAlgorithmArg() {
|
|
|
|
|
this.getInitCall().(EvpHashAlgorithmInitializer).getHashAlgorithmArg() = result
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override Expr getAlgorithmArg() {
|
|
|
|
|
this.getInitCall().(EvpPrimaryAlgorithmInitializer).getAlgorithmArg() = result
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override Crypto::AlgorithmValueConsumer getHashAlgorithmValueConsumer() {
|
|
|
|
|
AvcToCallArgFlow::flow(result.(OpenSSLAlgorithmValueConsumer).getResultNode(),
|
|
|
|
|
DataFlow::exprNode(this.getHashAlgorithmArg()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Signing, verification or unknown.
|
|
|
|
|
*/
|
|
|
|
|
@@ -170,15 +137,15 @@ abstract class EVP_Signature_Operation extends EVPOperation, Crypto::SignatureOp
|
|
|
|
|
* Keys in explicit arguments are found by overriden methods in extending classes.
|
|
|
|
|
*/
|
|
|
|
|
override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
|
|
|
|
|
result = DataFlow::exprNode(this.getInitCall().getKeyArg())
|
|
|
|
|
result = DataFlow::exprNode(this.getInitCall().(EvpKeyInitializer).getKeyArg())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
|
|
|
|
|
result = EVPOperation.super.getOutputArtifact()
|
|
|
|
|
result = EvpOperation.super.getOutputArtifact()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
|
|
|
|
|
result = EVPOperation.super.getInputConsumer()
|
|
|
|
|
result = EvpOperation.super.getInputConsumer()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -186,42 +153,58 @@ abstract class EVP_Signature_Operation extends EVPOperation, Crypto::SignatureOp
|
|
|
|
|
*/
|
|
|
|
|
override Crypto::ConsumerInputDataFlowNode getSignatureConsumer() { none() }
|
|
|
|
|
}
|
|
|
|
|
// class EVP_Signature_Call extends EVPOperation, EVP_Signature_Operation {
|
|
|
|
|
// EVP_Signature_Call() { this.(Call).getTarget().getName() in ["EVP_DigestSign", "EVP_PKEY_sign"] }
|
|
|
|
|
// /**
|
|
|
|
|
// * Output is the signature.
|
|
|
|
|
// */
|
|
|
|
|
// override Expr getOutputArg() { result = signatureOperationOutputArg(this) }
|
|
|
|
|
// /**
|
|
|
|
|
// * Input is the message to sign.
|
|
|
|
|
// */
|
|
|
|
|
// override Expr getInputArg() { result = this.(Call).getArgument(3) }
|
|
|
|
|
// }
|
|
|
|
|
// class EVP_Signature_Final_Call extends EVPFinal, EVP_Signature_Operation {
|
|
|
|
|
// EVP_Signature_Final_Call() {
|
|
|
|
|
// this.(Call).getTarget().getName() in [
|
|
|
|
|
// "EVP_DigestSignFinal", "EVP_SignFinal_ex", "EVP_SignFinal", "EVP_PKEY_sign_message_final"
|
|
|
|
|
// ]
|
|
|
|
|
// }
|
|
|
|
|
// override Expr getAlgorithmArg() {
|
|
|
|
|
// none()
|
|
|
|
|
// // // algorithm specified by the key and the key is provided in this operation
|
|
|
|
|
// // if this.(Call).getTarget().getName() in ["EVP_SignFinal", "EVP_SignFinal_ex"]
|
|
|
|
|
// // then result = getAlgorithmFromKey(this.getKeyConsumer().asExpr())
|
|
|
|
|
// // else
|
|
|
|
|
// // // or find algorithm in the initialization call
|
|
|
|
|
// // result = EVP_Signature_Operation.super.getAlgorithmArg()
|
|
|
|
|
// }
|
|
|
|
|
// override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
|
|
|
|
|
// // key provided as an argument
|
|
|
|
|
// if this.(Call).getTarget().getName() in ["EVP_SignFinal", "EVP_SignFinal_ex"]
|
|
|
|
|
// then result = DataFlow::exprNode(this.(Call).getArgument(3))
|
|
|
|
|
// else
|
|
|
|
|
// // or find key in the initialization call
|
|
|
|
|
// result = EVP_Signature_Operation.super.getKeyConsumer()
|
|
|
|
|
// }
|
|
|
|
|
// /**
|
|
|
|
|
// * Output is the signature.
|
|
|
|
|
// */
|
|
|
|
|
// override Expr getOutputArg() { result = signatureOperationOutputArg(this) }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
class EVP_Signature_Call extends EvpSignatureOperation {
|
|
|
|
|
EVP_Signature_Call() { this.(Call).getTarget().getName() in ["EVP_DigestSign", "EVP_PKEY_sign"] }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Output is the signature.
|
|
|
|
|
*/
|
|
|
|
|
override Expr getOutputArg() { result = signatureOperationOutputArg(this) }
|
|
|
|
|
|
|
|
|
|
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Input is the message to sign.
|
|
|
|
|
*/
|
|
|
|
|
override Expr getInputArg() { result = this.(Call).getArgument(3) }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class EVP_Signature_Final_Call extends EVPFinal, EvpSignatureOperation {
|
|
|
|
|
EVP_Signature_Final_Call() {
|
|
|
|
|
this.(Call).getTarget().getName() in [
|
|
|
|
|
"EVP_DigestSignFinal",
|
|
|
|
|
"EVP_SignFinal_ex",
|
|
|
|
|
"EVP_SignFinal",
|
|
|
|
|
"EVP_PKEY_sign_message_final"
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
|
|
|
|
|
|
|
|
|
//***********TODO: the algorithm arg might nto be the right type, can't use the initializer the same way if there
|
|
|
|
|
// are two initializers for two different algorithms */
|
|
|
|
|
override Expr getAlgorithmArg() {
|
|
|
|
|
this.getInitCall().(EvpPrimaryAlgorithmInitializer).getAlgorithmArg() = result
|
|
|
|
|
// // algorithm specified by the key and the key is provided in this operation
|
|
|
|
|
// if this.(Call).getTarget().getName() in ["EVP_SignFinal", "EVP_SignFinal_ex"]
|
|
|
|
|
// then result = getAlgorithmFromKey(this.getKeyConsumer().asExpr())
|
|
|
|
|
// else
|
|
|
|
|
// // or find algorithm in the initialization call
|
|
|
|
|
// result = EVP_Signature_Operation.super.getAlgorithmArg()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
|
|
|
|
|
// key provided as an argument
|
|
|
|
|
this.(Call).getTarget().getName() in ["EVP_SignFinal", "EVP_SignFinal_ex"] and
|
|
|
|
|
result = DataFlow::exprNode(this.(Call).getArgument(3))
|
|
|
|
|
or
|
|
|
|
|
// or find key in the initialization call
|
|
|
|
|
result = EvpSignatureOperation.super.getKeyConsumer()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Output is the signature.
|
|
|
|
|
*/
|
|
|
|
|
override Expr getOutputArg() { result = signatureOperationOutputArg(this) }
|
|
|
|
|
}
|
|
|
|
|
|