@@ -6,6 +6,10 @@ import semmle.code.java.controlflow.Dominance
66module JCAModel {
77 import Language
88
9+ abstract class JCAAlgorithmInstance extends Crypto:: AlgorithmInstance {
10+ abstract Crypto:: AlgorithmValueConsumer getConsumer ( ) ;
11+ }
12+
913 // TODO: Verify that the PBEWith% case works correctly
1014 bindingset [ algo]
1115 predicate cipher_names ( string algo ) {
@@ -49,6 +53,9 @@ module JCAModel {
4953 kdf .toUpperCase ( ) .matches ( [ "PBKDF2With%" , "PBEWith%" ] .toUpperCase ( ) )
5054 }
5155
56+ bindingset [ name]
57+ predicate elliptic_curve_names ( string name ) { Crypto:: isEllipticCurveAlgorithmName ( name ) }
58+
5259 bindingset [ name]
5360 Crypto:: TKeyDerivationType kdf_name_to_kdf_type ( string name , string withSubstring ) {
5461 name .matches ( "PBKDF2With%" ) and
@@ -110,6 +117,12 @@ module JCAModel {
110117 string getPadding ( ) { result = this .getValue ( ) .splitAt ( "/" , 2 ) }
111118 }
112119
120+ class EllipticCurveStringLiteral extends StringLiteral {
121+ EllipticCurveStringLiteral ( ) { elliptic_curve_names ( this .getValue ( ) ) }
122+
123+ string getStandardEllipticCurveName ( ) { result = this .getValue ( ) }
124+ }
125+
113126 class CipherGetInstanceCall extends Call {
114127 CipherGetInstanceCall ( ) {
115128 this .getCallee ( ) .hasQualifiedName ( "javax.crypto" , "Cipher" , "getInstance" )
@@ -139,17 +152,32 @@ module JCAModel {
139152 }
140153
141154 /**
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.
143156 */
144- private module AlgorithmStringToFetchConfig implements DataFlow:: ConfigSig {
157+ private module CipherAlgorithmStringToFetchConfig implements DataFlow:: ConfigSig {
145158 predicate isSource ( DataFlow:: Node src ) { src .asExpr ( ) instanceof CipherStringLiteral }
146159
147160 predicate isSink ( DataFlow:: Node sink ) {
148161 exists ( Crypto:: AlgorithmValueConsumer consumer | sink = consumer .getInputNode ( ) )
149162 }
150163 }
151164
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 > ;
153181
154182 /**
155183 * 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 {
160188 *
161189 * TODO: Model the case of relying on a provider default, but alert on it as a bad practice.
162190 */
163- class CipherStringLiteralPaddingAlgorithmInstance extends CipherStringLiteralAlgorithmInstance ,
164- Crypto:: PaddingAlgorithmInstance instanceof CipherStringLiteral
191+ class CipherStringLiteralPaddingAlgorithmInstance extends JCAAlgorithmInstance ,
192+ CipherStringLiteralAlgorithmInstance , Crypto:: PaddingAlgorithmInstance instanceof CipherStringLiteral
165193 {
166194 CipherStringLiteralPaddingAlgorithmInstance ( ) { exists ( super .getPadding ( ) ) } // TODO: provider defaults
167195
@@ -183,8 +211,8 @@ module JCAModel {
183211 }
184212 }
185213
186- class CipherStringLiteralModeAlgorithmInstance extends CipherStringLiteralPaddingAlgorithmInstance ,
187- Crypto:: ModeOfOperationAlgorithmInstance instanceof CipherStringLiteral
214+ class CipherStringLiteralModeAlgorithmInstance extends JCAAlgorithmInstance ,
215+ CipherStringLiteralPaddingAlgorithmInstance , Crypto:: ModeOfOperationAlgorithmInstance instanceof CipherStringLiteral
188216 {
189217 CipherStringLiteralModeAlgorithmInstance ( ) { exists ( super .getMode ( ) ) } // TODO: provider defaults
190218
@@ -216,15 +244,141 @@ module JCAModel {
216244 }
217245 }
218246
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
220372 {
373+ // NOTE: this consumer is generic, but cipher algorithms can be consumed
374+ // by getInstance as well as key generation
221375 Crypto:: AlgorithmValueConsumer consumer ;
222376
223377 CipherStringLiteralAlgorithmInstance ( ) {
224- AlgorithmStringToFetchFlow :: flow ( DataFlow:: exprNode ( this ) , consumer .getInputNode ( ) )
378+ CipherAlgorithmStringToFetchFlow :: flow ( DataFlow:: exprNode ( this ) , consumer .getInputNode ( ) )
225379 }
226380
227- Crypto:: AlgorithmValueConsumer getConsumer ( ) { result = consumer }
381+ override Crypto:: AlgorithmValueConsumer getConsumer ( ) { result = consumer }
228382
229383 override Crypto:: ModeOfOperationAlgorithmInstance getModeOfOperationAlgorithm ( ) {
230384 result = this // TODO: provider defaults
@@ -302,8 +456,8 @@ module JCAModel {
302456 override int getDigestLength ( ) { exists ( hash_name_to_hash_type ( hashName , result ) ) }
303457 }
304458
305- class OAEPPaddingAlgorithmInstance extends Crypto :: OAEPPaddingAlgorithmInstance ,
306- CipherStringLiteralPaddingAlgorithmInstance
459+ class OAEPPaddingAlgorithmInstance extends JCAAlgorithmInstance ,
460+ Crypto :: OAEPPaddingAlgorithmInstance , CipherStringLiteralPaddingAlgorithmInstance
307461 {
308462 override Crypto:: HashAlgorithmInstance getOAEPEncodingHashAlgorithm ( ) { result = this }
309463
@@ -323,7 +477,7 @@ module JCAModel {
323477 override Crypto:: ConsumerInputDataFlowNode getInputNode ( ) { result .asExpr ( ) = this }
324478
325479 CipherStringLiteral getOrigin ( string value ) {
326- AlgorithmStringToFetchFlow :: flow ( DataFlow:: exprNode ( result ) ,
480+ CipherAlgorithmStringToFetchFlow :: flow ( DataFlow:: exprNode ( result ) ,
327481 DataFlow:: exprNode ( this .( Expr ) .getAChildExpr * ( ) ) ) and
328482 value = result .getValue ( )
329483 }
@@ -651,7 +805,8 @@ module JCAModel {
651805 module KnownHashAlgorithmLiteralToMessageDigestFlow =
652806 DataFlow:: Global< KnownHashAlgorithmLiteralToMessageDigestConfig > ;
653807
654- class KnownHashAlgorithm extends Crypto:: HashAlgorithmInstance instanceof StringLiteral {
808+ class KnownHashAlgorithm extends JCAAlgorithmInstance , Crypto:: HashAlgorithmInstance instanceof StringLiteral
809+ {
655810 MessageDigestAlgorithmValueConsumer consumer ;
656811
657812 KnownHashAlgorithm ( ) {
@@ -660,7 +815,7 @@ module JCAModel {
660815 consumer .getInputNode ( ) )
661816 }
662817
663- MessageDigestAlgorithmValueConsumer getConsumer ( ) { result = consumer }
818+ override MessageDigestAlgorithmValueConsumer getConsumer ( ) { result = consumer }
664819
665820 override string getRawHashAlgorithmName ( ) { result = this .( StringLiteral ) .getValue ( ) }
666821
@@ -733,46 +888,19 @@ module JCAModel {
733888 }
734889 }
735890
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-
748891 // flow from instance created by getInstance to generateKey
749- module KeyGeneratorGetInstanceToGenerateConfig implements DataFlow:: ConfigSig {
892+ module KeyGeneratorAlgValueConsumerToGenerateConfig implements DataFlow:: ConfigSig {
750893 predicate isSource ( DataFlow:: Node src ) {
751- exists ( KeyGeneratorGetInstanceCall call | src . asExpr ( ) = call )
894+ exists ( KeyGenAlgorithmValueConsumer consumer | consumer . getResultNode ( ) = src )
752895 }
753896
754897 predicate isSink ( DataFlow:: Node sink ) {
755898 exists ( KeyGeneratorGenerateCall call | sink .asExpr ( ) = call .( MethodCall ) .getQualifier ( ) )
756899 }
757900 }
758901
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 > ;
776904
777905 class KeyGeneratorGenerateCall extends Crypto:: KeyGenerationOperationInstance instanceof MethodCall
778906 {
@@ -791,8 +919,10 @@ module JCAModel {
791919 override Crypto:: KeyArtifactType getOutputKeyType ( ) { result = type }
792920
793921 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
796926 )
797927 }
798928
@@ -879,15 +1009,16 @@ module JCAModel {
8791009
8801010 module MACInitCallToMACOperationFlow = DataFlow:: Global< MACInitCallToMACOperationFlowConfig > ;
8811011
882- class KnownMACAlgorithm extends Crypto:: MACAlgorithmInstance instanceof StringLiteral {
1012+ class KnownMACAlgorithm extends JCAAlgorithmInstance , Crypto:: MACAlgorithmInstance instanceof StringLiteral
1013+ {
8831014 MACGetInstanceAlgorithmValueConsumer consumer ;
8841015
8851016 KnownMACAlgorithm ( ) {
8861017 mac_names ( this .getValue ( ) ) and
8871018 MACKnownAlgorithmToConsumerFlow:: flow ( DataFlow:: exprNode ( this ) , consumer .getInputNode ( ) )
8881019 }
8891020
890- MACGetInstanceAlgorithmValueConsumer getConsumer ( ) { result = consumer }
1021+ override MACGetInstanceAlgorithmValueConsumer getConsumer ( ) { result = consumer }
8911022
8921023 override string getRawMACAlgorithmName ( ) { result = super .getValue ( ) }
8931024
@@ -1039,7 +1170,8 @@ module JCAModel {
10391170 }
10401171 }
10411172
1042- class KDFAlgorithmStringLiteral extends Crypto:: KeyDerivationAlgorithmInstance instanceof StringLiteral
1173+ class KDFAlgorithmStringLiteral extends JCAAlgorithmInstance ,
1174+ Crypto:: KeyDerivationAlgorithmInstance instanceof StringLiteral
10431175 {
10441176 SecretKeyFactoryKDFAlgorithmValueConsumer consumer ;
10451177
@@ -1054,10 +1186,10 @@ module JCAModel {
10541186 result = kdf_name_to_kdf_type ( super .getValue ( ) , _)
10551187 }
10561188
1057- SecretKeyFactoryKDFAlgorithmValueConsumer getConsumer ( ) { result = consumer }
1189+ override SecretKeyFactoryKDFAlgorithmValueConsumer getConsumer ( ) { result = consumer }
10581190 }
10591191
1060- class PBKDF2AlgorithmStringLiteral extends KDFAlgorithmStringLiteral ,
1192+ class PBKDF2AlgorithmStringLiteral extends JCAAlgorithmInstance , KDFAlgorithmStringLiteral ,
10611193 Crypto:: PBKDF2AlgorithmInstance , Crypto:: HMACAlgorithmInstance , Crypto:: HashAlgorithmInstance ,
10621194 Crypto:: AlgorithmValueConsumer
10631195 {
@@ -1158,4 +1290,5 @@ module JCAModel {
11581290
11591291 override string getIterationCountFixed ( ) { none ( ) }
11601292 }
1293+ // TODO: flow the GCGenParametersSpecCall to an init, and the init to the operations
11611294}
0 commit comments