// import cpp // import semmle.code.cpp.dataflow.new.DataFlow // import LibraryDetector // import OpenSSLKnownAlgorithmConstants // import experimental.Quantum.Language // class OpenSSLAlgorithmAdditionalFlowStep extends AdditionalFlowInputStep { // OpenSSLAlgorithmAdditionalFlowStep() { exists(AlgorithmPassthroughCall c | c.getInNode() = this) } // override DataFlow::Node getOutput() { // exists(AlgorithmPassthroughCall c | c.getInNode() = this and c.getOutNode() = result) // } // } // module AlgGetterToAlgConsumerConfig implements DataFlow::ConfigSig { // predicate isSource(DataFlow::Node source) { // exists(OpenSSLAlgorithmGetterCall c | c.getResultNode() = source) // } // predicate isSink(DataFlow::Node sink) { // exists(Crypto::AlgorithmConsumer c | c.getInputNode() = sink) // } // } // module AlgGetterToAlgConsumerFlow = DataFlow::Global; // 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 KnownOpenSSLAlgorithmToAlgorithmGetterConfig implements DataFlow::ConfigSig { // predicate isSource(DataFlow::Node source) { // source.asExpr() instanceof KnownOpenSSLAlgorithmConstant // } // 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 KnownOpenSSLAlgorithmToAlgorithmGetterFlow = // DataFlow::Global; // /** // * Cases like EVP_MD5(), // * there is no input, rather it directly gets an algorithm // * and returns it. // */ // class DirectGetterCall extends OpenSSLAlgorithmGetterCall { // DataFlow::Node resultNode; // Expr resultExpr; // DirectGetterCall() { // this instanceof KnownOpenSSLAlgorithmConstant and // this instanceof Call and // resultExpr = this and // resultNode.asExpr() = resultExpr // } // override DataFlow::Node getValueArgNode() { none() } // override DataFlow::Node getResultNode() { result = resultNode } // override Expr getValueArgExpr() { none() } // override Expr getResultExpr() { result = resultExpr } // } // // 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() { // resultExpr = this and // resultNode.asExpr() = this and // isPossibleOpenSSLFunction(this.getTarget()) 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 } // } // class EVPAsymCipherGetterCall extends OpenSSLAlgorithmGetterCall { // DataFlow::Node valueArgNode; // DataFlow::Node resultNode; // Expr valueArgExpr; // Expr resultExpr; // EVPAsymCipherGetterCall() { // isPossibleOpenSSLFunction(this.getTarget()) and // resultExpr = this and // resultNode.asExpr() = this and // this.getTarget().getName() = "EVP_ASYM_CIPHER_fetch" and // valueArgExpr = this.getArgument(1) 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 } // } // class EVPDigestGetterCall extends OpenSSLAlgorithmGetterCall { // DataFlow::Node valueArgNode; // DataFlow::Node resultNode; // Expr valueArgExpr; // Expr resultExpr; // EVPDigestGetterCall() { // resultExpr = this and // resultNode.asExpr() = this and // isPossibleOpenSSLFunction(this.getTarget()) and // ( // this.getTarget().getName() in [ // "EVP_get_digestbyname", "EVP_get_digestbyobj", "EVP_get_digestbynid" // ] and // valueArgExpr = this.getArgument(0) and // valueArgNode.asExpr() = valueArgExpr // or // this.getTarget().getName() = "EVP_MD_fetch" and // valueArgExpr = this.getArgument(1) 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 } // } // class EVPKDFFetch extends OpenSSLAlgorithmGetterCall { // DataFlow::Node valueArgNode; // DataFlow::Node resultNode; // Expr valueArgExpr; // Expr resultExpr; // EVPKDFFetch() { // resultExpr = this and // resultNode.asExpr() = this and // isPossibleOpenSSLFunction(this.getTarget()) and // this.getTarget().getName() in ["EVP_KDF_fetch"] and // valueArgExpr = this.getArgument(1) 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() } // // }