Skip to content

Commit 20e2c7c

Browse files
committed
Crypto: Overhaul/refactor of EVPInitialzers. Update cipher operation to disallow null key and IV on initializers (typically do not represent an actual key or IV).
1 parent 8f25380 commit 20e2c7c

File tree

9 files changed

+182
-137
lines changed

9 files changed

+182
-137
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import semmle.code.cpp.dataflow.new.DataFlow
2+
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
3+
4+
/**
5+
* Flows from algorithm values to operations, specific to OpenSSL
6+
*/
7+
module AvcToCallArgConfig implements DataFlow::ConfigSig {
8+
predicate isSource(DataFlow::Node source) {
9+
exists(OpenSSLAlgorithmValueConsumer c | c.getResultNode() = source)
10+
}
11+
12+
/**
13+
* Trace to any call accepting the algorithm.
14+
* NOTE: users must restrict this set to the operations they are interested in.
15+
*/
16+
predicate isSink(DataFlow::Node sink) { exists(Call c | c.getAnArgument() = sink.asExpr()) }
17+
}
18+
19+
module AvcToCallArgFlow = DataFlow::Global<AvcToCallArgConfig>;

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

Lines changed: 35 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3,60 +3,31 @@ private import experimental.quantum.OpenSSL.CtxFlow
33
private import OpenSSLOperationBase
44
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
55

6-
module EncValToInitEncArgConfig implements DataFlow::ConfigSig {
7-
predicate isSource(DataFlow::Node source) { source.asExpr().getValue().toInt() in [0, 1] }
8-
9-
predicate isSink(DataFlow::Node sink) {
10-
exists(EVP_Cipher_Initializer initCall | sink.asExpr() = initCall.getOperationSubtypeArg())
11-
}
12-
}
13-
14-
module EncValToInitEncArgFlow = DataFlow::Global<EncValToInitEncArgConfig>;
15-
16-
int getEncConfigValue(Expr e) {
17-
exists(EVP_Cipher_Initializer initCall | e = initCall.getOperationSubtypeArg()) and
18-
exists(DataFlow::Node a, DataFlow::Node b |
19-
EncValToInitEncArgFlow::flow(a, b) and b.asExpr() = e and result = a.asExpr().getValue().toInt()
20-
)
21-
}
22-
23-
bindingset[i]
24-
Crypto::KeyOperationSubtype intToCipherOperationSubtype(int i) {
25-
if i = 0
26-
then result instanceof Crypto::TEncryptMode
27-
else
28-
if i = 1
29-
then result instanceof Crypto::TDecryptMode
30-
else result instanceof Crypto::TUnknownKeyOperationMode
31-
}
32-
336
// TODO: need to add key consumer
347
abstract class EVP_Cipher_Initializer extends EvpKeyOperationSubtypeInitializer,
35-
EvpAlgorithmInitializer, EvpKeyInitializer, EvpIVInitializer
8+
EvpPrimaryAlgorithmInitializer, EvpKeyInitializer, EvpIVInitializer
369
{
37-
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
10+
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
3811

3912
override Expr getAlgorithmArg() { result = this.(Call).getArgument(1) }
40-
41-
abstract Expr getOperationSubtypeArg();
42-
43-
override Crypto::KeyOperationSubtype getKeyOperationSubtype() {
44-
if this.(Call).getTarget().getName().toLowerCase().matches("%encrypt%")
45-
then result instanceof Crypto::TEncryptMode
46-
else
47-
if this.(Call).getTarget().getName().toLowerCase().matches("%decrypt%")
48-
then result instanceof Crypto::TDecryptMode
49-
else
50-
if exists(getEncConfigValue(this.getOperationSubtypeArg()))
51-
then result = intToCipherOperationSubtype(getEncConfigValue(this.getOperationSubtypeArg()))
52-
else result instanceof Crypto::TUnknownKeyOperationMode
53-
}
5413
}
5514

5615
abstract class EVP_EX_Initializer extends EVP_Cipher_Initializer {
57-
override Expr getKeyArg() { result = this.(Call).getArgument(3) }
16+
override Expr getKeyArg() {
17+
// Null key indicates the key is not actually set
18+
// This pattern can occur during a multi-step initialization
19+
// TODO/Note: not flowing 0 to the sink, assuming a direct use of NULL for now
20+
result = this.(Call).getArgument(3) and
21+
(exists(result.getValue()) implies result.getValue().toInt() != 0)
22+
}
5823

59-
override Expr getIVArg() { result = this.(Call).getArgument(4) }
24+
override Expr getIVArg() {
25+
// Null IV indicates the IV is not actually set
26+
// This occurs given that setting the IV sometimes requires first setting the IV size.
27+
// TODO/Note: not flowing 0 to the sink, assuming a direct use of NULL for now
28+
result = this.(Call).getArgument(4) and
29+
(exists(result.getValue()) implies result.getValue().toInt() != 0)
30+
}
6031
}
6132

6233
abstract class EVP_EX2_Initializer extends EVP_Cipher_Initializer {
@@ -65,19 +36,26 @@ abstract class EVP_EX2_Initializer extends EVP_Cipher_Initializer {
6536
override Expr getIVArg() { result = this.(Call).getArgument(3) }
6637
}
6738

68-
class EVP_Cipher_EX_Init_Call extends EVP_EX_Initializer {
69-
EVP_Cipher_EX_Init_Call() {
39+
class EvpCipherEXInitCall extends EVP_EX_Initializer {
40+
EvpCipherEXInitCall() {
7041
this.(Call).getTarget().getName() in [
7142
"EVP_EncryptInit_ex", "EVP_DecryptInit_ex", "EVP_CipherInit_ex"
7243
]
7344
}
7445

75-
override Expr getOperationSubtypeArg() {
46+
override Expr getKeyOperationSubtypeArg() {
47+
// NOTE: for EncryptInit and DecryptInit there is no subtype arg
48+
// the subtype is determined automatically by the initializer based on the operation name
7649
this.(Call).getTarget().getName().toLowerCase().matches("%cipherinit%") and
7750
result = this.(Call).getArgument(5)
7851
}
7952
}
8053

54+
// if this.(Call).getTarget().getName().toLowerCase().matches("%encrypt%")
55+
// then result instanceof Crypto::TEncryptMode
56+
// else
57+
// if this.(Call).getTarget().getName().toLowerCase().matches("%decrypt%")
58+
// then result instanceof Crypto::TDecryptMode
8159
class EVP_Cipher_EX2_or_Simple_Init_Call extends EVP_EX2_Initializer {
8260
EVP_Cipher_EX2_or_Simple_Init_Call() {
8361
this.(Call).getTarget().getName() in [
@@ -86,7 +64,7 @@ class EVP_Cipher_EX2_or_Simple_Init_Call extends EVP_EX2_Initializer {
8664
]
8765
}
8866

89-
override Expr getOperationSubtypeArg() {
67+
override Expr getKeyOperationSubtypeArg() {
9068
this.(Call).getTarget().getName().toLowerCase().matches("%cipherinit%") and
9169
result = this.(Call).getArgument(4)
9270
}
@@ -95,7 +73,7 @@ class EVP_Cipher_EX2_or_Simple_Init_Call extends EVP_EX2_Initializer {
9573
class EVP_CipherInit_SKEY_Call extends EVP_EX2_Initializer {
9674
EVP_CipherInit_SKEY_Call() { this.(Call).getTarget().getName() in ["EVP_CipherInit_SKEY"] }
9775

98-
override Expr getOperationSubtypeArg() { result = this.(Call).getArgument(5) }
76+
override Expr getKeyOperationSubtypeArg() { result = this.(Call).getArgument(5) }
9977
}
10078

10179
class EVP_Cipher_Update_Call extends EvpUpdate {
@@ -105,7 +83,7 @@ class EVP_Cipher_Update_Call extends EvpUpdate {
10583
]
10684
}
10785

108-
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
86+
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
10987

11088
override Expr getInputArg() { result = this.(Call).getArgument(3) }
11189

@@ -154,10 +132,10 @@ class EVP_Cipher_Call extends EvpOperation, EVP_Cipher_Operation {
154132
override Expr getInputArg() { result = this.(Call).getArgument(2) }
155133

156134
override Expr getAlgorithmArg() {
157-
result = this.getInitCall().(EvpAlgorithmInitializer).getAlgorithmArg()
135+
result = this.getInitCall().(EvpPrimaryAlgorithmInitializer).getAlgorithmArg()
158136
}
159137

160-
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
138+
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
161139
}
162140

163141
class EVP_Cipher_Final_Call extends EVPFinal, EVP_Cipher_Operation {
@@ -178,10 +156,10 @@ class EVP_Cipher_Final_Call extends EVPFinal, EVP_Cipher_Operation {
178156
}
179157

180158
override Expr getAlgorithmArg() {
181-
result = this.getInitCall().(EvpAlgorithmInitializer).getAlgorithmArg()
159+
result = this.getInitCall().(EvpPrimaryAlgorithmInitializer).getAlgorithmArg()
182160
}
183161

184-
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
162+
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
185163
}
186164

187165
/**
@@ -195,9 +173,9 @@ class Evp_PKey_Cipher_Operation extends EVP_Cipher_Operation {
195173

196174
override Expr getInputArg() { result = this.(Call).getArgument(3) }
197175

198-
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
176+
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
199177

200178
override Expr getAlgorithmArg() {
201-
result = this.getInitCall().(EvpAlgorithmInitializer).getAlgorithmArg()
179+
result = this.getInitCall().(EvpPrimaryAlgorithmInitializer).getAlgorithmArg()
202180
}
203181
}

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

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ private import experimental.quantum.OpenSSL.CtxFlow
77
private import OpenSSLOperationBase
88
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
99

10-
abstract class EVP_Hash_Initializer extends EvpAlgorithmInitializer { }
11-
12-
class EVP_DigestInit_Variant_Calls extends EVP_Hash_Initializer {
10+
class EVP_DigestInit_Variant_Calls extends EvpPrimaryAlgorithmInitializer {
1311
EVP_DigestInit_Variant_Calls() {
1412
this.(Call).getTarget().getName() in [
1513
"EVP_DigestInit", "EVP_DigestInit_ex", "EVP_DigestInit_ex2"
@@ -18,15 +16,15 @@ class EVP_DigestInit_Variant_Calls extends EVP_Hash_Initializer {
1816

1917
override Expr getAlgorithmArg() { result = this.(Call).getArgument(1) }
2018

21-
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
19+
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
2220
}
2321

2422
class EVP_Digest_Update_Call extends EvpUpdate {
2523
EVP_Digest_Update_Call() { this.(Call).getTarget().getName() = "EVP_DigestUpdate" }
2624

2725
override Expr getInputArg() { result = this.(Call).getArgument(1) }
2826

29-
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
27+
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
3028
}
3129

3230
//https://docs.openssl.org/3.0/man3/EVP_DigestInit/#synopsis
@@ -35,7 +33,7 @@ class EVP_Q_Digest_Operation extends EvpOperation, Crypto::HashOperationInstance
3533

3634
override Expr getAlgorithmArg() { result = this.(Call).getArgument(1) }
3735

38-
override EVP_Hash_Initializer getInitCall() {
36+
override EvpInitializer getInitCall() {
3937
// This variant of digest does not use an init
4038
// and even if it were used, the init would be ignored/undefined
4139
none()
@@ -53,18 +51,18 @@ class EVP_Q_Digest_Operation extends EvpOperation, Crypto::HashOperationInstance
5351
result = EvpOperation.super.getInputConsumer()
5452
}
5553

56-
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
54+
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
5755
}
5856

5957
class EVP_Digest_Operation extends EvpOperation, Crypto::HashOperationInstance {
6058
EVP_Digest_Operation() { this.(Call).getTarget().getName() = "EVP_Digest" }
6159

6260
// There is no context argument for this function
63-
override CtxPointerSource getContextArg() { none() }
61+
override CtxPointerSource getContext() { none() }
6462

6563
override Expr getAlgorithmArg() { result = this.(Call).getArgument(4) }
6664

67-
override EVP_Hash_Initializer getInitCall() {
65+
override EvpPrimaryAlgorithmInitializer getInitCall() {
6866
// This variant of digest does not use an init
6967
// and even if it were used, the init would be ignored/undefined
7068
none()
@@ -90,7 +88,7 @@ class EVP_Digest_Final_Call extends EVPFinal, Crypto::HashOperationInstance {
9088
]
9189
}
9290

93-
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
91+
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
9492

9593
override Expr getOutputArg() { result = this.(Call).getArgument(1) }
9694

@@ -103,6 +101,6 @@ class EVP_Digest_Final_Call extends EVPFinal, Crypto::HashOperationInstance {
103101
}
104102

105103
override Expr getAlgorithmArg() {
106-
result = this.getInitCall().(EvpAlgorithmInitializer).getAlgorithmArg()
104+
result = this.getInitCall().(EvpPrimaryAlgorithmInitializer).getAlgorithmArg()
107105
}
108106
}

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ private import OpenSSLOperationBase
44
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
55
private import semmle.code.cpp.dataflow.new.DataFlow
66

7-
class EVPKeyGenInitialize extends EvpAlgorithmInitializer {
7+
class EVPKeyGenInitialize extends EvpPrimaryAlgorithmInitializer {
88
EVPKeyGenInitialize() {
99
this.(Call).getTarget().getName() in [
1010
"EVP_PKEY_keygen_init",
@@ -14,10 +14,13 @@ class EVPKeyGenInitialize extends EvpAlgorithmInitializer {
1414

1515
/**
1616
* The algorithm is encoded through the context argument.
17+
* The context may be directly created from an algorithm consumer,
18+
* or from a new operation off of a prior key. Either way,
19+
* we will treat this argument as the algorithm argument.
1720
*/
18-
override Expr getAlgorithmArg() { result = this.getContextArg() }
21+
override Expr getAlgorithmArg() { result = this.getContext() }
1922

20-
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
23+
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
2124
}
2225

2326
class EVPKeyGenOperation extends EVPFinal, Crypto::KeyGenerationOperationInstance {
@@ -31,13 +34,13 @@ class EVPKeyGenOperation extends EVPFinal, Crypto::KeyGenerationOperationInstanc
3134
keyResultNode.asDefiningArgument() = this.(Call).getArgument(1)
3235
}
3336

34-
override CtxPointerSource getContextArg() { result = this.(Call).getArgument(0) }
37+
override CtxPointerSource getContext() { result = this.(Call).getArgument(0) }
3538

3639
override Expr getAlgorithmArg() {
3740
this.(Call).getTarget().getName() = "EVP_PKEY_Q_keygen" and
3841
result = this.(Call).getArgument(0)
3942
or
40-
result = this.getInitCall().(EvpAlgorithmInitializer).getAlgorithmArg()
43+
result = this.getInitCall().(EvpPrimaryAlgorithmInitializer).getAlgorithmArg()
4144
}
4245

4346
override Crypto::KeyArtifactType getOutputKeyType() { result = Crypto::TAsymmetricKeyType() }

0 commit comments

Comments
 (0)