Make ArtifactConsumers instances of some Artifacts

TODO: refactor the interfaces
This commit is contained in:
Nicolas Will
2025-02-27 15:54:38 +01:00
parent ef0614ad45
commit 0354afc365
3 changed files with 69 additions and 41 deletions

View File

@@ -346,7 +346,7 @@ module JCAModel {
override Crypto::CipherOperationSubtype getCipherOperationSubtype() { result = mode }
override Crypto::ArtifactConsumer getNonceConsumer() {
override Crypto::NonceArtifactConsumer getNonceConsumer() {
result = sink.getState().(InitializedCipherModeFlowState).getInitCall().getNonceArg()
}
@@ -360,9 +360,10 @@ module JCAModel {
/**
* Initialization vectors and other nonce artifacts
*/
abstract class NonceParameterInstantiation extends NonceArtifactInstance instanceof ClassInstanceExpr
{
override DataFlow::Node getOutputNode() { result.asExpr() = this }
abstract class NonceParameterInstantiation extends ClassInstanceExpr {
DataFlow::Node getOutputNode() { result.asExpr() = this }
abstract DataFlow::Node getInputNode();
}
class IvParameterSpecInstance extends NonceParameterInstantiation {
@@ -396,32 +397,25 @@ module JCAModel {
}
}
module NonceArtifactToCipherInitCallConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) {
exists(NonceParameterInstantiation n |
src = n.getOutputNode() and
not exists(IvParameterSpecGetIvCall m | n.getInputNode().asExpr() = m)
)
}
predicate isSink(DataFlow::Node sink) {
exists(CipherInitCall c | c.getNonceArg() = sink.asExpr())
}
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(IvParameterSpecGetIvCall m |
node1.asExpr() = m.getQualifier() and
node2.asExpr() = m
)
or
exists(NonceParameterInstantiation n |
node1 = n.getInputNode() and
node2.asExpr() = n
)
}
predicate additionalFlowSteps(DataFlow::Node node1, DataFlow::Node node2) {
exists(IvParameterSpecGetIvCall m |
node1.asExpr() = m.getQualifier() and
node2.asExpr() = m
)
or
exists(NonceParameterInstantiation n |
node1 = n.getInputNode() and
node2 = n.getOutputNode()
)
}
module NonceArtifactToCipherInitCallFlow = DataFlow::Global<NonceArtifactToCipherInitCallConfig>;
class NonceAdditionalFlowInputStep extends AdditionalFlowInputStep {
DataFlow::Node output;
NonceAdditionalFlowInputStep() { additionalFlowSteps(this, output) }
override DataFlow::Node getOutput() { result = output }
}
/**
* A data-flow configuration to track flow from a mode field access to
@@ -487,7 +481,7 @@ module JCAModel {
}
}
class CipherInitCallNonceArgConsumer extends Crypto::ArtifactConsumer instanceof Expr {
class CipherInitCallNonceArgConsumer extends Crypto::NonceArtifactConsumer instanceof Expr {
CipherInitCallNonceArgConsumer() { this = any(CipherInitCall call).getNonceArg() }
override DataFlow::Node getInputNode() { result.asExpr() = this }

View File

@@ -65,6 +65,19 @@ 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) {
other instanceof NonceArtifactInstance and
// limit to only nonces for now
// 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
* tied to an output node (i.e., the result of the source of randomness)
@@ -94,6 +107,12 @@ class InsecureRandomnessInstance extends RandomnessInstance {
/**
* Artifact output to node input configuration
*/
abstract class AdditionalFlowInputStep extends DataFlow::Node {
abstract DataFlow::Node getOutput();
final DataFlow::Node getInput() { result = this }
}
module ArtifactUniversalFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source = any(Crypto::ArtifactElement artifact).getOutputNode()
@@ -106,14 +125,28 @@ module ArtifactUniversalFlowConfig implements DataFlow::ConfigSig {
predicate isBarrierIn(DataFlow::Node node) {
node = any(Crypto::FlowAwareElement element).getOutputNode()
}
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
node1.(AdditionalFlowInputStep).getOutput() = node2
}
}
module ArtifactUniversalFlow = DataFlow::Global<ArtifactUniversalFlowConfig>;
abstract class NonceArtifactInstance extends Crypto::NonceArtifactInstance {
class NonceArtifactInstance extends Crypto::NonceArtifactInstance {
NonceArtifactInstance() { this instanceof Crypto::NonceArtifactConsumer }
override predicate flowsTo(Crypto::FlowAwareElement other) {
ArtifactUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
}
override DataFlow::Node getOutputNode() {
result = this.(Crypto::NonceArtifactConsumer).getOutputNode()
}
override DataFlow::Node getInputNode() {
result = this.(Crypto::NonceArtifactConsumer).getInputNode()
}
}
/**
@@ -131,6 +164,10 @@ module GenericDataSourceUniversalFlowConfig implements DataFlow::ConfigSig {
predicate isBarrierIn(DataFlow::Node node) {
node = any(Crypto::FlowAwareElement element).getOutputNode()
}
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
node1.(AdditionalFlowInputStep).getOutput() = node2
}
}
module GenericDataSourceUniversalFlow = DataFlow::Global<GenericDataSourceUniversalFlowConfig>;

View File

@@ -205,12 +205,16 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
abstract AlgorithmElement getAKnownAlgorithmSource();
}
abstract class ArtifactConsumer extends ConsumerElement {
abstract class ArtifactConsumer extends ConsumerElement, ArtifactElement {
final override KnownElement getAKnownSource() { result = this.getAKnownArtifactSource() }
final ArtifactElement getAKnownArtifactSource() { result.flowsTo(this) }
}
abstract class NonceArtifactConsumer extends ArtifactConsumer {
NonceArtifactInstance asNonce() { result = this }
}
abstract class CipherOperationInstance extends OperationElement {
/**
* Gets the subtype of this cipher operation, distinguishing encryption, decryption, key wrapping, and key unwrapping.
@@ -220,7 +224,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
/**
* Gets the consumer of nonces/IVs associated with this cipher operation.
*/
abstract ArtifactConsumer getNonceConsumer();
abstract NonceArtifactConsumer getNonceConsumer();
/**
* Gets the consumer of plaintext or ciphertext input associated with this cipher operation.
@@ -586,13 +590,8 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
result = instance.getCipherOperationSubtype()
}
NodeBase getANonceOrUnknown() {
result =
this.asElement().(CipherOperationInstance).getNonceConsumer().getAKnownOrUnknownSourceNode()
}
NonceNode getANonce() {
result = this.asElement().(CipherOperationInstance).getNonceConsumer().getAKnownSourceNode()
result.asElement() = this.asElement().(CipherOperationInstance).getNonceConsumer().asNonce()
}
NodeBase getAMessageOrUnknown() {
@@ -614,9 +613,7 @@ module CryptographyBase<LocationSig Location, InputSig<Location> Input> {
or
// [KNOWN_OR_UNKNOWN]
key = "Nonce" and
if exists(this.getANonceOrUnknown())
then result = this.getANonceOrUnknown()
else result = this
if exists(this.getANonce()) then result = this.getANonce() else result = this
or
// [KNOWN_OR_UNKNOWN]
key = "Message" and