Skip to content

Commit 105ca2e

Browse files
committed
refactor EVP common classes
1 parent c046a30 commit 105ca2e

7 files changed

Lines changed: 153 additions & 169 deletions

File tree

cpp/ql/lib/experimental/quantum/OpenSSL/Operations/ECKeyGenOperation.qll

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,15 @@ private module AlgGetterToAlgConsumerConfig implements DataFlow::ConfigSig {
1616

1717
private module AlgGetterToAlgConsumerFlow = DataFlow::Global<AlgGetterToAlgConsumerConfig>;
1818

19-
class ECKeyGenOperation extends OpenSSLOperation, Crypto::KeyGenerationOperationInstance {
19+
class ECKeyGenOperation extends Crypto::KeyGenerationOperationInstance {
2020
ECKeyGenOperation() { this.(Call).getTarget().getName() = "EC_KEY_generate_key" }
2121

22-
override Expr getOutputArg() {
23-
result = this.(Call) // return value of call
24-
}
25-
2622
Expr getAlgorithmArg() { result = this.(Call).getArgument(0) }
2723

28-
override Expr getInputArg() {
29-
// there is no 'input', in the sense that no data is being manipulated by the operation.
30-
// There is an input of an algorithm, but that is not the intention of the operation input arg.
31-
none()
32-
}
33-
3424
override Crypto::KeyArtifactType getOutputKeyType() { result = Crypto::TAsymmetricKeyType() }
3525

3626
override Crypto::ArtifactOutputDataFlowNode getOutputKeyArtifact() {
37-
result = this.getOutputNode()
27+
result.asExpr() = this.(Call)
3828
}
3929

4030
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {

cpp/ql/lib/experimental/quantum/OpenSSL/Operations/EVPCipherInitializer.qll

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
private import experimental.quantum.Language
77
private import experimental.quantum.OpenSSL.CtxFlow as CTXFlow
8+
private import OpenSSLOperationBase
89

910
module EncValToInitEncArgConfig implements DataFlow::ConfigSig {
1011
predicate isSource(DataFlow::Node source) { source.asExpr().getValue().toInt() in [0, 1] }
@@ -34,19 +35,12 @@ Crypto::KeyOperationSubtype intToCipherOperationSubtype(int i) {
3435
}
3536

3637
// TODO: need to add key consumer
37-
abstract class EVP_Cipher_Initializer extends Call {
38-
Expr getContextArg() { result = this.(Call).getArgument(0) }
38+
abstract class EVP_Cipher_Initializer extends EVPInitialize {
39+
override Expr getAlgorithmArg() { result = this.(Call).getArgument(1) }
3940

40-
Expr getAlgorithmArg() { result = this.(Call).getArgument(1) }
41-
42-
abstract Expr getKeyArg();
43-
44-
abstract Expr getIVArg();
45-
46-
// abstract Crypto::CipherOperationSubtype getCipherOperationSubtype();
4741
abstract Expr getOperationSubtypeArg();
4842

49-
Crypto::KeyOperationSubtype getCipherOperationSubtype() {
43+
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
5044
if this.(Call).getTarget().getName().toLowerCase().matches("%encrypt%")
5145
then result instanceof Crypto::TEncryptMode
5246
else

cpp/ql/lib/experimental/quantum/OpenSSL/Operations/EVPCipherOperation.qll

Lines changed: 17 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,24 @@ private import EVPCipherInitializer
44
private import OpenSSLOperationBase
55
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
66

7-
private module AlgGetterToAlgConsumerConfig implements DataFlow::ConfigSig {
8-
predicate isSource(DataFlow::Node source) {
9-
exists(OpenSSLAlgorithmValueConsumer c | c.getResultNode() = source)
10-
}
117

12-
predicate isSink(DataFlow::Node sink) {
13-
exists(EVP_Cipher_Operation c | c.getInitCall().getAlgorithmArg() = sink.asExpr())
8+
class EVP_Cipher_Update_Call extends EVPUpdate {
9+
EVP_Cipher_Update_Call() {
10+
this.(Call).getTarget().getName() in [
11+
"EVP_EncryptUpdate", "EVP_DecryptUpdate", "EVP_CipherUpdate"
12+
]
1413
}
15-
}
1614

17-
private module AlgGetterToAlgConsumerFlow = DataFlow::Global<AlgGetterToAlgConsumerConfig>;
15+
override Expr getInputArg() { result = this.(Call).getArgument(3) }
16+
}
1817

19-
// import experimental.quantum.OpenSSL.AlgorithmValueConsumers.AlgorithmValueConsumers
20-
// import OpenSSLOperation
21-
// class EVPCipherOutput extends CipherOutputArtifact {
22-
// EVPCipherOutput() { exists(EVP_Cipher_Operation op | op.getOutputArg() = this) }
23-
// override DataFlow::Node getOutputNode() { result.asDefiningArgument() = this }
24-
// }
25-
//
2618
/**
2719
* see: https://docs.openssl.org/master/man3/EVP_EncryptInit/#synopsis
2820
* Base configuration for all EVP cipher operations.
2921
* NOTE: cannot extend instance of OpenSSLOperation, as we need to override
3022
* elements of OpenSSLOperation (i.e., we are creating an instance)
3123
*/
32-
abstract class EVP_Cipher_Operation extends OpenSSLOperation, Crypto::KeyOperationInstance {
33-
Expr getContextArg() { result = this.(Call).getArgument(0) }
34-
24+
abstract class EVP_Cipher_Operation extends EVPOperation, Crypto::KeyOperationInstance {
3525
override Expr getOutputArg() { result = this.(Call).getArgument(1) }
3626

3727
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
@@ -41,81 +31,40 @@ abstract class EVP_Cipher_Operation extends OpenSSLOperation, Crypto::KeyOperati
4131
result instanceof Crypto::TDecryptMode and
4232
this.(Call).getTarget().getName().toLowerCase().matches("%decrypt%")
4333
or
44-
result = this.getInitCall().getCipherOperationSubtype() and
34+
result = this.getInitCall().getKeyOperationSubtype() and
4535
this.(Call).getTarget().getName().toLowerCase().matches("%cipher%")
4636
}
4737

48-
EVP_Cipher_Initializer getInitCall() {
49-
CTXFlow::ctxArgFlowsToCtxArg(result.getContextArg(), this.getContextArg())
50-
}
51-
5238
override Crypto::ConsumerInputDataFlowNode getNonceConsumer() {
5339
this.getInitCall().getIVArg() = result.asExpr()
5440
}
5541

56-
override Crypto::ConsumerInputDataFlowNode getInputConsumer() { result = this.getInputNode() }
57-
5842
override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
5943
this.getInitCall().getKeyArg() = result.asExpr()
44+
// todo: or track to the EVP_PKEY_CTX_new
6045
}
6146

62-
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() { result = this.getOutputNode() }
47+
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
48+
result = this.(EVPOperation).getOutputArtifact()
49+
}
6350

64-
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
65-
AlgGetterToAlgConsumerFlow::flow(result.(OpenSSLAlgorithmValueConsumer).getResultNode(),
66-
DataFlow::exprNode(this.getInitCall().getAlgorithmArg()))
51+
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
52+
result = this.(EVPOperation).getInputConsumer()
6753
}
6854
}
6955

70-
class EVP_Cipher_Call extends EVP_Cipher_Operation {
56+
class EVP_Cipher_Call extends EVPOneShot, EVP_Cipher_Operation {
7157
EVP_Cipher_Call() { this.(Call).getTarget().getName() = "EVP_Cipher" }
7258

7359
override Expr getInputArg() { result = this.(Call).getArgument(2) }
7460
}
7561

76-
// NOTE: not modeled as cipher operations, these are intermediate calls
77-
class EVP_Cipher_Update_Call extends Call {
78-
EVP_Cipher_Update_Call() {
79-
this.(Call).getTarget().getName() in [
80-
"EVP_EncryptUpdate", "EVP_DecryptUpdate", "EVP_CipherUpdate"
81-
]
82-
}
83-
84-
Expr getInputArg() { result = this.(Call).getArgument(3) }
85-
86-
DataFlow::Node getInputNode() { result.asExpr() = this.getInputArg() }
87-
88-
Expr getContextArg() { result = this.(Call).getArgument(0) }
89-
}
9062

91-
class EVP_Cipher_Final_Call extends EVP_Cipher_Operation {
63+
class EVP_Cipher_Final_Call extends EVPFinal, EVP_Cipher_Operation {
9264
EVP_Cipher_Final_Call() {
9365
this.(Call).getTarget().getName() in [
9466
"EVP_EncryptFinal_ex", "EVP_DecryptFinal_ex", "EVP_CipherFinal_ex", "EVP_EncryptFinal",
9567
"EVP_DecryptFinal", "EVP_CipherFinal"
9668
]
9769
}
98-
99-
EVP_Cipher_Update_Call getUpdateCalls() {
100-
CTXFlow::ctxArgFlowsToCtxArg(result.getContextArg(), this.getContextArg())
101-
}
102-
103-
override Expr getInputArg() { result = this.getUpdateCalls().getInputArg() }
104-
105-
override Crypto::ConsumerInputDataFlowNode getInputConsumer() { result = this.getInputNode() }
106-
}
107-
108-
class EVP_PKEY_Operation extends EVP_Cipher_Operation {
109-
EVP_PKEY_Operation() {
110-
this.(Call).getTarget().getName() in ["EVP_PKEY_decrypt", "EVP_PKEY_encrypt"]
111-
}
112-
113-
override Expr getInputArg() { result = this.(Call).getArgument(3) }
114-
// TODO: how PKEY is initialized is different that symmetric cipher
115-
// Consider making an entirely new class for this and specializing
116-
// the get init call
117-
}
118-
119-
class EVPCipherInputArgument extends Expr {
120-
EVPCipherInputArgument() { exists(EVP_Cipher_Operation op | op.getInputArg() = this) }
12170
}

cpp/ql/lib/experimental/quantum/OpenSSL/Operations/EVPHashInitializer.qll

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
import cpp
2+
private import OpenSSLOperationBase
23

3-
abstract class EVP_Hash_Initializer extends Call {
4-
Expr getContextArg() { result = this.(Call).getArgument(0) }
5-
6-
abstract Expr getAlgorithmArg();
7-
}
4+
abstract class EVP_Hash_Initializer extends EVPInitialize {}
85

96
class EVP_DigestInit_Variant_Calls extends EVP_Hash_Initializer {
107
EVP_DigestInit_Variant_Calls() {

cpp/ql/lib/experimental/quantum/OpenSSL/Operations/EVPHashOperation.qll

Lines changed: 32 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -8,73 +8,49 @@ private import OpenSSLOperationBase
88
private import EVPHashInitializer
99
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
1010

11-
// import EVPHashConsumers
12-
abstract class EVP_Hash_Operation extends OpenSSLOperation, Crypto::HashOperationInstance {
13-
Expr getContextArg() { result = this.(Call).getArgument(0) }
1411

15-
EVP_Hash_Initializer getInitCall() {
16-
CTXFlow::ctxArgFlowsToCtxArg(result.getContextArg(), this.getContextArg())
17-
}
18-
19-
/**
20-
* By default, the algorithm value comes from the init call.
21-
* There are variants where this isn't true, in which case the
22-
* subclass should override this method.
23-
*/
24-
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
25-
AlgGetterToAlgConsumerFlow::flow(result.(OpenSSLAlgorithmValueConsumer).getResultNode(),
26-
DataFlow::exprNode(this.getInitCall().getAlgorithmArg()))
27-
}
28-
}
29-
30-
private module AlgGetterToAlgConsumerConfig implements DataFlow::ConfigSig {
31-
predicate isSource(DataFlow::Node source) {
32-
exists(OpenSSLAlgorithmValueConsumer c | c.getResultNode() = source)
33-
}
12+
class EVP_Digest_Update_Call extends EVPUpdate {
13+
EVP_Digest_Update_Call() { this.(Call).getTarget().getName() in ["EVP_DigestUpdate"] }
3414

35-
predicate isSink(DataFlow::Node sink) {
36-
exists(EVP_Hash_Operation c | c.getInitCall().getAlgorithmArg() = sink.asExpr())
37-
}
15+
override Expr getInputArg() { result = this.(Call).getArgument(1) }
3816
}
3917

40-
private module AlgGetterToAlgConsumerFlow = DataFlow::Global<AlgGetterToAlgConsumerConfig>;
4118

4219
//https://docs.openssl.org/3.0/man3/EVP_DigestInit/#synopsis
43-
class EVP_Q_Digest_Operation extends EVP_Hash_Operation {
20+
class EVP_Q_Digest_Operation extends EVPOneShot, Crypto::HashOperationInstance {
4421
EVP_Q_Digest_Operation() { this.(Call).getTarget().getName() = "EVP_Q_digest" }
4522

46-
//override Crypto::AlgorithmConsumer getAlgorithmConsumer() { }
23+
override Expr getAlgorithmArg() {
24+
result = this.(Call).getArgument(1)
25+
}
26+
4727
override EVP_Hash_Initializer getInitCall() {
4828
// This variant of digest does not use an init
4929
// and even if it were used, the init would be ignored/undefined
5030
none()
5131
}
5232

53-
override Expr getOutputArg() { result = this.(Call).getArgument(5) }
54-
5533
override Expr getInputArg() { result = this.(Call).getArgument(3) }
5634

57-
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() { result = this.getOutputNode() }
35+
override Expr getOutputArg() { result = this.(Call).getArgument(5) }
5836

59-
override Crypto::ConsumerInputDataFlowNode getInputConsumer() { result = this.getInputNode() }
37+
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
38+
result = this.(EVPOperation).getOutputArtifact()
39+
}
6040

61-
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
62-
// The operation is a direct algorithm consumer
63-
// NOTE: the operation itself is already modeld as a value consumer, so we can
64-
// simply return 'this', see modeled hash algorithm consuers for EVP_Q_Digest
65-
this = result
41+
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
42+
result = this.(EVPOperation).getInputConsumer()
6643
}
6744
}
6845

69-
class EVP_Digest_Operation extends EVP_Hash_Operation {
46+
class EVP_Digest_Operation extends EVPOneShot, Crypto::HashOperationInstance {
7047
EVP_Digest_Operation() { this.(Call).getTarget().getName() = "EVP_Digest" }
7148

7249
// There is no context argument for this function
7350
override Expr getContextArg() { none() }
7451

75-
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
76-
AlgGetterToAlgConsumerFlow::flow(result.(OpenSSLAlgorithmValueConsumer).getResultNode(),
77-
DataFlow::exprNode(this.(Call).getArgument(4)))
52+
override Expr getAlgorithmArg() {
53+
result = this.(Call).getArgument(4)
7854
}
7955

8056
override EVP_Hash_Initializer getInitCall() {
@@ -83,42 +59,33 @@ class EVP_Digest_Operation extends EVP_Hash_Operation {
8359
none()
8460
}
8561

86-
override Expr getOutputArg() { result = this.(Call).getArgument(2) }
87-
8862
override Expr getInputArg() { result = this.(Call).getArgument(0) }
8963

90-
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() { result = this.getOutputNode() }
91-
92-
override Crypto::ConsumerInputDataFlowNode getInputConsumer() { result = this.getInputNode() }
93-
}
94-
95-
// NOTE: not modeled as hash operations, these are intermediate calls
96-
class EVP_Digest_Update_Call extends Call {
97-
EVP_Digest_Update_Call() { this.(Call).getTarget().getName() in ["EVP_DigestUpdate"] }
98-
99-
Expr getInputArg() { result = this.(Call).getArgument(1) }
64+
override Expr getOutputArg() { result = this.(Call).getArgument(2) }
10065

101-
DataFlow::Node getInputNode() { result.asExpr() = this.getInputArg() }
66+
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
67+
result = this.(EVPOperation).getOutputArtifact()
68+
}
10269

103-
Expr getContextArg() { result = this.(Call).getArgument(0) }
70+
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
71+
result = this.(EVPOperation).getInputConsumer()
72+
}
10473
}
10574

106-
class EVP_Digest_Final_Call extends EVP_Hash_Operation {
75+
class EVP_Digest_Final_Call extends EVPFinal, Crypto::HashOperationInstance {
10776
EVP_Digest_Final_Call() {
10877
this.(Call).getTarget().getName() in [
10978
"EVP_DigestFinal", "EVP_DigestFinal_ex", "EVP_DigestFinalXOF"
11079
]
11180
}
11281

113-
EVP_Digest_Update_Call getUpdateCalls() {
114-
CTXFlow::ctxArgFlowsToCtxArg(result.getContextArg(), this.getContextArg())
115-
}
116-
117-
override Expr getInputArg() { result = this.getUpdateCalls().getInputArg() }
118-
119-
override Crypto::ConsumerInputDataFlowNode getInputConsumer() { result = this.getInputNode() }
120-
12182
override Expr getOutputArg() { result = this.(Call).getArgument(1) }
83+
84+
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
85+
result = this.(EVPOperation).getOutputArtifact()
86+
}
12287

123-
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() { result = this.getOutputNode() }
88+
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
89+
result = this.(EVPOperation).getInputConsumer()
90+
}
12491
}

0 commit comments

Comments
 (0)