Intermediate progress towards getting hashing upgraded. Still need to handle the final and update mechanics, matching the JCA. Similarly need to update cipher to follow the JCA for update/final as well.

This commit is contained in:
REDMOND\brodes
2025-05-02 16:33:52 -04:00
parent 94632931ba
commit 0a0be41527
11 changed files with 37 additions and 254 deletions

View File

@@ -2,3 +2,4 @@ import OpenSSLAlgorithmInstanceBase
import CipherAlgorithmInstance
import PaddingAlgorithmInstance
import BlockAlgorithmInstance
import HashAlgorithmInstance

View File

@@ -2,3 +2,4 @@ import OpenSSLAlgorithmValueConsumerBase
import CipherAlgorithmValueConsumer
import DirectAlgorithmValueConsumer
import PaddingAlgorithmValueConsumer
import HashAlgorithmValueConsumer

View File

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

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

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

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

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

@@ -4,9 +4,7 @@ import EVPCipherInitializer
import OpenSSLOperationBase
import experimental.Quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
// import experimental.Quantum.OpenSSL.AlgorithmValueConsumers.AlgorithmValueConsumers
// import OpenSSLOperation
module AlgGetterToAlgConsumerConfig implements DataFlow::ConfigSig {
private module AlgGetterToAlgConsumerConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
exists(OpenSSLAlgorithmValueConsumer c | c.getResultNode() = source)
}
@@ -16,8 +14,10 @@ module AlgGetterToAlgConsumerConfig implements DataFlow::ConfigSig {
}
}
module AlgGetterToAlgConsumerFlow = DataFlow::Global<AlgGetterToAlgConsumerConfig>;
private module AlgGetterToAlgConsumerFlow = DataFlow::Global<AlgGetterToAlgConsumerConfig>;
// import experimental.Quantum.OpenSSL.AlgorithmValueConsumers.AlgorithmValueConsumers
// import OpenSSLOperation
// class EVPCipherOutput extends CipherOutputArtifact {
// EVPCipherOutput() { exists(EVP_Cipher_Operation op | op.getOutputArg() = this) }
// override DataFlow::Node getOutputNode() { result.asDefiningArgument() = this }
@@ -81,6 +81,8 @@ class EVP_Cipher_Call extends EVP_Cipher_Operation {
override Expr getInputArg() { result = this.(Call).getArgument(2) }
}
// ******* TODO NEED to model UPDATE but not as the coree operation, rather a step towards final,
// see the JCA
// class EVP_Encrypt_Decrypt_or_Cipher_Update_Call extends EVP_Update_Call {
// EVP_Encrypt_Decrypt_or_Cipher_Update_Call() {
// this.(Call).getTarget().getName() in [

View File

@@ -1 +1,3 @@
import OpenSSLOperationBase
import EVPCipherOperation
import EVPHashOperation