mirror of
https://github.com/github/codeql.git
synced 2026-04-25 16:55:19 +02:00
Add JCA key (generation) modelling
This commit is contained in:
@@ -84,7 +84,7 @@ module JCAModel {
|
||||
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof CipherStringLiteral }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(CipherGetInstanceCall call | sink.asExpr() = call.getAlgorithmArg())
|
||||
exists(Crypto::AlgorithmValueConsumer consumer | sink = consumer.getInputNode())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,13 +102,13 @@ module JCAModel {
|
||||
class CipherStringLiteralAlgorithmInstance extends Crypto::CipherAlgorithmInstance,
|
||||
Crypto::ModeOfOperationAlgorithmInstance, Crypto::PaddingAlgorithmInstance instanceof CipherStringLiteral
|
||||
{
|
||||
CipherGetInstanceAlgorithmArg consumer;
|
||||
Crypto::AlgorithmValueConsumer consumer;
|
||||
|
||||
CipherStringLiteralAlgorithmInstance() {
|
||||
AlgorithmStringToFetchFlow::flow(DataFlow::exprNode(this), DataFlow::exprNode(consumer))
|
||||
AlgorithmStringToFetchFlow::flow(DataFlow::exprNode(this), consumer.getInputNode())
|
||||
}
|
||||
|
||||
CipherGetInstanceAlgorithmArg getConsumer() { result = consumer }
|
||||
Crypto::AlgorithmValueConsumer getConsumer() { result = consumer }
|
||||
|
||||
override Crypto::ModeOfOperationAlgorithmInstance getModeOfOperationAlgorithm() {
|
||||
result = this and exists(this.getRawModeAlgorithmName()) // TODO: provider defaults
|
||||
@@ -411,6 +411,19 @@ module JCAModel {
|
||||
}
|
||||
}
|
||||
|
||||
// e.g., getPublic or getPrivate
|
||||
class KeyPairGetKeyCall extends MethodCall {
|
||||
KeyPairGetKeyCall() {
|
||||
this.getCallee().hasQualifiedName("java.security", "KeyPair", "getPublic")
|
||||
or
|
||||
this.getCallee().hasQualifiedName("java.security", "KeyPair", "getPrivate")
|
||||
}
|
||||
|
||||
DataFlow::Node getInputNode() { result.asExpr() = this.getQualifier() }
|
||||
|
||||
DataFlow::Node getOutputNode() { result.asExpr() = this }
|
||||
}
|
||||
|
||||
predicate additionalFlowSteps(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(IvParameterSpecGetIvCall m |
|
||||
node1.asExpr() = m.getQualifier() and
|
||||
@@ -421,12 +434,17 @@ module JCAModel {
|
||||
node1 = n.getInputNode() and
|
||||
node2 = n.getOutputNode()
|
||||
)
|
||||
or
|
||||
exists(KeyPairGetKeyCall call |
|
||||
node1 = call.getInputNode() and
|
||||
node2 = call.getOutputNode()
|
||||
)
|
||||
}
|
||||
|
||||
class NonceAdditionalFlowInputStep extends AdditionalFlowInputStep {
|
||||
class ArtifactAdditionalFlowStep extends AdditionalFlowInputStep {
|
||||
DataFlow::Node output;
|
||||
|
||||
NonceAdditionalFlowInputStep() { additionalFlowSteps(this, output) }
|
||||
ArtifactAdditionalFlowStep() { additionalFlowSteps(this, output) }
|
||||
|
||||
override DataFlow::Node getOutput() { result = output }
|
||||
}
|
||||
@@ -605,4 +623,72 @@ module JCAModel {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class KeyGeneratorCallAlgorithmValueConsumer extends Crypto::AlgorithmValueConsumer {
|
||||
KeyGeneratorGetInstanceCall call;
|
||||
|
||||
KeyGeneratorCallAlgorithmValueConsumer() { this = call.getAlgorithmArg() }
|
||||
|
||||
override DataFlow::Node getInputNode() { result.asExpr() = this }
|
||||
|
||||
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
|
||||
result.(CipherStringLiteralAlgorithmInstance).getConsumer() = this
|
||||
}
|
||||
}
|
||||
|
||||
// flow from instance created by getInstance to generateKey
|
||||
module KeyGeneratorGetInstanceToGenerateConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node src) {
|
||||
exists(KeyGeneratorGetInstanceCall call | src.asExpr() = call)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(KeyGeneratorGenerateCall call | sink.asExpr() = call.(MethodCall).getQualifier())
|
||||
}
|
||||
}
|
||||
|
||||
module KeyGeneratorGetInstanceToGenerateFlow =
|
||||
DataFlow::Global<KeyGeneratorGetInstanceToGenerateConfig>;
|
||||
|
||||
class KeyGeneratorGetInstanceCall extends MethodCall {
|
||||
KeyGeneratorGetInstanceCall() {
|
||||
this.getCallee().hasQualifiedName("javax.crypto", "KeyGenerator", "getInstance")
|
||||
or
|
||||
this.getCallee().hasQualifiedName("java.security", "KeyPairGenerator", "getInstance")
|
||||
}
|
||||
|
||||
Expr getAlgorithmArg() { result = super.getArgument(0) }
|
||||
|
||||
predicate flowsTo(KeyGeneratorGenerateCall sink) {
|
||||
KeyGeneratorGetInstanceToGenerateFlow::flow(DataFlow::exprNode(this),
|
||||
DataFlow::exprNode(sink.(MethodCall).getQualifier()))
|
||||
}
|
||||
}
|
||||
|
||||
class KeyGeneratorGenerateCall extends Crypto::KeyGenerationOperationInstance instanceof MethodCall
|
||||
{
|
||||
Crypto::KeyArtifactType type;
|
||||
|
||||
KeyGeneratorGenerateCall() {
|
||||
this.getCallee().hasQualifiedName("javax.crypto", "KeyGenerator", "generateKey") and
|
||||
type instanceof Crypto::TSymmetricKeyType
|
||||
or
|
||||
this.getCallee().hasQualifiedName("java.security", "KeyPairGenerator", "generateKeyPair") and
|
||||
type instanceof Crypto::TAsymmetricKeyType
|
||||
}
|
||||
|
||||
override DataFlow::Node getOutputKeyArtifact() { result.asExpr() = this }
|
||||
|
||||
override Crypto::KeyArtifactType getOutputKeyType() { result = type }
|
||||
|
||||
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
|
||||
exists(KeyGeneratorGetInstanceCall getInstance |
|
||||
getInstance.flowsTo(this) and result = getInstance.getAlgorithmArg()
|
||||
)
|
||||
}
|
||||
|
||||
Crypto::AlgorithmInstance getAKnownAlgorithm() {
|
||||
result = this.getAnAlgorithmValueConsumer().getAKnownAlgorithmSource()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,12 @@ module CryptoInput implements InputSig<Language::Location> {
|
||||
result = node.asExpr() or
|
||||
result = node.asParameter()
|
||||
}
|
||||
|
||||
predicate artifactOutputFlowsToGenericInput(
|
||||
DataFlow::Node artifactOutput, DataFlow::Node otherInput
|
||||
) {
|
||||
ArtifactUniversalFlow::flow(artifactOutput, otherInput)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,16 +76,20 @@ class GenericRemoteDataSource extends Crypto::GenericRemoteDataSource {
|
||||
override string getAdditionalDescription() { result = this.toString() }
|
||||
}
|
||||
|
||||
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() }
|
||||
}
|
||||
/*
|
||||
* class ConstantDataSource extends Crypto::GenericConstantOrAllocationSource instanceof Literal {
|
||||
* ConstantDataSource() { not this instanceof Crypto::KnownElement }
|
||||
*
|
||||
* 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() }
|
||||
* }
|
||||
*/
|
||||
|
||||
/**
|
||||
* Random number generation, where each instance is modelled as the expression
|
||||
|
||||
@@ -7,11 +7,12 @@ import experimental.Quantum.Language
|
||||
from
|
||||
Crypto::CipherOperationNode op, Crypto::CipherAlgorithmNode a,
|
||||
Crypto::ModeOfOperationAlgorithmNode m, Crypto::PaddingAlgorithmNode p,
|
||||
Crypto::NonceArtifactNode nonce
|
||||
Crypto::NonceArtifactNode nonce, Crypto::KeyArtifactNode k
|
||||
where
|
||||
a = op.getAKnownCipherAlgorithm() and
|
||||
m = a.getModeOfOperation() and
|
||||
p = a.getPaddingAlgorithm() and
|
||||
nonce = op.getANonce()
|
||||
nonce = op.getANonce() and
|
||||
k = op.getAKey()
|
||||
select op, op.getCipherOperationSubtype(), a, a.getRawAlgorithmName(), m, m.getRawAlgorithmName(),
|
||||
p, p.getRawAlgorithmName(), nonce
|
||||
p, p.getRawAlgorithmName(), nonce, k, k.getSourceElement()
|
||||
|
||||
17
java/ql/src/experimental/Quantum/TestCipherKey.ql
Normal file
17
java/ql/src/experimental/Quantum/TestCipherKey.ql
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @name "PQC Test"
|
||||
*/
|
||||
|
||||
import experimental.Quantum.Language
|
||||
|
||||
from Crypto::CipherOperationNode op, Crypto::CipherAlgorithmNode a, Crypto::KeyArtifactNode k
|
||||
where
|
||||
a = op.getAKnownCipherAlgorithm() and
|
||||
k = op.getAKey()
|
||||
select op, op.getCipherOperationSubtype(), a, a.getRawAlgorithmName(), k, k.getSourceNode()
|
||||
/*
|
||||
* from Crypto::CipherOperationNode op
|
||||
* where op.getLocation().getFile().getBaseName() = "AsymmetricEncryptionMacHybridCryptosystem.java"
|
||||
* select op, op.getAKey().getSourceNode()
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user