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:
REDMOND\brodes
2025-03-05 15:17:52 -05:00
parent cce5f24b38
commit de3ff45cba
8 changed files with 652 additions and 150 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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%
// }
// }

View File

@@ -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

View File

@@ -0,0 +1,10 @@
import cpp
predicate isPossibleOpenSSLFunction(Function f) {
isPossibleOpenSSLLocation(f.getADeclarationLocation())
}
predicate isPossibleOpenSSLLocation(Location l){
l.toString().toLowerCase().matches("%openssl%")
}

View File

@@ -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() }
// }

View File

@@ -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