Skip to content

Commit cf2f0f1

Browse files
committed
Crypto: Initial model of signatures. Still incomplete for verification and correct handling of MACs.
1 parent eb20955 commit cf2f0f1

File tree

11 files changed

+144
-165
lines changed

11 files changed

+144
-165
lines changed

cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmInstances/OpenSSLAlgorithmInstances.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ import BlockAlgorithmInstance
55
import HashAlgorithmInstance
66
import EllipticCurveAlgorithmInstance
77
import SignatureAlgorithmInstance
8+
import MACAlgorithmInstance

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import cpp
99
private import experimental.quantum.OpenSSL.CtxFlow
10+
private import OpenSSLOperations
1011
private import OpenSSLOperationBase
1112

1213
/**

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

Lines changed: 115 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -4,113 +4,63 @@
44

55
private import experimental.quantum.Language
66
private import OpenSSLOperationBase
7+
private import experimental.quantum.OpenSSL.AvcFlow
78
private import experimental.quantum.OpenSSL.CtxFlow
89
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
910
private import experimental.quantum.OpenSSL.Operations.OpenSSLOperations
1011

11-
module OpenSSLKeyGenToArgConfig implements DataFlow::ConfigSig {
12-
predicate isSource(DataFlow::Node source) {
13-
exists(Crypto::KeyGenerationOperationInstance keygen | keygen.getOutputKeyArtifact() = source)
12+
// TODO: verification functions
13+
class EvpSignatureDigestInitializer extends EvpHashAlgorithmInitializer {
14+
Expr arg;
15+
16+
EvpSignatureDigestInitializer() {
17+
this.(Call).getTarget().getName() in ["EVP_DigestSignInit_ex", "EVP_DigestSignInit"] and
18+
arg = this.(Call).getArgument(2)
19+
or
20+
this.(Call).getTarget().getName() in ["EVP_SignInit", "EVP_SignInit_ex"] and
21+
arg = this.(Call).getArgument(1)
1422
}
1523

16-
predicate isSink(DataFlow::Node sink) { exists(Call c | c.getAnArgument() = sink.asExpr()) }
24+
override Expr getHashAlgorithmArg() { result = arg }
25+
26+
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
1727
}
1828

19-
module OpenSSLKeyGenToArgFlow = TaintTracking::Global<OpenSSLKeyGenToArgConfig>;
29+
class EvpSignatureKeyInitializer extends EvpKeyInitializer {
30+
Expr arg;
2031

21-
// TODO: verification functions
22-
class EVP_Signature_Initializer extends EVPInitialize {
23-
EVP_Signature_Initializer() {
24-
this.(Call).getTarget().getName() in [
25-
"EVP_DigestSignInit", "EVP_DigestSignInit_ex", "EVP_SignInit", "EVP_SignInit_ex",
26-
"EVP_PKEY_sign_init", "EVP_PKEY_sign_init_ex", "EVP_PKEY_sign_init_ex2",
27-
"EVP_PKEY_sign_message_init"
28-
]
32+
EvpSignatureKeyInitializer() {
33+
this.(Call).getTarget().getName() = "EVP_DigestSignInit_ex" and
34+
arg = this.(Call).getArgument(5)
35+
or
36+
this.(Call).getTarget().getName() = "EVP_DigestSignInit" and
37+
arg = this.(Call).getArgument(4)
2938
}
3039

31-
/**
32-
* Gets the algorithm associated with this initialization by following
33-
* where the algorithm is set through the context argument.
34-
*/
35-
Expr getAlgorithmArgFromCtx() {
36-
// exists(EVPPKeyAlgorithmConsumer source, DataFlow::Node sink |
37-
// result = source.getInputNode().asExpr() and
38-
// sink.asExpr() = this.getContextArg() and
39-
// OpenSSLCtxSourceToArgumentFlow::flow(source.getResultNode(), sink)
40-
// )
41-
// or
42-
result = this.getAlgorithmArgFromKey(this.getKeyArgFromCtx())
43-
}
44-
45-
Expr getAlgorithmArgFromKey(Expr keyArg) {
46-
exists(Crypto::KeyGenerationOperationInstance keygen |
47-
OpenSSLKeyGenToArgFlow::flow(keygen.getOutputKeyArtifact(), DataFlow::exprNode(keyArg)) and
48-
result = keygen.(OpenSSLOperation).getAlgorithmArg()
49-
)
50-
}
40+
override Expr getKeyArg() { result = arg }
5141

52-
/**
53-
* Gets the argument ingesting a key
54-
* by tracing the context arg back to a context creation
55-
*/
56-
Expr getKeyArgFromCtx() {
57-
exists(Call contextCreationCall |
58-
ctxArgOrRetFlowsToCtxArg(contextCreationCall, this.getContextArg()) and
59-
(
60-
contextCreationCall.getTarget().getName() = "EVP_PKEY_CTX_new" and
61-
result = contextCreationCall.getArgument(0)
62-
or
63-
contextCreationCall.getTarget().getName() = "EVP_PKEY_CTX_new_from_pkey" and
64-
result = contextCreationCall.getArgument(1)
65-
)
66-
)
67-
}
42+
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
43+
}
6844

69-
override Expr getAlgorithmArg() {
70-
// explicit algorithm as argument
71-
this.(Call).getTarget().getName() in ["EVP_PKEY_sign_init_ex2", "EVP_PKEY_sign_message_init"] and
72-
result = this.(Call).getArgument(1)
73-
// or
74-
// // algorithm (and key) specified in the context
75-
// this.(Call).getTarget().getName() in ["EVP_PKEY_sign_init", "EVP_PKEY_sign_init_ex"] and
76-
// result = getAlgorithmArgFromCtx()
77-
// or
78-
// // algorithm specified by the key
79-
// this.(Call).getTarget().getName() in ["EVP_DigestSignInit", "EVP_DigestSignInit_ex"] and
80-
// result = getAlgorithmArgFromKey()
81-
// // NOTE: for EVP_SignInit and EVP_SignInit_ex the algorithm is not specified
82-
// // rather the algorithm is specified by the key used for signing later in a final call.
83-
}
45+
class EvpSignaturePrimaryAlgorithmInitializer extends EvpPrimaryAlgorithmInitializer {
46+
Expr arg;
8447

85-
/**
86-
* Returns the key argument if there is one.
87-
* If the key was provided via the context, we track it to the context.
88-
*/
89-
override Expr getKeyArg() {
90-
this.(Call).getTarget().getName() = "EVP_DigestSignInit" and
91-
result = this.(Call).getArgument(4)
92-
or
93-
this.(Call).getTarget().getName() = "EVP_DigestSignInit_ex" and
94-
result = this.(Call).getArgument(5)
48+
EvpSignaturePrimaryAlgorithmInitializer() {
49+
// signature algorithm
50+
this.(Call).getTarget().getName() in ["EVP_PKEY_sign_init_ex2", "EVP_PKEY_sign_message_init"] and
51+
arg = this.(Call).getArgument(1)
9552
or
96-
this.(Call).getTarget().getName().matches("EVP_PKEY_%") and
97-
result = this.getKeyArgFromCtx()
53+
// configuration through the context argument
54+
this.(Call).getTarget().getName() in ["EVP_PKEY_sign_init", "EVP_PKEY_sign_init_ex"] and
55+
arg = this.getContext()
9856
}
9957

100-
/**
101-
* Signing, verification or unknown.
102-
*/
103-
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
104-
if this.(Call).getTarget().getName().toLowerCase().matches("%sign%")
105-
then result instanceof Crypto::TSignMode
106-
else
107-
if this.(Call).getTarget().getName().toLowerCase().matches("%verify%")
108-
then result instanceof Crypto::TVerifyMode
109-
else result instanceof Crypto::TUnknownKeyOperationMode
110-
}
58+
override Expr getAlgorithmArg() { result = arg }
59+
60+
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
11161
}
11262

113-
class EVP_Signature_Update_Call extends EVPUpdate {
63+
class EVP_Signature_Update_Call extends EvpUpdate {
11464
EVP_Signature_Update_Call() {
11565
this.(Call).getTarget().getName() in [
11666
"EVP_DigestSignUpdate", "EVP_SignUpdate", "EVP_PKEY_sign_message_update"
@@ -121,6 +71,8 @@ class EVP_Signature_Update_Call extends EVPUpdate {
12171
* Input is the message to sign.
12272
*/
12373
override Expr getInputArg() { result = this.(Call).getArgument(1) }
74+
75+
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
12476
}
12577

12678
/**
@@ -131,22 +83,37 @@ private Expr signatureOperationOutputArg(Call call) {
13183
if call.getTarget().getName() = "EVP_SignFinal_ex"
13284
then result = call.getArgument(2)
13385
else result = call.getArgument(1)
86+
////*******todo get rid of this predicate */
13487
}
13588

13689
/**
13790
* Base configuration for all EVP signature operations.
13891
*/
139-
abstract class EVP_Signature_Operation extends EVPOperation, Crypto::SignatureOperationInstance {
140-
EVP_Signature_Operation() {
92+
abstract class EvpSignatureOperation extends EvpOperation, Crypto::SignatureOperationInstance {
93+
EvpSignatureOperation() {
14194
this.(Call).getTarget().getName().matches("EVP_%") and
14295
// NULL output argument means the call is to get the size of the signature and such call is not an operation
14396
(
97+
// ******TODO review logic
14498
not exists(signatureOperationOutputArg(this).getValue())
14599
or
146100
signatureOperationOutputArg(this).getValue() != "0"
147101
)
148102
}
149103

104+
Expr getHashAlgorithmArg() {
105+
this.getInitCall().(EvpHashAlgorithmInitializer).getHashAlgorithmArg() = result
106+
}
107+
108+
override Expr getAlgorithmArg() {
109+
this.getInitCall().(EvpPrimaryAlgorithmInitializer).getAlgorithmArg() = result
110+
}
111+
112+
override Crypto::AlgorithmValueConsumer getHashAlgorithmValueConsumer() {
113+
AvcToCallArgFlow::flow(result.(OpenSSLAlgorithmValueConsumer).getResultNode(),
114+
DataFlow::exprNode(this.getHashAlgorithmArg()))
115+
}
116+
150117
/**
151118
* Signing, verification or unknown.
152119
*/
@@ -170,58 +137,74 @@ abstract class EVP_Signature_Operation extends EVPOperation, Crypto::SignatureOp
170137
* Keys in explicit arguments are found by overriden methods in extending classes.
171138
*/
172139
override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
173-
result = DataFlow::exprNode(this.getInitCall().getKeyArg())
140+
result = DataFlow::exprNode(this.getInitCall().(EvpKeyInitializer).getKeyArg())
174141
}
175142

176143
override Crypto::ArtifactOutputDataFlowNode getOutputArtifact() {
177-
result = EVPOperation.super.getOutputArtifact()
144+
result = EvpOperation.super.getOutputArtifact()
178145
}
179146

180147
override Crypto::ConsumerInputDataFlowNode getInputConsumer() {
181-
result = EVPOperation.super.getInputConsumer()
148+
result = EvpOperation.super.getInputConsumer()
182149
}
183150

184151
/**
185152
* TODO: only signing operations for now, change when verificaiton is added
186153
*/
187154
override Crypto::ConsumerInputDataFlowNode getSignatureConsumer() { none() }
188155
}
189-
// class EVP_Signature_Call extends EVPOperation, EVP_Signature_Operation {
190-
// EVP_Signature_Call() { this.(Call).getTarget().getName() in ["EVP_DigestSign", "EVP_PKEY_sign"] }
191-
// /**
192-
// * Output is the signature.
193-
// */
194-
// override Expr getOutputArg() { result = signatureOperationOutputArg(this) }
195-
// /**
196-
// * Input is the message to sign.
197-
// */
198-
// override Expr getInputArg() { result = this.(Call).getArgument(3) }
199-
// }
200-
// class EVP_Signature_Final_Call extends EVPFinal, EVP_Signature_Operation {
201-
// EVP_Signature_Final_Call() {
202-
// this.(Call).getTarget().getName() in [
203-
// "EVP_DigestSignFinal", "EVP_SignFinal_ex", "EVP_SignFinal", "EVP_PKEY_sign_message_final"
204-
// ]
205-
// }
206-
// override Expr getAlgorithmArg() {
207-
// none()
208-
// // // algorithm specified by the key and the key is provided in this operation
209-
// // if this.(Call).getTarget().getName() in ["EVP_SignFinal", "EVP_SignFinal_ex"]
210-
// // then result = getAlgorithmFromKey(this.getKeyConsumer().asExpr())
211-
// // else
212-
// // // or find algorithm in the initialization call
213-
// // result = EVP_Signature_Operation.super.getAlgorithmArg()
214-
// }
215-
// override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
216-
// // key provided as an argument
217-
// if this.(Call).getTarget().getName() in ["EVP_SignFinal", "EVP_SignFinal_ex"]
218-
// then result = DataFlow::exprNode(this.(Call).getArgument(3))
219-
// else
220-
// // or find key in the initialization call
221-
// result = EVP_Signature_Operation.super.getKeyConsumer()
222-
// }
223-
// /**
224-
// * Output is the signature.
225-
// */
226-
// override Expr getOutputArg() { result = signatureOperationOutputArg(this) }
227-
// }
156+
157+
class EVP_Signature_Call extends EvpSignatureOperation {
158+
EVP_Signature_Call() { this.(Call).getTarget().getName() in ["EVP_DigestSign", "EVP_PKEY_sign"] }
159+
160+
/**
161+
* Output is the signature.
162+
*/
163+
override Expr getOutputArg() { result = signatureOperationOutputArg(this) }
164+
165+
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
166+
167+
/**
168+
* Input is the message to sign.
169+
*/
170+
override Expr getInputArg() { result = this.(Call).getArgument(3) }
171+
}
172+
173+
class EVP_Signature_Final_Call extends EVPFinal, EvpSignatureOperation {
174+
EVP_Signature_Final_Call() {
175+
this.(Call).getTarget().getName() in [
176+
"EVP_DigestSignFinal",
177+
"EVP_SignFinal_ex",
178+
"EVP_SignFinal",
179+
"EVP_PKEY_sign_message_final"
180+
]
181+
}
182+
183+
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
184+
185+
//***********TODO: the algorithm arg might nto be the right type, can't use the initializer the same way if there
186+
// are two initializers for two different algorithms */
187+
override Expr getAlgorithmArg() {
188+
this.getInitCall().(EvpPrimaryAlgorithmInitializer).getAlgorithmArg() = result
189+
// // algorithm specified by the key and the key is provided in this operation
190+
// if this.(Call).getTarget().getName() in ["EVP_SignFinal", "EVP_SignFinal_ex"]
191+
// then result = getAlgorithmFromKey(this.getKeyConsumer().asExpr())
192+
// else
193+
// // or find algorithm in the initialization call
194+
// result = EVP_Signature_Operation.super.getAlgorithmArg()
195+
}
196+
197+
override Crypto::ConsumerInputDataFlowNode getKeyConsumer() {
198+
// key provided as an argument
199+
this.(Call).getTarget().getName() in ["EVP_SignFinal", "EVP_SignFinal_ex"] and
200+
result = DataFlow::exprNode(this.(Call).getArgument(3))
201+
or
202+
// or find key in the initialization call
203+
result = EvpSignatureOperation.super.getKeyConsumer()
204+
}
205+
206+
/**
207+
* Output is the signature.
208+
*/
209+
override Expr getOutputArg() { result = signatureOperationOutputArg(this) }
210+
}

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,32 @@ class EvpInitializerThroughKey extends EvpPrimaryAlgorithmInitializer, EvpKeySiz
145145
Expr getKeyArg() { result = EvpKeyInitializer.super.getKeyArg() }
146146
}
147147

148+
/**
149+
* A default initializer for any key operation that accepts a key as input.
150+
* A key initializer allows for a mechanic to go backwards to the key creation operation
151+
* and find the algorithm and key size.
152+
* If a user were to stipualte a key consumer for an operation but fail to indicate it as an
153+
* initializer, automatic tracing to the creation operation would not occur.
154+
* USERS SHOULD NOT NEED TO USE OR EXTEND THIS CLASS DIRECTLY.
155+
*
156+
* TODO: re-evaluate this approach
157+
*/
158+
class DefaultKeyInitializer extends EvpKeyInitializer instanceof Crypto::KeyOperationInstance {
159+
Expr arg;
160+
161+
DefaultKeyInitializer() {
162+
exists(Call c |
163+
c.getAChild*() = arg and
164+
arg = this.(Crypto::KeyOperationInstance).getKeyConsumer().asExpr() and
165+
c = this
166+
)
167+
}
168+
169+
override Expr getKeyArg() { result = arg }
170+
171+
override CtxPointerSource getContext() { result = this.(EvpOperation).getContext() }
172+
}
173+
148174
abstract class EvpIVInitializer extends EvpInitializer {
149175
abstract Expr getIVArg();
150176
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ import OpenSSLOperationBase
22
import EVPCipherOperation
33
import EVPHashOperation
44
import ECKeyGenOperation
5-
//import EVPSignatureOperation
5+
import EVPSignatureOperation
66
import EVPKeyGenOperation
77
import EVPPKeyCtxInitializer

cpp/ql/test/experimental/library-tests/quantum/signature_algorithms.expected

Lines changed: 0 additions & 5 deletions
This file was deleted.

cpp/ql/test/experimental/library-tests/quantum/signature_algorithms.ql

Lines changed: 0 additions & 6 deletions
This file was deleted.

cpp/ql/test/experimental/library-tests/quantum/signature_key_sources.expected

Lines changed: 0 additions & 5 deletions
This file was deleted.

cpp/ql/test/experimental/library-tests/quantum/signature_key_sources.ql

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)