Skip to content

Commit 01b98fc

Browse files
committed
quantum-c#: Add generic dataflow module
1 parent 1762959 commit 01b98fc

File tree

5 files changed

+87
-31
lines changed

5 files changed

+87
-31
lines changed

csharp/ql/lib/experimental/quantum/dotnet/AlgorithmInstances.qll

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,13 @@ class SigningNamedCurveAlgorithmInstance extends Crypto::EllipticCurveInstance i
2525
}
2626
}
2727

28-
class HashAlgorithmInstance extends Crypto::HashAlgorithmInstance instanceof HashAlgorithmName {
29-
HashAlgorithmConsumer consumer;
28+
class HashAlgorithmNameInstance extends Crypto::HashAlgorithmInstance instanceof HashAlgorithmName {
29+
HashAlgorithmNameConsumer consumer;
3030

31-
HashAlgorithmInstance() {
31+
HashAlgorithmNameInstance() {
3232
HashAlgorithmNameToUse::flow(DataFlow::exprNode(this), consumer.getInputNode())
3333
}
3434

35-
// Q: super.getHashFamily does not work because it is ambigous. But super.(HashAlgorithmName) does not work either.
3635
override Crypto::THashType getHashFamily() { result = this.(HashAlgorithmName).getHashFamily() }
3736

3837
override string getRawHashAlgorithmName() { result = super.getAlgorithmName() }

csharp/ql/lib/experimental/quantum/dotnet/AlgorithmValueConsumers.qll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ class ECDsaAlgorithmValueConsumer extends Crypto::AlgorithmValueConsumer {
1515
}
1616
}
1717

18-
class HashAlgorithmConsumer extends Crypto::AlgorithmValueConsumer {
19-
HashAlgorithmUser call;
18+
class HashAlgorithmNameConsumer extends Crypto::AlgorithmValueConsumer {
19+
HashAlgorithmNameUser call;
2020

21-
HashAlgorithmConsumer() { this = call.getHashAlgorithmUser() }
21+
HashAlgorithmNameConsumer() { this = call.getHashAlgorithmNameUser() }
2222

2323
override Crypto::ConsumerInputDataFlowNode getInputNode() { result.asExpr() = this }
2424

2525
override Crypto::AlgorithmInstance getAKnownAlgorithmSource() {
26-
exists(HashAlgorithmInstance l | l.getConsumer() = this and result = l)
26+
exists(HashAlgorithmNameInstance l | l.getConsumer() = this and result = l)
2727
}
2828
}

csharp/ql/lib/experimental/quantum/dotnet/Cryptography.qll

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,19 @@ class CryptographyCreateCall extends MethodCall {
2323
or
2424
result = this.(ECDsaCreateCallWithECCurve)
2525
}
26-
2726
}
2827

2928
class ECDsaCreateCall extends CryptographyCreateCall {
3029
ECDsaCreateCall() { this.getQualifier().getType().hasName("ECDsa") }
3130
}
3231

32+
// TODO
33+
// class HashAlgorithmCreateCall extends CryptographyCreateCall {
34+
// ValueOrRefType type;
35+
36+
// HashAlgorithmCreateCall() { type = this.getQualifier().getType().getDeclaringType() }
37+
// }
38+
3339
class RSACreateCall extends CryptographyCreateCall {
3440
RSACreateCall() { this.getQualifier().getType().hasName("RSA") }
3541
}
@@ -84,7 +90,11 @@ class HashAlgorithmName extends PropertyAccess {
8490

8591
string getAlgorithmName() { result = algorithmName }
8692

87-
Crypto::THashType getHashFamily() { hashAlgorithmToFamily(this.getAlgorithmName(), result, _) }
93+
Crypto::THashType getHashFamily() {
94+
if hashAlgorithmToFamily(this.getAlgorithmName(), _, _)
95+
then hashAlgorithmToFamily(this.getAlgorithmName(), result, _)
96+
else result = Crypto::OtherHashType()
97+
}
8898

8999
int getFixedDigestLength() { hashAlgorithmToFamily(this.getAlgorithmName(), _, result) }
90100
}
@@ -107,18 +117,18 @@ private predicate hashAlgorithmToFamily(
107117
hashName = "SHA3_384" and hashFamily = Crypto::SHA3() and digestLength = 384
108118
or
109119
hashName = "SHA3_512" and hashFamily = Crypto::SHA3() and digestLength = 512
110-
// Q: is there an idiomatic way to add a default type here?
120+
// TODO: is there an idiomatic way to add a default type here?
111121
}
112122

113-
class HashAlgorithmUser extends MethodCall {
123+
class HashAlgorithmNameUser extends MethodCall {
114124
Expr arg;
115125

116-
HashAlgorithmUser() {
126+
HashAlgorithmNameUser() {
117127
arg = this.getAnArgument() and
118128
arg.getType() instanceof HashAlgorithmNameType
119129
}
120130

121-
Expr getHashAlgorithmUser() { result = arg }
131+
Expr getHashAlgorithmNameUser() { result = arg }
122132
}
123133

124134
/**
@@ -173,6 +183,8 @@ class DotNetSigner extends MethodCall {
173183
)
174184
}
175185

186+
predicate isIntermediate() { none() }
187+
176188
Expr getSignatureOutput() {
177189
this.isSigner() and
178190
result = this

csharp/ql/lib/experimental/quantum/dotnet/FlowAnalysis.qll

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,27 +16,72 @@ module SigningNamedCurveToSignatureCreateFlowConfig implements DataFlow::ConfigS
1616
module SigningNamedCurveToSignatureCreateFlow =
1717
DataFlow::Global<SigningNamedCurveToSignatureCreateFlowConfig>;
1818

19-
/**
20-
* Flow from a known ECDsa property access to a `ECDsa.Create(sink)` call.
21-
*/
22-
private module CreateToUseFlowConfig implements DataFlow::ConfigSig {
23-
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof CryptographyCreateCall }
24-
25-
predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof DotNetSigner }
26-
27-
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
28-
node2.asExpr().(DotNetSigner).getQualifier() = node1.asExpr()
29-
}
30-
}
31-
32-
module CryptographyCreateToUseFlow = DataFlow::Global<CreateToUseFlowConfig>;
33-
3419
module HashAlgorithmNameToUseConfig implements DataFlow::ConfigSig {
3520
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof HashAlgorithmName }
3621

3722
predicate isSink(DataFlow::Node sink) {
38-
exists(HashAlgorithmConsumer consumer | sink = consumer.getInputNode())
23+
exists(HashAlgorithmNameConsumer consumer | sink = consumer.getInputNode())
3924
}
4025
}
4126

4227
module HashAlgorithmNameToUse = DataFlow::Global<HashAlgorithmNameToUseConfig>;
28+
29+
signature class CreationCallSig instanceof Call;
30+
31+
signature class UseCallSig instanceof QualifiableExpr {
32+
predicate isIntermediate();
33+
}
34+
35+
module CryptographyCreateToUseFlow = CreationToUseFlow<CryptographyCreateCall, DotNetSigner>;
36+
37+
module CreationToUseFlow<CreationCallSig Creation, UseCallSig Use> {
38+
private module CreationToUseConfig implements DataFlow::ConfigSig {
39+
predicate isSource(DataFlow::Node source) {
40+
source.asExpr() instanceof Creation
41+
or
42+
exists(Use use |
43+
source.asExpr() = use.(QualifiableExpr).getQualifier() and use.isIntermediate()
44+
)
45+
}
46+
47+
predicate isSink(DataFlow::Node sink) {
48+
exists(Use use | sink.asExpr() = use.(QualifiableExpr).getQualifier())
49+
}
50+
}
51+
52+
private module CreationToUseFlow = DataFlow::Global<CreationToUseConfig>;
53+
54+
Creation getCreationFromUse(
55+
Use use, CreationToUseFlow::PathNode source, CreationToUseFlow::PathNode sink
56+
) {
57+
source.getNode().asExpr() = result and
58+
sink.getNode().asExpr() = use.(MethodCall).getQualifier() and
59+
CreationToUseFlow::flowPath(source, sink)
60+
}
61+
62+
Use getUseFromCreation(
63+
Creation creation, CreationToUseFlow::PathNode source, CreationToUseFlow::PathNode sink
64+
) {
65+
source.getNode().asExpr() = creation and
66+
sink.getNode().asExpr() = result.(MethodCall).getQualifier() and
67+
CreationToUseFlow::flowPath(source, sink)
68+
}
69+
70+
Use getIntermediateUseFromUse(
71+
Use use, CreationToUseFlow::PathNode source, CreationToUseFlow::PathNode sink
72+
) {
73+
// Use sources are always intermediate uses.
74+
source.getNode().asExpr() = result.(QualifiableExpr).getQualifier() and
75+
sink.getNode().asExpr() = use.(QualifiableExpr).getQualifier() and
76+
CreationToUseFlow::flowPath(source, sink)
77+
}
78+
79+
// TODO: Remove this.
80+
Expr flowsTo(Expr expr) {
81+
exists(CreationToUseFlow::PathNode source, CreationToUseFlow::PathNode sink |
82+
source.getNode().asExpr() = expr and
83+
sink.getNode().asExpr() = result and
84+
CreationToUseFlow::flowPath(source, sink)
85+
)
86+
}
87+
}

csharp/ql/lib/experimental/quantum/dotnet/OperationInstances.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class ECDsaORRSASigningOperationInstance extends Crypto::SignatureOperationInsta
99
CryptographyCreateCall creator;
1010

1111
ECDsaORRSASigningOperationInstance() {
12-
CryptographyCreateToUseFlow::flow(DataFlow::exprNode(creator), DataFlow::exprNode(this))
12+
creator = CryptographyCreateToUseFlow::getCreationFromUse(this, _, _)
1313
}
1414

1515
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {

0 commit comments

Comments
 (0)