mirror of
https://github.com/github/codeql.git
synced 2026-05-04 21:25:44 +02:00
Refactor instances and consumers + add JCA hashes
This commit is contained in:
@@ -205,7 +205,7 @@ module JCAModel {
|
||||
*
|
||||
* For example, in `Cipher.getInstance(algorithm)`, this class represents `algorithm`.
|
||||
*/
|
||||
class CipherGetInstanceAlgorithmArg extends Crypto::AlgorithmConsumer instanceof Expr {
|
||||
class CipherGetInstanceAlgorithmArg extends Crypto::AlgorithmValueConsumer instanceof Expr {
|
||||
CipherGetInstanceCall call;
|
||||
|
||||
CipherGetInstanceAlgorithmArg() { this = call.getAlgorithmArg() }
|
||||
@@ -218,7 +218,7 @@ module JCAModel {
|
||||
value = result.getValue()
|
||||
}
|
||||
|
||||
override Crypto::AlgorithmElement getAKnownAlgorithmSource() {
|
||||
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
result.(CipherStringLiteralAlgorithmInstance).getConsumer() = this
|
||||
}
|
||||
}
|
||||
@@ -354,15 +354,17 @@ module JCAModel {
|
||||
|
||||
override Crypto::CipherOperationSubtype getCipherOperationSubtype() { result = mode }
|
||||
|
||||
override Crypto::NonceArtifactConsumer getNonceConsumer() {
|
||||
result = sink.getState().(InitializedCipherModeFlowState).getInitCall().getNonceArg()
|
||||
override DataFlow::Node getNonceConsumer() {
|
||||
result.asExpr() = sink.getState().(InitializedCipherModeFlowState).getInitCall().getNonceArg()
|
||||
}
|
||||
|
||||
override Crypto::CipherInputConsumer getInputConsumer() {
|
||||
result = doFinalize.getMessageArg().asExpr()
|
||||
override DataFlow::Node getInputConsumer() { result = doFinalize.getMessageArg() }
|
||||
|
||||
override DataFlow::Node getKeyConsumer() {
|
||||
result.asExpr() = sink.getState().(InitializedCipherModeFlowState).getInitCall().getKeyArg()
|
||||
}
|
||||
|
||||
override Crypto::AlgorithmConsumer getAlgorithmConsumer() { result = consumer }
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() { result = consumer }
|
||||
|
||||
override Crypto::CipherOutputArtifactInstance getOutputArtifact() {
|
||||
result = doFinalize.getOutput()
|
||||
@@ -493,27 +495,114 @@ module JCAModel {
|
||||
}
|
||||
}
|
||||
|
||||
class CipherInitCallNonceArgConsumer extends Crypto::NonceArtifactConsumer instanceof Expr {
|
||||
CipherInitCallNonceArgConsumer() { this = any(CipherInitCall call).getNonceArg() }
|
||||
|
||||
override DataFlow::Node getInputNode() { result.asExpr() = this }
|
||||
}
|
||||
|
||||
class CipherInitCallKeyConsumer extends Crypto::ArtifactConsumer {
|
||||
CipherInitCallKeyConsumer() { this = any(CipherInitCall call).getKeyArg() }
|
||||
|
||||
override DataFlow::Node getInputNode() { result.asExpr() = this }
|
||||
}
|
||||
|
||||
class CipherMessageInputConsumer extends Crypto::CipherInputConsumer {
|
||||
CipherMessageInputConsumer() { this = any(CipherOperationCall call).getMessageArg().asExpr() }
|
||||
|
||||
override DataFlow::Node getInputNode() { result.asExpr() = this }
|
||||
}
|
||||
|
||||
class CipherOperationCallOutput extends CipherOutputArtifact {
|
||||
CipherOperationCallOutput() { this = any(CipherOperationCall call).getOutput() }
|
||||
|
||||
override DataFlow::Node getOutputNode() { result.asExpr() = this }
|
||||
}
|
||||
|
||||
bindingset[hash]
|
||||
predicate hash_names(string hash) {
|
||||
hash.toUpperCase()
|
||||
.matches([
|
||||
"SHA-1", "SHA-256", "SHA-384", "SHA-512", "SHA3-224", "SHA3-256", "SHA3-384",
|
||||
"SHA3-512", "BLAKE2b", "BLAKE2s"
|
||||
].toUpperCase())
|
||||
}
|
||||
|
||||
// flow config from a known hash algorithm literal to MessageDigest.getInstance
|
||||
module KnownHashAlgorithmLiteralToMessageDigestConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { hash_names(src.asExpr().(StringLiteral).getValue()) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(MessageDigestGetInstanceCall call | sink.asExpr() = call.getAlgorithmArg())
|
||||
}
|
||||
}
|
||||
|
||||
module KnownHashAlgorithmLiteralToMessageDigestFlow =
|
||||
DataFlow::Global<KnownHashAlgorithmLiteralToMessageDigestConfig>;
|
||||
|
||||
class KnownHashAlgorithm extends Crypto::HashAlgorithmInstance instanceof StringLiteral {
|
||||
MessageDigestAlgorithmValueConsumer consumer;
|
||||
|
||||
KnownHashAlgorithm() {
|
||||
hash_names(this.getValue()) and
|
||||
KnownHashAlgorithmLiteralToMessageDigestFlow::flow(DataFlow::exprNode(this),
|
||||
consumer.getInputNode())
|
||||
}
|
||||
|
||||
MessageDigestAlgorithmValueConsumer getConsumer() { result = consumer }
|
||||
|
||||
override string getRawAlgorithmName() { result = this.(StringLiteral).getValue() }
|
||||
|
||||
override Crypto::THashType getHashFamily() {
|
||||
result = Crypto::OtherHashType() // TODO
|
||||
}
|
||||
}
|
||||
|
||||
class MessageDigestAlgorithmValueConsumer extends Crypto::AlgorithmValueConsumer {
|
||||
MessageDigestGetInstanceCall call;
|
||||
|
||||
MessageDigestAlgorithmValueConsumer() { this = call.getAlgorithmArg() }
|
||||
|
||||
override DataFlow::Node getInputNode() { result.asExpr() = this }
|
||||
|
||||
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
exists(KnownHashAlgorithm l | l.getConsumer() = this and result = l)
|
||||
}
|
||||
}
|
||||
|
||||
class MessageDigestGetInstanceCall extends MethodCall {
|
||||
MessageDigestGetInstanceCall() {
|
||||
this.getCallee().hasQualifiedName("java.security", "MessageDigest", "getInstance")
|
||||
}
|
||||
|
||||
Expr getAlgorithmArg() { result = this.getArgument(0) }
|
||||
|
||||
DigestHashOperation getDigestCall() {
|
||||
DigestGetInstanceToDigestFlow::flow(DataFlow::exprNode(this),
|
||||
DataFlow::exprNode(result.(DigestCall).getQualifier()))
|
||||
}
|
||||
}
|
||||
|
||||
class DigestCall extends MethodCall {
|
||||
DigestCall() { this.getCallee().hasQualifiedName("java.security", "MessageDigest", "digest") }
|
||||
|
||||
Expr getDigestArtifactOutput() { result = this }
|
||||
}
|
||||
|
||||
// flow config from MessageDigest.getInstance to MessageDigest.digest
|
||||
module DigestGetInstanceToDigestConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof MessageDigestGetInstanceCall }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(DigestCall c | c.getQualifier() = sink.asExpr())
|
||||
}
|
||||
}
|
||||
|
||||
module DigestGetInstanceToDigestFlow = DataFlow::Global<DigestGetInstanceToDigestConfig>;
|
||||
|
||||
class DigestArtifact extends DigestArtifactInstance {
|
||||
DigestArtifact() { this = any(DigestCall call).getDigestArtifactOutput() }
|
||||
|
||||
override DataFlow::Node getOutputNode() { result.asExpr() = this }
|
||||
}
|
||||
|
||||
class DigestHashOperation extends Crypto::HashOperationInstance instanceof DigestCall {
|
||||
override Crypto::DigestArtifactInstance getDigestArtifact() {
|
||||
result = this.(DigestCall).getDigestArtifactOutput()
|
||||
}
|
||||
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
exists(MessageDigestGetInstanceCall call |
|
||||
call.getDigestCall() = this and result = call.getAlgorithmArg()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,11 @@ module CryptoInput implements InputSig<Language::Location> {
|
||||
class LocatableElement = Language::Element;
|
||||
|
||||
class UnknownLocation = UnknownDefaultLocation;
|
||||
|
||||
LocatableElement dfn_to_element(DataFlow::Node node) {
|
||||
result = node.asExpr() or
|
||||
result = node.asParameter()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,6 +105,17 @@ class InsecureRandomnessInstance extends RandomnessInstance {
|
||||
InsecureRandomnessInstance() { exists(InsecureRandomnessSource node | this = node.asExpr()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Output artifact flow logic
|
||||
*/
|
||||
abstract class DigestArtifactInstance extends Crypto::DigestArtifactInstance {
|
||||
override predicate flowsTo(Crypto::FlowAwareElement other) {
|
||||
ArtifactUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
|
||||
}
|
||||
|
||||
override predicate isConsumerArtifact() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Artifact output to node input configuration
|
||||
*/
|
||||
@@ -115,6 +131,8 @@ abstract class CipherOutputArtifact extends Crypto::CipherOutputArtifactInstance
|
||||
override predicate flowsTo(Crypto::FlowAwareElement other) {
|
||||
ArtifactUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
|
||||
}
|
||||
|
||||
override predicate isConsumerArtifact() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,7 +162,7 @@ module GenericDataSourceUniversalFlowConfig implements DataFlow::ConfigSig {
|
||||
|
||||
module ArtifactUniversalFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source = any(Crypto::ArtifactElement artifact).getOutputNode()
|
||||
source = any(Crypto::ArtifactInstance artifact).getOutputNode()
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
|
||||
Reference in New Issue
Block a user