mirror of
https://github.com/github/codeql.git
synced 2026-04-26 01:05:15 +02:00
Merge pull request #2 from nicolaswill/knewbury01/JCA-sample
Implement first stage cryptography modelling and queries
This commit is contained in:
@@ -1,12 +1,121 @@
|
||||
private import codeql.cryptography.Model
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.security.FlowSources as FlowSources
|
||||
private import cpp as Lang
|
||||
|
||||
module CryptoInput implements InputSig<Lang::Location> {
|
||||
class DataFlowNode = DataFlow::Node;
|
||||
|
||||
class LocatableElement = Lang::Locatable;
|
||||
|
||||
class UnknownLocation = Lang::UnknownDefaultLocation;
|
||||
|
||||
LocatableElement dfn_to_element(DataFlow::Node node) {
|
||||
result = node.asExpr() or
|
||||
result = node.asParameter() or
|
||||
result = node.asVariable()
|
||||
}
|
||||
}
|
||||
|
||||
module Crypto = CryptographyBase<Lang::Location, CryptoInput>;
|
||||
|
||||
import OpenSSL
|
||||
/**
|
||||
* Artifact output to node input configuration
|
||||
*/
|
||||
abstract class AdditionalFlowInputStep extends DataFlow::Node {
|
||||
abstract DataFlow::Node getOutput();
|
||||
|
||||
final DataFlow::Node getInput() { result = this }
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic data source to node input configuration
|
||||
*/
|
||||
module GenericDataSourceUniversalFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source = any(Crypto::GenericDataSourceInstance i).getOutputNode()
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(Crypto::FlowAwareElement other).getInputNode()
|
||||
}
|
||||
|
||||
predicate isBarrierOut(DataFlow::Node node) {
|
||||
node = any(Crypto::FlowAwareElement element).getInputNode()
|
||||
}
|
||||
|
||||
predicate isBarrierIn(DataFlow::Node node) {
|
||||
node = any(Crypto::FlowAwareElement element).getOutputNode()
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
node1.(AdditionalFlowInputStep).getOutput() = node2
|
||||
}
|
||||
}
|
||||
|
||||
// // // 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 string getAdditionalDescription() { result = this.toString() }
|
||||
// // }
|
||||
// /**
|
||||
// * Definitions of various generic data sources
|
||||
// */
|
||||
// // final class DefaultFlowSource = SourceNode;
|
||||
// // final class DefaultRemoteFlowSource = RemoteFlowSource;
|
||||
// // class GenericLocalDataSource extends Crypto::GenericLocalDataSource {
|
||||
// // GenericLocalDataSource() {
|
||||
// // any(DefaultFlowSource src | not src instanceof DefaultRemoteFlowSource).asExpr() = this
|
||||
// // }
|
||||
// // override DataFlow::Node getOutputNode() { result.asExpr() = this }
|
||||
// // override predicate flowsTo(Crypto::FlowAwareElement other) {
|
||||
// // GenericDataSourceUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
|
||||
// // }
|
||||
// // override string getAdditionalDescription() { result = this.toString() }
|
||||
// // }
|
||||
// // class GenericRemoteDataSource extends Crypto::GenericRemoteDataSource {
|
||||
// // GenericRemoteDataSource() { any(DefaultRemoteFlowSource src).asExpr() = this }
|
||||
// // override DataFlow::Node getOutputNode() { result.asExpr() = this }
|
||||
// // override predicate flowsTo(Crypto::FlowAwareElement other) {
|
||||
// // GenericDataSourceUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
|
||||
// // }
|
||||
// // override string getAdditionalDescription() { result = this.toString() }
|
||||
// // }
|
||||
// module GenericDataSourceUniversalFlow = DataFlow::Global<GenericDataSourceUniversalFlowConfig>;
|
||||
module ArtifactUniversalFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source = any(Crypto::ArtifactInstance artifact).getOutputNode()
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(Crypto::FlowAwareElement other).getInputNode()
|
||||
}
|
||||
|
||||
predicate isBarrierOut(DataFlow::Node node) {
|
||||
node = any(Crypto::FlowAwareElement element).getInputNode()
|
||||
}
|
||||
|
||||
predicate isBarrierIn(DataFlow::Node node) {
|
||||
node = any(Crypto::FlowAwareElement element).getOutputNode()
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
node1.(AdditionalFlowInputStep).getOutput() = node2
|
||||
}
|
||||
}
|
||||
|
||||
module ArtifactUniversalFlow = DataFlow::Global<ArtifactUniversalFlowConfig>;
|
||||
|
||||
abstract class CipherOutputArtifact extends Crypto::KeyOperationOutputArtifactInstance {
|
||||
override predicate flowsTo(Crypto::FlowAwareElement other) {
|
||||
ArtifactUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
|
||||
}
|
||||
}
|
||||
|
||||
import OpenSSL.OpenSSL
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
|
||||
module OpenSSLModel {
|
||||
import Language
|
||||
|
||||
abstract class KeyDerivationOperation extends Crypto::KeyDerivationOperation { }
|
||||
|
||||
class SHA1Algo extends Crypto::HashAlgorithm instanceof MacroAccess {
|
||||
SHA1Algo() { this.getMacro().getName() = "SN_sha1" }
|
||||
|
||||
override string getRawAlgorithmName() { result = "SN_sha1" }
|
||||
|
||||
override Crypto::THashType getHashType() { result instanceof Crypto::SHA1 }
|
||||
}
|
||||
|
||||
module AlgorithmToEVPKeyDeriveConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof KeyDerivationAlgorithm }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(EVP_KDF_derive kdo | sink.asExpr() = kdo.getAlgorithmArg())
|
||||
}
|
||||
}
|
||||
|
||||
module AlgorithmToEVPKeyDeriveFlow = DataFlow::Global<AlgorithmToEVPKeyDeriveConfig>;
|
||||
|
||||
predicate algorithm_to_EVP_KDF_derive(Crypto::Algorithm algo, EVP_KDF_derive derive) {
|
||||
algo.(Expr).getEnclosingFunction() = derive.(Expr).getEnclosingFunction()
|
||||
}
|
||||
|
||||
class EVP_KDF_derive extends KeyDerivationOperation instanceof FunctionCall {
|
||||
EVP_KDF_derive() { this.getTarget().getName() = "EVP_KDF_derive" }
|
||||
|
||||
override Crypto::Algorithm getAlgorithm() { algorithm_to_EVP_KDF_derive(result, this) }
|
||||
|
||||
Expr getAlgorithmArg() { result = this.(FunctionCall).getArgument(3) }
|
||||
}
|
||||
|
||||
abstract class KeyDerivationAlgorithm extends Crypto::KeyDerivationAlgorithm { }
|
||||
|
||||
class EVP_KDF_fetch_Call extends FunctionCall {
|
||||
EVP_KDF_fetch_Call() { this.getTarget().getName() = "EVP_KDF_fetch" }
|
||||
|
||||
Expr getAlgorithmArg() { result = this.getArgument(1) }
|
||||
}
|
||||
|
||||
predicate kdf_names(string algo) { algo = ["HKDF", "PKCS12KDF"] }
|
||||
|
||||
class KDFAlgorithmStringLiteral extends Crypto::NodeBase instanceof StringLiteral {
|
||||
KDFAlgorithmStringLiteral() { kdf_names(this.getValue().toUpperCase()) }
|
||||
|
||||
override string toString() { result = this.(StringLiteral).toString() }
|
||||
|
||||
string getValue() { result = this.(StringLiteral).getValue() }
|
||||
}
|
||||
|
||||
private module AlgorithmStringToFetchConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof KDFAlgorithmStringLiteral }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(EVP_KDF_fetch_Call call | sink.asExpr() = call.getAlgorithmArg())
|
||||
}
|
||||
}
|
||||
|
||||
module AlgorithmStringToFetchFlow = DataFlow::Global<AlgorithmStringToFetchConfig>;
|
||||
|
||||
predicate algorithmStringToKDFFetchArgFlow(string name, KDFAlgorithmStringLiteral origin, Expr arg) {
|
||||
exists(EVP_KDF_fetch_Call sinkCall |
|
||||
origin.getValue().toUpperCase() = name and
|
||||
arg = sinkCall.getAlgorithmArg() and
|
||||
AlgorithmStringToFetchFlow::flow(DataFlow::exprNode(origin), DataFlow::exprNode(arg))
|
||||
)
|
||||
}
|
||||
|
||||
class HKDF extends KeyDerivationAlgorithm, Crypto::HKDF instanceof Expr {
|
||||
KDFAlgorithmStringLiteral origin;
|
||||
|
||||
HKDF() { algorithmStringToKDFFetchArgFlow("HKDF", origin, this) }
|
||||
|
||||
override string getRawAlgorithmName() { result = origin.getValue() }
|
||||
|
||||
override Crypto::HashAlgorithm getHashAlgorithm() { none() }
|
||||
|
||||
override Crypto::LocatableElement getOrigin(string name) {
|
||||
result = origin and name = origin.toString()
|
||||
}
|
||||
}
|
||||
|
||||
class PKCS12KDF extends KeyDerivationAlgorithm, Crypto::PKCS12KDF instanceof Expr {
|
||||
KDFAlgorithmStringLiteral origin;
|
||||
|
||||
PKCS12KDF() { algorithmStringToKDFFetchArgFlow("PKCS12KDF", origin, this) }
|
||||
|
||||
override string getRawAlgorithmName() { result = origin.getValue() }
|
||||
|
||||
override Crypto::HashAlgorithm getHashAlgorithm() { none() }
|
||||
|
||||
override Crypto::NodeBase getOrigin(string name) {
|
||||
result = origin and name = origin.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
97
cpp/ql/lib/experimental/Quantum/OpenSSL/CtxFlow.qll
Normal file
97
cpp/ql/lib/experimental/Quantum/OpenSSL/CtxFlow.qll
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* In OpenSSL, flow between 'context' parameters is often used to
|
||||
* store state/config of how an operation will eventually be performed.
|
||||
* Tracing algorithms and configurations to operations therefore
|
||||
* requires tracing context parameters for many OpenSSL apis.
|
||||
*
|
||||
* This library provides a dataflow analysis to track context parameters
|
||||
* between any two functions accepting openssl context parameters.
|
||||
* The dataflow takes into consideration flowing through duplication and copy calls
|
||||
* as well as flow through flow killers (free/reset calls).
|
||||
*
|
||||
* TODO: we may need to revisit 'free' as a dataflow killer, depending on how
|
||||
* we want to model use after frees.
|
||||
*
|
||||
* This library also provides classes to represent context Types and relevant
|
||||
* arguments/expressions.
|
||||
*/
|
||||
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
|
||||
class CTXType extends Type {
|
||||
CTXType() {
|
||||
// TODO: should we limit this to an openssl path?
|
||||
this.getUnspecifiedType().stripType().getName().matches("evp_%ctx_%st")
|
||||
}
|
||||
}
|
||||
|
||||
class CTXPointerExpr extends Expr {
|
||||
CTXPointerExpr() {
|
||||
this.getType() instanceof CTXType and
|
||||
this.getType() instanceof PointerType
|
||||
}
|
||||
}
|
||||
|
||||
class CTXPointerArgument extends CTXPointerExpr {
|
||||
CTXPointerArgument() { exists(Call c | c.getAnArgument() = this) }
|
||||
|
||||
Call getCall() { result.getAnArgument() = this }
|
||||
}
|
||||
|
||||
class CTXClearCall extends Call {
|
||||
CTXClearCall() {
|
||||
this.getTarget().getName().toLowerCase().matches(["%free%", "%reset%"]) and
|
||||
this.getAnArgument() instanceof CTXPointerArgument
|
||||
}
|
||||
}
|
||||
|
||||
class CTXCopyOutArgCall extends Call {
|
||||
CTXCopyOutArgCall() {
|
||||
this.getTarget().getName().toLowerCase().matches(["%copy%"]) and
|
||||
this.getAnArgument() instanceof CTXPointerArgument
|
||||
}
|
||||
}
|
||||
|
||||
class CTXCopyReturnCall extends Call {
|
||||
CTXCopyReturnCall() {
|
||||
this.getTarget().getName().toLowerCase().matches(["%dup%"]) and
|
||||
this.getAnArgument() instanceof CTXPointerArgument and
|
||||
this instanceof CTXPointerExpr
|
||||
}
|
||||
}
|
||||
|
||||
module OpenSSLCTXArgumentFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof CTXPointerArgument }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof CTXPointerArgument }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
exists(CTXClearCall c | c.getAnArgument() = node.asExpr())
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(CTXCopyOutArgCall c |
|
||||
c.getAnArgument() = node1.asExpr() and
|
||||
c.getAnArgument() = node2.asExpr() and
|
||||
node1.asExpr() != node2.asExpr() and
|
||||
node2.asExpr().getType() instanceof CTXType
|
||||
)
|
||||
or
|
||||
exists(CTXCopyReturnCall c |
|
||||
c.getAnArgument() = node1.asExpr() and
|
||||
c = node2.asExpr() and
|
||||
node1.asExpr() != node2.asExpr() and
|
||||
node2.asExpr().getType() instanceof CTXType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module OpenSSLCTXArgumentFlow = DataFlow::Global<OpenSSLCTXArgumentFlowConfig>;
|
||||
|
||||
predicate ctxFlowsTo(CTXPointerArgument source, CTXPointerArgument sink) {
|
||||
exists(DataFlow::Node a, DataFlow::Node b |
|
||||
OpenSSLCTXArgumentFlow::flow(a, b) and
|
||||
a.asExpr() = source and
|
||||
b.asExpr() = sink
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import EVPCipherInitializer
|
||||
import EVPCipherOperation
|
||||
import EVPCipherAlgorithmSource
|
||||
|
||||
class EVP_Cipher_Initializer_Algorithm_Consumer extends Crypto::AlgorithmConsumer instanceof EVPCipherInitializerAlgorithmArgument
|
||||
{
|
||||
override DataFlow::Node getInputNode() { result.asExpr() = this }
|
||||
|
||||
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
result.(KnownOpenSSLCipherConstantAlgorithmInstance).getConsumer() = this
|
||||
}
|
||||
}
|
||||
|
||||
// //TODO: need a key consumer
|
||||
// class EVP_Initializer_Key_Consumer extends Crypto::KeyConsumer instanceof EVP_Cipher_Inititalizer isntanceof InitializerKeyArgument{
|
||||
// }
|
||||
class EVP_Cipher_Initializer_IV_Consumer extends Crypto::NonceArtifactConsumer instanceof EVPCipherInitializerIVArgument
|
||||
{
|
||||
override DataFlow::Node getInputNode() { result.asExpr() = this }
|
||||
}
|
||||
|
||||
class EVP_Cipher_Input_Consumer extends Crypto::CipherInputConsumer instanceof EVPCipherInputArgument
|
||||
{
|
||||
override DataFlow::Node getInputNode() { result.asExpr() = this }
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import cpp
|
||||
import experimental.Quantum.Language
|
||||
import OpenSSLAlgorithmGetter
|
||||
|
||||
predicate knownOpenSSLConstantToHashFamilyType(KnownOpenSSLAlgorithmConstant e, Crypto::THashType type) {
|
||||
exists(string name | e.getAlgType().toLowerCase().matches("hash") |
|
||||
name = e.getNormalizedName() and
|
||||
(
|
||||
name.matches("BLAKE2B") and type instanceof Crypto::BLAKE2B
|
||||
or
|
||||
name.matches("BLAKE2S") and type instanceof Crypto::BLAKE2S
|
||||
or
|
||||
name.matches("GOST%") and type instanceof Crypto::GOSTHash
|
||||
or
|
||||
name.matches("MD2") and type instanceof Crypto::MD2
|
||||
or
|
||||
name.matches("MD4") and type instanceof Crypto::MD4
|
||||
or
|
||||
name.matches("MD5") and type instanceof Crypto::MD5
|
||||
or
|
||||
name.matches("MDC2") and type instanceof Crypto::MDC2
|
||||
or
|
||||
name.matches("POLY1305") and type instanceof Crypto::POLY1305
|
||||
or
|
||||
name.matches(["SHA", "SHA1"]) and type instanceof Crypto::SHA1
|
||||
or
|
||||
name.matches("SHA+%") and not name.matches(["SHA1", "SHA3-"]) and type instanceof Crypto::SHA2
|
||||
or
|
||||
name.matches("SHA3-%") and type instanceof Crypto::SHA3
|
||||
or
|
||||
name.matches(["SHAKE"]) and type instanceof Crypto::SHAKE
|
||||
or
|
||||
name.matches("SM3") and type instanceof Crypto::SM3
|
||||
or
|
||||
name.matches("RIPEMD160") and type instanceof Crypto::RIPEMD160
|
||||
or
|
||||
name.matches("WHIRLPOOL") and type instanceof Crypto::WHIRLPOOL
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
class KnownOpenSSLHashConstantAlgorithmInstance extends Crypto::HashAlgorithmInstance instanceof KnownOpenSSLAlgorithmConstant
|
||||
{
|
||||
OpenSSLAlgorithmGetterCall getterCall;
|
||||
|
||||
KnownOpenSSLHashConstantAlgorithmInstance() {
|
||||
// Not just any known value, but specifically a known hash
|
||||
this.(KnownOpenSSLAlgorithmConstant).getAlgType().toLowerCase().matches("hash") and
|
||||
(
|
||||
// Two possibilities:
|
||||
// 1) The source is a literal and flows to a getter, then we know we have an instance
|
||||
// 2) The source is a KnownOpenSSLAlgorithm is call, and we know we have an instance immediately from that
|
||||
// Possibility 1:
|
||||
this instanceof Literal and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
// Sink is an argument to a CipherGetterCall
|
||||
sink = getterCall.(OpenSSLAlgorithmGetterCall).getValueArgNode() and
|
||||
// Source is `this`
|
||||
src.asExpr() = this and
|
||||
// This traces to a getter
|
||||
KnownOpenSSLAlgorithmToAlgorithmGetterFlow::flow(src, sink)
|
||||
)
|
||||
or
|
||||
// Possibility 2:
|
||||
this instanceof DirectGetterCall and getterCall = this
|
||||
)
|
||||
}
|
||||
|
||||
Crypto::AlgorithmConsumer getConsumer() {
|
||||
AlgGetterToAlgConsumerFlow::flow(getterCall.getResultNode(), DataFlow::exprNode(result))
|
||||
}
|
||||
|
||||
override Crypto::THashType getHashFamily() {
|
||||
knownOpenSSLConstantToHashFamilyType(this, result) or
|
||||
not knownOpenSSLConstantToHashFamilyType(this, _) and result = Crypto::OtherHashType()
|
||||
}
|
||||
|
||||
override string getRawAlgorithmName() { result = this.(Literal).getValue().toString() }
|
||||
|
||||
// override int getHashSize() { none() } //TODO
|
||||
}
|
||||
30
cpp/ql/lib/experimental/Quantum/OpenSSL/EVPHashConsumers.qll
Normal file
30
cpp/ql/lib/experimental/Quantum/OpenSSL/EVPHashConsumers.qll
Normal file
@@ -0,0 +1,30 @@
|
||||
import EVPHashInitializer
|
||||
import EVPHashOperation
|
||||
import EVPHashAlgorithmSource
|
||||
|
||||
class EVP_Digest_Initializer_Algorithm_Consumer extends Crypto::AlgorithmValueConsumer instanceof EVPDigestInitializerAlgorithmArgument
|
||||
{
|
||||
override DataFlow::Node getInputNode() { result.asExpr() = this }
|
||||
|
||||
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
result.(KnownOpenSSLHashConstantAlgorithmInstance).getConsumer() = this
|
||||
}
|
||||
}
|
||||
|
||||
class EVP_Q_Digest_Algorithm_Consumer extends Crypto::AlgorithmValueConsumer instanceof EVP_Q_Digest_Algorithm_Argument
|
||||
{
|
||||
override DataFlow::Node getInputNode() { result.asExpr() = this }
|
||||
|
||||
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
result.(KnownOpenSSLHashConstantAlgorithmInstance).getConsumer() = this
|
||||
}
|
||||
}
|
||||
|
||||
class EVP_Digest_Algorithm_Consumer extends Crypto::AlgorithmValueConsumer instanceof EVP_Digest_Algorithm_Argument
|
||||
{
|
||||
override DataFlow::Node getInputNode() { result.asExpr() = this }
|
||||
|
||||
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
result.(KnownOpenSSLHashConstantAlgorithmInstance).getConsumer() = this
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import cpp
|
||||
|
||||
abstract class EVP_Hash_Inititalizer extends Call {
|
||||
Expr getContextArg() { result = this.(Call).getArgument(0) }
|
||||
|
||||
abstract Expr getAlgorithmArg();
|
||||
}
|
||||
|
||||
class EVP_DigestInit_Variant_Calls extends EVP_Hash_Inititalizer {
|
||||
EVP_DigestInit_Variant_Calls() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_DigestInit", "EVP_DigestInit_ex", "EVP_DigestInit_ex2"
|
||||
]
|
||||
}
|
||||
|
||||
override Expr getAlgorithmArg() { result = this.(Call).getArgument(1) }
|
||||
|
||||
}
|
||||
|
||||
|
||||
class EVPDigestInitializerAlgorithmArgument extends Expr {
|
||||
EVPDigestInitializerAlgorithmArgument() {
|
||||
exists(EVP_Hash_Inititalizer initCall | this = initCall.getAlgorithmArg())
|
||||
}
|
||||
}
|
||||
83
cpp/ql/lib/experimental/Quantum/OpenSSL/EVPHashOperation.qll
Normal file
83
cpp/ql/lib/experimental/Quantum/OpenSSL/EVPHashOperation.qll
Normal file
@@ -0,0 +1,83 @@
|
||||
import experimental.Quantum.Language
|
||||
import CtxFlow as CTXFlow
|
||||
import LibraryDetector
|
||||
import EVPHashInitializer
|
||||
import EVPHashConsumers
|
||||
|
||||
abstract class EVP_Hash_Operation extends Crypto::HashOperationInstance instanceof Call {
|
||||
Expr getContextArg() { result = this.(Call).getArgument(0) }
|
||||
|
||||
EVP_Hash_Inititalizer getInitCall() {
|
||||
CTXFlow::ctxFlowsTo(result.getContextArg(), this.getContextArg())
|
||||
}
|
||||
}
|
||||
|
||||
//https://docs.openssl.org/3.0/man3/EVP_DigestInit/#synopsis
|
||||
class EVP_Q_Digest_Operation extends EVP_Hash_Operation {
|
||||
EVP_Q_Digest_Operation() {
|
||||
this.(Call).getTarget().getName() = "EVP_Q_digest" and
|
||||
isPossibleOpenSSLFunction(this.(Call).getTarget())
|
||||
}
|
||||
|
||||
override Crypto::AlgorithmConsumer getAlgorithmConsumer() { this.(Call).getArgument(1) = result }
|
||||
|
||||
override EVP_Hash_Inititalizer getInitCall() {
|
||||
// This variant of digest does not use an init
|
||||
// and even if it were used, the init would be ignored/undefined
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
class EVP_Q_Digest_Algorithm_Argument extends Expr {
|
||||
EVP_Q_Digest_Algorithm_Argument() {
|
||||
exists(EVP_Q_Digest_Operation op | this = op.(Call).getArgument(1))
|
||||
}
|
||||
}
|
||||
|
||||
class EVP_Digest_Operation extends EVP_Hash_Operation {
|
||||
EVP_Digest_Operation() {
|
||||
this.(Call).getTarget().getName() = "EVP_Digest" and
|
||||
isPossibleOpenSSLFunction(this.(Call).getTarget())
|
||||
}
|
||||
|
||||
// There is no context argument for this function
|
||||
override Expr getContextArg() { none() }
|
||||
|
||||
override Crypto::AlgorithmConsumer getAlgorithmConsumer() { this.(Call).getArgument(4) = result }
|
||||
|
||||
override EVP_Hash_Inititalizer getInitCall() {
|
||||
// This variant of digest does not use an init
|
||||
// and even if it were used, the init would be ignored/undefined
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
class EVP_Digest_Algorithm_Argument extends Expr {
|
||||
EVP_Digest_Algorithm_Argument() {
|
||||
exists(EVP_Digest_Operation op | this = op.(Call).getArgument(4))
|
||||
}
|
||||
}
|
||||
|
||||
class EVP_DigestUpdate_Operation extends EVP_Hash_Operation {
|
||||
EVP_DigestUpdate_Operation() {
|
||||
this.(Call).getTarget().getName() = "EVP_DigestUpdate" and
|
||||
isPossibleOpenSSLFunction(this.(Call).getTarget())
|
||||
}
|
||||
|
||||
override Crypto::AlgorithmConsumer getAlgorithmConsumer() {
|
||||
this.getInitCall().getAlgorithmArg() = result
|
||||
}
|
||||
}
|
||||
|
||||
class EVP_DigestFinal_Variants_Operation extends EVP_Hash_Operation {
|
||||
EVP_DigestFinal_Variants_Operation() {
|
||||
this.(Call).getTarget().getName() in [
|
||||
"EVP_DigestFinal", "EVP_DigestFinal_ex", "EVP_DigestFinalXOF"
|
||||
] and
|
||||
isPossibleOpenSSLFunction(this.(Call).getTarget())
|
||||
}
|
||||
|
||||
override Crypto::AlgorithmConsumer getAlgorithmConsumer() {
|
||||
this.getInitCall().getAlgorithmArg() = result
|
||||
}
|
||||
}
|
||||
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%")
|
||||
}
|
||||
|
||||
274
cpp/ql/lib/experimental/Quantum/OpenSSL/OpenSSL.qll
Normal file
274
cpp/ql/lib/experimental/Quantum/OpenSSL/OpenSSL.qll
Normal file
@@ -0,0 +1,274 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
|
||||
module OpenSSLModel {
|
||||
import experimental.Quantum.Language
|
||||
import experimental.Quantum.OpenSSL.AlgorithmInstances.Instances
|
||||
import experimental.Quantum.OpenSSL.AlgorithmValueConsumers.AlgorithmValueConsumers
|
||||
import experimental.Quantum.OpenSSL.Operations.Operations
|
||||
// import experimental.Quantum.OpenSSL.EVPCipherOperation
|
||||
// import experimental.Quantum.OpenSSL.EVPHashOperation
|
||||
// import experimental.Quantum.OpenSSL.EVPCipherAlgorithmSource
|
||||
// import experimental.Quantum.OpenSSL.EVPHashAlgorithmSource
|
||||
// import experimental.Quantum.OpenSSL.Random
|
||||
// // Imports the additional algorithm flow step for OpenSSL
|
||||
// import experimental.Quantum.OpenSSL.OpenSSLAlgorithmGetter
|
||||
// // TODO: trace CTX from init variants to the context arg of EVP update calls
|
||||
// //https://docs.openssl.org/master/man3/EVP_EncryptInit/#synopsis
|
||||
// abstract class EVP_Cipher_Init_Call extends Call {
|
||||
// Expr getContextArg() { result = this.getArgument(0) }
|
||||
// abstract Expr getKeyArg();
|
||||
// abstract Expr getIVArg();
|
||||
// abstract Crypto::CipherOperationSubtype getCipherOperationSubtype();
|
||||
// }
|
||||
// abstract class EVP_Cipher_EX_Init_Call extends EVP_Cipher_Init_Call {
|
||||
// override Expr getKeyArg() { result = this.getArgument(3) }
|
||||
// override Expr getIVArg() { result = this.getArgument(4) }
|
||||
// }
|
||||
// abstract class EVP_Cipher_EX2_Init_Call extends EVP_Cipher_Init_Call {
|
||||
// override Expr getKeyArg() { result = this.getArgument(2) }
|
||||
// override Expr getIVArg() { result = this.getArgument(3) }
|
||||
// }
|
||||
// abstract class EVP_Cipher_Operation_Call extends Crypto::CipherOperationInstance instanceof Call {
|
||||
// Expr getContextArg() { result = this.(Call).getArgument(0) }
|
||||
// abstract Expr getInputArg();
|
||||
// Expr getOutputArg() { result = this.(Call).getArgument(1) }
|
||||
// abstract Expr getInitCall();
|
||||
// }
|
||||
// abstract class EVP_Update_Call extends EVP_Cipher_Operation_Call {
|
||||
// override Expr getInputArg() { result = this.(Call).getArgument(3) }
|
||||
// }
|
||||
// abstract class EVP_Final_Call extends EVP_Cipher_Operation_Call{
|
||||
// override Expr getInputArg() { none() }
|
||||
// }
|
||||
// class EVP_Cipher_Call extends EVP_Cipher_Operation_Call{
|
||||
// // TODO/QUESTION: what is the better way to do this?
|
||||
// EVP_Cipher_Call() { this.(Call).getTarget().getName() = "EVP_Cipher" }
|
||||
// override Expr getInputArg() { result = this.(Call).getArgument(2) }
|
||||
// override Expr getOutputArg() { result = this.(Call).getArgument(1) }
|
||||
// override Crypto::CipherOperationSubtype getCipherOperationSubtype(){
|
||||
// result instanceof Crypto::EncryptionSubtype
|
||||
// }
|
||||
// override Expr getInitCall(){
|
||||
// //TODO:
|
||||
// none()
|
||||
// }
|
||||
// override Crypto::NonceArtifactConsumer getNonceConsumer(){
|
||||
// none()
|
||||
// }
|
||||
// override Crypto::CipherInputConsumer getInputConsumer(){
|
||||
// none()
|
||||
// }
|
||||
// override Crypto::CipherOutputArtifactInstance getOutputArtifact(){
|
||||
// none()
|
||||
// }
|
||||
// override Crypto::AlgorithmConsumer getAlgorithmConsumer(){
|
||||
// none()
|
||||
// }
|
||||
// }
|
||||
//TODO: what about EVP_CIpher
|
||||
// class EVP_EncryptUpdateCall extends Crypto::CipherOperationInstance instanceof Call {
|
||||
// // NICK QUESTION: is there a better way to tie this to openssl?
|
||||
// EVP_EncryptUpdateCall() { this.getTarget().getName() = "EVP_EncryptUpdate" }
|
||||
// Expr getContextArg() { result = super.getArgument(0) }
|
||||
// Expr getInputArg() { result = super.getArgument(3) }
|
||||
// Expr getOutputArg() { result = super.getArgument(1) }
|
||||
// override Crypto::CipherOperationSubtype getCipherOperationSubtype(){
|
||||
// result instanceof Crypto::EncryptionSubtype
|
||||
// }
|
||||
// override Crypto::NonceArtifactConsumer getNonceConsumer(){
|
||||
// none()
|
||||
// }
|
||||
// override Crypto::CipherInputConsumer getInputConsumer(){
|
||||
// none()
|
||||
// }
|
||||
// override Crypto::CipherOutputArtifactInstance getOutputArtifact(){
|
||||
// none()
|
||||
// }
|
||||
// override Crypto::AlgorithmConsumer getAlgorithmConsumer(){
|
||||
// none()
|
||||
// }
|
||||
// }
|
||||
//EVP_EncryptUpdate
|
||||
// /**
|
||||
// * Hash function references in OpenSSL.
|
||||
// */
|
||||
// predicate hash_ref_type_mapping_known(string name, Crypto::THashType algo) {
|
||||
// // `ma` name has an LN_ or SN_ prefix, which we want to ignore
|
||||
// // capture any name after the _ prefix using regex matching
|
||||
// name = ["sha1", "sha160"] and algo instanceof Crypto::SHA1
|
||||
// or
|
||||
// name = ["sha224", "sha256", "sha384", "sha512"] and algo instanceof Crypto::SHA2
|
||||
// or
|
||||
// name = ["sha3-224", "sha3-256", "sha3-384", "sha3-512"] and algo instanceof Crypto::SHA3
|
||||
// or
|
||||
// name = "md2" and algo instanceof Crypto::MD2
|
||||
// or
|
||||
// name = "md4" and algo instanceof Crypto::MD4
|
||||
// or
|
||||
// name = "md5" and algo instanceof Crypto::MD5
|
||||
// or
|
||||
// name = "ripemd160" and algo instanceof Crypto::RIPEMD160
|
||||
// or
|
||||
// name = "whirlpool" and algo instanceof Crypto::WHIRLPOOL
|
||||
// }
|
||||
// predicate hash_ref_type_mapping(FunctionCallOrMacroAccess ref, string name, Crypto::THashType algo) {
|
||||
// name = ref.getTargetName().regexpCapture("(?:SN_|LN_|EVP_)([a-z0-9]+)", 1) and
|
||||
// hash_ref_type_mapping_known(name, algo)
|
||||
// }
|
||||
// class FunctionCallOrMacroAccess extends Element {
|
||||
// FunctionCallOrMacroAccess() { this instanceof FunctionCall or this instanceof MacroAccess }
|
||||
// string getTargetName() {
|
||||
// result = this.(FunctionCall).getTarget().getName()
|
||||
// or
|
||||
// result = this.(MacroAccess).getMacroName()
|
||||
// }
|
||||
// }
|
||||
// class HashAlgorithmCallOrMacro extends Crypto::HashAlgorithmInstance instanceof FunctionCallOrMacroAccess
|
||||
// {
|
||||
// HashAlgorithmCallOrMacro() { hash_ref_type_mapping(this, _, _) }
|
||||
// string getTargetName() { result = this.(FunctionCallOrMacroAccess).getTargetName() }
|
||||
// }
|
||||
// class HashAlgorithm extends Crypto::HashAlgorithm {
|
||||
// HashAlgorithmCallOrMacro instance;
|
||||
// HashAlgorithm() { this = Crypto::THashAlgorithm(instance) }
|
||||
// override string getSHA2OrSHA3DigestSize(Location location) {
|
||||
// (
|
||||
// this.getHashType() instanceof Crypto::SHA2 or
|
||||
// this.getHashType() instanceof Crypto::SHA3
|
||||
// ) and
|
||||
// exists(string name |
|
||||
// hash_ref_type_mapping(instance, name, this.getHashType()) and
|
||||
// result = name.regexpFind("\\d{3}", 0, _) and
|
||||
// location = instance.getLocation()
|
||||
// )
|
||||
// }
|
||||
// override string getRawAlgorithmName() { result = instance.getTargetName() }
|
||||
// override Crypto::THashType getHashType() { hash_ref_type_mapping(instance, _, result) }
|
||||
// Element getInstance() { result = instance }
|
||||
// override Location getLocation() { result = instance.getLocation() }
|
||||
// }
|
||||
// /**
|
||||
// * Data-flow configuration for key derivation algorithm flow to EVP_KDF_derive.
|
||||
// */
|
||||
// module AlgorithmToEVPKeyDeriveConfig implements DataFlow::ConfigSig {
|
||||
// predicate isSource(DataFlow::Node source) {
|
||||
// source.asExpr() = any(KeyDerivationAlgorithm a).getInstance()
|
||||
// }
|
||||
// predicate isSink(DataFlow::Node sink) {
|
||||
// exists(EVP_KDF_derive kdo |
|
||||
// sink.asExpr() = kdo.getCall().getAlgorithmArg()
|
||||
// or
|
||||
// sink.asExpr() = kdo.getCall().getContextArg() // via `EVP_KDF_CTX_set_params`
|
||||
// )
|
||||
// }
|
||||
// predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
// none() // TODO
|
||||
// }
|
||||
// }
|
||||
// module AlgorithmToEVPKeyDeriveFlow = DataFlow::Global<AlgorithmToEVPKeyDeriveConfig>;
|
||||
// predicate algorithm_to_EVP_KDF_derive(KeyDerivationAlgorithm algo, EVP_KDF_derive derive) {
|
||||
// none()
|
||||
// }
|
||||
// /**
|
||||
// * Key derivation operation (e.g., `EVP_KDF_derive`)
|
||||
// */
|
||||
// class EVP_KDF_derive_FunctionCall extends Crypto::KeyDerivationOperationInstance instanceof FunctionCall
|
||||
// {
|
||||
// EVP_KDF_derive_FunctionCall() { this.getTarget().getName() = "EVP_KDF_derive" }
|
||||
// Expr getAlgorithmArg() { result = super.getArgument(3) }
|
||||
// Expr getContextArg() { result = super.getArgument(0) }
|
||||
// }
|
||||
// class EVP_KDF_derive extends Crypto::KeyDerivationOperation {
|
||||
// EVP_KDF_derive_FunctionCall instance;
|
||||
// EVP_KDF_derive() { this = Crypto::TKeyDerivationOperation(instance) }
|
||||
// override Crypto::Algorithm getAlgorithm() { algorithm_to_EVP_KDF_derive(result, this) }
|
||||
// EVP_KDF_derive_FunctionCall getCall() { result = instance }
|
||||
// }
|
||||
// /**
|
||||
// * Key derivation algorithm nodes
|
||||
// */
|
||||
// abstract class KeyDerivationAlgorithm extends Crypto::KeyDerivationAlgorithm {
|
||||
// abstract Expr getInstance();
|
||||
// }
|
||||
// /**
|
||||
// * `EVP_KDF_fetch` returns a key derivation algorithm.
|
||||
// */
|
||||
// class EVP_KDF_fetch_Call extends FunctionCall {
|
||||
// EVP_KDF_fetch_Call() { this.getTarget().getName() = "EVP_KDF_fetch" }
|
||||
// Expr getAlgorithmArg() { result = this.getArgument(1) }
|
||||
// }
|
||||
// class EVP_KDF_fetch_AlgorithmArg extends Crypto::KeyDerivationAlgorithmInstance instanceof Expr {
|
||||
// EVP_KDF_fetch_AlgorithmArg() { exists(EVP_KDF_fetch_Call call | this = call.getAlgorithmArg()) }
|
||||
// }
|
||||
// predicate kdf_names(string algo) { algo = ["HKDF", "PKCS12KDF", "PBKDF2"] }
|
||||
// class KDFAlgorithmStringLiteral extends StringLiteral {
|
||||
// KDFAlgorithmStringLiteral() { kdf_names(this.getValue().toUpperCase()) }
|
||||
// }
|
||||
// private module AlgorithmStringToFetchConfig implements DataFlow::ConfigSig {
|
||||
// predicate isSource(DataFlow::Node src) { src.asExpr() instanceof KDFAlgorithmStringLiteral }
|
||||
// predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof EVP_KDF_fetch_AlgorithmArg }
|
||||
// }
|
||||
// module AlgorithmStringToFetchFlow = DataFlow::Global<AlgorithmStringToFetchConfig>;
|
||||
// predicate algorithmStringToKDFFetchArgFlow(
|
||||
// string name, KDFAlgorithmStringLiteral origin, EVP_KDF_fetch_AlgorithmArg arg
|
||||
// ) {
|
||||
// origin.getValue().toUpperCase() = name and
|
||||
// AlgorithmStringToFetchFlow::flow(DataFlow::exprNode(origin), DataFlow::exprNode(arg))
|
||||
// }
|
||||
// /**
|
||||
// * HKDF key derivation algorithm.
|
||||
// */
|
||||
// class HKDF extends KeyDerivationAlgorithm, Crypto::HKDF {
|
||||
// KDFAlgorithmStringLiteral origin;
|
||||
// EVP_KDF_fetch_AlgorithmArg instance;
|
||||
// HKDF() {
|
||||
// this = Crypto::TKeyDerivationAlgorithm(instance) and
|
||||
// algorithmStringToKDFFetchArgFlow("HKDF", origin, instance)
|
||||
// }
|
||||
// override string getRawAlgorithmName() { result = origin.getValue() }
|
||||
// override Crypto::HashAlgorithm getHashAlgorithm() { none() }
|
||||
// override Crypto::LocatableElement getOrigin(string name) {
|
||||
// result = origin and name = origin.toString()
|
||||
// }
|
||||
// override Expr getInstance() { result = origin }
|
||||
// }
|
||||
// /**
|
||||
// * PBKDF2 key derivation algorithm.
|
||||
// */
|
||||
// class PBKDF2 extends KeyDerivationAlgorithm, Crypto::PBKDF2 {
|
||||
// KDFAlgorithmStringLiteral origin;
|
||||
// EVP_KDF_fetch_AlgorithmArg instance;
|
||||
// PBKDF2() {
|
||||
// this = Crypto::TKeyDerivationAlgorithm(instance) and
|
||||
// algorithmStringToKDFFetchArgFlow("PBKDF2", origin, instance)
|
||||
// }
|
||||
// override string getRawAlgorithmName() { result = origin.getValue() }
|
||||
// override string getIterationCount(Location location) { none() } // TODO
|
||||
// override string getKeyLength(Location location) { none() } // TODO
|
||||
// override Crypto::HashAlgorithm getHashAlgorithm() { none() } // TODO
|
||||
// override Crypto::LocatableElement getOrigin(string name) {
|
||||
// result = origin and name = origin.toString()
|
||||
// }
|
||||
// override Expr getInstance() { result = instance }
|
||||
// }
|
||||
// /**
|
||||
// * PKCS12KDF key derivation algorithm.
|
||||
// */
|
||||
// class PKCS12KDF extends KeyDerivationAlgorithm, Crypto::PKCS12KDF {
|
||||
// KDFAlgorithmStringLiteral origin;
|
||||
// EVP_KDF_fetch_AlgorithmArg instance;
|
||||
// PKCS12KDF() {
|
||||
// this = Crypto::TKeyDerivationAlgorithm(instance) and
|
||||
// algorithmStringToKDFFetchArgFlow("PKCS12KDF", origin, instance)
|
||||
// }
|
||||
// override string getRawAlgorithmName() { result = origin.getValue() }
|
||||
// override string getIterationCount(Location location) { none() } // TODO
|
||||
// override string getIDByte(Location location) { none() } // TODO
|
||||
// override Crypto::HashAlgorithm getHashAlgorithm() { none() } // TODO
|
||||
// override Crypto::LocatableElement getOrigin(string name) {
|
||||
// result = origin and name = origin.toString()
|
||||
// }
|
||||
// override Expr getInstance() { result = instance }
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,495 @@
|
||||
|
||||
// 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<AlgGetterToAlgConsumerConfig>;
|
||||
// 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<KnownOpenSSLAlgorithmToAlgorithmGetterConfig>;
|
||||
// /**
|
||||
// * 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() }
|
||||
// // }
|
||||
File diff suppressed because it is too large
Load Diff
21
cpp/ql/lib/experimental/Quantum/OpenSSL/Random.qll
Normal file
21
cpp/ql/lib/experimental/Quantum/OpenSSL/Random.qll
Normal file
@@ -0,0 +1,21 @@
|
||||
import cpp
|
||||
private import experimental.Quantum.Language
|
||||
private import codeql.cryptography.Model
|
||||
private import LibraryDetector
|
||||
private import semmle.code.cpp.dataflow.new.DataFlow
|
||||
|
||||
class OpenSSLRandomNumberGeneratorInstance extends Crypto::RandomNumberGenerationInstance instanceof Call
|
||||
{
|
||||
OpenSSLRandomNumberGeneratorInstance() {
|
||||
this.(Call).getTarget().getName() in ["RAND_bytes", "RAND_pseudo_bytes"] and
|
||||
isPossibleOpenSSLFunction(this.(Call).getTarget())
|
||||
}
|
||||
|
||||
override Crypto::DataFlowNode getOutputNode() {
|
||||
result.asDefiningArgument() = this.(Call).getArgument(0)
|
||||
}
|
||||
|
||||
override predicate flowsTo(Crypto::FlowAwareElement other) {
|
||||
ArtifactUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/**
|
||||
* @name "Print CBOM Graph"
|
||||
* @description "Outputs a graph representation of the cryptographic bill of materials."
|
||||
* @kind graph
|
||||
* @id cbomgraph
|
||||
*/
|
||||
|
||||
import experimental.Quantum.Language
|
||||
|
||||
string getPropertyString(Crypto::NodeBase node, string key) {
|
||||
result =
|
||||
strictconcat(any(string value, Location location, string parsed |
|
||||
node.properties(key, value, location) and
|
||||
parsed = "(" + value + "," + location.toString() + ")"
|
||||
|
|
||||
parsed
|
||||
), ","
|
||||
)
|
||||
}
|
||||
|
||||
string getLabel(Crypto::NodeBase node) { result = node.toString() }
|
||||
|
||||
query predicate nodes(Crypto::NodeBase node, string key, string value) {
|
||||
key = "semmle.label" and
|
||||
value = getLabel(node)
|
||||
or
|
||||
// CodeQL's DGML output does not include a location
|
||||
key = "Location" and
|
||||
value = node.getLocation().toString()
|
||||
or
|
||||
// Known unknown edges should be reported as properties rather than edges
|
||||
node = node.getChild(key) and
|
||||
value = "<unknown>"
|
||||
or
|
||||
// Report properties
|
||||
value = getPropertyString(node, key)
|
||||
}
|
||||
|
||||
query predicate edges(Crypto::NodeBase source, Crypto::NodeBase target, string key, string value) {
|
||||
key = "semmle.label" and
|
||||
target = source.getChild(value) and
|
||||
// Known unknowns are reported as properties rather than edges
|
||||
not source = target
|
||||
}
|
||||
|
||||
query predicate graphProperties(string key, string value) {
|
||||
key = "semmle.graphKind" and value = "graph"
|
||||
}
|
||||
21
cpp/ql/src/experimental/Quantum/PrintCBOMGraph.ql
Normal file
21
cpp/ql/src/experimental/Quantum/PrintCBOMGraph.ql
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @name Print CBOM Graph
|
||||
* @description Outputs a graph representation of the cryptographic bill of materials.
|
||||
* This query only supports DGML output, as CodeQL DOT output omits properties.
|
||||
* @kind graph
|
||||
* @id cpp/print-cbom-graph
|
||||
*/
|
||||
|
||||
import experimental.Quantum.Language
|
||||
|
||||
query predicate nodes(Crypto::NodeBase node, string key, string value) {
|
||||
Crypto::nodes_graph_impl(node, key, value)
|
||||
}
|
||||
|
||||
query predicate edges(Crypto::NodeBase source, Crypto::NodeBase target, string key, string value) {
|
||||
Crypto::edges_graph_impl(source, target, key, value)
|
||||
}
|
||||
|
||||
query predicate graphProperties(string key, string value) {
|
||||
key = "semmle.graphKind" and value = "graph"
|
||||
}
|
||||
Reference in New Issue
Block a user