mirror of
https://github.com/github/codeql.git
synced 2026-04-26 01:05:15 +02:00
.
This commit is contained in:
@@ -9,6 +9,12 @@ module CryptoInput implements InputSig<Lang::Location> {
|
||||
class LocatableElement = Lang::Locatable;
|
||||
|
||||
class UnknownLocation = Lang::UnknownDefaultLocation;
|
||||
|
||||
LocatableElement dfn_to_element(DataFlow::Node node) {
|
||||
result = node.asExpr() or
|
||||
result = node.asParameter() or
|
||||
result = node.asVariable()
|
||||
}
|
||||
}
|
||||
|
||||
module Crypto = CryptographyBase<Lang::Location, CryptoInput>;
|
||||
|
||||
@@ -1,181 +0,0 @@
|
||||
import cpp
|
||||
import experimental.Quantum.Language
|
||||
import EVPCipherConsumers
|
||||
import OpenSSLAlgorithmGetter
|
||||
|
||||
/**
|
||||
* Given a `KnownOpenSSLAlgorithmConstant`, converts this to a cipher family type.
|
||||
* Does not bind if there is know mapping (no mapping to 'unknown' or 'other').
|
||||
*/
|
||||
predicate knownOpenSSLConstantToCipherFamilyType(
|
||||
KnownOpenSSLAlgorithmConstant e, Crypto::TCipherType type
|
||||
) {
|
||||
exists(string name | e.getAlgType().toLowerCase().matches("%encryption") |
|
||||
name = e.getNormalizedName() and
|
||||
(
|
||||
name.matches("AES%") and type instanceof Crypto::AES
|
||||
or
|
||||
name.matches("ARIA") and type instanceof Crypto::ARIA
|
||||
or
|
||||
name.matches("BLOWFISH") and type instanceof Crypto::BLOWFISH
|
||||
or
|
||||
name.matches("BF") and type instanceof Crypto::BLOWFISH
|
||||
or
|
||||
name.matches("CAMELLIA%") and type instanceof Crypto::CAMELLIA
|
||||
or
|
||||
name.matches("CHACHA20") and type instanceof Crypto::CHACHA20
|
||||
or
|
||||
name.matches("CAST5") and type instanceof Crypto::CAST5
|
||||
or
|
||||
name.matches("2DES") and type instanceof Crypto::DoubleDES
|
||||
or
|
||||
name.matches(["3DES", "TRIPLEDES"]) and type instanceof Crypto::TripleDES
|
||||
or
|
||||
name.matches("DES") and type instanceof Crypto::DES
|
||||
or
|
||||
name.matches("DESX") and type instanceof Crypto::DESX
|
||||
or
|
||||
name.matches("GOST%") and type instanceof Crypto::GOST
|
||||
or
|
||||
name.matches("IDEA") and type instanceof Crypto::IDEA
|
||||
or
|
||||
name.matches("KUZNYECHIK") and type instanceof Crypto::KUZNYECHIK
|
||||
or
|
||||
name.matches("MAGMA") and type instanceof Crypto::MAGMA
|
||||
or
|
||||
name.matches("RC2") and type instanceof Crypto::RC2
|
||||
or
|
||||
name.matches("RC4") and type instanceof Crypto::RC4
|
||||
or
|
||||
name.matches("RC5") and type instanceof Crypto::RC5
|
||||
or
|
||||
name.matches("RSA") and type instanceof Crypto::RSA
|
||||
or
|
||||
name.matches("SEED") and type instanceof Crypto::SEED
|
||||
or
|
||||
name.matches("SM4") and type instanceof Crypto::SM4
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
class KnownOpenSSLCipherConstantAlgorithmInstance extends Crypto::CipherAlgorithmInstance instanceof KnownOpenSSLAlgorithmConstant
|
||||
{
|
||||
OpenSSLAlgorithmGetterCall getterCall;
|
||||
|
||||
KnownOpenSSLCipherConstantAlgorithmInstance() {
|
||||
// Not just any known value, but specifically a known cipher operation
|
||||
this.(KnownOpenSSLAlgorithmConstant).getAlgType().toLowerCase().matches("%encryption") and
|
||||
(
|
||||
// Two possibilities:
|
||||
// 1) The source is a literal and flows to a getter, then we know we have an instance
|
||||
// 2) The source is a KnownOpenSSLAlgorithm is call, and we know we have an instance immediately from that
|
||||
// Possibility 1:
|
||||
this instanceof Literal and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.(OpenSSLAlgorithmGetterCall).getValueArgNode() and
|
||||
// Source is `this`
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSSLAlgorithmToAlgorithmGetterFlow::flow(src, sink)
|
||||
)
|
||||
or
|
||||
// Possibility 2:
|
||||
this instanceof DirectGetterCall and getterCall = this
|
||||
)
|
||||
}
|
||||
|
||||
Crypto::AlgorithmConsumer getConsumer() {
|
||||
AlgGetterToAlgConsumerFlow::flow(getterCall.getResultNode(), DataFlow::exprNode(result))
|
||||
}
|
||||
|
||||
override Crypto::ModeOfOperationAlgorithmInstance getModeOfOperationAlgorithm() {
|
||||
// if there is a block mode associated with the same element, then that's the block mode
|
||||
// note, if none are associated, we may need to parse if the cipher is a block cipher
|
||||
// to determine if this is an unknown vs not relevant.
|
||||
result = this
|
||||
}
|
||||
|
||||
override Crypto::PaddingAlgorithmInstance getPaddingAlgorithm() { none() }
|
||||
|
||||
override string getRawAlgorithmName() { result = this.(Literal).getValue().toString() }
|
||||
|
||||
override Crypto::TCipherType getCipherFamily() {
|
||||
knownOpenSSLConstantToCipherFamilyType(this, result)
|
||||
or
|
||||
not knownOpenSSLConstantToCipherFamilyType(this, _) and result = Crypto::OtherCipherType()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a `KnownOpenSSLAlgorithmConstant`, converts this to a cipher family type.
|
||||
* Does not bind if there is know mapping (no mapping to 'unknown' or 'other').
|
||||
*/
|
||||
predicate knownOpenSSLConstantToBlockModeFamilyType(
|
||||
KnownOpenSSLAlgorithmConstant e, Crypto::TBlockCipherModeOperationType type
|
||||
) {
|
||||
exists(string name | e.getAlgType().toLowerCase().matches("block_mode") |
|
||||
name = e.getNormalizedName() and
|
||||
(
|
||||
name.matches("CBC") and type instanceof Crypto::CBC
|
||||
or
|
||||
name.matches("CFB%") and type instanceof Crypto::CFB
|
||||
or
|
||||
name.matches("CTR") and type instanceof Crypto::CTR
|
||||
or
|
||||
name.matches("GCM") and type instanceof Crypto::GCM
|
||||
or
|
||||
name.matches("OFB") and type instanceof Crypto::OFB
|
||||
or
|
||||
name.matches("XTS") and type instanceof Crypto::XTS
|
||||
or
|
||||
name.matches("CCM") and type instanceof Crypto::CCM
|
||||
or
|
||||
name.matches("GCM") and type instanceof Crypto::GCM
|
||||
or
|
||||
name.matches("CCM") and type instanceof Crypto::CCM
|
||||
or
|
||||
name.matches("ECB") and type instanceof Crypto::ECB
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
class KnownOpenSSLBlockModeConstantAlgorithmInstance extends Crypto::ModeOfOperationAlgorithmInstance instanceof KnownOpenSSLAlgorithmConstant
|
||||
{
|
||||
OpenSSLAlgorithmGetterCall getterCall;
|
||||
|
||||
KnownOpenSSLBlockModeConstantAlgorithmInstance() {
|
||||
// Not just any known value, but specifically a known cipher operation
|
||||
this.(KnownOpenSSLAlgorithmConstant).getAlgType().toLowerCase().matches("block_mode") and
|
||||
(
|
||||
// Two possibilities:
|
||||
// 1) The source is a literal and flows to a getter, then we know we have an instance
|
||||
// 2) The source is a KnownOpenSSLAlgorithm is call, and we know we have an instance immediately from that
|
||||
// Possibility 1:
|
||||
this instanceof Literal and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.(OpenSSLAlgorithmGetterCall).getValueArgNode() and
|
||||
// Source is `this`
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSSLAlgorithmToAlgorithmGetterFlow::flow(src, sink)
|
||||
)
|
||||
or
|
||||
// Possibility 2:
|
||||
this instanceof DirectGetterCall and getterCall = this
|
||||
)
|
||||
}
|
||||
|
||||
override Crypto::TBlockCipherModeOperationType getModeType() {
|
||||
knownOpenSSLConstantToBlockModeFamilyType(this, result)
|
||||
or
|
||||
not knownOpenSSLConstantToBlockModeFamilyType(this, _) and result = Crypto::OtherMode()
|
||||
}
|
||||
|
||||
// NOTE: I'm not going to attempt to parse out the mode specific part, so returning
|
||||
// the same as the raw name for now.
|
||||
override string getRawModeAlgorithmName() { result = this.(Literal).getValue().toString() }
|
||||
|
||||
override string getRawAlgorithmName() { result = this.getRawModeAlgorithmName() }
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
import experimental.Quantum.Language
|
||||
import CtxFlow as CTXFlow
|
||||
|
||||
module EncValToInitEncArgConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source.asExpr().getValue().toInt() in [0, 1] }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(EVP_Cipher_Inititalizer initCall | sink.asExpr() = initCall.getOperataionSubtypeArg())
|
||||
}
|
||||
}
|
||||
|
||||
module EncValToInitEncArgFlow = DataFlow::Global<EncValToInitEncArgConfig>;
|
||||
|
||||
int getEncConfigValue(Expr e) {
|
||||
exists(EVP_Cipher_Inititalizer initCall | e = initCall.getOperataionSubtypeArg()) and
|
||||
exists(DataFlow::Node a, DataFlow::Node b |
|
||||
EncValToInitEncArgFlow::flow(a, b) and b.asExpr() = e and result = a.asExpr().getValue().toInt()
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[i]
|
||||
Crypto::CipherOperationSubtype intToCipherOperationSubtype(int i) {
|
||||
if i = 0
|
||||
then result instanceof Crypto::EncryptionSubtype
|
||||
else
|
||||
if i = 1
|
||||
then result instanceof Crypto::DecryptionSubtype
|
||||
else result instanceof Crypto::UnknownCipherOperationSubtype
|
||||
}
|
||||
|
||||
// TODO: need to add key consumer
|
||||
abstract class EVP_Cipher_Inititalizer extends Call {
|
||||
Expr getContextArg() { result = this.(Call).getArgument(0) }
|
||||
|
||||
Expr getAlgorithmArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
abstract Expr getKeyArg();
|
||||
|
||||
abstract Expr getIVArg();
|
||||
|
||||
// abstract Crypto::CipherOperationSubtype getCipherOperationSubtype();
|
||||
|
||||
abstract Expr getOperataionSubtypeArg();
|
||||
|
||||
Crypto::CipherOperationSubtype getCipherOperationSubtype() {
|
||||
if this.(Call).getTarget().getName().toLowerCase().matches("%encrypt%")
|
||||
then result instanceof Crypto::EncryptionSubtype
|
||||
else
|
||||
if this.(Call).getTarget().getName().toLowerCase().matches("%decrypt%")
|
||||
then result instanceof Crypto::DecryptionSubtype
|
||||
else
|
||||
if exists(getEncConfigValue(this.getOperataionSubtypeArg()))
|
||||
then result = intToCipherOperationSubtype(getEncConfigValue(this.getOperataionSubtypeArg()))
|
||||
else result instanceof Crypto::UnknownCipherOperationSubtype
|
||||
}
|
||||
}
|
||||
|
||||
abstract class EVP_EX_Initializer extends EVP_Cipher_Inititalizer {
|
||||
override Expr getKeyArg() { result = this.(Call).getArgument(3) }
|
||||
|
||||
override Expr getIVArg() { result = this.(Call).getArgument(4) }
|
||||
}
|
||||
|
||||
abstract class EVP_EX2_Initializer extends EVP_Cipher_Inititalizer {
|
||||
override Expr getKeyArg() { result = this.(Call).getArgument(2) }
|
||||
|
||||
override Expr getIVArg() { result = this.(Call).getArgument(3) }
|
||||
}
|
||||
|
||||
class EVP_Cipher_EX_Init_Call extends EVP_EX_Initializer {
|
||||
EVP_Cipher_EX_Init_Call() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_EncryptInit_ex", "EVP_DecryptInit_ex", "EVP_CipherInit_ex"
|
||||
]
|
||||
}
|
||||
|
||||
override Expr getOperataionSubtypeArg() {
|
||||
this.(Call).getTarget().getName().toLowerCase().matches("%cipherinit%") and
|
||||
result = this.(Call).getArgument(5)
|
||||
}
|
||||
}
|
||||
|
||||
// abstract class EVP_CipherInit extends EVP_Cipher_Inititalizer{
|
||||
// abstract Expr getOperataionSubtypeArg();
|
||||
// }
|
||||
// class EVP_CipherInit_ex_Call extends EVP_EX_Initializer, EVP_CipherInit {
|
||||
// EVP_CipherInit_ex_Call() { this.(Call).getTarget().getName() = "EVP_CipherInit_ex" }
|
||||
// override Crypto::CipherOperationSubtype getCipherOperationSubtype() {
|
||||
// result instanceof Crypto::EncryptionSubtype
|
||||
// }
|
||||
// override Expr getOperataionSubtypeArg(){
|
||||
// result = this.(Call).getArgument(5)
|
||||
// }
|
||||
// }
|
||||
// class EVP_CipherInit_ex2_Call extends EVP_EX_Initializer, EVP_CipherInit {
|
||||
// EVP_CipherInit_ex2_Call() { this.(Call).getTarget().getName() = "EVP_CipherInit_ex2" }
|
||||
// override Crypto::CipherOperationSubtype getCipherOperationSubtype() {
|
||||
// result instanceof Crypto::EncryptionSubtype
|
||||
// }
|
||||
// override Expr getOperataionSubtypeArg(){
|
||||
// result = this.(Call).getArgument(4)
|
||||
// }
|
||||
// }
|
||||
class EVP_Cipher_EX2_or_Simple_Init_Call extends EVP_EX2_Initializer {
|
||||
EVP_Cipher_EX2_or_Simple_Init_Call() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_EncryptInit_ex2", "EVP_DecryptInit_ex2", "EVP_CipherInit_ex2",
|
||||
"EVP_EncryptInit", "EVP_DecryptInit", "EVP_CipherInit"
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
override Expr getOperataionSubtypeArg() {
|
||||
this.(Call).getTarget().getName().toLowerCase().matches("%cipherinit%") and
|
||||
result = this.(Call).getArgument(4)
|
||||
}
|
||||
}
|
||||
|
||||
class EVP_CipherInit_SKEY_Call extends EVP_EX2_Initializer {
|
||||
EVP_CipherInit_SKEY_Call() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_CipherInit_SKEY"
|
||||
]
|
||||
}
|
||||
|
||||
override Expr getOperataionSubtypeArg() {
|
||||
result = this.(Call).getArgument(5)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// class EVP_CipherInit extends EVP_Cipher_Inititalizer {
|
||||
// EVP_CipherInit() { this.(Call).getTarget().getName() = "EVP_CipherInit" }
|
||||
// override Expr getKeyArg() { result = this.(Call).getArgument(2) }
|
||||
// override Expr getIVArg() { result = this.(Call).getArgument(3) }
|
||||
// override Crypto::CipherOperationSubtype getCipherOperationSubtype() {
|
||||
// result instanceof Crypto::EncryptionSubtype
|
||||
// }
|
||||
// }
|
||||
class EVPCipherInitializerAlgorithmArgument extends Expr {
|
||||
EVPCipherInitializerAlgorithmArgument() {
|
||||
exists(EVP_Cipher_Inititalizer initCall | this = initCall.getAlgorithmArg())
|
||||
}
|
||||
}
|
||||
class EVPCipherInitializerKeyArgument extends Expr {
|
||||
EVPCipherInitializerKeyArgument() {
|
||||
exists(EVP_Cipher_Inititalizer initCall | this = initCall.getKeyArg())
|
||||
}
|
||||
}
|
||||
class EVPCipherInitializerIVArgument extends Expr {
|
||||
EVPCipherInitializerIVArgument() { exists(EVP_Cipher_Inititalizer initCall | this = initCall.getIVArg()) }
|
||||
}
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
import experimental.Quantum.Language
|
||||
import CtxFlow as CTXFlow
|
||||
import EVPCipherInitializer
|
||||
import EVPCipherConsumers
|
||||
|
||||
//https://docs.openssl.org/master/man3/EVP_EncryptInit/#synopsis
|
||||
abstract class EVP_Cipher_Operation extends Crypto::CipherOperationInstance instanceof Call {
|
||||
Expr getContextArg() { result = this.(Call).getArgument(0) }
|
||||
|
||||
abstract Expr getInputArg();
|
||||
|
||||
Expr getOutputArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
override Crypto::CipherOperationSubtype getCipherOperationSubtype() {
|
||||
result instanceof Crypto::EncryptionSubtype and
|
||||
this.(Call).getTarget().getName().toLowerCase().matches("%encrypt%")
|
||||
or
|
||||
result instanceof Crypto::DecryptionSubtype and
|
||||
this.(Call).getTarget().getName().toLowerCase().matches("%decrypt%")
|
||||
or
|
||||
result = this.getInitCall().getCipherOperationSubtype() and
|
||||
this.(Call).getTarget().getName().toLowerCase().matches("%cipher%")
|
||||
}
|
||||
|
||||
EVP_Cipher_Inititalizer getInitCall() {
|
||||
CTXFlow::ctxFlowsTo(result.getContextArg(), this.getContextArg())
|
||||
}
|
||||
|
||||
override Crypto::NonceArtifactConsumer getNonceConsumer() {
|
||||
this.getInitCall().getIVArg() = result
|
||||
}
|
||||
|
||||
override Crypto::CipherInputConsumer getInputConsumer() { this.getInputArg() = result }
|
||||
|
||||
override Crypto::CipherOutputArtifactInstance getOutputArtifact() { this.getOutputArg() = result }
|
||||
|
||||
override Crypto::AlgorithmConsumer getAlgorithmConsumer() {
|
||||
this.getInitCall().getAlgorithmArg() = result
|
||||
}
|
||||
}
|
||||
|
||||
abstract class EVP_Update_Call extends EVP_Cipher_Operation { }
|
||||
|
||||
abstract class EVP_Final_Call extends EVP_Cipher_Operation {
|
||||
override Expr getInputArg() { none() }
|
||||
}
|
||||
|
||||
class EVP_Cipher_Call extends EVP_Cipher_Operation {
|
||||
EVP_Cipher_Call() { this.(Call).getTarget().getName() = "EVP_Cipher" }
|
||||
|
||||
override Expr getInputArg() { result = this.(Call).getArgument(2) }
|
||||
}
|
||||
|
||||
class EVP_Encrypt_Decrypt_or_Cipher_Update_Call extends EVP_Update_Call {
|
||||
EVP_Encrypt_Decrypt_or_Cipher_Update_Call() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_EncryptUpdate", "EVP_DecryptUpdate", "EVP_CipherUpdate"
|
||||
]
|
||||
}
|
||||
|
||||
override Expr getInputArg() { result = this.(Call).getArgument(3) }
|
||||
}
|
||||
|
||||
class EVP_Encrypt_Decrypt_or_Cipher_Final_Call extends EVP_Final_Call {
|
||||
EVP_Encrypt_Decrypt_or_Cipher_Final_Call() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_EncryptFinal_ex", "EVP_DecryptFinal_ex", "EVP_CipherFinal_ex", "EVP_EncryptFinal",
|
||||
"EVP_DecryptFinal", "EVP_CipherFinal"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
class EVP_PKEY_Operation extends EVP_Cipher_Operation {
|
||||
EVP_PKEY_Operation() {
|
||||
this.(Call).getTarget().getName() in ["EVP_PKEY_decrypt", "EVP_PKEY_encrypt"]
|
||||
}
|
||||
|
||||
override Expr getInputArg() { result = this.(Call).getArgument(3) }
|
||||
// TODO: how PKEY is initialized is different that symmetric cipher
|
||||
// Consider making an entirely new class for this and specializing
|
||||
// the get init call
|
||||
}
|
||||
|
||||
class EVPCipherOutput extends CipherOutputArtifact {
|
||||
EVPCipherOutput() { exists(EVP_Cipher_Operation op | op.getOutputArg() = this) }
|
||||
|
||||
override DataFlow::Node getOutputNode() { result.asExpr() = this }
|
||||
}
|
||||
|
||||
class EVPCipherInputArgument extends Expr {
|
||||
EVPCipherInputArgument() { exists(EVP_Cipher_Operation op | op.getInputArg() = this) }
|
||||
}
|
||||
@@ -3,127 +3,93 @@ import semmle.code.cpp.dataflow.new.DataFlow
|
||||
|
||||
module OpenSSLModel {
|
||||
import experimental.Quantum.Language
|
||||
import experimental.Quantum.OpenSSL.EVPCipherOperation
|
||||
import experimental.Quantum.OpenSSL.EVPHashOperation
|
||||
import experimental.Quantum.OpenSSL.EVPCipherAlgorithmSource
|
||||
import experimental.Quantum.OpenSSL.EVPHashAlgorithmSource
|
||||
import experimental.Quantum.OpenSSL.Random
|
||||
// Imports the additional algorithm flow step for OpenSSL
|
||||
import experimental.Quantum.OpenSSL.OpenSSLAlgorithmGetter
|
||||
|
||||
|
||||
// // TODO: trace CTX from init variants to the context arg of EVP update calls
|
||||
// //https://docs.openssl.org/master/man3/EVP_EncryptInit/#synopsis
|
||||
// abstract class EVP_Cipher_Init_Call extends Call {
|
||||
// Expr getContextArg() { result = this.getArgument(0) }
|
||||
// abstract Expr getKeyArg();
|
||||
|
||||
// abstract Expr getIVArg();
|
||||
|
||||
// abstract Crypto::CipherOperationSubtype getCipherOperationSubtype();
|
||||
// }
|
||||
|
||||
// abstract class EVP_Cipher_EX_Init_Call extends EVP_Cipher_Init_Call {
|
||||
// override Expr getKeyArg() { result = this.getArgument(3) }
|
||||
|
||||
// override Expr getIVArg() { result = this.getArgument(4) }
|
||||
// }
|
||||
|
||||
// abstract class EVP_Cipher_EX2_Init_Call extends EVP_Cipher_Init_Call {
|
||||
// override Expr getKeyArg() { result = this.getArgument(2) }
|
||||
|
||||
// override Expr getIVArg() { result = this.getArgument(3) }
|
||||
// }
|
||||
|
||||
// abstract class EVP_Cipher_Operation_Call extends Crypto::CipherOperationInstance instanceof Call {
|
||||
// Expr getContextArg() { result = this.(Call).getArgument(0) }
|
||||
// abstract Expr getInputArg();
|
||||
// Expr getOutputArg() { result = this.(Call).getArgument(1) }
|
||||
// abstract Expr getInitCall();
|
||||
// }
|
||||
|
||||
// abstract class EVP_Update_Call extends EVP_Cipher_Operation_Call {
|
||||
// override Expr getInputArg() { result = this.(Call).getArgument(3) }
|
||||
|
||||
// }
|
||||
|
||||
// abstract class EVP_Final_Call extends EVP_Cipher_Operation_Call{
|
||||
// override Expr getInputArg() { none() }
|
||||
|
||||
// }
|
||||
|
||||
// class EVP_Cipher_Call extends EVP_Cipher_Operation_Call{
|
||||
// // TODO/QUESTION: what is the better way to do this?
|
||||
// EVP_Cipher_Call() { this.(Call).getTarget().getName() = "EVP_Cipher" }
|
||||
|
||||
// override Expr getInputArg() { result = this.(Call).getArgument(2) }
|
||||
|
||||
// override Expr getOutputArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
// override Crypto::CipherOperationSubtype getCipherOperationSubtype(){
|
||||
// result instanceof Crypto::EncryptionSubtype
|
||||
// }
|
||||
|
||||
// override Expr getInitCall(){
|
||||
// //TODO:
|
||||
// none()
|
||||
// }
|
||||
|
||||
// override Crypto::NonceArtifactConsumer getNonceConsumer(){
|
||||
// none()
|
||||
// }
|
||||
|
||||
// override Crypto::CipherInputConsumer getInputConsumer(){
|
||||
// none()
|
||||
// }
|
||||
|
||||
// override Crypto::CipherOutputArtifactInstance getOutputArtifact(){
|
||||
// none()
|
||||
// }
|
||||
|
||||
// override Crypto::AlgorithmConsumer getAlgorithmConsumer(){
|
||||
// none()
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
import experimental.Quantum.OpenSSL.AlgorithmInstances.Instances
|
||||
import experimental.Quantum.OpenSSL.AlgorithmValueConsumers.AlgorithmValueConsumers
|
||||
import experimental.Quantum.OpenSSL.Operations.Operations
|
||||
// import experimental.Quantum.OpenSSL.EVPCipherOperation
|
||||
// import experimental.Quantum.OpenSSL.EVPHashOperation
|
||||
// import experimental.Quantum.OpenSSL.EVPCipherAlgorithmSource
|
||||
// import experimental.Quantum.OpenSSL.EVPHashAlgorithmSource
|
||||
// import experimental.Quantum.OpenSSL.Random
|
||||
// // Imports the additional algorithm flow step for OpenSSL
|
||||
// import experimental.Quantum.OpenSSL.OpenSSLAlgorithmGetter
|
||||
// // TODO: trace CTX from init variants to the context arg of EVP update calls
|
||||
// //https://docs.openssl.org/master/man3/EVP_EncryptInit/#synopsis
|
||||
// abstract class EVP_Cipher_Init_Call extends Call {
|
||||
// Expr getContextArg() { result = this.getArgument(0) }
|
||||
// abstract Expr getKeyArg();
|
||||
// abstract Expr getIVArg();
|
||||
// abstract Crypto::CipherOperationSubtype getCipherOperationSubtype();
|
||||
// }
|
||||
// abstract class EVP_Cipher_EX_Init_Call extends EVP_Cipher_Init_Call {
|
||||
// override Expr getKeyArg() { result = this.getArgument(3) }
|
||||
// override Expr getIVArg() { result = this.getArgument(4) }
|
||||
// }
|
||||
// abstract class EVP_Cipher_EX2_Init_Call extends EVP_Cipher_Init_Call {
|
||||
// override Expr getKeyArg() { result = this.getArgument(2) }
|
||||
// override Expr getIVArg() { result = this.getArgument(3) }
|
||||
// }
|
||||
// abstract class EVP_Cipher_Operation_Call extends Crypto::CipherOperationInstance instanceof Call {
|
||||
// Expr getContextArg() { result = this.(Call).getArgument(0) }
|
||||
// abstract Expr getInputArg();
|
||||
// Expr getOutputArg() { result = this.(Call).getArgument(1) }
|
||||
// abstract Expr getInitCall();
|
||||
// }
|
||||
// abstract class EVP_Update_Call extends EVP_Cipher_Operation_Call {
|
||||
// override Expr getInputArg() { result = this.(Call).getArgument(3) }
|
||||
// }
|
||||
// abstract class EVP_Final_Call extends EVP_Cipher_Operation_Call{
|
||||
// override Expr getInputArg() { none() }
|
||||
// }
|
||||
// class EVP_Cipher_Call extends EVP_Cipher_Operation_Call{
|
||||
// // TODO/QUESTION: what is the better way to do this?
|
||||
// EVP_Cipher_Call() { this.(Call).getTarget().getName() = "EVP_Cipher" }
|
||||
// override Expr getInputArg() { result = this.(Call).getArgument(2) }
|
||||
// override Expr getOutputArg() { result = this.(Call).getArgument(1) }
|
||||
// override Crypto::CipherOperationSubtype getCipherOperationSubtype(){
|
||||
// result instanceof Crypto::EncryptionSubtype
|
||||
// }
|
||||
// override Expr getInitCall(){
|
||||
// //TODO:
|
||||
// none()
|
||||
// }
|
||||
// override Crypto::NonceArtifactConsumer getNonceConsumer(){
|
||||
// none()
|
||||
// }
|
||||
// override Crypto::CipherInputConsumer getInputConsumer(){
|
||||
// none()
|
||||
// }
|
||||
// override Crypto::CipherOutputArtifactInstance getOutputArtifact(){
|
||||
// none()
|
||||
// }
|
||||
// override Crypto::AlgorithmConsumer getAlgorithmConsumer(){
|
||||
// none()
|
||||
// }
|
||||
// }
|
||||
//TODO: what about EVP_CIpher
|
||||
|
||||
|
||||
// class EVP_EncryptUpdateCall extends Crypto::CipherOperationInstance instanceof Call {
|
||||
// // NICK QUESTION: is there a better way to tie this to openssl?
|
||||
// EVP_EncryptUpdateCall() { this.getTarget().getName() = "EVP_EncryptUpdate" }
|
||||
|
||||
// Expr getContextArg() { result = super.getArgument(0) }
|
||||
|
||||
// Expr getInputArg() { result = super.getArgument(3) }
|
||||
|
||||
// Expr getOutputArg() { result = super.getArgument(1) }
|
||||
|
||||
// override Crypto::CipherOperationSubtype getCipherOperationSubtype(){
|
||||
// result instanceof Crypto::EncryptionSubtype
|
||||
// }
|
||||
|
||||
// override Crypto::NonceArtifactConsumer getNonceConsumer(){
|
||||
// none()
|
||||
// }
|
||||
|
||||
// override Crypto::CipherInputConsumer getInputConsumer(){
|
||||
// none()
|
||||
// }
|
||||
|
||||
// override Crypto::CipherOutputArtifactInstance getOutputArtifact(){
|
||||
// none()
|
||||
// }
|
||||
|
||||
// override Crypto::AlgorithmConsumer getAlgorithmConsumer(){
|
||||
// none()
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
//EVP_EncryptUpdate
|
||||
|
||||
// /**
|
||||
// * Hash function references in OpenSSL.
|
||||
// */
|
||||
@@ -146,34 +112,26 @@ module OpenSSLModel {
|
||||
// or
|
||||
// name = "whirlpool" and algo instanceof Crypto::WHIRLPOOL
|
||||
// }
|
||||
|
||||
// predicate hash_ref_type_mapping(FunctionCallOrMacroAccess ref, string name, Crypto::THashType algo) {
|
||||
// name = ref.getTargetName().regexpCapture("(?:SN_|LN_|EVP_)([a-z0-9]+)", 1) and
|
||||
// hash_ref_type_mapping_known(name, algo)
|
||||
// }
|
||||
|
||||
// class FunctionCallOrMacroAccess extends Element {
|
||||
// FunctionCallOrMacroAccess() { this instanceof FunctionCall or this instanceof MacroAccess }
|
||||
|
||||
// string getTargetName() {
|
||||
// result = this.(FunctionCall).getTarget().getName()
|
||||
// or
|
||||
// result = this.(MacroAccess).getMacroName()
|
||||
// }
|
||||
// }
|
||||
|
||||
// class HashAlgorithmCallOrMacro extends Crypto::HashAlgorithmInstance instanceof FunctionCallOrMacroAccess
|
||||
// {
|
||||
// HashAlgorithmCallOrMacro() { hash_ref_type_mapping(this, _, _) }
|
||||
|
||||
// string getTargetName() { result = this.(FunctionCallOrMacroAccess).getTargetName() }
|
||||
// }
|
||||
|
||||
// class HashAlgorithm extends Crypto::HashAlgorithm {
|
||||
// HashAlgorithmCallOrMacro instance;
|
||||
|
||||
// HashAlgorithm() { this = Crypto::THashAlgorithm(instance) }
|
||||
|
||||
// override string getSHA2OrSHA3DigestSize(Location location) {
|
||||
// (
|
||||
// this.getHashType() instanceof Crypto::SHA2 or
|
||||
@@ -185,16 +143,11 @@ module OpenSSLModel {
|
||||
// location = instance.getLocation()
|
||||
// )
|
||||
// }
|
||||
|
||||
// override string getRawAlgorithmName() { result = instance.getTargetName() }
|
||||
|
||||
// override Crypto::THashType getHashType() { hash_ref_type_mapping(instance, _, result) }
|
||||
|
||||
// Element getInstance() { result = instance }
|
||||
|
||||
// override Location getLocation() { result = instance.getLocation() }
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Data-flow configuration for key derivation algorithm flow to EVP_KDF_derive.
|
||||
// */
|
||||
@@ -202,7 +155,6 @@ module OpenSSLModel {
|
||||
// predicate isSource(DataFlow::Node source) {
|
||||
// source.asExpr() = any(KeyDerivationAlgorithm a).getInstance()
|
||||
// }
|
||||
|
||||
// predicate isSink(DataFlow::Node sink) {
|
||||
// exists(EVP_KDF_derive kdo |
|
||||
// sink.asExpr() = kdo.getCall().getAlgorithmArg()
|
||||
@@ -210,155 +162,113 @@ module OpenSSLModel {
|
||||
// sink.asExpr() = kdo.getCall().getContextArg() // via `EVP_KDF_CTX_set_params`
|
||||
// )
|
||||
// }
|
||||
|
||||
// predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
// none() // TODO
|
||||
// }
|
||||
// }
|
||||
|
||||
// module AlgorithmToEVPKeyDeriveFlow = DataFlow::Global<AlgorithmToEVPKeyDeriveConfig>;
|
||||
|
||||
// predicate algorithm_to_EVP_KDF_derive(KeyDerivationAlgorithm algo, EVP_KDF_derive derive) {
|
||||
// none()
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Key derivation operation (e.g., `EVP_KDF_derive`)
|
||||
// */
|
||||
// class EVP_KDF_derive_FunctionCall extends Crypto::KeyDerivationOperationInstance instanceof FunctionCall
|
||||
// {
|
||||
// EVP_KDF_derive_FunctionCall() { this.getTarget().getName() = "EVP_KDF_derive" }
|
||||
|
||||
// Expr getAlgorithmArg() { result = super.getArgument(3) }
|
||||
|
||||
// Expr getContextArg() { result = super.getArgument(0) }
|
||||
// }
|
||||
|
||||
// class EVP_KDF_derive extends Crypto::KeyDerivationOperation {
|
||||
// EVP_KDF_derive_FunctionCall instance;
|
||||
|
||||
// EVP_KDF_derive() { this = Crypto::TKeyDerivationOperation(instance) }
|
||||
|
||||
// override Crypto::Algorithm getAlgorithm() { algorithm_to_EVP_KDF_derive(result, this) }
|
||||
|
||||
// EVP_KDF_derive_FunctionCall getCall() { result = instance }
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Key derivation algorithm nodes
|
||||
// */
|
||||
// abstract class KeyDerivationAlgorithm extends Crypto::KeyDerivationAlgorithm {
|
||||
// abstract Expr getInstance();
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * `EVP_KDF_fetch` returns a key derivation algorithm.
|
||||
// */
|
||||
// class EVP_KDF_fetch_Call extends FunctionCall {
|
||||
// EVP_KDF_fetch_Call() { this.getTarget().getName() = "EVP_KDF_fetch" }
|
||||
|
||||
// Expr getAlgorithmArg() { result = this.getArgument(1) }
|
||||
// }
|
||||
|
||||
// class EVP_KDF_fetch_AlgorithmArg extends Crypto::KeyDerivationAlgorithmInstance instanceof Expr {
|
||||
// EVP_KDF_fetch_AlgorithmArg() { exists(EVP_KDF_fetch_Call call | this = call.getAlgorithmArg()) }
|
||||
// }
|
||||
|
||||
// predicate kdf_names(string algo) { algo = ["HKDF", "PKCS12KDF", "PBKDF2"] }
|
||||
|
||||
// class KDFAlgorithmStringLiteral extends StringLiteral {
|
||||
// KDFAlgorithmStringLiteral() { kdf_names(this.getValue().toUpperCase()) }
|
||||
// }
|
||||
|
||||
// private module AlgorithmStringToFetchConfig implements DataFlow::ConfigSig {
|
||||
// predicate isSource(DataFlow::Node src) { src.asExpr() instanceof KDFAlgorithmStringLiteral }
|
||||
|
||||
// predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof EVP_KDF_fetch_AlgorithmArg }
|
||||
// }
|
||||
|
||||
// module AlgorithmStringToFetchFlow = DataFlow::Global<AlgorithmStringToFetchConfig>;
|
||||
|
||||
// predicate algorithmStringToKDFFetchArgFlow(
|
||||
// string name, KDFAlgorithmStringLiteral origin, EVP_KDF_fetch_AlgorithmArg arg
|
||||
// ) {
|
||||
// origin.getValue().toUpperCase() = name and
|
||||
// AlgorithmStringToFetchFlow::flow(DataFlow::exprNode(origin), DataFlow::exprNode(arg))
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * HKDF key derivation algorithm.
|
||||
// */
|
||||
// class HKDF extends KeyDerivationAlgorithm, Crypto::HKDF {
|
||||
// KDFAlgorithmStringLiteral origin;
|
||||
// EVP_KDF_fetch_AlgorithmArg instance;
|
||||
|
||||
// HKDF() {
|
||||
// this = Crypto::TKeyDerivationAlgorithm(instance) and
|
||||
// algorithmStringToKDFFetchArgFlow("HKDF", origin, instance)
|
||||
// }
|
||||
|
||||
// override string getRawAlgorithmName() { result = origin.getValue() }
|
||||
|
||||
// override Crypto::HashAlgorithm getHashAlgorithm() { none() }
|
||||
|
||||
// override Crypto::LocatableElement getOrigin(string name) {
|
||||
// result = origin and name = origin.toString()
|
||||
// }
|
||||
|
||||
// override Expr getInstance() { result = origin }
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * PBKDF2 key derivation algorithm.
|
||||
// */
|
||||
// class PBKDF2 extends KeyDerivationAlgorithm, Crypto::PBKDF2 {
|
||||
// KDFAlgorithmStringLiteral origin;
|
||||
// EVP_KDF_fetch_AlgorithmArg instance;
|
||||
|
||||
// PBKDF2() {
|
||||
// this = Crypto::TKeyDerivationAlgorithm(instance) and
|
||||
// algorithmStringToKDFFetchArgFlow("PBKDF2", origin, instance)
|
||||
// }
|
||||
|
||||
// override string getRawAlgorithmName() { result = origin.getValue() }
|
||||
|
||||
// override string getIterationCount(Location location) { none() } // TODO
|
||||
|
||||
// override string getKeyLength(Location location) { none() } // TODO
|
||||
|
||||
// override Crypto::HashAlgorithm getHashAlgorithm() { none() } // TODO
|
||||
|
||||
// override Crypto::LocatableElement getOrigin(string name) {
|
||||
// result = origin and name = origin.toString()
|
||||
// }
|
||||
|
||||
// override Expr getInstance() { result = instance }
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * PKCS12KDF key derivation algorithm.
|
||||
// */
|
||||
// class PKCS12KDF extends KeyDerivationAlgorithm, Crypto::PKCS12KDF {
|
||||
// KDFAlgorithmStringLiteral origin;
|
||||
// EVP_KDF_fetch_AlgorithmArg instance;
|
||||
|
||||
// PKCS12KDF() {
|
||||
// this = Crypto::TKeyDerivationAlgorithm(instance) and
|
||||
// algorithmStringToKDFFetchArgFlow("PKCS12KDF", origin, instance)
|
||||
// }
|
||||
|
||||
// override string getRawAlgorithmName() { result = origin.getValue() }
|
||||
|
||||
// override string getIterationCount(Location location) { none() } // TODO
|
||||
|
||||
// override string getIDByte(Location location) { none() } // TODO
|
||||
|
||||
// override Crypto::HashAlgorithm getHashAlgorithm() { none() } // TODO
|
||||
|
||||
// override Crypto::LocatableElement getOrigin(string name) {
|
||||
// result = origin and name = origin.toString()
|
||||
// }
|
||||
|
||||
// override Expr getInstance() { result = instance }
|
||||
// }
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -318,6 +318,8 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
|
||||
abstract class CipherOutputArtifactInstance extends ArtifactInstance {
|
||||
final override DataFlowNode getInputNode() { none() }
|
||||
|
||||
override predicate isConsumerArtifact() { none() }
|
||||
}
|
||||
|
||||
// Artifacts that may be outputs or inputs
|
||||
@@ -967,6 +969,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
|
||||
newtype TPaddingType =
|
||||
PKCS1_v1_5() or // RSA encryption/signing padding
|
||||
PSS() or
|
||||
PKCS7() or // Standard block cipher padding (PKCS5 for 8-byte blocks)
|
||||
ANSI_X9_23() or // Zero-padding except last byte = padding length
|
||||
NoPadding() or // Explicit no-padding
|
||||
@@ -988,6 +991,8 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
|
||||
final private predicate paddingToNameMapping(TPaddingType type, string name) {
|
||||
type instanceof PKCS1_v1_5 and name = "PKCS1_v1_5"
|
||||
or
|
||||
type instanceof PSS and name = "PSS"
|
||||
or
|
||||
type instanceof PKCS7 and name = "PKCS7"
|
||||
or
|
||||
type instanceof ANSI_X9_23 and name = "ANSI_X9_23"
|
||||
|
||||
Reference in New Issue
Block a user