Merge pull request #2 from nicolaswill/knewbury01/JCA-sample

Implement first stage cryptography modelling and queries
This commit is contained in:
Nicolas Will
2025-04-30 16:39:56 +02:00
committed by GitHub
47 changed files with 8862 additions and 276 deletions

View File

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

View File

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

View 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
)
}

View File

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

View File

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

View 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
}
}

View File

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

View 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
}
}

View File

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

View File

@@ -0,0 +1,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 }
// }
}

View File

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

View 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())
}
}

View File

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

View 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"
}