@@ -6,6 +6,10 @@ import semmle.code.java.controlflow.Dominance
6
6
module JCAModel {
7
7
import Language
8
8
9
+ abstract class JCAAlgorithmInstance extends Crypto:: AlgorithmInstance {
10
+ abstract Crypto:: AlgorithmValueConsumer getConsumer ( ) ;
11
+ }
12
+
9
13
// TODO: Verify that the PBEWith% case works correctly
10
14
bindingset [ algo]
11
15
predicate cipher_names ( string algo ) {
@@ -49,6 +53,9 @@ module JCAModel {
49
53
kdf .toUpperCase ( ) .matches ( [ "PBKDF2With%" , "PBEWith%" ] .toUpperCase ( ) )
50
54
}
51
55
56
+ bindingset [ name]
57
+ predicate elliptic_curve_names ( string name ) { Crypto:: isEllipticCurveAlgorithmName ( name ) }
58
+
52
59
bindingset [ name]
53
60
Crypto:: TKeyDerivationType kdf_name_to_kdf_type ( string name , string withSubstring ) {
54
61
name .matches ( "PBKDF2With%" ) and
@@ -110,6 +117,12 @@ module JCAModel {
110
117
string getPadding ( ) { result = this .getValue ( ) .splitAt ( "/" , 2 ) }
111
118
}
112
119
120
+ class EllipticCurveStringLiteral extends StringLiteral {
121
+ EllipticCurveStringLiteral ( ) { elliptic_curve_names ( this .getValue ( ) ) }
122
+
123
+ string getStandardEllipticCurveName ( ) { result = this .getValue ( ) }
124
+ }
125
+
113
126
class CipherGetInstanceCall extends Call {
114
127
CipherGetInstanceCall ( ) {
115
128
this .getCallee ( ) .hasQualifiedName ( "javax.crypto" , "Cipher" , "getInstance" )
@@ -139,17 +152,32 @@ module JCAModel {
139
152
}
140
153
141
154
/**
142
- * Data-flow configuration modelling flow from a cipher string literal to a `CipherGetInstanceCall` argument.
155
+ * Data-flow configuration modelling flow from a cipher string literal to a value consumer argument.
143
156
*/
144
- private module AlgorithmStringToFetchConfig implements DataFlow:: ConfigSig {
157
+ private module CipherAlgorithmStringToFetchConfig implements DataFlow:: ConfigSig {
145
158
predicate isSource ( DataFlow:: Node src ) { src .asExpr ( ) instanceof CipherStringLiteral }
146
159
147
160
predicate isSink ( DataFlow:: Node sink ) {
148
161
exists ( Crypto:: AlgorithmValueConsumer consumer | sink = consumer .getInputNode ( ) )
149
162
}
150
163
}
151
164
152
- module AlgorithmStringToFetchFlow = TaintTracking:: Global< AlgorithmStringToFetchConfig > ;
165
+ module CipherAlgorithmStringToFetchFlow =
166
+ TaintTracking:: Global< CipherAlgorithmStringToFetchConfig > ;
167
+
168
+ /**
169
+ * Data-flow configuration modelling flow from a cipher string literal to a value consumer argument.
170
+ */
171
+ private module EllipticCurveAlgorithmStringToFetchConfig implements DataFlow:: ConfigSig {
172
+ predicate isSource ( DataFlow:: Node src ) { src .asExpr ( ) instanceof EllipticCurveStringLiteral }
173
+
174
+ predicate isSink ( DataFlow:: Node sink ) {
175
+ exists ( Crypto:: AlgorithmValueConsumer consumer | sink = consumer .getInputNode ( ) )
176
+ }
177
+ }
178
+
179
+ module EllipticCurveAlgorithmStringToFetchFlow =
180
+ TaintTracking:: Global< EllipticCurveAlgorithmStringToFetchConfig > ;
153
181
154
182
/**
155
183
* Note: padding and a mode of operation will only exist when the padding / mode (*and its type*) are determinable.
@@ -160,8 +188,8 @@ module JCAModel {
160
188
*
161
189
* TODO: Model the case of relying on a provider default, but alert on it as a bad practice.
162
190
*/
163
- class CipherStringLiteralPaddingAlgorithmInstance extends CipherStringLiteralAlgorithmInstance ,
164
- Crypto:: PaddingAlgorithmInstance instanceof CipherStringLiteral
191
+ class CipherStringLiteralPaddingAlgorithmInstance extends JCAAlgorithmInstance ,
192
+ CipherStringLiteralAlgorithmInstance , Crypto:: PaddingAlgorithmInstance instanceof CipherStringLiteral
165
193
{
166
194
CipherStringLiteralPaddingAlgorithmInstance ( ) { exists ( super .getPadding ( ) ) } // TODO: provider defaults
167
195
@@ -183,8 +211,8 @@ module JCAModel {
183
211
}
184
212
}
185
213
186
- class CipherStringLiteralModeAlgorithmInstance extends CipherStringLiteralPaddingAlgorithmInstance ,
187
- Crypto:: ModeOfOperationAlgorithmInstance instanceof CipherStringLiteral
214
+ class CipherStringLiteralModeAlgorithmInstance extends JCAAlgorithmInstance ,
215
+ CipherStringLiteralPaddingAlgorithmInstance , Crypto:: ModeOfOperationAlgorithmInstance instanceof CipherStringLiteral
188
216
{
189
217
CipherStringLiteralModeAlgorithmInstance ( ) { exists ( super .getMode ( ) ) } // TODO: provider defaults
190
218
@@ -216,15 +244,141 @@ module JCAModel {
216
244
}
217
245
}
218
246
219
- class CipherStringLiteralAlgorithmInstance extends Crypto:: CipherAlgorithmInstance instanceof CipherStringLiteral
247
+ class KeyGeneratorGetInstanceCall extends MethodCall {
248
+ KeyGeneratorGetInstanceCall ( ) {
249
+ this .getCallee ( ) .hasQualifiedName ( "javax.crypto" , "KeyGenerator" , "getInstance" )
250
+ or
251
+ this .getCallee ( ) .hasQualifiedName ( "java.security" , "KeyPairGenerator" , "getInstance" )
252
+ }
253
+
254
+ Expr getAlgorithmArg ( ) { result = super .getArgument ( 0 ) }
255
+ }
256
+
257
+ // For general elliptic curves, getInstance("EC") is used
258
+ // and java.security.spec.ECGenParameterSpec("<CURVE NAME>") is what sets the specific curve.
259
+ // The result of ECGenParameterSpec is passed to KeyPairGenerator.initialize
260
+ // If the curve is not specified, the default is used.
261
+ // We would trace the use of this inside a KeyPairGenerator.initialize
262
+ class ECGenParameterSpecCall extends ClassInstanceExpr {
263
+ ECGenParameterSpecCall ( ) {
264
+ this .( ClassInstanceExpr )
265
+ .getConstructedType ( )
266
+ .hasQualifiedName ( "java.security.spec" , "ECGenParameterSpec" )
267
+ }
268
+
269
+ Expr getAlgorithmArg ( ) { result = super .getArgument ( 0 ) }
270
+
271
+ KeyPairGeneratorInitializeCall getInitializeConsumerCall ( ) {
272
+ exists ( DataFlow:: Node sink |
273
+ ECGenParameterSpecCallToInitializeFlow:: flow ( DataFlow:: exprNode ( this ) , sink ) and
274
+ result .getAnArgument ( ) = sink .asExpr ( )
275
+ )
276
+ }
277
+ }
278
+
279
+ abstract class KeyGenAlgorithmValueConsumer extends Crypto:: AlgorithmValueConsumer {
280
+ // abstract predicate flowsToKeyGenerateCallQualifier(KeyGeneratorGenerateCall sink);
281
+ abstract DataFlow:: Node getResultNode ( ) ;
282
+ }
283
+
284
+ class KeyPairGeneratorInitializeCall extends MethodCall {
285
+ KeyPairGeneratorInitializeCall ( ) {
286
+ this .getCallee ( ) .hasQualifiedName ( "java.security" , "KeyPairGenerator" , "initialize" )
287
+ }
288
+
289
+ Expr getKeyArg ( ) {
290
+ result = this .getArgument ( 0 ) and
291
+ result .getType ( ) instanceof IntegralType
292
+ }
293
+ }
294
+
295
+ private module ECGenParameterSpecCallToInitializeConfig implements DataFlow:: ConfigSig {
296
+ predicate isSource ( DataFlow:: Node src ) { src .asExpr ( ) instanceof ECGenParameterSpecCall }
297
+
298
+ predicate isSink ( DataFlow:: Node sink ) {
299
+ exists ( KeyPairGeneratorInitializeCall c | c .getAnArgument ( ) = sink .asExpr ( ) )
300
+ }
301
+ }
302
+
303
+ module ECGenParameterSpecCallToInitializeFlow =
304
+ DataFlow:: Global< ECGenParameterSpecCallToInitializeConfig > ;
305
+
306
+ class ECGenParameterSpecAlgorithmValueConsumer extends KeyGenAlgorithmValueConsumer {
307
+ ECGenParameterSpecCall call ;
308
+
309
+ ECGenParameterSpecAlgorithmValueConsumer ( ) { this = call .getAlgorithmArg ( ) }
310
+
311
+ override Crypto:: ConsumerInputDataFlowNode getInputNode ( ) { result .asExpr ( ) = this }
312
+
313
+ override DataFlow:: Node getResultNode ( ) {
314
+ // Traversing to the initialilzer directly and calling this the 'result'
315
+ // to simplify the trace. In theory you would trace from the call
316
+ // through the initializer, but we already have a trace to the initializer
317
+ // so using this instead of altering/creating data flow configs.
318
+ call .getInitializeConsumerCall ( ) .getQualifier ( ) = result .asExpr ( )
319
+ }
320
+
321
+ override Crypto:: AlgorithmInstance getAKnownAlgorithmSource ( ) {
322
+ result .( JCAAlgorithmInstance ) .getConsumer ( ) = this
323
+ }
324
+ }
325
+
326
+ class KeyGeneratorGetInstanceAlgorithmValueConsumer extends KeyGenAlgorithmValueConsumer {
327
+ KeyGeneratorGetInstanceCall call ;
328
+
329
+ KeyGeneratorGetInstanceAlgorithmValueConsumer ( ) { this = call .getAlgorithmArg ( ) }
330
+
331
+ override Crypto:: ConsumerInputDataFlowNode getInputNode ( ) { result .asExpr ( ) = this }
332
+
333
+ override DataFlow:: Node getResultNode ( ) { result .asExpr ( ) = call }
334
+
335
+ override Crypto:: AlgorithmInstance getAKnownAlgorithmSource ( ) {
336
+ // The source is any instance whose consumer is this
337
+ result .( JCAAlgorithmInstance ) .getConsumer ( ) = this
338
+ }
339
+ }
340
+
341
+ class EllipticCurveStringLiteralAlgorithmInstance extends JCAAlgorithmInstance ,
342
+ Crypto:: EllipticCurveAlgorithmInstance instanceof StringLiteral
343
+ {
344
+ Crypto:: AlgorithmValueConsumer consumer ;
345
+
346
+ EllipticCurveStringLiteralAlgorithmInstance ( ) {
347
+ // Trace a known elliptic curve algorithm string literal to a key gen consumer
348
+ EllipticCurveAlgorithmStringToFetchFlow:: flow ( DataFlow:: exprNode ( this ) ,
349
+ consumer .getInputNode ( ) )
350
+ }
351
+
352
+ override Crypto:: AlgorithmValueConsumer getConsumer ( ) { result = consumer }
353
+
354
+ override string getRawEllipticCurveAlgorithmName ( ) { result = super .getValue ( ) }
355
+
356
+ override string getStandardCurveName ( ) { result = this .getRawEllipticCurveAlgorithmName ( ) }
357
+
358
+ override Crypto:: TEllipticCurveType getEllipticCurveFamily ( ) {
359
+ Crypto:: isEllipticCurveAlgorithm ( this .getRawEllipticCurveAlgorithmName ( ) , _, result )
360
+ }
361
+
362
+ override string getKeySize ( ) {
363
+ exists ( int keySize |
364
+ Crypto:: isEllipticCurveAlgorithm ( this .getRawEllipticCurveAlgorithmName ( ) , keySize , _) and
365
+ result = keySize .toString ( )
366
+ )
367
+ }
368
+ }
369
+
370
+ class CipherStringLiteralAlgorithmInstance extends JCAAlgorithmInstance ,
371
+ Crypto:: CipherAlgorithmInstance instanceof CipherStringLiteral
220
372
{
373
+ // NOTE: this consumer is generic, but cipher algorithms can be consumed
374
+ // by getInstance as well as key generation
221
375
Crypto:: AlgorithmValueConsumer consumer ;
222
376
223
377
CipherStringLiteralAlgorithmInstance ( ) {
224
- AlgorithmStringToFetchFlow :: flow ( DataFlow:: exprNode ( this ) , consumer .getInputNode ( ) )
378
+ CipherAlgorithmStringToFetchFlow :: flow ( DataFlow:: exprNode ( this ) , consumer .getInputNode ( ) )
225
379
}
226
380
227
- Crypto:: AlgorithmValueConsumer getConsumer ( ) { result = consumer }
381
+ override Crypto:: AlgorithmValueConsumer getConsumer ( ) { result = consumer }
228
382
229
383
override Crypto:: ModeOfOperationAlgorithmInstance getModeOfOperationAlgorithm ( ) {
230
384
result = this // TODO: provider defaults
@@ -302,8 +456,8 @@ module JCAModel {
302
456
override int getDigestLength ( ) { exists ( hash_name_to_hash_type ( hashName , result ) ) }
303
457
}
304
458
305
- class OAEPPaddingAlgorithmInstance extends Crypto :: OAEPPaddingAlgorithmInstance ,
306
- CipherStringLiteralPaddingAlgorithmInstance
459
+ class OAEPPaddingAlgorithmInstance extends JCAAlgorithmInstance ,
460
+ Crypto :: OAEPPaddingAlgorithmInstance , CipherStringLiteralPaddingAlgorithmInstance
307
461
{
308
462
override Crypto:: HashAlgorithmInstance getOAEPEncodingHashAlgorithm ( ) { result = this }
309
463
@@ -323,7 +477,7 @@ module JCAModel {
323
477
override Crypto:: ConsumerInputDataFlowNode getInputNode ( ) { result .asExpr ( ) = this }
324
478
325
479
CipherStringLiteral getOrigin ( string value ) {
326
- AlgorithmStringToFetchFlow :: flow ( DataFlow:: exprNode ( result ) ,
480
+ CipherAlgorithmStringToFetchFlow :: flow ( DataFlow:: exprNode ( result ) ,
327
481
DataFlow:: exprNode ( this .( Expr ) .getAChildExpr * ( ) ) ) and
328
482
value = result .getValue ( )
329
483
}
@@ -651,7 +805,8 @@ module JCAModel {
651
805
module KnownHashAlgorithmLiteralToMessageDigestFlow =
652
806
DataFlow:: Global< KnownHashAlgorithmLiteralToMessageDigestConfig > ;
653
807
654
- class KnownHashAlgorithm extends Crypto:: HashAlgorithmInstance instanceof StringLiteral {
808
+ class KnownHashAlgorithm extends JCAAlgorithmInstance , Crypto:: HashAlgorithmInstance instanceof StringLiteral
809
+ {
655
810
MessageDigestAlgorithmValueConsumer consumer ;
656
811
657
812
KnownHashAlgorithm ( ) {
@@ -660,7 +815,7 @@ module JCAModel {
660
815
consumer .getInputNode ( ) )
661
816
}
662
817
663
- MessageDigestAlgorithmValueConsumer getConsumer ( ) { result = consumer }
818
+ override MessageDigestAlgorithmValueConsumer getConsumer ( ) { result = consumer }
664
819
665
820
override string getRawHashAlgorithmName ( ) { result = this .( StringLiteral ) .getValue ( ) }
666
821
@@ -733,46 +888,19 @@ module JCAModel {
733
888
}
734
889
}
735
890
736
- class KeyGeneratorCallAlgorithmValueConsumer extends Crypto:: AlgorithmValueConsumer {
737
- KeyGeneratorGetInstanceCall call ;
738
-
739
- KeyGeneratorCallAlgorithmValueConsumer ( ) { this = call .getAlgorithmArg ( ) }
740
-
741
- override Crypto:: ConsumerInputDataFlowNode getInputNode ( ) { result .asExpr ( ) = this }
742
-
743
- override Crypto:: AlgorithmInstance getAKnownAlgorithmSource ( ) {
744
- result .( CipherStringLiteralAlgorithmInstance ) .getConsumer ( ) = this
745
- }
746
- }
747
-
748
891
// flow from instance created by getInstance to generateKey
749
- module KeyGeneratorGetInstanceToGenerateConfig implements DataFlow:: ConfigSig {
892
+ module KeyGeneratorAlgValueConsumerToGenerateConfig implements DataFlow:: ConfigSig {
750
893
predicate isSource ( DataFlow:: Node src ) {
751
- exists ( KeyGeneratorGetInstanceCall call | src . asExpr ( ) = call )
894
+ exists ( KeyGenAlgorithmValueConsumer consumer | consumer . getResultNode ( ) = src )
752
895
}
753
896
754
897
predicate isSink ( DataFlow:: Node sink ) {
755
898
exists ( KeyGeneratorGenerateCall call | sink .asExpr ( ) = call .( MethodCall ) .getQualifier ( ) )
756
899
}
757
900
}
758
901
759
- module KeyGeneratorGetInstanceToGenerateFlow =
760
- DataFlow:: Global< KeyGeneratorGetInstanceToGenerateConfig > ;
761
-
762
- class KeyGeneratorGetInstanceCall extends MethodCall {
763
- KeyGeneratorGetInstanceCall ( ) {
764
- this .getCallee ( ) .hasQualifiedName ( "javax.crypto" , "KeyGenerator" , "getInstance" )
765
- or
766
- this .getCallee ( ) .hasQualifiedName ( "java.security" , "KeyPairGenerator" , "getInstance" )
767
- }
768
-
769
- Expr getAlgorithmArg ( ) { result = super .getArgument ( 0 ) }
770
-
771
- predicate flowsToKeyGenerateCallQualifier ( KeyGeneratorGenerateCall sink ) {
772
- KeyGeneratorGetInstanceToGenerateFlow:: flow ( DataFlow:: exprNode ( this ) ,
773
- DataFlow:: exprNode ( sink .( MethodCall ) .getQualifier ( ) ) )
774
- }
775
- }
902
+ module KeyGeneratorAlgValueConsumerToGenerateFlow =
903
+ DataFlow:: Global< KeyGeneratorAlgValueConsumerToGenerateConfig > ;
776
904
777
905
class KeyGeneratorGenerateCall extends Crypto:: KeyGenerationOperationInstance instanceof MethodCall
778
906
{
@@ -791,8 +919,10 @@ module JCAModel {
791
919
override Crypto:: KeyArtifactType getOutputKeyType ( ) { result = type }
792
920
793
921
override Crypto:: AlgorithmValueConsumer getAnAlgorithmValueConsumer ( ) {
794
- exists ( KeyGeneratorGetInstanceCall getInstance |
795
- getInstance .flowsToKeyGenerateCallQualifier ( this ) and result = getInstance .getAlgorithmArg ( )
922
+ exists ( KeyGenAlgorithmValueConsumer consumer |
923
+ KeyGeneratorAlgValueConsumerToGenerateFlow:: flow ( consumer .getResultNode ( ) ,
924
+ DataFlow:: exprNode ( this .( Call ) .getQualifier ( ) ) ) and
925
+ result = consumer
796
926
)
797
927
}
798
928
@@ -879,15 +1009,16 @@ module JCAModel {
879
1009
880
1010
module MACInitCallToMACOperationFlow = DataFlow:: Global< MACInitCallToMACOperationFlowConfig > ;
881
1011
882
- class KnownMACAlgorithm extends Crypto:: MACAlgorithmInstance instanceof StringLiteral {
1012
+ class KnownMACAlgorithm extends JCAAlgorithmInstance , Crypto:: MACAlgorithmInstance instanceof StringLiteral
1013
+ {
883
1014
MACGetInstanceAlgorithmValueConsumer consumer ;
884
1015
885
1016
KnownMACAlgorithm ( ) {
886
1017
mac_names ( this .getValue ( ) ) and
887
1018
MACKnownAlgorithmToConsumerFlow:: flow ( DataFlow:: exprNode ( this ) , consumer .getInputNode ( ) )
888
1019
}
889
1020
890
- MACGetInstanceAlgorithmValueConsumer getConsumer ( ) { result = consumer }
1021
+ override MACGetInstanceAlgorithmValueConsumer getConsumer ( ) { result = consumer }
891
1022
892
1023
override string getRawMACAlgorithmName ( ) { result = super .getValue ( ) }
893
1024
@@ -1039,7 +1170,8 @@ module JCAModel {
1039
1170
}
1040
1171
}
1041
1172
1042
- class KDFAlgorithmStringLiteral extends Crypto:: KeyDerivationAlgorithmInstance instanceof StringLiteral
1173
+ class KDFAlgorithmStringLiteral extends JCAAlgorithmInstance ,
1174
+ Crypto:: KeyDerivationAlgorithmInstance instanceof StringLiteral
1043
1175
{
1044
1176
SecretKeyFactoryKDFAlgorithmValueConsumer consumer ;
1045
1177
@@ -1054,10 +1186,10 @@ module JCAModel {
1054
1186
result = kdf_name_to_kdf_type ( super .getValue ( ) , _)
1055
1187
}
1056
1188
1057
- SecretKeyFactoryKDFAlgorithmValueConsumer getConsumer ( ) { result = consumer }
1189
+ override SecretKeyFactoryKDFAlgorithmValueConsumer getConsumer ( ) { result = consumer }
1058
1190
}
1059
1191
1060
- class PBKDF2AlgorithmStringLiteral extends KDFAlgorithmStringLiteral ,
1192
+ class PBKDF2AlgorithmStringLiteral extends JCAAlgorithmInstance , KDFAlgorithmStringLiteral ,
1061
1193
Crypto:: PBKDF2AlgorithmInstance , Crypto:: HMACAlgorithmInstance , Crypto:: HashAlgorithmInstance ,
1062
1194
Crypto:: AlgorithmValueConsumer
1063
1195
{
@@ -1158,4 +1290,5 @@ module JCAModel {
1158
1290
1159
1291
override string getIterationCountFixed ( ) { none ( ) }
1160
1292
}
1293
+ // TODO: flow the GCGenParametersSpecCall to an init, and the init to the operations
1161
1294
}
0 commit comments