1
1
import java
2
2
3
+ module Params {
4
+ import Language
5
+ import BouncyCastle.FlowAnalysis
6
+ import BouncyCastle.AlgorithmInstances
7
+
8
+ /**
9
+ * A model of the `Parameters` class in Bouncy Castle.
10
+ */
11
+ class Parameters extends RefType {
12
+ Parameters ( ) {
13
+ // Matches `org.bouncycastle.crypto.params`, `org.bouncycastle.asn1.x9`, etc.
14
+ this .getPackage ( ) .getName ( ) .matches ( "org.bouncycastle.%" ) and
15
+ this .getName ( ) .matches ( "%Parameters" )
16
+ }
17
+ }
18
+
19
+ class KeyParameters extends Parameters {
20
+ KeyParameters ( ) {
21
+ this .getPackage ( ) .getName ( ) = "org.bouncycastle.crypto.params" and
22
+ this .getName ( ) .matches ( "%KeyParameters" )
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Any call that returns a BouncyCastle parameters object. This type is used
28
+ * to model data flow to resolve algorithm instances like elliptic curves.
29
+ *
30
+ * Examples:
31
+ * ```
32
+ * curveParams = SECNamedCurves.getByName(...);
33
+ * domainParams = new ECDomainParameters(...);
34
+ * ```
35
+ */
36
+ class ParametersInstantiation extends Call {
37
+ ParametersInstantiation ( ) {
38
+ // Class instantiations
39
+ this .( ConstructorCall )
40
+ .getConstructedType ( )
41
+ .getPackage ( )
42
+ .getName ( )
43
+ .matches ( "org.bouncycastle.%" ) and
44
+ this .( ConstructorCall ) .getConstructedType ( ) instanceof Parameters
45
+ or
46
+ // (Static) factory methods
47
+ this .( MethodCall )
48
+ .getCallee ( )
49
+ .getDeclaringType ( )
50
+ .getPackage ( )
51
+ .getName ( )
52
+ .matches ( "org.bouncycastle.%" ) and
53
+ this .( MethodCall ) .getType ( ) instanceof Parameters
54
+ }
55
+
56
+ // Can be overridden by subclasses which take a key size argument.
57
+ Expr getKeySizeArg ( ) { none ( ) }
58
+
59
+ Crypto:: ConsumerInputDataFlowNode getAKeySizeConsumer ( ) {
60
+ result .asExpr ( ) = this .getKeySizeArg ( )
61
+ }
62
+
63
+ // Can be overridden by subclasses which take an algorithm argument.
64
+ Expr getAlgorithmArg ( ) { none ( ) }
65
+
66
+ Crypto:: AlgorithmValueConsumer getAnAlgorithmValueConsumer ( ) {
67
+ result .getInputNode ( ) .asExpr ( ) = this .getAlgorithmArg ( )
68
+ }
69
+
70
+ Expr getAParametersArg ( ) {
71
+ result = this .getAnArgument ( ) and
72
+ result .getType ( ) instanceof Parameters
73
+ }
74
+
75
+ Crypto:: ConsumerInputDataFlowNode getAParametersConsumer ( ) {
76
+ result .asExpr ( ) = this .getAParametersArg ( )
77
+ }
78
+ }
79
+
80
+ class X9ECParametersInstantiation extends ParametersInstantiation {
81
+ X9ECParametersInstantiation ( ) { this .( Expr ) .getType ( ) .getName ( ) = "X9ECParameters" }
82
+
83
+ override Expr getAlgorithmArg ( ) { result = this .getArgument ( 0 ) }
84
+ }
85
+
86
+ class EllipticCurveStringLiteralArg extends EllipticCurveAlgorithmValueConsumer instanceof Expr {
87
+ ParametersInstantiation params ;
88
+
89
+ EllipticCurveStringLiteralArg ( ) { this = params .getAlgorithmArg ( ) }
90
+
91
+ override Crypto:: ConsumerInputDataFlowNode getInputNode ( ) { result .asExpr ( ) = this }
92
+
93
+ override Crypto:: AlgorithmInstance getAKnownAlgorithmSource ( ) {
94
+ result .( EllipticCurveStringLiteralInstance ) .getConsumer ( ) = this
95
+ }
96
+ }
97
+ }
98
+
3
99
/**
4
100
* Models for the signature algorithms defined by the `org.bouncycastle.crypto.signers` package.
5
101
*/
@@ -26,6 +122,40 @@ module Signers {
26
122
MethodCall getAMethodCall ( string name ) {
27
123
result .getCallee ( ) .hasQualifiedName ( this .getPackage ( ) .getName ( ) , this .getName ( ) , name )
28
124
}
125
+
126
+ // Overridden by subclasses to provide the message argument.
127
+ Expr getMessageArg ( MethodCall call ) {
128
+ call .getCallee ( ) .getName ( ) = "update" and
129
+ result = call .getArgument ( 0 )
130
+ }
131
+
132
+ // Overridden by subclasses to provide the signature argument.
133
+ Expr getSignatureArg ( MethodCall call ) {
134
+ call .getCallee ( ) .getName ( ) = "verifySignature" and
135
+ result = call .getArgument ( 0 )
136
+ }
137
+
138
+ // Overridden by subclasses to provide the signature output.
139
+ Expr getSignatureOutput ( MethodCall call ) {
140
+ call .getCallee ( ) .getName ( ) = "generateSignature" and
141
+ result = call
142
+ }
143
+ }
144
+
145
+ class ECDSASigner extends Signer {
146
+ ECDSASigner ( ) { this .getName ( ) .matches ( "ECDSA%" ) }
147
+
148
+ override Expr getMessageArg ( MethodCall call ) {
149
+ // For ECDSA the message is passed directly to `generateSignature()`.
150
+ call .getCallee ( ) .getName ( ) .matches ( [ "generateSignature" , "verifySignature" ] ) and
151
+ result = call .getArgument ( 0 )
152
+ }
153
+
154
+ override Expr getSignatureArg ( MethodCall call ) {
155
+ // For ECDSA, r and s are passed to `verifySignature()` as separate arguments.
156
+ call .getCallee ( ) .getName ( ) = "verifySignature" and
157
+ result = call .getArgument ( [ 1 , 2 ] )
158
+ }
29
159
}
30
160
31
161
/**
@@ -45,7 +175,17 @@ module Signers {
45
175
46
176
Expr getForSigningArg ( ) { result = this .getArgument ( 0 ) }
47
177
48
- Expr getKeyArg ( ) { result = this .getArgument ( 1 ) }
178
+ Expr getKeyArg ( ) {
179
+ this .getParameterArg ( ) .getType ( ) instanceof Params:: KeyParameters and
180
+ result = this .getParameterArg ( )
181
+ }
182
+
183
+ // The second argument is used to provide parameters (like the key) to the signer.
184
+ Expr getParameterArg ( ) { result = this .getArgument ( 1 ) }
185
+
186
+ Crypto:: ConsumerInputDataFlowNode getAParametersConsumer ( ) {
187
+ result .asExpr ( ) = this .getParameterArg ( )
188
+ }
49
189
50
190
// TODO: Support dataflow for the operation sub-type.
51
191
Crypto:: KeyOperationSubtype getKeyOperationSubtype ( ) {
@@ -68,36 +208,48 @@ module Signers {
68
208
* verify the signature, respectively.
69
209
*/
70
210
private class SignerUseCall extends MethodCall {
71
- SignerUseCall ( ) { this = any ( Signer signer ) .getAUseCall ( ) }
211
+ Signer signer ;
212
+
213
+ SignerUseCall ( ) { this = signer .getAUseCall ( ) }
72
214
73
215
predicate isIntermediate ( ) { this .getCallee ( ) .getName ( ) = "update" }
74
216
75
- Expr getInput ( ) { result = this . getArgument ( 0 ) }
217
+ Expr getMessageInput ( ) { result = signer . getMessageArg ( this ) }
76
218
77
- Expr getOutput ( ) { result = this }
219
+ Expr getSignatureInput ( ) { result = signer .getSignatureArg ( this ) }
220
+
221
+ Expr getSignatureOutput ( ) { result = signer .getSignatureOutput ( this ) }
78
222
}
79
223
80
224
/**
81
225
* Instantiate the flow analysis module for the `Signer` class.
82
226
*/
83
- private module FlowAnalysis =
227
+ private module SignerFlow =
84
228
NewToInitToUseFlowAnalysis< SignerNewCall , SignerInitCall , SignerUseCall > ;
85
229
86
230
/**
87
231
* A signing operation instance is a call to either `update()`, `generateSignature()`,
88
232
* or `verifySignature()` on a `Signer` instance.
89
233
*/
90
- class SignatureOperationInstance extends Crypto:: KeyOperationInstance instanceof SignerUseCall {
234
+ class SignatureOperationInstance extends Crypto:: SignatureOperationInstance instanceof SignerUseCall
235
+ {
91
236
SignatureOperationInstance ( ) { not this .isIntermediate ( ) }
92
237
93
238
override Crypto:: AlgorithmValueConsumer getAnAlgorithmValueConsumer ( ) {
94
- result = FlowAnalysis:: getNewFromUse ( this , _, _)
239
+ result = this .getParameters ( ) .getAnAlgorithmValueConsumer ( )
240
+ or
241
+ result = SignerFlow:: getNewFromUse ( this , _, _)
95
242
}
96
243
97
244
override Crypto:: KeyOperationSubtype getKeyOperationSubtype ( ) {
98
- if FlowAnalysis:: hasInit ( this )
99
- then result = this .getInitCall ( ) .getKeyOperationSubtype ( )
100
- else result = Crypto:: TUnknownKeyOperationMode ( )
245
+ // This is less expensive and more robust than resolving the subtype using
246
+ // dataflow from the `forSigning` argument to `init()`.
247
+ if super .getMethod ( ) .getName ( ) = "generateSignature"
248
+ then result = Crypto:: TSignMode ( )
249
+ else
250
+ if super .getMethod ( ) .getName ( ) = "verifySignature"
251
+ then result = Crypto:: TVerifyMode ( )
252
+ else result = Crypto:: TUnknownKeyOperationMode ( )
101
253
}
102
254
103
255
override Crypto:: ConsumerInputDataFlowNode getKeyConsumer ( ) {
@@ -107,18 +259,36 @@ module Signers {
107
259
override Crypto:: ConsumerInputDataFlowNode getNonceConsumer ( ) { none ( ) }
108
260
109
261
override Crypto:: ConsumerInputDataFlowNode getInputConsumer ( ) {
110
- result .asExpr ( ) = this .getAnUpdateCall ( ) .getInput ( )
262
+ // Inputs to signers with streaming APIs
263
+ result .asExpr ( ) = this .getAnUpdateCall ( ) .getMessageInput ( )
264
+ or
265
+ // Inputs to signers with one shot APIs
266
+ result .asExpr ( ) = super .getMessageInput ( )
267
+ }
268
+
269
+ override Crypto:: ConsumerInputDataFlowNode getSignatureArtifactConsumer ( ) {
270
+ result .asExpr ( ) = super .getSignatureInput ( )
111
271
}
112
272
113
273
override Crypto:: ArtifactOutputDataFlowNode getOutputArtifact ( ) {
114
- this . getKeyOperationSubtype ( ) = Crypto :: TSignMode ( ) and
115
- result .asExpr ( ) = super .getOutput ( )
274
+ // Signature output
275
+ result .asExpr ( ) = super .getSignatureOutput ( )
116
276
}
117
277
118
- SignerInitCall getInitCall ( ) { result = FlowAnalysis :: getInitFromUse ( this , _, _) }
278
+ SignerInitCall getInitCall ( ) { result = SignerFlow :: getInitFromUse ( this , _, _) }
119
279
120
280
SignerUseCall getAnUpdateCall ( ) {
121
- result = FlowAnalysis:: getAnIntermediateUseFromFinalUse ( this , _, _)
281
+ result = SignerFlow:: getAnIntermediateUseFromFinalUse ( this , _, _)
282
+ }
283
+
284
+ Crypto:: KeyArtifactOutputInstance getKey ( ) { result .flowsTo ( this .getInitCall ( ) .getKeyArg ( ) ) }
285
+
286
+ Generators:: KeyGenerationOperationInstance getKeyGenerationOperationInstance ( ) {
287
+ result .getKeyArtifactOutputInstance ( ) = this .getKey ( )
288
+ }
289
+
290
+ Params:: ParametersInstantiation getParameters ( ) {
291
+ result = this .getKeyGenerationOperationInstance ( ) .getParameters ( )
122
292
}
123
293
}
124
294
}
@@ -194,6 +364,11 @@ module Generators {
194
364
// TODO: We may need to model this using the `parameters` argument passed to
195
365
// the `init()` method.
196
366
Crypto:: ConsumerInputDataFlowNode getKeySizeConsumer ( ) { none ( ) }
367
+
368
+ // The `KeyGenerationParameters` argument used to configure the key generator.
369
+ Crypto:: ConsumerInputDataFlowNode getAParametersConsumer ( ) {
370
+ result .asExpr ( ) = this .getArgument ( 0 )
371
+ }
197
372
}
198
373
199
374
/**
@@ -216,6 +391,14 @@ module Generators {
216
391
private module KeyGeneratorFlow =
217
392
NewToInitToUseFlowAnalysis< KeyGeneratorNewCall , KeyGeneratorInitCall , KeyGeneratorUseCall > ;
218
393
394
+ private module ParametersFlow =
395
+ ParametersToInitFlowAnalysis< Params:: ParametersInstantiation , KeyGeneratorInitCall > ;
396
+
397
+ Params:: ParametersInstantiation getParametersFromInit ( KeyGeneratorInitCall init ) {
398
+ result = ParametersFlow:: getParametersFromInit ( init , _, _) and
399
+ result instanceof Params:: X9ECParametersInstantiation
400
+ }
401
+
219
402
/**
220
403
* A key generation operation instance is a call to `generateKey()` or
221
404
* `generateKeyPair()` on a key generator defined under
@@ -224,6 +407,10 @@ module Generators {
224
407
class KeyGenerationOperationInstance extends Crypto:: KeyGenerationOperationInstance instanceof KeyGeneratorUseCall
225
408
{
226
409
override Crypto:: AlgorithmValueConsumer getAnAlgorithmValueConsumer ( ) {
410
+ // The algorithm value consumer flows through a parameters argument to `init()`
411
+ result = this .getParameters ( ) .getAnAlgorithmValueConsumer ( )
412
+ or
413
+ // The algorithm is implicit in the key generator type
227
414
result = KeyGeneratorFlow:: getNewFromUse ( this , _, _)
228
415
}
229
416
@@ -240,17 +427,12 @@ module Generators {
240
427
override Crypto:: ConsumerInputDataFlowNode getKeySizeConsumer ( ) {
241
428
result = KeyGeneratorFlow:: getInitFromUse ( this , _, _) .getKeySizeConsumer ( )
242
429
}
243
- }
244
- }
245
430
246
- /**
247
- * Models for cryptographic parameters defined by the `org.bouncycastle.crypto.params` package.
248
- */
249
- module Parameters {
250
- class KeyGenerationParameters extends RefType {
251
- KeyGenerationParameters ( ) {
252
- this .getPackage ( ) .getName ( ) = "org.bouncycastle.crypto.params" and
253
- this .getName ( ) .matches ( "%KeyGenerationParameters" )
431
+ Params:: ParametersInstantiation getParameters ( ) {
432
+ exists ( KeyGeneratorInitCall init |
433
+ init = KeyGeneratorFlow:: getInitFromUse ( this , _, _) and
434
+ result = ParametersFlow:: getParametersFromInit ( init , _, _)
435
+ )
254
436
}
255
437
}
256
438
}
0 commit comments