forked from github/codeql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathKeyConcepts.qll
More file actions
227 lines (183 loc) · 7.51 KB
/
KeyConcepts.qll
File metadata and controls
227 lines (183 loc) · 7.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
import Language
/**
* Key Material Concept
* any class that implements `java.security.spec.KeySpec`
*/
class KeyMaterialObject extends Class {
KeyMaterialObject() {
exists(RefType t |
this.extendsOrImplements*(t) and
t.hasQualifiedName("java.security.spec", "KeySpec")
)
}
}
/**
* KeyMaterial
* ie some plain material that gets used to generate a Key
*/
class KeyMaterialInstantiation extends Crypto::KeyMaterialInstance instanceof ClassInstanceExpr {
KeyMaterialInstantiation() {
this.(ClassInstanceExpr).getConstructedType() instanceof KeyMaterialObject
}
override DataFlow::Node getOutputNode() { result.asExpr() = this }
override DataFlow::Node getInputNode() {
result.asExpr() = this.(ClassInstanceExpr).getArgument(0)
}
//TODO
override predicate flowsTo(Crypto::FlowAwareElement other) { none() }
}
abstract class JCAKeyGenerationCall extends Call { }
private class JCAKeyGenerationCallWithMaterialArg extends JCAKeyGenerationCall {
JCAKeyGenerationCallWithMaterialArg() {
exists(string s | s in ["generatePrivate", "generatePublic", "translateKey"] |
this.getCallee().hasQualifiedName("java.security", "KeyFactory", s)
)
}
DataFlow::Node getInputData() { result.asExpr() = this.getArgument(0) }
}
private class JCAKeyGenerationCallWithoutMaterialArg extends JCAKeyGenerationCall {
JCAKeyGenerationCallWithoutMaterialArg() {
this.getCallee().hasQualifiedName("javax.crypto", "KeyGenerator", "generateKey")
}
DataFlow::Node getInputData() { result.asExpr() = this.getArgument(0) }
}
abstract class KeyGenerators extends Class {
Method getInstance() { result = this.getAMethod() and result.hasName("getInstance") }
abstract Method keySizeSetter();
}
class KeyGenerator extends KeyGenerators {
KeyGenerator() { this.hasQualifiedName("javax.crypto", "KeyGenerator") }
override Method keySizeSetter() { result = this.getAMethod() and result.hasName("init") }
}
class KeyFactory extends KeyGenerators {
KeyFactory() { this.hasQualifiedName("java.security", "KeyFactory") }
//todo this requires flow from a keyspec
override Method keySizeSetter() { none() }
}
class KeyPairGenerator extends KeyGenerators {
KeyPairGenerator() { this.hasQualifiedName("java.security", "KeyPairGenerator") }
override Method keySizeSetter() { result = this.getAMethod() and result.hasName("initialize") }
}
/**
* Data-flow configuration modelling flow from a string literal to a `KeyGeneratorsGetInstanceCall` argument.
*/
private module KeyGenAlgorithmStringToFetchFlow implements DataFlow::ConfigSig {
//TODO narrow this type based on JCA standard names doc for whats possible here, like is done for the cipher algs
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof StringLiteral }
predicate isSink(DataFlow::Node sink) {
exists(KeyGenerators gen, Call c |
c.getCallee() = gen.getInstance() and
c.getArgument(0) = sink.asExpr()
)
}
}
module KeyGenAlgorithmStringToFetchFlowIns = DataFlow::Global<KeyGenAlgorithmStringToFetchFlow>;
/**
* The key generation algorithm argument to a `KeyGeneratorsGetInstanceCall `.
*
* For example, in `KeyGenerator.getInstance(algorithm)`, this class represents `algorithm`.
*
* the algorithm is both what the resulting key is meant to be used for but also informs how it
* was created
*/
class KeyDerivationAlgorithmArg extends Crypto::KeyDerivationAlgorithmInstance instanceof Expr {
Call getInstanceCall;
KeyDerivationAlgorithmArg() {
exists(KeyGenerators gen |
getInstanceCall.getCallee() = gen.getInstance() and this = getInstanceCall.getArgument(0)
)
}
/**
* Returns the `StringLiteral` from which this argument is derived, if known.
*/
StringLiteral getOrigin() {
KeyGenAlgorithmStringToFetchFlowIns::flow(DataFlow::exprNode(result),
DataFlow::exprNode(this.(Expr).getAChildExpr*()))
}
Call getCall() { result = getInstanceCall }
}
/**
* A data-flow configuration to track flow from a integer value to
* the keysize argument of the various `init` methods of the KeyGeneratorsGetInstanceCall types
*/
private module IntToKeyGeneratorInitConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof IntegerLiteral }
predicate isSink(DataFlow::Node sink) {
exists(KeyGenerators c, Call call |
call.getCallee() = c.keySizeSetter() and call.getArgument(0) = sink.asExpr()
)
}
}
module IntToKeyGeneratorInitConfigFlow = DataFlow::Global<IntToKeyGeneratorInitConfig>;
/**
* Data-flow configuration modelling flow from a keygenerator type getinstance call
* to generation step
*/
module KeyDerivationOperationInstanceConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) {
exists(Call getInstanceCall, KeyGenerators kg |
kg.getInstance() = getInstanceCall.getCallee() and
src.asExpr() = getInstanceCall
)
}
predicate isSink(DataFlow::Node sink) {
exists(JCAKeyGenerationCall call | sink.asExpr() = call.getQualifier())
}
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(Call getInstanceCall, KeyGenerators kg, Call keySizeSetterCall |
kg.getInstance() = getInstanceCall.getCallee() and
node1.asExpr() = getInstanceCall.getQualifier() and
kg.keySizeSetter() = keySizeSetterCall.getCallee() and
node2.asExpr() = keySizeSetterCall.getQualifier()
)
}
}
module KeyDerivationOperationInstanceConfigFlow =
DataFlow::Global<KeyDerivationOperationInstanceConfig>;
class KeyDerivationOperationInstance extends Crypto::KeyDerivationOperationInstance instanceof Call {
Crypto::KeyDerivationAlgorithmInstance algorithm;
JCAKeyGenerationCall generateCall;
KeyDerivationOperationInstance() {
exists(KeyDerivationAlgorithmArg arg, DataFlow::Node source, DataFlow::Node sink |
this = generateCall and
generateCall.getQualifier() = sink.asExpr() and
KeyDerivationOperationInstanceConfigFlow::flow(source, sink) and
algorithm = arg and
source.asExpr() = arg.getCall()
)
}
//TODO fill these out using various flows defined above
override Crypto::KeyDerivationAlgorithmInstance getAlgorithm() { result = algorithm }
override Crypto::KeyMaterialInstance getInputKeyMaterial() { none() }
override Crypto::KeyArtifactInstance getOutputKey() { none() }
//exists(KeyObject key | result = key and key.getOutputNode() = this) }
}
/**
* A Key Object
*/
class KeyObject extends Crypto::KeyArtifactInstance instanceof Variable {
Crypto::KeyDerivationOperationInstance instantiation;
KeyObject() {
exists(RefType t |
instantiation = this.getInitializer() and
this.getType().(RefType).extendsOrImplements*(t) and
t.hasQualifiedName("java.security", "Key")
)
}
override DataFlow::Node getOutputNode() { result.asExpr() = instantiation }
//TODO fix by using the KeyDerivationOperationInstance type in this type
override DataFlow::Node getInputNode() {
result.asExpr() = instantiation
}
override DataFlow::Node getKeySize() { exists(DataFlow::Node src, DataFlow::Node sink, Call initcall
|
IntToKeyGeneratorInitConfigFlow::flow(src, sink)
and result = src
and initcall.getArgument(0) = sink.asExpr()
//init qualifier same as keygen qualifier, we need to use more of the connected concepts tho, this is re-inventing them every time we need something
and initcall.getQualifier() = instantiation.(JCAKeyGenerationCall).getQualifier().(VarAccess).getVariable().getAnAccess()
)
}
//TODO
override predicate flowsTo(Crypto::FlowAwareElement other) { none() }
}