Skip to content

Commit 938b47c

Browse files
committed
Crypto: Debug missing hashes associated with HMAC. EVP_PKEY_get1_RSA is now just a passthrough, it is not a known implicit operation call. Some final operations generating null outputs are now removed from possible final operartions (typically used to determine buffer lenghth and not actually performing the operation). Misc. false positive/error fixes and code clean up, and added missing models.
1 parent 422352c commit 938b47c

File tree

10 files changed

+467
-355
lines changed

10 files changed

+467
-355
lines changed

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,7 @@ class KnownOpenSslKeyAgreementAlgorithmExpr extends Expr instanceof KnownOpenSsl
172172

173173
predicate knownOpenSslAlgorithmOperationCall(Call c, string normalized, string algType) {
174174
c.getTarget().getName() in [
175-
"EVP_RSA_gen", "RSA_generate_key_ex", "RSA_generate_key", "RSA_new", "RSA_sign", "RSA_verify",
176-
"EVP_PKEY_get1_RSA"
175+
"EVP_RSA_gen", "RSA_generate_key_ex", "RSA_generate_key", "RSA_new", "RSA_sign", "RSA_verify"
177176
] and
178177
normalized = "RSA" and
179178
algType = "ASYMMETRIC_ENCRYPTION"

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

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,11 @@ abstract class EvpCipherInitializer extends OperationStep {
3636
// non-constants (e.g., variable accesses, which require data-flow to determine the value)
3737
// A zero (null) value typically indicates use of this operation step to initialize
3838
// other out parameters in a multi-step initialization.
39-
(exists(result.asExpr().getValue()) implies result.asExpr().getValue().toInt() != 0)
39+
(
40+
exists(result.asIndirectExpr().getValue())
41+
implies
42+
result.asIndirectExpr().getValue().toInt() != 0
43+
)
4044
}
4145

4246
override DataFlow::Node getOutput(IOType type) {
@@ -58,11 +62,15 @@ abstract class EvpEXInitializer extends EvpCipherInitializer {
5862
// non-constants (e.g., variable accesses, which require data-flow to determine the value)
5963
// A zero (null) value typically indicates use of this operation step to initialize
6064
// other out parameters in a multi-step initialization.
61-
result.asExpr() = this.getArgument(3) and type = KeyIO()
65+
result.asIndirectExpr() = this.getArgument(3) and type = KeyIO()
6266
or
63-
result.asExpr() = this.getArgument(4) and type = IVorNonceIO()
67+
result.asIndirectExpr() = this.getArgument(4) and type = IVorNonceIO()
6468
) and
65-
(exists(result.asExpr().getValue()) implies result.asExpr().getValue().toInt() != 0)
69+
(
70+
exists(result.asIndirectExpr().getValue())
71+
implies
72+
result.asIndirectExpr().getValue().toInt() != 0
73+
)
6674
}
6775
}
6876

@@ -73,9 +81,9 @@ abstract class EvpEX2Initializer extends EvpCipherInitializer {
7381
override DataFlow::Node getInput(IOType type) {
7482
result = super.getInput(type)
7583
or
76-
result.asExpr() = this.getArgument(2) and type = KeyIO()
84+
result.asIndirectExpr() = this.getArgument(2) and type = KeyIO()
7785
or
78-
result.asExpr() = this.getArgument(3) and type = IVorNonceIO()
86+
result.asIndirectExpr() = this.getArgument(3) and type = IVorNonceIO()
7987
}
8088
}
8189

@@ -110,6 +118,7 @@ class Evp_Cipher_EX2_or_Simple_Init_Call extends EvpEX2Initializer {
110118
result = super.getInput(type)
111119
or
112120
this.getTarget().getName().toLowerCase().matches("%cipherinit%") and
121+
// the key op subtype is an int, use asExpr
113122
result.asExpr() = this.getArgument(4) and
114123
type = KeyOperationSubtypeIO()
115124
}
@@ -129,7 +138,7 @@ class EvpPkeyEncryptDecryptInit extends OperationStep {
129138
override DataFlow::Node getInput(IOType type) {
130139
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
131140
or
132-
result.asExpr() = this.getArgument(1) and type = OsslParamIO()
141+
result.asIndirectExpr() = this.getArgument(1) and type = OsslParamIO()
133142
}
134143

135144
override DataFlow::Node getOutput(IOType type) {
@@ -145,6 +154,7 @@ class EvpCipherInitSKeyCall extends EvpEX2Initializer {
145154
override DataFlow::Node getInput(IOType type) {
146155
result = super.getInput(type)
147156
or
157+
// the key op subtype is an int, use asExpr
148158
result.asExpr() = this.getArgument(5) and
149159
type = KeyOperationSubtypeIO()
150160
}
@@ -163,11 +173,11 @@ class EvpCipherUpdateCall extends OperationStep {
163173
override DataFlow::Node getInput(IOType type) {
164174
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
165175
or
166-
result.asExpr() = this.getArgument(3) and type = PlaintextIO()
176+
result.asIndirectExpr() = this.getArgument(3) and type = PlaintextIO()
167177
}
168178

169179
override DataFlow::Node getOutput(IOType type) {
170-
result.asExpr() = this.getArgument(1) and type = CiphertextIO()
180+
result.asDefiningArgument() = this.getArgument(1) and type = CiphertextIO()
171181
or
172182
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
173183
}
@@ -184,13 +194,13 @@ class EvpCipherCall extends EvpCipherOperationFinalStep {
184194
override DataFlow::Node getInput(IOType type) {
185195
super.getInput(type) = result
186196
or
187-
result.asExpr() = this.getArgument(2) and type = PlaintextIO()
197+
result.asIndirectExpr() = this.getArgument(2) and type = PlaintextIO()
188198
}
189199

190200
override DataFlow::Node getOutput(IOType type) {
191201
super.getOutput(type) = result
192202
or
193-
result.asExpr() = this.getArgument(1) and type = CiphertextIO()
203+
result.asDefiningArgument() = this.getArgument(1) and type = CiphertextIO()
194204
}
195205
}
196206

@@ -234,13 +244,13 @@ class EvpPKeyCipherOperation extends EvpCipherOperationFinalStep {
234244
override DataFlow::Node getInput(IOType type) {
235245
super.getInput(type) = result
236246
or
237-
result.asExpr() = this.getArgument(3) and type = PlaintextIO()
247+
result.asIndirectExpr() = this.getArgument(3) and type = PlaintextIO()
238248
}
239249

240250
override DataFlow::Node getOutput(IOType type) {
241251
super.getOutput(type) = result
242252
or
243-
result.asExpr() = this.getArgument(1) and
253+
result.asDefiningArgument() = this.getArgument(1) and
244254
type = CiphertextIO() and
245255
this.getStepType() = FinalStep()
246256
// TODO: could indicate text lengths here, as well

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class EvpDigestUpdateCall extends OperationStep instanceof Call {
4747
override DataFlow::Node getInput(IOType type) {
4848
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
4949
or
50-
result.asExpr() = this.getArgument(1) and type = PlaintextIO()
50+
result.asIndirectExpr() = this.getArgument(1) and type = PlaintextIO()
5151
}
5252

5353
override DataFlow::Node getOutput(IOType type) {
@@ -70,7 +70,7 @@ class EvpQDigestOperation extends FinalDigestOperation instanceof Call {
7070
or
7171
result.asIndirectExpr() = this.getArgument(0) and type = ContextIO()
7272
or
73-
result.asExpr() = this.getArgument(3) and type = PlaintextIO()
73+
result.asIndirectExpr() = this.getArgument(3) and type = PlaintextIO()
7474
}
7575

7676
override DataFlow::Node getOutput(IOType type) {
@@ -87,7 +87,7 @@ class EvpDigestOperation extends FinalDigestOperation instanceof Call {
8787
override DataFlow::Node getInput(IOType type) {
8888
result.asIndirectExpr() = this.getArgument(4) and type = PrimaryAlgorithmIO()
8989
or
90-
result.asExpr() = this.getArgument(0) and type = PlaintextIO()
90+
result.asIndirectExpr() = this.getArgument(0) and type = PlaintextIO()
9191
}
9292

9393
override DataFlow::Node getOutput(IOType type) {

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

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ class ECKeyGen extends OperationStep instanceof Call {
1616
result.asIndirectExpr() = this.(Call).getArgument(0) and type = ContextIO()
1717
}
1818

19-
override DataFlow::Node getOutput(IOType type) { result.asExpr() = this and type = KeyIO() }
19+
override DataFlow::Node getOutput(IOType type) {
20+
result.asDefiningArgument() = this and type = KeyIO()
21+
}
2022

2123
override OperationStepType getStepType() { result = ContextCreationStep() }
2224
}
@@ -59,7 +61,7 @@ class EvpPKeyQKeyGen extends KeyGenFinalOperationStep instanceof Call {
5961
override DataFlow::Node getOutput(IOType type) {
6062
result.asDefiningArgument() = this.getArgument(0) and type = ContextIO()
6163
or
62-
result.asExpr() = this and type = KeyIO()
64+
result.asDefiningArgument() = this and type = KeyIO()
6365
}
6466

6567
override DataFlow::Node getInput(IOType type) {
@@ -68,15 +70,15 @@ class EvpPKeyQKeyGen extends KeyGenFinalOperationStep instanceof Call {
6870
// When arg 3 is a derived type, it is a curve name, otherwise it is a key size for RSA if provided
6971
// and arg 2 is the algorithm type
7072
this.getArgument(3).getType().getUnderlyingType() instanceof DerivedType and
71-
result.asExpr() = this.getArgument(3) and
73+
result.asIndirectExpr() = this.getArgument(3) and
7274
type = PrimaryAlgorithmIO()
7375
or
7476
not this.getArgument(3).getType().getUnderlyingType() instanceof DerivedType and
75-
result.asExpr() = this.getArgument(2) and
77+
result.asIndirectExpr() = this.getArgument(2) and
7678
type = PrimaryAlgorithmIO()
7779
or
7880
not this.getArgument(3).getType().getUnderlyingType() instanceof DerivedType and
79-
result.asExpr() = this.getArgument(3) and
81+
result.asIndirectExpr() = this.getArgument(3) and
8082
type = KeySizeIO()
8183
}
8284
}
@@ -87,7 +89,9 @@ class EvpPKeyQKeyGen extends KeyGenFinalOperationStep instanceof Call {
8789
class EvpRsaGen extends KeyGenFinalOperationStep instanceof Call {
8890
EvpRsaGen() { this.getTarget().getName() = "EVP_RSA_gen" }
8991

90-
override DataFlow::Node getOutput(IOType type) { result.asExpr() = this and type = KeyIO() }
92+
override DataFlow::Node getOutput(IOType type) {
93+
result.asDefiningArgument() = this and type = KeyIO()
94+
}
9195

9296
override DataFlow::Node getInput(IOType type) {
9397
result.asExpr() = this.getArgument(0) and type = KeySizeIO()
@@ -100,7 +104,9 @@ class EvpRsaGen extends KeyGenFinalOperationStep instanceof Call {
100104
class RsaGenerateKey extends KeyGenFinalOperationStep instanceof Call {
101105
RsaGenerateKey() { this.getTarget().getName() = "RSA_generate_key" }
102106

103-
override DataFlow::Node getOutput(IOType type) { result.asExpr() = this and type = KeyIO() }
107+
override DataFlow::Node getOutput(IOType type) {
108+
result.asDefiningArgument() = this and type = KeyIO()
109+
}
104110

105111
override DataFlow::Node getInput(IOType type) {
106112
result.asExpr() = this.getArgument(0) and type = KeySizeIO()
@@ -150,12 +156,14 @@ class EvpNewMacKey extends KeyGenFinalOperationStep {
150156

151157
override DataFlow::Node getInput(IOType type) {
152158
// the raw key that is configured into the output key
153-
result.asExpr() = this.getArgument(2) and type = KeyIO()
159+
result.asIndirectExpr() = this.getArgument(2) and type = KeyIO()
154160
or
155161
result.asExpr() = this.getArgument(3) and type = KeySizeIO()
156162
}
157163

158-
override DataFlow::Node getOutput(IOType type) { result.asExpr() = this and type = KeyIO() }
164+
override DataFlow::Node getOutput(IOType type) {
165+
result.asIndirectExpr() = this and type = KeyIO()
166+
}
159167
}
160168

161169
/// TODO: https://docs.openssl.org/3.0/man3/EVP_PKEY_new/#synopsis

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

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -198,15 +198,17 @@ abstract class OperationStep extends Call {
198198
* If `sink` is `this`, then this holds true.
199199
*/
200200
predicate flowsToOperationStep(OperationStep sink) {
201-
OperationStepFlow::flow(this.getAnOutput(), [sink.getAnInput(), sink.getAnOutput()])
201+
sink = this or
202+
OperationStepCtxFlow::flow(this.getAnOutput(), [sink.getAnInput(), sink.getAnOutput()])
202203
}
203204

204205
/**
205206
* Holds if this operation step flows from the given `OperationStep` (`source`).
206207
* If `source` is `this`, then this holds true.
207208
*/
208209
predicate flowsFromOperationStep(OperationStep source) {
209-
OperationStepFlow::flow(source.getAnOutput(), [this.getAnInput(), this.getAnOutput()])
210+
source = this or
211+
OperationStepCtxFlow::flow(source.getAnOutput(), [this.getAnInput(), this.getAnOutput()])
210212
}
211213

212214
/**
@@ -224,22 +226,17 @@ abstract class OperationStep extends Call {
224226
* the operation allows for multiple inputs (like plaintext for cipher update calls before final).
225227
*/
226228
OperationStep getDominatingInitializersToStep(IOType type) {
227-
(result.flowsToOperationStep(this) or result = this) and
229+
result.flowsToOperationStep(this) and
228230
result.setsValue(type) and
229231
(
230232
// Do not consider a 'reset' to occur on updates
231233
// but only for resets that are part of the same update/finalize
232234
// progression (e.g., an update for an unrelated finalize is ignored)
233-
result.getStepType() = UpdateStep() and
234-
not exists(OperationStep op |
235-
result.flowsToOperationStep(op) and
236-
op.flowsToOperationStep(this) and
237-
op != this and
238-
op.getStepType() = FinalStep()
239-
)
235+
result.getStepType() = UpdateStep()
240236
or
241237
not exists(OperationStep reset |
242238
result != reset and
239+
result != this and
243240
reset.setsValue(type) and
244241
reset.flowsToOperationStep(this) and
245242
result.flowsToOperationStep(reset)
@@ -443,7 +440,7 @@ private class CtxParamGenCall extends CtxPassThroughCall {
443440
/**
444441
* A flow configuration from any non-final `OperationStep` to any other `OperationStep`.
445442
*/
446-
module OperationStepFlowConfig implements DataFlow::ConfigSig {
443+
module OperationStepCtxFlowConfig implements DataFlow::ConfigSig {
447444
predicate isSource(DataFlow::Node source) {
448445
exists(OperationStep s |
449446
s.getAnOutput() = source or
@@ -469,7 +466,9 @@ module OperationStepFlowConfig implements DataFlow::ConfigSig {
469466
or
470467
// Flow only through context and key inputs and outputs
471468
// keys and context generally hold unifying context that link multiple steps
469+
// Flow only out of finalize operations through key outputs, otherwise stop at final operations
472470
exists(OperationStep s, IOType inType, IOType outType |
471+
(s.getStepType() = FinalStep() implies outType = KeyIO()) and
473472
(
474473
inType = ContextIO()
475474
or
@@ -489,7 +488,7 @@ module OperationStepFlowConfig implements DataFlow::ConfigSig {
489488
}
490489
}
491490

492-
module OperationStepFlow = DataFlow::Global<OperationStepFlowConfig>;
491+
module OperationStepCtxFlow = DataFlow::Global<OperationStepCtxFlowConfig>;
493492

494493
/**
495494
* A flow from AVC to the first `OperationStep` the AVC reaches as an input.

0 commit comments

Comments
 (0)