Skip to content

Commit 9278a41

Browse files
committed
Merge branch 'brodes/cipher_operation' of https://github.com/nicolaswill/codeql into brodes/cipher_operation
2 parents b695641 + d18dac0 commit 9278a41

File tree

5 files changed

+240
-39
lines changed

5 files changed

+240
-39
lines changed

java/ql/lib/experimental/Quantum/JCA.qll

Lines changed: 92 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ module JCAModel {
8484
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof CipherStringLiteral }
8585

8686
predicate isSink(DataFlow::Node sink) {
87-
exists(CipherGetInstanceCall call | sink.asExpr() = call.getAlgorithmArg())
87+
exists(Crypto::AlgorithmValueConsumer consumer | sink = consumer.getInputNode())
8888
}
8989
}
9090

@@ -102,13 +102,13 @@ module JCAModel {
102102
class CipherStringLiteralAlgorithmInstance extends Crypto::CipherAlgorithmInstance,
103103
Crypto::ModeOfOperationAlgorithmInstance, Crypto::PaddingAlgorithmInstance instanceof CipherStringLiteral
104104
{
105-
CipherGetInstanceAlgorithmArg consumer;
105+
Crypto::AlgorithmValueConsumer consumer;
106106

107107
CipherStringLiteralAlgorithmInstance() {
108-
AlgorithmStringToFetchFlow::flow(DataFlow::exprNode(this), DataFlow::exprNode(consumer))
108+
AlgorithmStringToFetchFlow::flow(DataFlow::exprNode(this), consumer.getInputNode())
109109
}
110110

111-
CipherGetInstanceAlgorithmArg getConsumer() { result = consumer }
111+
Crypto::AlgorithmValueConsumer getConsumer() { result = consumer }
112112

113113
override Crypto::ModeOfOperationAlgorithmInstance getModeOfOperationAlgorithm() {
114114
result = this and exists(this.getRawModeAlgorithmName()) // TODO: provider defaults
@@ -411,6 +411,19 @@ module JCAModel {
411411
}
412412
}
413413

414+
// e.g., getPublic or getPrivate
415+
class KeyPairGetKeyCall extends MethodCall {
416+
KeyPairGetKeyCall() {
417+
this.getCallee().hasQualifiedName("java.security", "KeyPair", "getPublic")
418+
or
419+
this.getCallee().hasQualifiedName("java.security", "KeyPair", "getPrivate")
420+
}
421+
422+
DataFlow::Node getInputNode() { result.asExpr() = this.getQualifier() }
423+
424+
DataFlow::Node getOutputNode() { result.asExpr() = this }
425+
}
426+
414427
predicate additionalFlowSteps(DataFlow::Node node1, DataFlow::Node node2) {
415428
exists(IvParameterSpecGetIvCall m |
416429
node1.asExpr() = m.getQualifier() and
@@ -421,12 +434,17 @@ module JCAModel {
421434
node1 = n.getInputNode() and
422435
node2 = n.getOutputNode()
423436
)
437+
or
438+
exists(KeyPairGetKeyCall call |
439+
node1 = call.getInputNode() and
440+
node2 = call.getOutputNode()
441+
)
424442
}
425443

426-
class NonceAdditionalFlowInputStep extends AdditionalFlowInputStep {
444+
class ArtifactAdditionalFlowStep extends AdditionalFlowInputStep {
427445
DataFlow::Node output;
428446

429-
NonceAdditionalFlowInputStep() { additionalFlowSteps(this, output) }
447+
ArtifactAdditionalFlowStep() { additionalFlowSteps(this, output) }
430448

431449
override DataFlow::Node getOutput() { result = output }
432450
}
@@ -605,4 +623,72 @@ module JCAModel {
605623
)
606624
}
607625
}
626+
627+
class KeyGeneratorCallAlgorithmValueConsumer extends Crypto::AlgorithmValueConsumer {
628+
KeyGeneratorGetInstanceCall call;
629+
630+
KeyGeneratorCallAlgorithmValueConsumer() { this = call.getAlgorithmArg() }
631+
632+
override DataFlow::Node getInputNode() { result.asExpr() = this }
633+
634+
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
635+
result.(CipherStringLiteralAlgorithmInstance).getConsumer() = this
636+
}
637+
}
638+
639+
// flow from instance created by getInstance to generateKey
640+
module KeyGeneratorGetInstanceToGenerateConfig implements DataFlow::ConfigSig {
641+
predicate isSource(DataFlow::Node src) {
642+
exists(KeyGeneratorGetInstanceCall call | src.asExpr() = call)
643+
}
644+
645+
predicate isSink(DataFlow::Node sink) {
646+
exists(KeyGeneratorGenerateCall call | sink.asExpr() = call.(MethodCall).getQualifier())
647+
}
648+
}
649+
650+
module KeyGeneratorGetInstanceToGenerateFlow =
651+
DataFlow::Global<KeyGeneratorGetInstanceToGenerateConfig>;
652+
653+
class KeyGeneratorGetInstanceCall extends MethodCall {
654+
KeyGeneratorGetInstanceCall() {
655+
this.getCallee().hasQualifiedName("javax.crypto", "KeyGenerator", "getInstance")
656+
or
657+
this.getCallee().hasQualifiedName("java.security", "KeyPairGenerator", "getInstance")
658+
}
659+
660+
Expr getAlgorithmArg() { result = super.getArgument(0) }
661+
662+
predicate flowsTo(KeyGeneratorGenerateCall sink) {
663+
KeyGeneratorGetInstanceToGenerateFlow::flow(DataFlow::exprNode(this),
664+
DataFlow::exprNode(sink.(MethodCall).getQualifier()))
665+
}
666+
}
667+
668+
class KeyGeneratorGenerateCall extends Crypto::KeyGenerationOperationInstance instanceof MethodCall
669+
{
670+
Crypto::KeyArtifactType type;
671+
672+
KeyGeneratorGenerateCall() {
673+
this.getCallee().hasQualifiedName("javax.crypto", "KeyGenerator", "generateKey") and
674+
type instanceof Crypto::TSymmetricKeyType
675+
or
676+
this.getCallee().hasQualifiedName("java.security", "KeyPairGenerator", "generateKeyPair") and
677+
type instanceof Crypto::TAsymmetricKeyType
678+
}
679+
680+
override DataFlow::Node getOutputKeyArtifact() { result.asExpr() = this }
681+
682+
override Crypto::KeyArtifactType getOutputKeyType() { result = type }
683+
684+
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
685+
exists(KeyGeneratorGetInstanceCall getInstance |
686+
getInstance.flowsTo(this) and result = getInstance.getAlgorithmArg()
687+
)
688+
}
689+
690+
Crypto::AlgorithmInstance getAKnownAlgorithm() {
691+
result = this.getAnAlgorithmValueConsumer().getAKnownAlgorithmSource()
692+
}
693+
}
608694
}

java/ql/lib/experimental/Quantum/Language.qll

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ module CryptoInput implements InputSig<Language::Location> {
3030
result = node.asExpr() or
3131
result = node.asParameter()
3232
}
33+
34+
predicate artifactOutputFlowsToGenericInput(
35+
DataFlow::Node artifactOutput, DataFlow::Node otherInput
36+
) {
37+
ArtifactUniversalFlow::flow(artifactOutput, otherInput)
38+
}
3339
}
3440

3541
/**
@@ -70,16 +76,20 @@ class GenericRemoteDataSource extends Crypto::GenericRemoteDataSource {
7076
override string getAdditionalDescription() { result = this.toString() }
7177
}
7278

73-
class ConstantDataSource extends Crypto::GenericConstantOrAllocationSource instanceof Literal {
74-
override DataFlow::Node getOutputNode() { result.asExpr() = this }
75-
76-
override predicate flowsTo(Crypto::FlowAwareElement other) {
77-
// TODO: separate config to avoid blowing up data-flow analysis
78-
GenericDataSourceUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
79-
}
80-
81-
override string getAdditionalDescription() { result = this.toString() }
82-
}
79+
/*
80+
* class ConstantDataSource extends Crypto::GenericConstantOrAllocationSource instanceof Literal {
81+
* ConstantDataSource() { not this instanceof Crypto::KnownElement }
82+
*
83+
* override DataFlow::Node getOutputNode() { result.asExpr() = this }
84+
*
85+
* override predicate flowsTo(Crypto::FlowAwareElement other) {
86+
* // TODO: separate config to avoid blowing up data-flow analysis
87+
* GenericDataSourceUniversalFlow::flow(this.getOutputNode(), other.getInputNode())
88+
* }
89+
*
90+
* override string getAdditionalDescription() { result = this.toString() }
91+
* }
92+
*/
8393

8494
/**
8595
* Random number generation, where each instance is modelled as the expression

java/ql/src/experimental/Quantum/TestCipher.ql

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ import experimental.Quantum.Language
77
from
88
Crypto::CipherOperationNode op, Crypto::CipherAlgorithmNode a,
99
Crypto::ModeOfOperationAlgorithmNode m, Crypto::PaddingAlgorithmNode p,
10-
Crypto::NonceArtifactNode nonce
10+
Crypto::NonceArtifactNode nonce, Crypto::KeyArtifactNode k
1111
where
1212
a = op.getAKnownCipherAlgorithm() and
1313
m = a.getModeOfOperation() and
1414
p = a.getPaddingAlgorithm() and
15-
nonce = op.getANonce()
15+
nonce = op.getANonce() and
16+
k = op.getAKey()
1617
select op, op.getCipherOperationSubtype(), a, a.getRawAlgorithmName(), m, m.getRawAlgorithmName(),
17-
p, p.getRawAlgorithmName(), nonce
18+
p, p.getRawAlgorithmName(), nonce, k, k.getSourceElement()
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/**
2+
* @name "PQC Test"
3+
*/
4+
5+
import experimental.Quantum.Language
6+
7+
from Crypto::CipherOperationNode op, Crypto::CipherAlgorithmNode a, Crypto::KeyArtifactNode k
8+
where
9+
a = op.getAKnownCipherAlgorithm() and
10+
k = op.getAKey()
11+
select op, op.getCipherOperationSubtype(), a, a.getRawAlgorithmName(), k, k.getSourceNode()
12+
/*
13+
* from Crypto::CipherOperationNode op
14+
* where op.getLocation().getFile().getBaseName() = "AsymmetricEncryptionMacHybridCryptosystem.java"
15+
* select op, op.getAKey().getSourceNode()
16+
*/
17+

0 commit comments

Comments
 (0)