mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
201 lines
6.6 KiB
Plaintext
201 lines
6.6 KiB
Plaintext
/**
|
|
* Provides classes for modeling OpenSSL's EVP signature operations
|
|
*/
|
|
|
|
private import experimental.quantum.Language
|
|
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
|
|
|
|
// TODO: verification functions
|
|
class EvpSignatureDigestInitializer extends EvpHashAlgorithmInitializer {
|
|
Expr arg;
|
|
|
|
EvpSignatureDigestInitializer() {
|
|
this.(Call).getTarget().getName() in ["EVP_DigestSignInit_ex", "EVP_DigestSignInit"] and
|
|
arg = this.(Call).getArgument(2)
|
|
or
|
|
this.(Call).getTarget().getName() in ["EVP_SignInit", "EVP_SignInit_ex"] and
|
|
arg = this.(Call).getArgument(1)
|
|
}
|
|
|
|
override Expr getHashAlgorithmArg() { result = arg }
|
|
|
|
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
|
}
|
|
|
|
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"
|
|
]
|
|
}
|
|
|
|
/**
|
|
* Input is the message to sign.
|
|
*/
|
|
override Expr getInputArg() { result = this.(Call).getArgument(1) }
|
|
|
|
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
|
|
}
|
|
|
|
/**
|
|
* We model output explicit output arguments as predicate to use it in constructors.
|
|
* The predicate must cover all EVP_Signature_Operation subclasses.
|
|
*/
|
|
pragma[inline]
|
|
private Expr signatureOperationOutputArg(Call call) {
|
|
if call.getTarget().getName() = "EVP_SignFinal_ex"
|
|
then result = call.getArgument(2)
|
|
else result = call.getArgument(1)
|
|
}
|
|
|
|
/**
|
|
* The base configuration for all EVP signature operations.
|
|
*/
|
|
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
|
|
(
|
|
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.
|
|
*/
|
|
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
|
|
// TODO: if this KeyOperationSubtype does not match initialization call's KeyOperationSubtype then we found a bug
|
|
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 Crypto::ConsumerInputDataFlowNode getNonceConsumer() {
|
|
// TODO: some signing operations may have explicit nonce generators
|
|
none()
|
|
}
|
|
|
|
/**
|
|
* Keys provided in the initialization call or in a context are found by this method.
|
|
* Keys in explicit arguments are found by overridden methods in extending classes.
|
|
*/
|
|
override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
|
|
result = DataFlow::exprNode(this.getInitCall().(EvpKeyInitializer).getKeyArg())
|
|
}
|
|
|
|
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
|
|
result = EvpOperation.super.getOutputArtifact()
|
|
}
|
|
|
|
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
|
|
result = EvpOperation.super.getInputConsumer()
|
|
}
|
|
|
|
/**
|
|
* TODO: only signing operations for now, change when verificaiton is added
|
|
*/
|
|
override Crypto::ConsumerInputDataFlowNode getSignatureConsumer() { none() }
|
|
}
|
|
|
|
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) }
|
|
|
|
override Expr getAlgorithmArg() {
|
|
this.getInitCall().(EvpPrimaryAlgorithmInitializer).getAlgorithmArg() = result
|
|
}
|
|
|
|
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) }
|
|
}
|