Skip to content

Commit 16c136e

Browse files
committed
openssl keygen & tracking of keys-contexts-algorithms
1 parent 02fb52c commit 16c136e

File tree

6 files changed

+139
-22
lines changed

6 files changed

+139
-22
lines changed

cpp/ql/lib/experimental/quantum/OpenSSL/AlgorithmValueConsumers/PKeyAlgorithmValueConsumer.qll

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ private import experimental.quantum.Language
33
private import experimental.quantum.OpenSSL.AlgorithmInstances.KnownAlgorithmConstants
44
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumerBase
55
private import experimental.quantum.OpenSSL.AlgorithmInstances.OpenSSLAlgorithmInstances
6+
private import experimental.quantum.OpenSSL.Operations.EVPKeyGenOperation
7+
private import experimental.quantum.OpenSSL.Operations.OpenSSLOperationBase
8+
private import experimental.quantum.OpenSSL.CtxFlow
69

710
abstract class PKeyValueConsumer extends OpenSSLAlgorithmValueConsumer { }
811

@@ -17,14 +20,13 @@ class EVPPKeyAlgorithmConsumer extends PKeyValueConsumer {
1720
// in these cases, the operation will be created separately for the same function.
1821
this.(Call).getTarget().getName() in [
1922
"EVP_PKEY_CTX_new_id", "EVP_PKEY_new_raw_private_key", "EVP_PKEY_new_raw_public_key",
20-
"EVP_PKEY_new_mac_key", "EVP_PKEY_CTX_new"
23+
"EVP_PKEY_new_mac_key"
2124
] and
2225
valueArgNode.asExpr() = this.(Call).getArgument(0)
2326
or
2427
this.(Call).getTarget().getName() in [
2528
"EVP_PKEY_CTX_new_from_name", "EVP_PKEY_new_raw_private_key_ex",
2629
"EVP_PKEY_new_raw_public_key_ex", "EVP_PKEY_CTX_ctrl", "EVP_PKEY_CTX_set_group_name",
27-
"EVP_PKEY_CTX_new_from_pkey"
2830
] and
2931
valueArgNode.asExpr() = this.(Call).getArgument(1)
3032
or
@@ -59,3 +61,61 @@ class EVPPKeyAlgorithmConsumer extends PKeyValueConsumer {
5961
// when trying to get the valueArg with getInputNode.
6062
Expr getValueArgExpr() { result = valueArgNode.asExpr() }
6163
}
64+
65+
// TODO: not sure where to put these
66+
67+
/**
68+
* Given context expression (EVP_PKEY_CTX), finds the algorithm.
69+
*/
70+
Expr getAlgorithmFromCtx(CtxPointerExpr ctx) {
71+
exists(EVPPKeyAlgorithmConsumer source |
72+
result = source.getValueArgExpr() and
73+
ctxFlowsToCtxArg(source.getResultNode().asExpr(), ctx)
74+
)
75+
or
76+
result = getAlgorithmFromKey(getKeyFromCtx(ctx))
77+
}
78+
79+
/**
80+
* Given context expression (EVP_PKEY_CTX), finds the key used to initialize the context.
81+
*/
82+
Expr getKeyFromCtx(CtxPointerExpr ctx) {
83+
exists(Call contextCreationCall |
84+
ctxFlowsToCtxArg(contextCreationCall, ctx) and (
85+
contextCreationCall.getTarget().getName() = "EVP_PKEY_CTX_new" and
86+
result = contextCreationCall.getArgument(0)
87+
or
88+
contextCreationCall.getTarget().getName() = "EVP_PKEY_CTX_new_from_pkey" and
89+
result = contextCreationCall.getArgument(1)
90+
)
91+
)
92+
}
93+
94+
/**
95+
* Flow from key creation to key used in a call
96+
*/
97+
module OpenSSLKeyFlowConfig implements DataFlow::ConfigSig {
98+
predicate isSource(DataFlow::Node source) {
99+
exists(EVPKeyGenOperation keygen |
100+
keygen.getOutputKeyArtifact() = source
101+
)
102+
}
103+
104+
predicate isSink(DataFlow::Node sink) {
105+
exists(OpenSSLOperation call |
106+
call.(Call).getAnArgument() = sink.asExpr()
107+
)
108+
}
109+
}
110+
111+
module OpenSSLKeyFlow = TaintTracking::Global<OpenSSLKeyFlowConfig>;
112+
113+
/**
114+
* Given key expression (EVP_PKEY), finds the algorithm.
115+
*/
116+
Expr getAlgorithmFromKey(Expr key) {
117+
exists(EVPKeyGenOperation keygen |
118+
OpenSSLKeyFlow::flow(keygen.getOutputKeyArtifact(), DataFlow::exprNode(key)) and
119+
result = keygen.getAlgorithmArg()
120+
)
121+
}

cpp/ql/lib/experimental/quantum/OpenSSL/CtxFlow.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ private class CtxType extends Type {
4747
/**
4848
* A pointer to a CtxType
4949
*/
50-
private class CtxPointerExpr extends Expr {
50+
class CtxPointerExpr extends Expr {
5151
CtxPointerExpr() {
5252
this.getType() instanceof CtxType and
5353
this.getType() instanceof PointerType
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
private import experimental.quantum.Language
2+
private import experimental.quantum.OpenSSL.CtxFlow as CTXFlow
3+
private import OpenSSLOperationBase
4+
private import experimental.quantum.OpenSSL.AlgorithmValueConsumers.OpenSSLAlgorithmValueConsumers
5+
private import semmle.code.cpp.dataflow.new.DataFlow
6+
7+
8+
class EVPKeyGenInitialize extends EVPInitialize {
9+
EVPKeyGenInitialize() { this.(Call).getTarget().getName() in [
10+
"EVP_PKEY_keygen_init", "EVP_PKEY_paramgen_init"
11+
]
12+
}
13+
14+
override Expr getAlgorithmArg() {
15+
result = getAlgorithmFromCtx(this.getContextArg())
16+
}
17+
}
18+
19+
class EVPKeyGenOperation extends EVPOperation, Crypto::KeyGenerationOperationInstance {
20+
EVPKeyGenOperation() { this.(Call).getTarget().getName() in [
21+
"EVP_PKEY_generate", "EVP_PKEY_paramgen", "EVP_PKEY_keygen", "EVP_PKEY_Q_keygen"
22+
]
23+
}
24+
25+
override Expr getAlgorithmArg() {
26+
if this.(Call).getTarget().getName() = "EVP_PKEY_Q_keygen" then
27+
result = this.(Call).getArgument(0)
28+
else
29+
result = EVPOperation.super.getAlgorithmArg()
30+
}
31+
32+
override Crypto::KeyArtifactType getOutputKeyType() { result = Crypto::TAsymmetricKeyType() }
33+
34+
override Expr getInputArg() { none() }
35+
36+
override Expr getOutputArg() { result = this.(Call).getArgument(1) }
37+
38+
override Crypto::ArtifactOutputDataFlowNode getOutputKeyArtifact() {
39+
result = EVPOperation.super.getOutputKeyArtifact()
40+
}
41+
42+
override Crypto::ConsumerInputDataFlowNode getKeySizeConsumer() {
43+
none() // TODO
44+
}
45+
46+
override int getKeySizeFixed() {
47+
none() // TODO
48+
}
49+
}

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

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

10+
1011
// TODO: verification functions
1112
class EVP_Signature_Initializer extends EVPInitialize {
1213
boolean isAlgorithmSpecifiedByKey;
@@ -30,17 +31,17 @@ class EVP_Signature_Initializer extends EVPInitialize {
3031
)
3132
}
3233

33-
/**
34-
* Returns the argument that specifies the algorithm or none if the algorithm is implicit (from context or from key).
35-
* Note that the key may be not provided in the initialization call.
36-
*/
3734
override Expr getAlgorithmArg() {
38-
if isAlgorithmSpecifiedByKey = true or isAlgorithmSpecifiedByCtx = true
39-
then none()
40-
else (
41-
this.(Call).getTarget().getName() in ["EVP_PKEY_sign_init_ex2", "EVP_PKEY_sign_message_init"] and
35+
if this.(Call).getTarget().getName() in ["EVP_PKEY_sign_init_ex2", "EVP_PKEY_sign_message_init"] then
4236
result = this.(Call).getArgument(1)
43-
)
37+
else
38+
if isAlgorithmSpecifiedByKey = true then
39+
result = getAlgorithmFromKey(this.getKeyArg())
40+
else
41+
if isAlgorithmSpecifiedByCtx = true then
42+
result = getAlgorithmFromCtx(this.getContextArg())
43+
else
44+
none()
4445
}
4546

4647
/**
@@ -55,10 +56,7 @@ class EVP_Signature_Initializer extends EVPInitialize {
5556
result = this.(Call).getArgument(5)
5657
or
5758
this.(Call).getTarget().getName().matches("EVP_PKEY_%") and
58-
exists(EVPPKeyAlgorithmConsumer source |
59-
result = source.getValueArgExpr() and
60-
ctxFlowsToCtxArg(source.getResultNode().asExpr(), this.getContextArg())
61-
)
59+
result = getKeyFromCtx(this.getContextArg())
6260
}
6361

6462
/**
@@ -103,7 +101,7 @@ private Expr signatureOperationOutputArg(Call call) {
103101
abstract class EVP_Signature_Operation extends EVPOperation, Crypto::SignatureOperationInstance {
104102
EVP_Signature_Operation() {
105103
this.(Call).getTarget().getName().matches("EVP_%") and
106-
// NULL output argument means the call is to get the size of the signature
104+
// NULL output argument means the call is to get the size of the signature and such call is not an operation
107105
(
108106
not exists(signatureOperationOutputArg(this).getValue())
109107
or

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ abstract class OpenSSLOperation extends Crypto::OperationInstance instanceof Cal
1313
abstract Expr getAlgorithmArg();
1414

1515
/**
16-
* Algorithm is specified in initialization call or is implicitly established by the key.
16+
* Algorithm is specified in initialization call or is implicitly established by the key or context.
1717
*/
1818
override Crypto::AlgorithmValueConsumer getAnAlgorithmValueConsumer() {
1919
AlgGetterToAlgConsumerFlow::flow(result.(OpenSSLAlgorithmValueConsumer).getResultNode(),
@@ -38,7 +38,8 @@ abstract class EVPInitialize extends Call {
3838
Crypto::KeyOperationSubtype getKeyOperationSubtype() { none() }
3939

4040
/**
41-
* Explicitly specified algorithm or none if implicit (e.g., established by the key).
41+
* Explicitly specified algorithm or algorithm established by the key or context
42+
* (should track flows to the key and/or context to return the algorithm expression)
4243
* None if not applicable.
4344
*/
4445
Expr getAlgorithmArg() { none() }
@@ -131,6 +132,10 @@ abstract class EVPOperation extends OpenSSLOperation {
131132
result = DataFlow::exprNode(this.getOutputArg())
132133
}
133134

135+
Crypto::ArtifactOutputDataFlowNode getOutputKeyArtifact() {
136+
result = DataFlow::exprNode(this.getOutputArg())
137+
}
138+
134139
/**
135140
* Input consumer is the input argument of the call.
136141
*/
Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import cpp
22
import experimental.quantum.Language
3+
import experimental.quantum.OpenSSL.AlgorithmValueConsumers.PKeyAlgorithmValueConsumer
4+
import experimental.quantum.OpenSSL.CtxFlow
35
import experimental.quantum.OpenSSL.Operations.EVPSignatureOperation
6+
import experimental.quantum.OpenSSL.Operations.OpenSSLOperationBase
47

5-
6-
from EVP_Signature_Operation n
7-
select n, n.(Call).getTarget().getName(), n.getOutputArg()
8+
from Crypto::SignatureOperationNode n
9+
select n, n.asElement(), n.getAnInputArtifact(), n.getAnOutputArtifact(), n.getAKey(),
10+
n.asElement().(OpenSSLOperation).getAlgorithmArg()
11+
// n.asElement().(Crypto::OperationInstance).getAnAlgorithmValueConsumer(),
12+
// n.getAnAlgorithmOrGenericSource()

0 commit comments

Comments
 (0)