mirror of
https://github.com/github/codeql.git
synced 2025-12-18 09:43:15 +01:00
759 lines
26 KiB
Plaintext
759 lines
26 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.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
|
|
private import experimental.quantum.OpenSSL.Operations.OpenSSLOperations
|
|
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances
|
|
|
|
/**
|
|
* A base class for final signature operations.
|
|
* The operation must be known to always be a signature operation,
|
|
* and not a MAC operation. Used for both verification and signing.
|
|
* NOTE: even an operation that may be a mac or signature but is known to take in
|
|
* only signature configurations should extend `SignatureOrMacFinalOperation`.
|
|
*/
|
|
abstract class SignatureFinalOperation extends OperationStep {
|
|
override OperationStepType getStepType() { result = FinalStep() }
|
|
}
|
|
|
|
/**
|
|
* A base class for final signature or MAC operations.
|
|
* The operation must be known to always be a signature or MAC operation.
|
|
* Used for both verification or signing.
|
|
*/
|
|
abstract class SignatureOrMacFinalOperation extends OperationStep {
|
|
override OperationStepType getStepType() { result = FinalStep() }
|
|
}
|
|
|
|
/**
|
|
* A call to EVP_DigestSignInit or EVP_DigestSignInit_ex.
|
|
*/
|
|
class EvpSignatureDigestInitializer extends OperationStep {
|
|
EvpSignatureDigestInitializer() {
|
|
this.getTarget().getName() in ["EVP_DigestSignInit_ex", "EVP_DigestSignInit"]
|
|
}
|
|
|
|
override DataFlow::Node getInput(IOType type) {
|
|
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
this.getTarget().getName() = "EVP_DigestSignInit_ex" and
|
|
result.asIndirectExpr() = this.getArgument(3) and
|
|
type = OsslLibContextIO()
|
|
or
|
|
result.asIndirectExpr() = this.getArgument(2) and type = HashAlgorithmIO()
|
|
or
|
|
this.getTarget().getName() = "EVP_DigestSignInit" and
|
|
result.asIndirectExpr() = this.getArgument(4) and
|
|
type = KeyIO()
|
|
or
|
|
this.getTarget().getName() = "EVP_DigestSignInit_ex" and
|
|
result.asIndirectExpr() = this.getArgument(5) and
|
|
type = KeyIO()
|
|
or
|
|
this.getTarget().getName() = "EVP_DigestSignInit_ex" and
|
|
result.asIndirectExpr() = this.getArgument(6) and
|
|
type = OsslParamIO()
|
|
}
|
|
|
|
override DataFlow::Node getOutput(IOType type) {
|
|
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
// EVP_PKEY_CTX
|
|
result.asDefiningArgument() = this.getArgument(1) and type = ContextIO()
|
|
}
|
|
|
|
override OperationStepType getStepType() { result = InitializerStep() }
|
|
}
|
|
|
|
/**
|
|
* A call to EVP_SignInit or EVP_SignInit_ex.
|
|
*/
|
|
class EvpSignInit extends OperationStep {
|
|
EvpSignInit() { this.getTarget().getName() in ["EVP_SignInit", "EVP_SignInit_ex"] }
|
|
|
|
override DataFlow::Node getInput(IOType type) {
|
|
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
result.asIndirectExpr() = this.getArgument(1) and type = HashAlgorithmIO()
|
|
}
|
|
|
|
override DataFlow::Node getOutput(IOType type) {
|
|
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
|
}
|
|
|
|
override OperationStepType getStepType() { result = InitializerStep() }
|
|
}
|
|
|
|
/**
|
|
* A call to:
|
|
* - EVP_PKEY_sign_init_ex
|
|
* - EVP_PKEY_sign_init_ex2
|
|
* - EVP_PKEY_sign_init
|
|
* - EVP_PKEY_sign_message_init
|
|
*/
|
|
class EvpPkeySignInit extends OperationStep {
|
|
EvpPkeySignInit() {
|
|
this.getTarget().getName() in [
|
|
"EVP_PKEY_sign_init_ex", "EVP_PKEY_sign_init_ex2", "EVP_PKEY_sign_init",
|
|
"EVP_PKEY_sign_message_init"
|
|
]
|
|
}
|
|
|
|
override DataFlow::Node getInput(IOType type) {
|
|
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
this.getTarget().getName() in ["EVP_PKEY_sign_init_ex2", "EVP_PKEY_sign_message_init"] and
|
|
result.asIndirectExpr() = this.getArgument(1) and
|
|
type = PrimaryAlgorithmIO()
|
|
or
|
|
this.getTarget().getName() = "EVP_PKEY_sign_init_ex" and
|
|
result.asIndirectExpr() = this.getArgument(1) and
|
|
type = OsslParamIO()
|
|
or
|
|
// Argument 2 (0 based) only exists for EVP_PKEY_sign_init_ex2 and EVP_PKEY_sign_message_init
|
|
result.asIndirectExpr() = this.getArgument(2) and type = OsslParamIO()
|
|
}
|
|
|
|
override DataFlow::Node getOutput(IOType type) {
|
|
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
|
}
|
|
|
|
override OperationStepType getStepType() { result = InitializerStep() }
|
|
}
|
|
|
|
/**
|
|
* A call to EVP_DIgestSignUpdate, EVP_SignUpdate or EVP_PKEY_sign_message_update.
|
|
*/
|
|
class EvpSignatureUpdateCall extends OperationStep {
|
|
EvpSignatureUpdateCall() {
|
|
this.getTarget().getName() in [
|
|
"EVP_DigestSignUpdate", "EVP_SignUpdate", "EVP_PKEY_sign_message_update"
|
|
]
|
|
}
|
|
|
|
override DataFlow::Node getInput(IOType type) {
|
|
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
result.asIndirectExpr() = this.getArgument(1) and type = PlaintextIO()
|
|
}
|
|
|
|
override DataFlow::Node getOutput(IOType type) {
|
|
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
|
}
|
|
|
|
override OperationStepType getStepType() { result = UpdateStep() }
|
|
}
|
|
|
|
/**
|
|
* A call to EVP_SignFinal or EVP_SignFinal_ex.
|
|
*/
|
|
class EvpSignFinal extends SignatureFinalOperation {
|
|
EvpSignFinal() { this.getTarget().getName() in ["EVP_SignFinal_ex", "EVP_SignFinal"] }
|
|
|
|
override DataFlow::Node getInput(IOType type) {
|
|
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
result.asIndirectExpr() = this.getArgument(3) and type = KeyIO()
|
|
or
|
|
// params above 3 (0-based) only exist for EVP_SignFinal_ex
|
|
result.asIndirectExpr() = this.getArgument(4) and
|
|
type = OsslLibContextIO()
|
|
}
|
|
|
|
override DataFlow::Node getOutput(IOType type) {
|
|
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
result.asDefiningArgument() = this.getArgument(1) and type = SignatureIO()
|
|
or
|
|
result.asDefiningArgument() = this.getArgument(2) and type = SignatureSizeIO()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A call to EVP_PKEY_sign.
|
|
*/
|
|
class EvpPkeySign extends SignatureFinalOperation {
|
|
EvpPkeySign() {
|
|
this.getTarget().getName() = "EVP_PKEY_sign" and
|
|
// Setting signature to NULL is not a final sign step but an
|
|
// intermediary step used to get the required buffer size.
|
|
// not tracking these calls.
|
|
(
|
|
exists(this.(Call).getArgument(1).getValue())
|
|
implies
|
|
this.(Call).getArgument(1).getValue().toInt() != 0
|
|
)
|
|
}
|
|
|
|
override DataFlow::Node getInput(IOType type) {
|
|
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
result.asIndirectExpr() = this.getArgument(3) and type = PlaintextIO()
|
|
}
|
|
|
|
override DataFlow::Node getOutput(IOType type) {
|
|
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
result.asDefiningArgument() = this.getArgument(1) and type = SignatureIO()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A call to EVP_DigestSign.
|
|
* This is a mac or sign operation.
|
|
*/
|
|
class EvpDigestSign extends SignatureOrMacFinalOperation {
|
|
EvpDigestSign() { this.getTarget().getName() = "EVP_DigestSign" }
|
|
|
|
override DataFlow::Node getInput(IOType type) {
|
|
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
result.asIndirectExpr() = this.getArgument(3) and type = PlaintextIO()
|
|
}
|
|
|
|
override DataFlow::Node getOutput(IOType type) {
|
|
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
result.asDefiningArgument() = this.getArgument(1) and type = SignatureIO()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A call to EVP_PKEY_sign_message_final.
|
|
*/
|
|
class EvpPkeySignFinal extends SignatureFinalOperation {
|
|
EvpPkeySignFinal() {
|
|
this.getTarget().getName() = "EVP_PKEY_sign_message_final" and
|
|
// Setting signature to NULL is not a final sign step but an
|
|
// intermediary step used to get the required buffer size.
|
|
// not tracking these calls.
|
|
(
|
|
exists(this.(Call).getArgument(1).getValue())
|
|
implies
|
|
this.(Call).getArgument(1).getValue().toInt() != 0
|
|
)
|
|
}
|
|
|
|
override DataFlow::Node getInput(IOType type) {
|
|
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
|
}
|
|
|
|
override DataFlow::Node getOutput(IOType type) {
|
|
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
result.asDefiningArgument() = this.getArgument(1) and type = SignatureIO()
|
|
or
|
|
result.asExpr() = this.getArgument(2) and type = SignatureSizeIO()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A call to EVP_DigestSignFinal.
|
|
* This is a mac or sign operation.
|
|
*/
|
|
class EvpDigestSignFinal extends SignatureOrMacFinalOperation {
|
|
EvpDigestSignFinal() {
|
|
this.getTarget().getName() = "EVP_DigestSignFinal" and
|
|
// Setting signature to NULL is not a final sign step but an
|
|
// intermediary step used to get the required buffer size.
|
|
// not tracking these calls.
|
|
(
|
|
exists(this.(Call).getArgument(1).getValue())
|
|
implies
|
|
this.(Call).getArgument(1).getValue().toInt() != 0
|
|
)
|
|
}
|
|
|
|
override DataFlow::Node getInput(IOType type) {
|
|
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
|
}
|
|
|
|
override DataFlow::Node getOutput(IOType type) {
|
|
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
result.asDefiningArgument() = this.getArgument(1) and type = SignatureIO()
|
|
}
|
|
|
|
override OperationStepType getStepType() { result = FinalStep() }
|
|
}
|
|
|
|
/**
|
|
* A call to EVP_DigestVerifyInit or EVP_DigestVerifyInit_ex.
|
|
*/
|
|
class EvpDigestVerifyInit extends OperationStep {
|
|
EvpDigestVerifyInit() {
|
|
this.getTarget().getName() in ["EVP_DigestVerifyInit", "EVP_DigestVerifyInit_ex"]
|
|
}
|
|
|
|
override DataFlow::Node getInput(IOType type) {
|
|
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
result.asIndirectExpr() = this.getArgument(2) and type = HashAlgorithmIO()
|
|
or
|
|
this.getTarget().getName() = "EVP_DigestVerifyInit_ex" and
|
|
result.asIndirectExpr() = this.getArgument(3) and
|
|
type = OsslLibContextIO()
|
|
or
|
|
this.getTarget().getName() = "EVP_DigestVerifyInit_ex" and
|
|
result.asIndirectExpr() = this.getArgument(5) and
|
|
type = KeyIO()
|
|
or
|
|
this.getTarget().getName() = "EVP_DigestVerifyInit" and
|
|
result.asIndirectExpr() = this.getArgument(4) and
|
|
type = KeyIO()
|
|
or
|
|
this.getTarget().getName() = "EVP_DigestVerifyInit_ex" and
|
|
result.asIndirectExpr() = this.getArgument(6) and
|
|
type = OsslParamIO()
|
|
}
|
|
|
|
override DataFlow::Node getOutput(IOType type) {
|
|
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
result.asDefiningArgument() = this.getArgument(1) and type = ContextIO()
|
|
}
|
|
|
|
override OperationStepType getStepType() { result = InitializerStep() }
|
|
}
|
|
|
|
/**
|
|
* A call to EVP_DigestVerifyUpdate.
|
|
*/
|
|
class EvpDigestVerifyUpdate extends OperationStep {
|
|
EvpDigestVerifyUpdate() { this.getTarget().getName() = "EVP_DigestVerifyUpdate" }
|
|
|
|
override DataFlow::Node getInput(IOType type) {
|
|
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
result.asIndirectExpr() = this.getArgument(1) and type = PlaintextIO()
|
|
}
|
|
|
|
override DataFlow::Node getOutput(IOType type) {
|
|
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
|
}
|
|
|
|
override OperationStepType getStepType() { result = UpdateStep() }
|
|
}
|
|
|
|
/**
|
|
* A call to EVP_DigestVerifyFinal
|
|
*/
|
|
class EvpDigestVerifyFinal extends SignatureFinalOperation {
|
|
EvpDigestVerifyFinal() { this.getTarget().getName() = "EVP_DigestVerifyFinal" }
|
|
|
|
override DataFlow::Node getInput(IOType type) {
|
|
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
result.asIndirectExpr() = this.getArgument(1) and type = SignatureIO()
|
|
}
|
|
|
|
override DataFlow::Node getOutput(IOType type) {
|
|
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A call to EVP_DigestVerify
|
|
*/
|
|
class EvpDigestVerify extends SignatureFinalOperation {
|
|
EvpDigestVerify() { this.getTarget().getName() = "EVP_DigestVerify" }
|
|
|
|
override DataFlow::Node getInput(IOType type) {
|
|
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
result.asIndirectExpr() = this.getArgument(1) and type = SignatureIO()
|
|
or
|
|
result.asIndirectExpr() = this.getArgument(3) and type = PlaintextIO()
|
|
}
|
|
|
|
override DataFlow::Node getOutput(IOType type) {
|
|
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A call to `EVP_PKEY_verify_init`, `EVP_PKEY_verify_init_ex`,
|
|
* `EVP_PKEY_verify_init_ex2`, or `EVP_PKEY_verify_message_init`
|
|
* https://docs.openssl.org/master/man3/EVP_PKEY_verify/#synopsis
|
|
*/
|
|
class EvpVerifyInit extends OperationStep {
|
|
EvpVerifyInit() {
|
|
this.getTarget().getName() in [
|
|
"EVP_PKEY_verify_init", "EVP_PKEY_verify_init_ex", "EVP_PKEY_verify_init_ex2",
|
|
"EVP_PKEY_verify_message_init"
|
|
]
|
|
}
|
|
|
|
override DataFlow::Node getInput(IOType type) {
|
|
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
this.getTarget().getName() = "EVP_PKEY_verify_init_ex" and
|
|
result.asIndirectExpr() = this.getArgument(1) and
|
|
type = OsslParamIO()
|
|
or
|
|
this.getTarget().getName() in ["EVP_PKEY_verify_init_ex2", "EVP_PKEY_verify_message_init"] and
|
|
result.asIndirectExpr() = this.getArgument(1) and
|
|
type = PrimaryAlgorithmIO()
|
|
or
|
|
this.getTarget().getName() in ["EVP_PKEY_verify_init_ex2", "EVP_PKEY_verify_message_init"] and
|
|
result.asIndirectExpr() = this.getArgument(2) and
|
|
type = OsslParamIO()
|
|
}
|
|
|
|
override DataFlow::Node getOutput(IOType type) {
|
|
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
|
}
|
|
|
|
override OperationStepType getStepType() { result = InitializerStep() }
|
|
}
|
|
|
|
/**
|
|
* A call to `EVP_PKEY_CTX_set_signature`
|
|
* https://docs.openssl.org/master/man3/EVP_PKEY_verify/
|
|
*/
|
|
class EvpCtxSetSignatureInitializer extends OperationStep {
|
|
EvpCtxSetSignatureInitializer() { this.getTarget().getName() = "EVP_PKEY_CTX_set_signature" }
|
|
|
|
override DataFlow::Node getInput(IOType type) {
|
|
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
result.asIndirectExpr() = this.getArgument(1) and type = SignatureIO()
|
|
or
|
|
result.asExpr() = this.getArgument(2) and type = SignatureSizeIO()
|
|
}
|
|
|
|
override DataFlow::Node getOutput(IOType type) {
|
|
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
|
}
|
|
|
|
override OperationStepType getStepType() { result = InitializerStep() }
|
|
}
|
|
|
|
/**
|
|
* A call to `EVP_PKEY_verify_message_update`.
|
|
*/
|
|
class EvpVerifyMessageUpdate extends OperationStep {
|
|
EvpVerifyMessageUpdate() { this.getTarget().getName() = "EVP_PKEY_verify_message_update" }
|
|
|
|
override DataFlow::Node getInput(IOType type) {
|
|
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
result.asIndirectExpr() = this.getArgument(1) and type = PlaintextIO()
|
|
or
|
|
result.asExpr() = this.getArgument(2) and type = PlaintextSizeIO()
|
|
}
|
|
|
|
override DataFlow::Node getOutput(IOType type) {
|
|
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
|
}
|
|
|
|
override OperationStepType getStepType() { result = UpdateStep() }
|
|
}
|
|
|
|
/**
|
|
* A call to `EVP_PKEY_verify_message_final`.
|
|
*/
|
|
class EvpVerifyMessageFinal extends SignatureFinalOperation {
|
|
EvpVerifyMessageFinal() { this.getTarget().getName() = "EVP_PKEY_verify_message_final" }
|
|
|
|
override DataFlow::Node getInput(IOType type) {
|
|
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
|
}
|
|
|
|
override DataFlow::Node getOutput(IOType type) {
|
|
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A call to `EVP_PKEY_verify`
|
|
*/
|
|
class EvpVerify extends SignatureFinalOperation {
|
|
EvpVerify() { this.getTarget().getName() = "EVP_PKEY_verify" }
|
|
|
|
override DataFlow::Node getInput(IOType type) {
|
|
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
result.asIndirectExpr() = this.getArgument(1) and type = SignatureIO()
|
|
or
|
|
result.asExpr() = this.getArgument(2) and type = SignatureSizeIO()
|
|
or
|
|
result.asIndirectExpr() = this.getArgument(3) and type = PlaintextIO()
|
|
or
|
|
result.asExpr() = this.getArgument(4) and type = PlaintextSizeIO()
|
|
}
|
|
|
|
override DataFlow::Node getOutput(IOType type) {
|
|
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A call to `RSA_sign` or `RSA_verify`.
|
|
* https://docs.openssl.org/3.0/man3/RSA_sign/
|
|
*/
|
|
class RsaSignorVerify extends SignatureFinalOperation {
|
|
RsaSignorVerify() { this.getTarget().getName() in ["RSA_sign", "RSA_verify"] }
|
|
|
|
override DataFlow::Node getInput(IOType type) {
|
|
// Arg 0 is an NID (so asExpr not asIndirectExpr)
|
|
result.asExpr() = this.getArgument(0) and type = HashAlgorithmIO()
|
|
or
|
|
result.asIndirectExpr() = this.getArgument(1) and type = PlaintextIO()
|
|
or
|
|
result.asExpr() = this.getArgument(2) and type = PlaintextSizeIO()
|
|
or
|
|
this.getTarget().getName() = "RSA_verify" and
|
|
result.asIndirectExpr() = this.getArgument(3) and
|
|
type = SignatureIO()
|
|
or
|
|
this.getTarget().getName() = "RSA_verify" and
|
|
result.asIndirectExpr() = this.getArgument(4) and
|
|
type = SignatureSizeIO()
|
|
or
|
|
result.asIndirectExpr() = this.getArgument(5) and type = KeyIO()
|
|
}
|
|
|
|
override DataFlow::Node getOutput(IOType type) {
|
|
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
this.getTarget().getName() = "RSA_sign" and
|
|
result.asDefiningArgument() = this.getArgument(3) and
|
|
type = SignatureIO()
|
|
or
|
|
this.getTarget().getName() = "RSA_sign" and
|
|
type = SignatureSizeIO() and
|
|
result.asDefiningArgument() = this.getArgument(4)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A call to `DSA_do_sign` or `DSA_do_verify`
|
|
*/
|
|
class DsaDoSignOrVerify extends SignatureFinalOperation {
|
|
DsaDoSignOrVerify() { this.getTarget().getName() in ["DSA_do_sign", "DSA_do_verify"] }
|
|
|
|
override DataFlow::Node getInput(IOType type) {
|
|
result.asIndirectExpr() = this.getArgument(0) and type = PlaintextIO()
|
|
or
|
|
result.asExpr() = this.getArgument(1) and type = PlaintextSizeIO()
|
|
or
|
|
this.getTarget().getName() = "DSA_do_sign" and
|
|
result.asIndirectExpr() = this.getArgument(2) and
|
|
type = KeyIO()
|
|
or
|
|
this.getTarget().getName() = "DSA_do_verify" and
|
|
result.asIndirectExpr() = this.getArgument(2) and
|
|
type = SignatureIO()
|
|
or
|
|
this.getTarget().getName() = "DSA_do_verify" and
|
|
result.asIndirectExpr() = this.getArgument(3) and
|
|
type = KeyIO()
|
|
}
|
|
|
|
override DataFlow::Node getOutput(IOType type) {
|
|
this.getTarget().getName() = "DSA_do_sign" and
|
|
result.asIndirectExpr() = this and
|
|
type = SignatureIO()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A Call to `EVP_VerifyInit` or `EVP_VerifyInit_ex`
|
|
* - int EVP_VerifyInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl);
|
|
* - int EVP_VerifyInit(EVP_MD_CTX *ctx, const EVP_MD *type);
|
|
*/
|
|
class EVP_VerifyInitCall extends OperationStep {
|
|
EVP_VerifyInitCall() { this.getTarget().getName() in ["EVP_VerifyInit", "EVP_VerifyInit_ex"] }
|
|
|
|
override DataFlow::Node getInput(IOType type) {
|
|
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
result.asIndirectExpr() = this.getArgument(1) and type = HashAlgorithmIO()
|
|
}
|
|
|
|
override DataFlow::Node getOutput(IOType type) {
|
|
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
|
}
|
|
|
|
override OperationStepType getStepType() { result = InitializerStep() }
|
|
}
|
|
|
|
/**
|
|
* A call to `EVP_VerifyUpdate`
|
|
* - int EVP_VerifyUpdate(EVP_MD_CTX *ctx, const void *d, unsigned int cnt);
|
|
*/
|
|
class EVP_VerifyUpdateCall extends OperationStep {
|
|
EVP_VerifyUpdateCall() { this.getTarget().getName() = "EVP_VerifyUpdate" }
|
|
|
|
override DataFlow::Node getInput(IOType type) {
|
|
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
result.asIndirectExpr() = this.getArgument(1) and type = PlaintextIO()
|
|
or
|
|
result.asIndirectExpr() = this.getArgument(2) and type = PlaintextSizeIO()
|
|
}
|
|
|
|
override DataFlow::Node getOutput(IOType type) {
|
|
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
|
}
|
|
|
|
override OperationStepType getStepType() { result = UpdateStep() }
|
|
}
|
|
|
|
/**
|
|
* A call to `EVP_VerifyFinal` or `EVP_VerifyFinal_ex`
|
|
* - int EVP_VerifyFinal_ex(EVP_MD_CTX *ctx, const unsigned char *sigbuf,
|
|
* unsigned int siglen, EVP_PKEY *pkey,
|
|
* OSSL_LIB_CTX *libctx, const char *propq);
|
|
*- int EVP_VerifyFinal(EVP_MD_CTX *ctx, unsigned char *sigbuf, unsigned int siglen,
|
|
* EVP_PKEY *pkey); *
|
|
*/
|
|
class EVP_VerifyFinalCall extends SignatureFinalOperation {
|
|
EVP_VerifyFinalCall() { this.getTarget().getName() in ["EVP_VerifyFinal", "EVP_VerifyFinal_ex"] }
|
|
|
|
override DataFlow::Node getInput(IOType type) {
|
|
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
|
|
or
|
|
result.asIndirectExpr() = this.getArgument(1) and type = SignatureIO()
|
|
or
|
|
result.asExpr() = this.getArgument(2) and type = SignatureSizeIO()
|
|
or
|
|
result.asIndirectExpr() = this.getArgument(3) and type = KeyIO()
|
|
or
|
|
result.asIndirectExpr() = this.getArgument(4) and type = OsslLibContextIO()
|
|
// TODO: arg 5 propq?
|
|
}
|
|
|
|
override DataFlow::Node getOutput(IOType type) {
|
|
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
|
|
}
|
|
|
|
override OperationStepType getStepType() { result = FinalStep() }
|
|
}
|
|
|
|
/**
|
|
* An instance of a signature operation.
|
|
* This is an OpenSSL specific class that extends the base SignatureOperationInstance.
|
|
*/
|
|
class OpenSslSignatureOperationInstance extends Crypto::SignatureOperationInstance instanceof SignatureFinalOperation
|
|
{
|
|
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
|
super.getPrimaryAlgorithmValueConsumer() = result
|
|
}
|
|
|
|
/**
|
|
* Signing, verification or unknown.
|
|
*/
|
|
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
|
|
// NOTE: if this KeyOperationSubtype does not match initialization call's KeyOperationSubtype then we found a bug
|
|
if super.getTarget().getName().toLowerCase().matches("%sign%")
|
|
then result instanceof Crypto::TSignMode
|
|
else
|
|
if super.getTarget().getName().toLowerCase().matches("%verify%")
|
|
then result instanceof Crypto::TVerifyMode
|
|
else result instanceof Crypto::TUnknownKeyOperationMode
|
|
}
|
|
|
|
override Crypto::ConsumerInputDataFlowNode getNonceConsumer() {
|
|
// some signing operations may have explicit nonce generators
|
|
super.getDominatingInitializersToStep(IVorNonceIO()).getInput(IVorNonceIO()) = result
|
|
}
|
|
|
|
override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
|
|
super.getDominatingInitializersToStep(KeyIO()).getInput(KeyIO()) = result
|
|
}
|
|
|
|
override Crypto::ConsumerInputDataFlowNode getSignatureConsumer() {
|
|
super.getDominatingInitializersToStep(SignatureIO()).getInput(SignatureIO()) = result
|
|
}
|
|
|
|
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
|
|
super.getOutputStepFlowingToStep(SignatureIO()).getOutput(SignatureIO()) = result
|
|
}
|
|
|
|
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
|
|
super.getDominatingInitializersToStep(PlaintextIO()).getInput(PlaintextIO()) = result
|
|
}
|
|
|
|
override Crypto::AlgorithmValueConsumer getHashAlgorithmValueConsumer() {
|
|
super
|
|
.getDominatingInitializersToStep(HashAlgorithmIO())
|
|
.getAlgorithmValueConsumerForInput(HashAlgorithmIO()) = result
|
|
or
|
|
// Handle cases where the hash is set through the primary algorithm
|
|
// RSA-SHA256 for example
|
|
// NOTE: assuming the hash would not be overridden, or if it is it is undefined
|
|
// i.e., if the above dominating initializer exists and the primary algorithm
|
|
// specifies a hash, consider both valid hash AVCs.
|
|
// TODO: can this behavior be build into the get dominating initializers?
|
|
super.getPrimaryAlgorithmValueConsumer() = result and
|
|
exists(OpenSslAlgorithmInstance i |
|
|
i.getAvc() = result and i instanceof Crypto::HashAlgorithmInstance
|
|
)
|
|
}
|
|
|
|
override predicate hasHashAlgorithmConsumer() {
|
|
exists(super.getDominatingInitializersToStep(HashAlgorithmIO()))
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A class for signature or MAC operation instances.
|
|
* This is an OpenSSL specific class that extends the base SignatureOrMacOperationInstance.
|
|
*/
|
|
class OpenSslSignatureOrMacOperationInstance extends Crypto::SignatureOrMacOperationInstance instanceof SignatureOrMacFinalOperation
|
|
{
|
|
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
|
super.getPrimaryAlgorithmValueConsumer() = result
|
|
}
|
|
|
|
/**
|
|
* Signing, verification or unknown.
|
|
*/
|
|
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
|
|
result instanceof Crypto::TSignMode or result instanceof Crypto::TMacMode
|
|
}
|
|
|
|
override Crypto::ConsumerInputDataFlowNode getNonceConsumer() {
|
|
// some signing operations may have explicit nonce generators
|
|
super.getDominatingInitializersToStep(IVorNonceIO()).getInput(IVorNonceIO()) = result
|
|
}
|
|
|
|
override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
|
|
super.getDominatingInitializersToStep(KeyIO()).getInput(KeyIO()) = result
|
|
}
|
|
|
|
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
|
|
super.getOutputStepFlowingToStep(SignatureIO()).getOutput(SignatureIO()) = result
|
|
}
|
|
|
|
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
|
|
super.getDominatingInitializersToStep(PlaintextIO()).getInput(PlaintextIO()) = result
|
|
}
|
|
|
|
override Crypto::AlgorithmValueConsumer getHashAlgorithmValueConsumer() {
|
|
super
|
|
.getDominatingInitializersToStep(HashAlgorithmIO())
|
|
.getAlgorithmValueConsumerForInput(HashAlgorithmIO()) = result
|
|
or
|
|
// Handle cases where the hash is set through the primary algorithm
|
|
// RSA-SHA256 for example
|
|
// NOTE: assuming the hash would not be overridden, or if it is it is undefined
|
|
// i.e., if the above dominating initializer exists and the primary algorithm
|
|
// specifies a hash, consider both valid hash AVCs.
|
|
// TODO: can this behavior be build into the get dominating initializers?
|
|
super.getPrimaryAlgorithmValueConsumer() = result and
|
|
exists(OpenSslAlgorithmInstance i |
|
|
i.getAvc() = result and i instanceof Crypto::HashAlgorithmInstance
|
|
)
|
|
}
|
|
|
|
override predicate hasHashAlgorithmConsumer() {
|
|
exists(super.getDominatingInitializersToStep(HashAlgorithmIO()))
|
|
}
|
|
}
|