mirror of
https://github.com/github/codeql.git
synced 2026-04-22 23:35:14 +02:00
Misc updates for OpenSSL modeling to trace algorithm literals to known alg getters, and converting the literal to a TCipherType.
This commit is contained in:
@@ -49,19 +49,19 @@ module GenericDataSourceUniversalFlowConfig implements DataFlow::ConfigSig {
|
||||
|
||||
|
||||
|
||||
// TODO: I think this will be inefficient, no?
|
||||
class ConstantDataSource extends Crypto::GenericConstantOrAllocationSource instanceof Literal {
|
||||
override DataFlow::Node getOutputNode() {
|
||||
result.asExpr() = this
|
||||
}
|
||||
// // TODO: I think this will be inefficient, no?
|
||||
// class ConstantDataSource extends Crypto::GenericConstantOrAllocationSource instanceof Literal {
|
||||
// override DataFlow::Node getOutputNode() {
|
||||
// result.asExpr() = this
|
||||
// }
|
||||
|
||||
override predicate flowsTo(Crypto::FlowAwareElement other) {
|
||||
// TODO: separate config to avoid blowing up data-flow analysis
|
||||
GenericDataSourceUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
|
||||
}
|
||||
// override predicate flowsTo(Crypto::FlowAwareElement other) {
|
||||
// // TODO: separate config to avoid blowing up data-flow analysis
|
||||
// GenericDataSourceUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
|
||||
// }
|
||||
|
||||
override string getAdditionalDescription() { result = this.toString() }
|
||||
}
|
||||
// override string getAdditionalDescription() { result = this.toString() }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Definitions of various generic data sources
|
||||
|
||||
@@ -8,17 +8,14 @@ class CTXType extends Type {
|
||||
}
|
||||
|
||||
class CTXPointerExpr extends Expr {
|
||||
CTXPointerExpr() {
|
||||
this.getType() instanceof CTXType and
|
||||
this.getType() instanceof PointerType
|
||||
CTXPointerExpr() {
|
||||
this.getType() instanceof CTXType and
|
||||
this.getType() instanceof PointerType
|
||||
}
|
||||
}
|
||||
|
||||
class CTXPointerArgument extends CTXPointerExpr {
|
||||
CTXPointerArgument() {
|
||||
|
||||
exists(Call c | c.getAnArgument() = this)
|
||||
}
|
||||
CTXPointerArgument() { exists(Call c | c.getAnArgument() = this) }
|
||||
|
||||
Call getCall() { result.getAnArgument() = this }
|
||||
}
|
||||
@@ -31,14 +28,14 @@ class CTXClearCall extends Call {
|
||||
}
|
||||
|
||||
class CTXCopyOutArgCall extends Call {
|
||||
CTXCopyOutArgCall() {
|
||||
CTXCopyOutArgCall() {
|
||||
this.getTarget().getName().toLowerCase().matches(["%copy%"]) and
|
||||
this.getAnArgument() instanceof CTXPointerArgument
|
||||
}
|
||||
}
|
||||
|
||||
class CTXCopyReturnCall extends Call {
|
||||
CTXCopyReturnCall() {
|
||||
CTXCopyReturnCall() {
|
||||
this.getTarget().getName().toLowerCase().matches(["%dup%"]) and
|
||||
this.getAnArgument() instanceof CTXPointerArgument and
|
||||
this instanceof CTXPointerExpr
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
import cpp
|
||||
import experimental.Quantum.Language
|
||||
import EVPCipherConsumers
|
||||
import OpenSSLAlgorithmGetter
|
||||
|
||||
predicate literalToCipherFamilyType(Literal e, Crypto::TCipherType type) {
|
||||
exists(string name, string algType | algType.toLowerCase().matches("%encryption") |
|
||||
resolveAlgorithmFromLiteral(e, name, algType) 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 CipherKnownAlgorithmLiteralAlgorithmInstance extends Crypto::CipherAlgorithmInstance instanceof Literal
|
||||
{
|
||||
CipherKnownAlgorithmLiteralAlgorithmInstance() {
|
||||
exists(EVPCipherGetterCall c, DataFlow::Node src, DataFlow::Node sink |
|
||||
sink = c.getValueArgNode() and
|
||||
src.asExpr() = this and
|
||||
KnownAlgorithmLiteralToAlgorithmGetterFlow::flow(src, sink) and
|
||||
// Not just any known value, but specifically a known cipher operation
|
||||
exists(string algType |
|
||||
resolveAlgorithmFromLiteral(src.asExpr(), _, algType) and
|
||||
algType.toLowerCase().matches("%encryption")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
Crypto::AlgorithmConsumer getConsumer() { none() } //result = consumer }
|
||||
|
||||
override Crypto::ModeOfOperationAlgorithmInstance getModeOfOperationAlgorithm() {
|
||||
none() // TODO: provider defaults
|
||||
}
|
||||
|
||||
override Crypto::PaddingAlgorithmInstance getPaddingAlgorithm() { none() }
|
||||
|
||||
override string getRawAlgorithmName() { result = this.(Literal).getValue().toString() }
|
||||
|
||||
override Crypto::TCipherType getCipherFamily() { literalToCipherFamilyType(this, result) }
|
||||
}
|
||||
// override Crypto::TCipherType getCipherFamily() {
|
||||
// if this.cipherNameMappingKnown(_, super.getAlgorithmName())
|
||||
// then this.cipherNameMappingKnown(result, super.getAlgorithmName())
|
||||
// else result instanceof Crypto::OtherCipherType
|
||||
// }
|
||||
// bindingset[name]
|
||||
// private predicate cipherNameMappingKnown(Crypto::TCipherType type, string name) {
|
||||
// name = "AES" and
|
||||
// type instanceof Crypto::AES
|
||||
// or
|
||||
// name = "DES" and
|
||||
// type instanceof Crypto::DES
|
||||
// or
|
||||
// name = "TripleDES" and
|
||||
// type instanceof Crypto::TripleDES
|
||||
// or
|
||||
// name = "IDEA" and
|
||||
// type instanceof Crypto::IDEA
|
||||
// or
|
||||
// name = "CAST5" and
|
||||
// type instanceof Crypto::CAST5
|
||||
// or
|
||||
// name = "ChaCha20" and
|
||||
// type instanceof Crypto::ChaCha20
|
||||
// or
|
||||
// name = "RC4" and
|
||||
// type instanceof Crypto::RC4
|
||||
// or
|
||||
// name = "RC5" and
|
||||
// type instanceof Crypto::RC5
|
||||
// or
|
||||
// name = "RSA" and
|
||||
// type instanceof Crypto::RSA
|
||||
// }
|
||||
// private predicate modeToNameMappingKnown(Crypto::TBlockCipherModeOperationType type, string name) {
|
||||
// type instanceof Crypto::ECB and name = "ECB"
|
||||
// or
|
||||
// type instanceof Crypto::CBC and name = "CBC"
|
||||
// or
|
||||
// type instanceof Crypto::GCM and name = "GCM"
|
||||
// or
|
||||
// type instanceof Crypto::CTR and name = "CTR"
|
||||
// or
|
||||
// type instanceof Crypto::XTS and name = "XTS"
|
||||
// or
|
||||
// type instanceof Crypto::CCM and name = "CCM"
|
||||
// or
|
||||
// type instanceof Crypto::SIV and name = "SIV"
|
||||
// or
|
||||
// type instanceof Crypto::OCB and name = "OCB"
|
||||
// }
|
||||
// override Crypto::TBlockCipherModeOperationType getModeType() {
|
||||
// if this.modeToNameMappingKnown(_, super.getMode())
|
||||
// then this.modeToNameMappingKnown(result, super.getMode())
|
||||
// else result instanceof Crypto::OtherMode
|
||||
// }
|
||||
// override string getRawModeAlgorithmName() { result = super.getMode() }
|
||||
// override string getRawPaddingAlgorithmName() { result = super.getPadding() }
|
||||
// bindingset[name]
|
||||
// private predicate paddingToNameMappingKnown(Crypto::TPaddingType type, string name) {
|
||||
// type instanceof Crypto::NoPadding and name = "NOPADDING"
|
||||
// or
|
||||
// type instanceof Crypto::PKCS7 and name = ["PKCS5Padding", "PKCS7Padding"] // TODO: misnomer in the JCA?
|
||||
// or
|
||||
// type instanceof Crypto::OAEP and name.matches("OAEP%") // TODO: handle OAEPWith%
|
||||
// }
|
||||
// }
|
||||
@@ -1,6 +1,6 @@
|
||||
import EVPCipherInitializer
|
||||
import EVPCipherOperation
|
||||
import AlgorithmSource
|
||||
import EVPCipherAlgorithmSource
|
||||
|
||||
|
||||
class EVP_Cipher_Initializer_Algorithm_Consumer extends Crypto::AlgorithmConsumer instanceof EVPCipherInitializerAlgorithmArgument
|
||||
@@ -8,7 +8,7 @@ class EVP_Cipher_Initializer_Algorithm_Consumer extends Crypto::AlgorithmConsume
|
||||
override DataFlow::Node getInputNode() { result.asExpr() = this }
|
||||
|
||||
override Crypto::AlgorithmElement getAKnownAlgorithmSource() {
|
||||
result.(CipherLiteralAlgorithmInstance).getConsumer() = this
|
||||
result.(CipherKnownAlgorithmLiteralAlgorithmInstance).getConsumer() = this
|
||||
}
|
||||
}
|
||||
// //TODO: need a key consumer
|
||||
|
||||
10
cpp/ql/lib/experimental/Quantum/OpenSSL/LibraryDetector.qll
Normal file
10
cpp/ql/lib/experimental/Quantum/OpenSSL/LibraryDetector.qll
Normal file
@@ -0,0 +1,10 @@
|
||||
import cpp
|
||||
|
||||
predicate isPossibleOpenSSLFunction(Function f) {
|
||||
isPossibleOpenSSLLocation(f.getADeclarationLocation())
|
||||
}
|
||||
|
||||
predicate isPossibleOpenSSLLocation(Location l){
|
||||
l.toString().toLowerCase().matches("%openssl%")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,436 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
import LibraryDetector
|
||||
import OpenSSLKnownAlgorithmConstants
|
||||
|
||||
abstract class AlgorithmPassthroughCall extends Call {
|
||||
abstract DataFlow::Node getInNode();
|
||||
|
||||
abstract DataFlow::Node getOutNode();
|
||||
}
|
||||
|
||||
class CopyAndDupAlgorithmPassthroughCall extends AlgorithmPassthroughCall {
|
||||
DataFlow::Node inNode;
|
||||
DataFlow::Node outNode;
|
||||
|
||||
CopyAndDupAlgorithmPassthroughCall() {
|
||||
// Flow out through any return or other argument of the same type
|
||||
// Assume flow in and out is asIndirectExpr or asDefinitingArgument since a pointer is assumed
|
||||
// to be involved
|
||||
// NOTE: not attempting to detect openssl specific copy/dup functions, but anything suspected to be copy/dup
|
||||
this.getTarget().getName().toLowerCase().matches(["%_dup", "%_copy"]) and
|
||||
exists(Expr inArg, Type t |
|
||||
inArg = this.getAnArgument() and t = inArg.getUnspecifiedType().stripType()
|
||||
|
|
||||
inNode.asIndirectExpr() = inArg and
|
||||
(
|
||||
// Case 1: flow through another argument as an out arg of the same type
|
||||
exists(Expr outArg |
|
||||
outArg = this.getAnArgument() and
|
||||
outArg != inArg and
|
||||
outArg.getUnspecifiedType().stripType() = t
|
||||
|
|
||||
outNode.asDefiningArgument() = outArg
|
||||
)
|
||||
or
|
||||
// Case 2: flow through the return value if the result is the same as the intput type
|
||||
exists(Expr outArg | outArg = this and outArg.getUnspecifiedType().stripType() = t |
|
||||
outNode.asIndirectExpr() = outArg
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getInNode() { result = inNode }
|
||||
|
||||
override DataFlow::Node getOutNode() { result = outNode }
|
||||
}
|
||||
|
||||
class NIDToPointerPassthroughCall extends AlgorithmPassthroughCall {
|
||||
DataFlow::Node inNode;
|
||||
DataFlow::Node outNode;
|
||||
|
||||
NIDToPointerPassthroughCall() {
|
||||
this.getTarget().getName() in ["OBJ_nid2obj", "OBJ_nid2ln", "OBJ_nid2sn"] and
|
||||
inNode.asExpr() = this.getArgument(0) and
|
||||
outNode.asExpr() = this
|
||||
//outNode.asIndirectExpr() = this
|
||||
}
|
||||
|
||||
override DataFlow::Node getInNode() { result = inNode }
|
||||
|
||||
override DataFlow::Node getOutNode() { result = outNode }
|
||||
}
|
||||
|
||||
class PointerToPointerPassthroughCall extends AlgorithmPassthroughCall {
|
||||
DataFlow::Node inNode;
|
||||
DataFlow::Node outNode;
|
||||
|
||||
PointerToPointerPassthroughCall() {
|
||||
this.getTarget().getName() = "OBJ_txt2obj" and
|
||||
inNode.asIndirectExpr() = this.getArgument(0) and
|
||||
outNode.asIndirectExpr() = this
|
||||
or
|
||||
//outNode.asExpr() = this
|
||||
this.getTarget().getName() in ["OBJ_obj2txt", "i2t_ASN1_OBJECT"] and
|
||||
inNode.asIndirectExpr() = this.getArgument(2) and
|
||||
outNode.asDefiningArgument() = this.getArgument(0)
|
||||
}
|
||||
|
||||
override DataFlow::Node getInNode() { result = inNode }
|
||||
|
||||
override DataFlow::Node getOutNode() { result = outNode }
|
||||
}
|
||||
|
||||
class PointerToNIDPassthroughCall extends AlgorithmPassthroughCall {
|
||||
DataFlow::Node inNode;
|
||||
DataFlow::Node outNode;
|
||||
|
||||
PointerToNIDPassthroughCall() {
|
||||
this.getTarget().getName() in ["OBJ_obj2nid", "OBJ_ln2nid", "OBJ_sn2nid", "OBJ_txt2nid"] and
|
||||
(
|
||||
inNode.asIndirectExpr() = this.getArgument(0)
|
||||
or
|
||||
inNode.asExpr() = this.getArgument(0)
|
||||
) and
|
||||
outNode.asExpr() = this
|
||||
}
|
||||
|
||||
override DataFlow::Node getInNode() { result = inNode }
|
||||
|
||||
override DataFlow::Node getOutNode() { result = outNode }
|
||||
}
|
||||
|
||||
predicate knownPassThroughStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(AlgorithmPassthroughCall c | c.getInNode() = node1 and c.getOutNode() = node2)
|
||||
}
|
||||
|
||||
abstract class OpenSSLAlgorithmGetterCall extends Call {
|
||||
abstract DataFlow::Node getValueArgNode();
|
||||
|
||||
abstract DataFlow::Node getResultNode();
|
||||
|
||||
abstract Expr getValueArgExpr();
|
||||
|
||||
abstract Expr getResultExpr();
|
||||
}
|
||||
|
||||
module KnownAlgorithmLiteralToAlgorithmGetterConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
(
|
||||
source.asExpr() instanceof Literal and
|
||||
// 0 sources, for nid are unknown, and 0 otherwise represents a null assignment (ignore as unknown)
|
||||
exists(source.asExpr().(Literal).getValue().toInt()) implies source.asExpr().(Literal).getValue().toInt() != 0
|
||||
//resolveAlgorithmFromLiteral(source.asExpr(),_,_)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(OpenSSLAlgorithmGetterCall c | c.getValueArgNode() = sink)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
// False positive reducer, don't flow out through argv
|
||||
exists(VariableAccess va, Variable v |
|
||||
v.getAnAccess() = va and va = node.asExpr()
|
||||
or
|
||||
va = node.asIndirectExpr()
|
||||
|
|
||||
v.getName().matches("%argv")
|
||||
)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
knownPassThroughStep(node1, node2)
|
||||
}
|
||||
}
|
||||
|
||||
module KnownAlgorithmLiteralToAlgorithmGetterFlow =
|
||||
DataFlow::Global<KnownAlgorithmLiteralToAlgorithmGetterConfig>;
|
||||
|
||||
// https://www.openssl.org/docs/manmaster/man3/EVP_CIPHER_fetch.html
|
||||
class EVPCipherGetterCall extends OpenSSLAlgorithmGetterCall {
|
||||
DataFlow::Node valueArgNode;
|
||||
DataFlow::Node resultNode;
|
||||
Expr valueArgExpr;
|
||||
Expr resultExpr;
|
||||
|
||||
EVPCipherGetterCall() {
|
||||
// Flow out through the return pointer itself (trace the pointer, not what it is pointing to)
|
||||
resultExpr = this and
|
||||
resultNode.asExpr() = this and
|
||||
(
|
||||
this.getTarget().getName() in ["EVP_get_cipherbyname", "EVP_get_cipherbyobj"] and
|
||||
valueArgExpr = this.getArgument(0) and
|
||||
valueArgNode.asExpr() = valueArgExpr
|
||||
or
|
||||
this.getTarget().getName() = "EVP_CIPHER_fetch" and
|
||||
valueArgExpr = this.getArgument(1) and
|
||||
valueArgNode.asExpr() = valueArgExpr
|
||||
or
|
||||
this.getTarget().getName() = "EVP_get_cipherbynid" and
|
||||
valueArgExpr = this.getArgument(0) and
|
||||
valueArgNode.asExpr() = valueArgExpr
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getValueArgNode() { result = valueArgNode }
|
||||
|
||||
override DataFlow::Node getResultNode() { result = resultNode }
|
||||
|
||||
override Expr getValueArgExpr() { result = valueArgExpr }
|
||||
|
||||
override Expr getResultExpr() { result = resultExpr }
|
||||
}
|
||||
// /**
|
||||
// * Predicates/classes for identifying algorithm sinks.
|
||||
// * An Algorithm Sink is a function that takes an algorithm as an argument.
|
||||
// * In particular, any function that takes in an algorithm that until the call
|
||||
// * the algorithm is not definitely known to be an algorithm (e.g., an integer used as an identifier to fetch an algorithm)
|
||||
// */
|
||||
// //TODO: enforce a hierarchy of AlgorithmSinkArgument, e.g., so I can get all Asymmetric SinkArguments that includes all the strictly RSA etc.
|
||||
// import cpp
|
||||
// // import experimental.cryptography.utils.OpenSSL.LibraryFunction
|
||||
// // import experimental.cryptography.CryptoAlgorithmNames
|
||||
// predicate isAlgorithmSink(AlgorithmSinkArgument arg, string algType) { arg.algType() = algType }
|
||||
// abstract class AlgorithmSinkArgument extends Expr {
|
||||
// AlgorithmSinkArgument() {
|
||||
// exists(Call c | c.getAnArgument() = this and openSSLLibraryFunc(c.getTarget()))
|
||||
// }
|
||||
// /**
|
||||
// * Gets the function call in which the argument exists
|
||||
// */
|
||||
// Call getSinkCall() { result.getAnArgument() = this }
|
||||
// abstract string algType();
|
||||
// }
|
||||
// // https://www.openssl.org/docs/manmaster/man3/EVP_CIPHER_fetch.html
|
||||
// predicate cipherAlgorithmSink(string funcName, int argInd) {
|
||||
// funcName in ["EVP_get_cipherbyname", "EVP_get_cipherbynid", "EVP_get_cipherbyobj"] and argInd = 0
|
||||
// or
|
||||
// funcName = "EVP_CIPHER_fetch" and argInd = 1
|
||||
// }
|
||||
// class CipherAlgorithmSink extends AlgorithmSinkArgument {
|
||||
// CipherAlgorithmSink() {
|
||||
// exists(Call c, string funcName, int argInd |
|
||||
// funcName = c.getTarget().getName() and this = c.getArgument(argInd)
|
||||
// |
|
||||
// cipherAlgorithmSink(funcName, argInd)
|
||||
// )
|
||||
// }
|
||||
// override string algType() { result = getSymmetricEncryptionType() }
|
||||
// }
|
||||
// // https://www.openssl.org/docs/manmaster/man3/EVP_MAC_fetch
|
||||
// predicate macAlgorithmSink(string funcName, int argInd) {
|
||||
// (funcName = "EVP_MAC_fetch" and argInd = 1)
|
||||
// }
|
||||
// class MACAlgorithmSink extends AlgorithmSinkArgument {
|
||||
// MACAlgorithmSink() {
|
||||
// exists(Call c, string funcName, int argInd |
|
||||
// funcName = c.getTarget().getName() and this = c.getArgument(argInd)
|
||||
// |
|
||||
// macAlgorithmSink(funcName, argInd)
|
||||
// )
|
||||
// }
|
||||
// override string algType() { result = "TBD" }
|
||||
// }
|
||||
// // https://www.openssl.org/docs/manmaster/man3/EVP_MD_fetch
|
||||
// predicate messageDigestAlgorithmSink(string funcName, int argInd) {
|
||||
// funcName in ["EVP_get_digestbyname", "EVP_get_digestbynid", "EVP_get_digestbyobj"] and argInd = 0
|
||||
// or
|
||||
// funcName = "EVP_MD_fetch" and argInd = 1
|
||||
// }
|
||||
// class MessageDigestAlgorithmSink extends AlgorithmSinkArgument {
|
||||
// MessageDigestAlgorithmSink() {
|
||||
// exists(Call c, string funcName, int argInd |
|
||||
// funcName = c.getTarget().getName() and this = c.getArgument(argInd)
|
||||
// |
|
||||
// messageDigestAlgorithmSink(funcName, argInd)
|
||||
// )
|
||||
// }
|
||||
// override string algType() { result = getHashType() }
|
||||
// }
|
||||
// // https://www.openssl.org/docs/manmaster/man3/EVP_KEYEXCH_fetch
|
||||
// // https://www.openssl.org/docs/manmaster/man3/EVP_KEM_fetch
|
||||
// predicate keyExchangeAlgorithmSink(string funcName, int argInd) {
|
||||
// funcName = "EVP_KEYEXCH_fetch" and argInd = 1
|
||||
// or
|
||||
// funcName = "EVP_KEM_fetch" and argInd = 1
|
||||
// }
|
||||
// class KeyExchangeAlgorithmSink extends AlgorithmSinkArgument {
|
||||
// KeyExchangeAlgorithmSink() {
|
||||
// exists(Call c, string funcName, int argInd |
|
||||
// funcName = c.getTarget().getName() and this = c.getArgument(argInd)
|
||||
// |
|
||||
// keyExchangeAlgorithmSink(funcName, argInd)
|
||||
// )
|
||||
// }
|
||||
// override string algType() { result = getKeyExchangeType() }
|
||||
// }
|
||||
// // https://www.openssl.org/docs/manmaster/man3/EVP_KEYMGMT_fetch
|
||||
// predicate keyManagementAlgorithmSink(string funcName, int argInd) {
|
||||
// funcName = "EVP_KEYMGMT_fetch" and argInd = 1
|
||||
// }
|
||||
// class KeyManagementAlgorithmSink extends AlgorithmSinkArgument {
|
||||
// KeyManagementAlgorithmSink() {
|
||||
// exists(Call c, string funcName, int argInd |
|
||||
// funcName = c.getTarget().getName() and this = c.getArgument(argInd)
|
||||
// |
|
||||
// keyManagementAlgorithmSink(funcName, argInd)
|
||||
// )
|
||||
// }
|
||||
// override string algType() { result = "TBD" }
|
||||
// }
|
||||
// // https://www.openssl.org/docs/manmaster/man3/EVP_KDF
|
||||
// predicate keyDerivationAlgorithmSink(string funcName, int argInd) {
|
||||
// funcName = "EVP_KDF_fetch" and argInd = 1
|
||||
// }
|
||||
// class KeyDerivationAlgorithmSink extends AlgorithmSinkArgument {
|
||||
// KeyDerivationAlgorithmSink() {
|
||||
// exists(Call c, string funcName, int argInd |
|
||||
// funcName = c.getTarget().getName() and this = c.getArgument(argInd)
|
||||
// |
|
||||
// keyDerivationAlgorithmSink(funcName, argInd)
|
||||
// )
|
||||
// }
|
||||
// override string algType() { result = getKeyDerivationType() }
|
||||
// }
|
||||
// // https://www.openssl.org/docs/manmaster/man3/EVP_ASYM_CIPHER_fetch
|
||||
// // https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_new_id
|
||||
// // https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_new_CMAC_key.html
|
||||
// predicate asymmetricCipherAlgorithmSink(string funcName, int argInd) {
|
||||
// funcName = "EVP_ASYM_CIPHER_fetch" and argInd = 1
|
||||
// or
|
||||
// funcName = "EVP_PKEY_new_CMAC_key" and argInd = 3
|
||||
// // NOTE: other cases are handled by AsymmetricAlgorithmSink
|
||||
// }
|
||||
// class AsymmetricCipherAlgorithmSink extends AlgorithmSinkArgument {
|
||||
// AsymmetricCipherAlgorithmSink() {
|
||||
// exists(Call c, string funcName, int argInd |
|
||||
// funcName = c.getTarget().getName() and this = c.getArgument(argInd)
|
||||
// |
|
||||
// asymmetricCipherAlgorithmSink(funcName, argInd)
|
||||
// )
|
||||
// }
|
||||
// override string algType() { result = "ASYMMETRIC_ENCRYPTION" }
|
||||
// }
|
||||
// class AsymmetricCipherAlgorithmSink_EVP_PKEY_Q_keygen extends AlgorithmSinkArgument {
|
||||
// AsymmetricCipherAlgorithmSink_EVP_PKEY_Q_keygen() {
|
||||
// exists(Call c, string funcName |
|
||||
// funcName = c.getTarget().getName() and
|
||||
// this = c.getArgument(3)
|
||||
// |
|
||||
// funcName = "EVP_PKEY_Q_keygen" and
|
||||
// c.getArgument(3).getType().getUnderlyingType() instanceof IntegralType
|
||||
// )
|
||||
// }
|
||||
// override string algType() { result = "ASYMMETRIC_ENCRYPTION" }
|
||||
// }
|
||||
// // https://www.openssl.org/docs/manmaster/man3/EVP_RAND_fetch
|
||||
// predicate randomAlgorithmSink(string funcName, int argInd) {
|
||||
// funcName = "EVP_RAND_fetch" and argInd = 1
|
||||
// }
|
||||
// class RandomAlgorithmSink extends AlgorithmSinkArgument {
|
||||
// RandomAlgorithmSink() {
|
||||
// exists(Call c, string funcName, int argInd |
|
||||
// funcName = c.getTarget().getName() and this = c.getArgument(argInd)
|
||||
// |
|
||||
// randomAlgorithmSink(funcName, argInd)
|
||||
// )
|
||||
// }
|
||||
// override string algType() { result = "TBD" }
|
||||
// }
|
||||
// // https://www.openssl.org/docs/manmaster/man3/EVP_SIGNATURE_fetch
|
||||
// predicate signatureAlgorithmSink(string funcName, int argInd) {
|
||||
// funcName = "EVP_SIGNATURE_fetch" and argInd = 1
|
||||
// }
|
||||
// class SignatureAlgorithmSink extends AlgorithmSinkArgument {
|
||||
// SignatureAlgorithmSink() {
|
||||
// exists(Call c, string funcName, int argInd |
|
||||
// funcName = c.getTarget().getName() and this = c.getArgument(argInd)
|
||||
// |
|
||||
// signatureAlgorithmSink(funcName, argInd)
|
||||
// )
|
||||
// }
|
||||
// override string algType() { result = getSignatureType() }
|
||||
// }
|
||||
// // https://www.openssl.org/docs/manmaster/man3/EC_KEY_new_by_curve_name.html
|
||||
// // https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_set_ec_paramgen_curve_nid.html
|
||||
// predicate ellipticCurveAlgorithmSink(string funcName, int argInd) {
|
||||
// funcName in ["EC_KEY_new_by_curve_name", "EVP_EC_gen"] and argInd = 0
|
||||
// or
|
||||
// funcName = "EC_KEY_new_by_curve_name_ex" and argInd = 2
|
||||
// or
|
||||
// funcName in ["EVP_PKEY_CTX_set_ec_paramgen_curve_nid"] and argInd = 1
|
||||
// }
|
||||
// class EllipticCurveAlgorithmSink extends AlgorithmSinkArgument {
|
||||
// EllipticCurveAlgorithmSink() {
|
||||
// exists(Call c, string funcName, int argInd |
|
||||
// funcName = c.getTarget().getName() and this = c.getArgument(argInd)
|
||||
// |
|
||||
// ellipticCurveAlgorithmSink(funcName, argInd)
|
||||
// )
|
||||
// }
|
||||
// override string algType() { result = getEllipticCurveType() }
|
||||
// }
|
||||
// /**
|
||||
// * Special cased to address the fact that arg index 3 (zero offset based) is the curve name.
|
||||
// * ASSUMPTION: if the arg ind 3 is a char* assume it is an elliptic curve
|
||||
// */
|
||||
// class EllipticCurveAlgorithmSink_EVP_PKEY_Q_keygen extends AlgorithmSinkArgument {
|
||||
// EllipticCurveAlgorithmSink_EVP_PKEY_Q_keygen() {
|
||||
// exists(Call c, string funcName |
|
||||
// funcName = c.getTarget().getName() and
|
||||
// this = c.getArgument(3)
|
||||
// |
|
||||
// funcName = "EVP_PKEY_Q_keygen" and
|
||||
// c.getArgument(3).getType().getUnderlyingType() instanceof PointerType and
|
||||
// c.getArgument(3).getType().getUnderlyingType().stripType() instanceof CharType
|
||||
// )
|
||||
// }
|
||||
// override string algType() { result = getEllipticCurveType() }
|
||||
// }
|
||||
// // https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_new_id.html
|
||||
// // https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_new_raw_private_key.html
|
||||
// // https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_new.html
|
||||
// // https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_ctrl.html
|
||||
// // https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_Q_keygen.html
|
||||
// // https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_ctrl.html
|
||||
// predicate asymmetricAlgorithmSink(string funcName, int argInd) {
|
||||
// funcName = "EVP_PKEY_CTX_new_id" and argInd = 0
|
||||
// or
|
||||
// funcName = "EVP_PKEY_CTX_new_from_name" and argInd = 1
|
||||
// or
|
||||
// funcName in [
|
||||
// "EVP_PKEY_new_raw_private_key", "EVP_PKEY_new_raw_public_key", "EVP_PKEY_new_mac_key"
|
||||
// ] and
|
||||
// argInd = 0
|
||||
// or
|
||||
// funcName in ["EVP_PKEY_new_raw_private_key_ex", "EVP_PKEY_new_raw_public_key_ex"] and argInd = 1
|
||||
// or
|
||||
// // special casing this as arg index 3 must be specified depending on if RSA or ECC, and otherwise not specified for other algs
|
||||
// // funcName = "EVP_PKEY_Q_keygen" and argInd = 2
|
||||
// funcName in ["EVP_PKEY_CTX_ctrl", "EVP_PKEY_CTX_set_group_name"] and argInd = 1
|
||||
// // TODO consider void cases EVP_PKEY_new
|
||||
// }
|
||||
// class AsymmetricAlgorithmSink extends AlgorithmSinkArgument {
|
||||
// AsymmetricAlgorithmSink() {
|
||||
// exists(Call c, string funcName, int argInd |
|
||||
// funcName = c.getTarget().getName() and this = c.getArgument(argInd)
|
||||
// |
|
||||
// asymmetricAlgorithmSink(funcName, argInd)
|
||||
// )
|
||||
// }
|
||||
// override string algType() { result = getAsymmetricType() }
|
||||
// }
|
||||
// class AsymmetricAlgorithmSink_EVP_PKEY_Q_keygen extends AlgorithmSinkArgument {
|
||||
// AsymmetricAlgorithmSink_EVP_PKEY_Q_keygen() {
|
||||
// exists(Call c, string funcName |
|
||||
// funcName = c.getTarget().getName() and
|
||||
// this = c.getArgument(2)
|
||||
// |
|
||||
// funcName = "EVP_PKEY_Q_keygen" and
|
||||
// not exists(c.getArgument(3))
|
||||
// )
|
||||
// }
|
||||
// override string algType() { result = getAsymmetricType() }
|
||||
// }
|
||||
@@ -1,104 +1,5 @@
|
||||
import cpp
|
||||
import experimental.Quantum.Language
|
||||
import EVPCipherConsumers
|
||||
|
||||
/**
|
||||
* Note: padding and a mode of operation will only exist when the padding / mode (*and its type*) are determinable.
|
||||
* This is because the mode will always be specified alongside the algorithm and never independently.
|
||||
* Therefore, we can always assume that a determinable algorithm will have a determinable mode.
|
||||
*
|
||||
* In the case that only an algorithm is specified, e.g., "AES", the provider provides a default mode.
|
||||
*
|
||||
* TODO: Model the case of relying on a provider default, but alert on it as a bad practice.
|
||||
*/
|
||||
class CipherLiteralAlgorithmInstance extends Crypto::CipherAlgorithmInstance instanceof ConstantDataSource
|
||||
{
|
||||
Crypto::AlgorithmConsumer consumer; // TODO: I need to make this an open SSL algorithm consumer specifically
|
||||
|
||||
CipherLiteralAlgorithmInstance() {
|
||||
GenericDataSourceUniversalFlow::flow(DataFlow::exprNode(this), DataFlow::exprNode(consumer))
|
||||
}
|
||||
|
||||
Crypto::AlgorithmConsumer getConsumer() { result = consumer }
|
||||
|
||||
override Crypto::ModeOfOperationAlgorithmInstance getModeOfOperationAlgorithm() {
|
||||
none() // TODO: provider defaults
|
||||
}
|
||||
|
||||
override Crypto::PaddingAlgorithmInstance getPaddingAlgorithm() { none() }
|
||||
|
||||
override string getRawAlgorithmName() { result = this.(Literal).getValue().toString() }
|
||||
|
||||
override Crypto::TCipherType getCipherFamily() { none() }
|
||||
}
|
||||
|
||||
// override Crypto::TCipherType getCipherFamily() {
|
||||
// if this.cipherNameMappingKnown(_, super.getAlgorithmName())
|
||||
// then this.cipherNameMappingKnown(result, super.getAlgorithmName())
|
||||
// else result instanceof Crypto::OtherCipherType
|
||||
// }
|
||||
// bindingset[name]
|
||||
// private predicate cipherNameMappingKnown(Crypto::TCipherType type, string name) {
|
||||
// name = "AES" and
|
||||
// type instanceof Crypto::AES
|
||||
// or
|
||||
// name = "DES" and
|
||||
// type instanceof Crypto::DES
|
||||
// or
|
||||
// name = "TripleDES" and
|
||||
// type instanceof Crypto::TripleDES
|
||||
// or
|
||||
// name = "IDEA" and
|
||||
// type instanceof Crypto::IDEA
|
||||
// or
|
||||
// name = "CAST5" and
|
||||
// type instanceof Crypto::CAST5
|
||||
// or
|
||||
// name = "ChaCha20" and
|
||||
// type instanceof Crypto::ChaCha20
|
||||
// or
|
||||
// name = "RC4" and
|
||||
// type instanceof Crypto::RC4
|
||||
// or
|
||||
// name = "RC5" and
|
||||
// type instanceof Crypto::RC5
|
||||
// or
|
||||
// name = "RSA" and
|
||||
// type instanceof Crypto::RSA
|
||||
// }
|
||||
// private predicate modeToNameMappingKnown(Crypto::TBlockCipherModeOperationType type, string name) {
|
||||
// type instanceof Crypto::ECB and name = "ECB"
|
||||
// or
|
||||
// type instanceof Crypto::CBC and name = "CBC"
|
||||
// or
|
||||
// type instanceof Crypto::GCM and name = "GCM"
|
||||
// or
|
||||
// type instanceof Crypto::CTR and name = "CTR"
|
||||
// or
|
||||
// type instanceof Crypto::XTS and name = "XTS"
|
||||
// or
|
||||
// type instanceof Crypto::CCM and name = "CCM"
|
||||
// or
|
||||
// type instanceof Crypto::SIV and name = "SIV"
|
||||
// or
|
||||
// type instanceof Crypto::OCB and name = "OCB"
|
||||
// }
|
||||
// override Crypto::TBlockCipherModeOperationType getModeType() {
|
||||
// if this.modeToNameMappingKnown(_, super.getMode())
|
||||
// then this.modeToNameMappingKnown(result, super.getMode())
|
||||
// else result instanceof Crypto::OtherMode
|
||||
// }
|
||||
// override string getRawModeAlgorithmName() { result = super.getMode() }
|
||||
// override string getRawPaddingAlgorithmName() { result = super.getPadding() }
|
||||
// bindingset[name]
|
||||
// private predicate paddingToNameMappingKnown(Crypto::TPaddingType type, string name) {
|
||||
// type instanceof Crypto::NoPadding and name = "NOPADDING"
|
||||
// or
|
||||
// type instanceof Crypto::PKCS7 and name = ["PKCS5Padding", "PKCS7Padding"] // TODO: misnomer in the JCA?
|
||||
// or
|
||||
// type instanceof Crypto::OAEP and name.matches("OAEP%") // TODO: handle OAEPWith%
|
||||
// }
|
||||
// }
|
||||
/**
|
||||
* Resolves literal `e` to a known algorithm name, nid, normalized name, and algType
|
||||
* if `e` resolves to a known algorithm.
|
||||
@@ -992,7 +893,7 @@ predicate knownOpenSSLAlgorithm(string name, int nid, string normalized, string
|
||||
or
|
||||
name = "hmac-sha1" and nid = 781 and normalized = "SHA1" and algType = "HASH"
|
||||
or
|
||||
name = "md_gost94" and nid = 809 and normalized = "GOST94" and algType = "SYMMETRIC_ENCRYPTION"
|
||||
name = "md_gost94" and nid = 809 and normalized = "GOST94" and algType = "HASH"
|
||||
or
|
||||
name = "gost94" and nid = 812 and normalized = "GOST94" and algType = "SYMMETRIC_ENCRYPTION"
|
||||
or
|
||||
@@ -2432,7 +2333,7 @@ predicate knownOpenSSLAlgorithm(string name, int nid, string normalized, string
|
||||
or
|
||||
name = "pbe-md2-des" and nid = 9 and normalized = "MD2" and algType = "HASH"
|
||||
or
|
||||
name = "pbe-md2-des" and nid = 9 and normalized = "2DES" and algType = "SYMMETRIC_ENCRYPTION"
|
||||
name = "pbe-md2-des" and nid = 9 and normalized = "DES" and algType = "SYMMETRIC_ENCRYPTION"
|
||||
or
|
||||
name = "pbe-md2-rc2-64" and nid = 168 and normalized = "RC2" and algType = "SYMMETRIC_ENCRYPTION"
|
||||
or
|
||||
Reference in New Issue
Block a user