mirror of
https://github.com/github/codeql.git
synced 2026-05-01 03:35:13 +02:00
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:
@@ -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
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user