Tracing new notion of known getters, which now includes direct getters for cipher and hash. Removed a redundant hash qll, and fixed misplacement of has type in model.

This commit is contained in:
REDMOND\brodes
2025-03-10 11:46:26 -04:00
parent 451808616e
commit 0672027822
7 changed files with 107 additions and 121 deletions

View File

@@ -3,7 +3,13 @@ import experimental.Quantum.Language
import EVPCipherConsumers
import OpenSSLAlgorithmGetter
predicate literalToCipherFamilyType(Literal e, Crypto::TCipherType type) {
/**
* Given a literal `e`, converts this to a cipher family type.
* The literal must be a known literal representing a cipher algorithm.
* If the literal does not represent any known cipher algorithm,
* this predicate will not hold (i.e., it will not bind an unknown to an unknown cipher type)
*/
predicate literalToCipherFamilyType(Literal e, Crypto::TCipherType type) {
exists(string name, string algType | algType.toLowerCase().matches("%encryption") |
resolveAlgorithmFromLiteral(e, name, algType) and
(
@@ -52,25 +58,36 @@ predicate literalToCipherFamilyType(Literal e, Crypto::TCipherType type) {
)
}
class CipherKnownAlgorithmLiteralAlgorithmInstance extends Crypto::CipherAlgorithmInstance instanceof Literal
class KnownOpenSSLCipherConstantAlgorithmInstance extends Crypto::CipherAlgorithmInstance instanceof KnownOpenSSLAlgorithmConstant
{
OpenSSLAlgorithmGetterCall cipherGetterCall;
CipherKnownAlgorithmLiteralAlgorithmInstance() {
exists(DataFlow::Node src, DataFlow::Node sink |
sink = cipherGetterCall.getValueArgNode() and
src.asExpr() = this and
KnownAlgorithmLiteralToAlgorithmGetterFlow::flow(src, sink) and
// Not just any known value, but specifically a known cipher operation
exists(string algType |
resolveAlgorithmFromLiteral(src.asExpr(), _, algType) and
algType.toLowerCase().matches("%encryption")
OpenSSLAlgorithmGetterCall getterCall;
KnownOpenSSLCipherConstantAlgorithmInstance() {
// Not just any known value, but specifically a known cipher operation
this.(KnownOpenSSLAlgorithmConstant).getAlgType().toLowerCase().matches("%encryption") 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(cipherGetterCall.getResultNode(), DataFlow::exprNode(result))
}
Crypto::AlgorithmConsumer getConsumer() {
AlgGetterToAlgConsumerFlow::flow(getterCall.getResultNode(), DataFlow::exprNode(result))
}
override Crypto::ModeOfOperationAlgorithmInstance getModeOfOperationAlgorithm() {
none() // TODO: provider defaults

View File

@@ -2,24 +2,24 @@ 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 DataFlow::Node getInputNode() { result.asExpr() = this }
override Crypto::AlgorithmElement getAKnownAlgorithmSource() {
result.(CipherKnownAlgorithmLiteralAlgorithmInstance).getConsumer() = this
}
override Crypto::AlgorithmElement 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_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 }
class EVP_Cipher_Input_Consumer extends Crypto::CipherInputConsumer instanceof EVPCipherInputArgument
{
override DataFlow::Node getInputNode() { result.asExpr() = this }
}

View File

@@ -1,67 +0,0 @@
import cpp
import experimental.Quantum.Language
import EVPCipherConsumers
import OpenSSLAlgorithmGetter
predicate literalToHashFamilyType(Literal e, Crypto::THashType type) {
exists(string name, string algType | algType.toLowerCase().matches("%hash") |
resolveAlgorithmFromLiteral(e, name, algType) and
(
name.matches("BLAKE2B") and type instanceof Crypto::BLAKE2B
or
name.matches("BLAKE2S") and type instanceof Crypto::BLAKE2S
or
name.matches("RIPEMD160") and type instanceof Crypto::RIPEMD160
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("POLY1305") and type instanceof Crypto::POLY1305
or
name.matches(["SHA1", "SHA"]) and type instanceof Crypto::SHA1
or
name.matches("SHA2") 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("WHIRLPOOL") and type instanceof Crypto::WHIRLPOOL
// TODO: what about MD_GOST?
)
)
}
class HashKnownAlgorithmLiteralAlgorithmInstance extends Crypto::HashAlgorithmInstance instanceof Literal
{
OpenSSLAlgorithmGetterCall getterCall;
HashKnownAlgorithmLiteralAlgorithmInstance() {
exists(DataFlow::Node src, DataFlow::Node sink |
sink = getterCall.getValueArgNode() and
src.asExpr() = this and
KnownAlgorithmLiteralToAlgorithmGetterFlow::flow(src, sink) and
// Not just any known value, but specifically a known cipher operation
exists(string algType |
resolveAlgorithmFromLiteral(src.asExpr(), _, algType) and
algType.toLowerCase().matches("hash")
)
)
}
// TODO: should this not be part of the abstract algorithm definition?
Crypto::AlgorithmConsumer getConsumer() {
AlgGetterToAlgConsumerFlow::flow(getterCall.getResultNode(), DataFlow::exprNode(result))
}
override Crypto::THashType getHashFamily() { literalToHashFamilyType(this, result) }
override int getHashSize() { none() } //TODO
override string getRawAlgorithmName() { result = this.(Literal).getValue().toString() }
}

View File

@@ -1,6 +1,5 @@
import cpp
import experimental.Quantum.Language
import EVPHashConsumers
import OpenSSLAlgorithmGetter
predicate literalToHashFamilyType(Literal e, Crypto::THashType type) {
@@ -11,12 +10,16 @@ predicate literalToHashFamilyType(Literal e, Crypto::THashType type) {
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
@@ -31,40 +34,45 @@ predicate literalToHashFamilyType(Literal e, Crypto::THashType type) {
or
name.matches("RIPEMD160") and type instanceof Crypto::RIPEMD160
or
//or
//TODO: need to handle MACs differently, including md_GOST94
// name.matches("%GOST%") and type instanceof Crypto::GOST
name.matches("WHIRLPOOL") and type instanceof Crypto::WHIRLPOOL
)
)
}
class HashKnownAlgorithmLiteralAlgorithmInstance extends Crypto::HashAlgorithmInstance instanceof Literal
class KnownOpenSSLHashConstantAlgorithmInstance extends Crypto::HashAlgorithmInstance instanceof KnownOpenSSLAlgorithmConstant
{
OpenSSLAlgorithmGetterCall cipherGetterCall;
OpenSSLAlgorithmGetterCall getterCall;
HashKnownAlgorithmLiteralAlgorithmInstance() {
exists(DataFlow::Node src, DataFlow::Node sink |
sink = cipherGetterCall.getValueArgNode() and
src.asExpr() = this and
KnownAlgorithmLiteralToAlgorithmGetterFlow::flow(src, sink) and
// Not just any known value, but specifically a known cipher operation
exists(string algType |
resolveAlgorithmFromLiteral(src.asExpr(), _, algType) and
algType.toLowerCase().matches("hash")
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(cipherGetterCall.getResultNode(), DataFlow::exprNode(result))
AlgGetterToAlgConsumerFlow::flow(getterCall.getResultNode(), DataFlow::exprNode(result))
}
override Crypto::THashType getHashFamily() {
literalToHashFamilyType(this, result)
}
override Crypto::THashType getHashFamily() { literalToHashFamilyType(this, result) }
override string getRawAlgorithmName() { result = this.(Literal).getValue().toString() }
override int getHashSize() {none() }//TODO
override int getHashSize() { none() } //TODO
}

View File

@@ -6,7 +6,7 @@ class EVP_Digest_Initializer_Algorithm_Consumer extends Crypto::AlgorithmConsume
override DataFlow::Node getInputNode() { result.asExpr() = this }
override Crypto::AlgorithmElement getAKnownAlgorithmSource() {
result.(HashKnownAlgorithmLiteralAlgorithmInstance).getConsumer() = this
result.(KnownOpenSSLHashConstantAlgorithmInstance).getConsumer() = this
}
}
@@ -14,7 +14,7 @@ class EVP_Q_Digest_Algorithm_Consumer extends Crypto::AlgorithmConsumer instance
override DataFlow::Node getInputNode() { result.asExpr() = this }
override Crypto::AlgorithmElement getAKnownAlgorithmSource() {
result.(HashKnownAlgorithmLiteralAlgorithmInstance).getConsumer() = this
result.(KnownOpenSSLHashConstantAlgorithmInstance).getConsumer() = this
}
}
@@ -22,6 +22,6 @@ class EVP_Digest_Algorithm_Consumer extends Crypto::AlgorithmConsumer instanceof
override DataFlow::Node getInputNode() { result.asExpr() = this }
override Crypto::AlgorithmElement getAKnownAlgorithmSource() {
result.(HashKnownAlgorithmLiteralAlgorithmInstance).getConsumer() = this
result.(KnownOpenSSLHashConstantAlgorithmInstance).getConsumer() = this
}
}

View File

@@ -128,8 +128,10 @@ abstract class OpenSSLAlgorithmGetterCall extends Call {
abstract Expr getResultExpr();
}
module KnownAlgorithmLiteralToAlgorithmGetterConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { resolveAlgorithmFromLiteral(source.asExpr(), _, _) }
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)
@@ -151,8 +153,33 @@ module KnownAlgorithmLiteralToAlgorithmGetterConfig implements DataFlow::ConfigS
}
}
module KnownAlgorithmLiteralToAlgorithmGetterFlow =
DataFlow::Global<KnownAlgorithmLiteralToAlgorithmGetterConfig>;
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 {

View File

@@ -1042,6 +1042,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
MD2() or
MD4() or
MD5() or
MDC2() or
POLY1305() or
SHA1() or
SHA2() or