mirror of
https://github.com/github/codeql.git
synced 2026-04-12 10:34:02 +02:00
437 lines
16 KiB
Plaintext
437 lines
16 KiB
Plaintext
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() }
|
|
// }
|