@@ -56,6 +56,9 @@ module JCAModel {
5656 bindingset [ name]
5757 predicate elliptic_curve_names ( string name ) { Crypto:: isEllipticCurveAlgorithmName ( name ) }
5858
59+ bindingset [ name]
60+ predicate key_agreement_names ( string name ) { Crypto:: isKeyAgreementAlgorithmName ( name ) }
61+
5962 bindingset [ name]
6063 Crypto:: TKeyDerivationType kdf_name_to_kdf_type ( string name , string withSubstring ) {
6164 name .matches ( "PBKDF2With%" ) and
@@ -123,6 +126,10 @@ module JCAModel {
123126 string getStandardEllipticCurveName ( ) { result = this .getValue ( ) }
124127 }
125128
129+ class KeyAgreementStringLiteral extends StringLiteral {
130+ KeyAgreementStringLiteral ( ) { key_agreement_names ( this .getValue ( ) ) }
131+ }
132+
126133 class CipherGetInstanceCall extends Call {
127134 CipherGetInstanceCall ( ) {
128135 this .getCallee ( ) .hasQualifiedName ( "javax.crypto" , "Cipher" , "getInstance" )
@@ -166,7 +173,7 @@ module JCAModel {
166173 TaintTracking:: Global< CipherAlgorithmStringToFetchConfig > ;
167174
168175 /**
169- * Data-flow configuration modelling flow from a cipher string literal to a value consumer argument.
176+ * Data-flow configuration modelling flow from a elliptic curve literal to a value consumer argument.
170177 */
171178 private module EllipticCurveAlgorithmStringToFetchConfig implements DataFlow:: ConfigSig {
172179 predicate isSource ( DataFlow:: Node src ) { src .asExpr ( ) instanceof EllipticCurveStringLiteral }
@@ -211,6 +218,89 @@ module JCAModel {
211218 }
212219 }
213220
221+ /**
222+ * Data-flow configuration modelling flow from a key agreement literal to a value consumer argument.
223+ */
224+ private module KeyAgreementAlgorithmStringToFetchConfig implements DataFlow:: ConfigSig {
225+ predicate isSource ( DataFlow:: Node src ) { src .asExpr ( ) instanceof KeyAgreementStringLiteral }
226+
227+ predicate isSink ( DataFlow:: Node sink ) {
228+ exists ( Crypto:: AlgorithmValueConsumer consumer | sink = consumer .getInputNode ( ) )
229+ }
230+ }
231+
232+ module KeyAgreementAlgorithmStringToFetchFlow =
233+ TaintTracking:: Global< KeyAgreementAlgorithmStringToFetchConfig > ;
234+
235+ class KeyAgreementInitCall extends MethodCall {
236+ KeyAgreementInitCall ( ) {
237+ this .getCallee ( ) .hasQualifiedName ( "javax.crypto" , "KeyAgreement" , "init" )
238+ }
239+
240+ Expr getServerKeyArg ( ) { result = this .getArgument ( 0 ) }
241+ }
242+
243+ private module KeyAgreementInitQualifierToSecretGenQualifierConfig implements DataFlow:: ConfigSig {
244+ predicate isSource ( DataFlow:: Node src ) {
245+ exists ( KeyAgreementInitCall init | src .asExpr ( ) = init .getQualifier ( ) )
246+ }
247+
248+ predicate isSink ( DataFlow:: Node sink ) {
249+ exists ( KeyAgreementGenerateSecretCall c | sink .asExpr ( ) = c .getQualifier ( ) )
250+ }
251+
252+ /**
253+ * Barrier if we go into another init, assume the second init overwrites the first
254+ */
255+ predicate isBarrierIn ( DataFlow:: Node node ) { isSource ( node ) }
256+ }
257+
258+ module KeyAgreementInitQualifierToSecretGenQualifierFlow =
259+ DataFlow:: Global< KeyAgreementInitQualifierToSecretGenQualifierConfig > ;
260+
261+ class KeyAgreementGenerateSecretCall extends MethodCall {
262+ KeyAgreementGenerateSecretCall ( ) {
263+ this .getCallee ( ) .hasQualifiedName ( "javax.crypto" , "KeyAgreement" , "generateSecret" )
264+ }
265+
266+ KeyAgreementInitCall getKeyAgreementInitCall ( ) {
267+ KeyAgreementInitQualifierToSecretGenQualifierFlow:: flow ( DataFlow:: exprNode ( result
268+ .getQualifier ( ) ) , DataFlow:: exprNode ( this .getQualifier ( ) ) )
269+ }
270+ }
271+
272+ private module KeyAgreementAVCToInitQualifierConfig implements DataFlow:: ConfigSig {
273+ predicate isSource ( DataFlow:: Node src ) {
274+ exists ( KeyAgreementAlgorithmValueConsumer consumer | consumer .getResultNode ( ) = src )
275+ }
276+
277+ predicate isSink ( DataFlow:: Node sink ) {
278+ exists ( KeyAgreementInitCall init | sink .asExpr ( ) = init .getQualifier ( ) )
279+ }
280+ }
281+
282+ module KeyAgreementAVCToInitQualifierFlow =
283+ DataFlow:: Global< KeyAgreementAVCToInitQualifierConfig > ;
284+
285+ class KeyAgreementSecretGenerationOperationInstance extends Crypto:: KeyAgreementSecretGenerationOperationInstance instanceof KeyAgreementGenerateSecretCall
286+ {
287+ override Crypto:: ConsumerInputDataFlowNode getServerKeyConsumer ( ) {
288+ this .( KeyAgreementGenerateSecretCall ) .getKeyAgreementInitCall ( ) .getServerKeyArg ( ) =
289+ result .asExpr ( )
290+ }
291+
292+ override Crypto:: ConsumerInputDataFlowNode getPeerKeyConsumer ( ) {
293+ none ( ) //TODO
294+ }
295+
296+ override Crypto:: AlgorithmValueConsumer getAnAlgorithmValueConsumer ( ) {
297+ none ( ) // TODO: key agreeement has it's own algorithm consumer, separate from the key
298+ // TODO: the char pred must trace from the consumer to here,
299+ // in theory, along that path we would get the init and doPhase, but can I just get those
300+ // separately avoiding a complicated config state for dataflow?
301+ }
302+ }
303+
214304 class CipherStringLiteralModeAlgorithmInstance extends JCAAlgorithmInstance ,
215305 CipherStringLiteralPaddingAlgorithmInstance , Crypto:: ModeOfOperationAlgorithmInstance instanceof CipherStringLiteral
216306 {
@@ -339,7 +429,7 @@ module JCAModel {
339429 }
340430
341431 class EllipticCurveStringLiteralAlgorithmInstance extends JCAAlgorithmInstance ,
342- Crypto:: EllipticCurveAlgorithmInstance instanceof StringLiteral
432+ Crypto:: EllipticCurveAlgorithmInstance instanceof EllipticCurveStringLiteral
343433 {
344434 Crypto:: AlgorithmValueConsumer consumer ;
345435
@@ -367,6 +457,47 @@ module JCAModel {
367457 }
368458 }
369459
460+ class KeyAgreementGetInstanceCall extends MethodCall {
461+ KeyAgreementGetInstanceCall ( ) {
462+ this .getCallee ( ) .hasQualifiedName ( "javax.crypto" , "KeyAgreement" , "getInstance" )
463+ }
464+
465+ Expr getAlgorithmArg ( ) { result = super .getArgument ( 0 ) }
466+ }
467+
468+ class KeyAgreementAlgorithmValueConsumer extends Crypto:: AlgorithmValueConsumer {
469+ KeyAgreementGetInstanceCall call ;
470+
471+ KeyAgreementAlgorithmValueConsumer ( ) { this = call .getAlgorithmArg ( ) }
472+
473+ DataFlow:: Node getResultNode ( ) { result .asExpr ( ) = call }
474+
475+ override Crypto:: ConsumerInputDataFlowNode getInputNode ( ) { result .asExpr ( ) = this }
476+
477+ override Crypto:: AlgorithmInstance getAKnownAlgorithmSource ( ) {
478+ result .( KeyAgreementStringLiteralAlgorithmInstance ) .getConsumer ( ) = this
479+ }
480+ }
481+
482+ class KeyAgreementStringLiteralAlgorithmInstance extends JCAAlgorithmInstance ,
483+ Crypto:: KeyAgreementAlgorithmInstance instanceof KeyAgreementStringLiteral
484+ {
485+ Crypto:: AlgorithmValueConsumer consumer ;
486+
487+ KeyAgreementStringLiteralAlgorithmInstance ( ) {
488+ KeyAgreementAlgorithmStringToFetchFlow:: flow ( DataFlow:: exprNode ( this ) , consumer .getInputNode ( ) )
489+ }
490+
491+ override Crypto:: AlgorithmValueConsumer getConsumer ( ) { result = consumer }
492+ // override Crypto::EllipticCurveAlgorithmInstance getEllipticCurveAlgorithm() {
493+ // this.(KeyAgreementStringLiteral).getValue().toUpperCase() in ["X25519", "X448"] and
494+ // // NOTE: this relies upon modeling the elliptic curve on 'this' separately
495+ // result = this
496+ // // TODO: or is ecdh and go find the curve
497+ // // this.(KeyAgreementStringLiteral).toString().toUpperCase() = ["ECDH"]
498+ // }
499+ }
500+
370501 class CipherStringLiteralAlgorithmInstance extends JCAAlgorithmInstance ,
371502 Crypto:: CipherAlgorithmInstance instanceof CipherStringLiteral
372503 {
0 commit comments