@@ -363,80 +363,134 @@ private class CipherMode extends TCipherMode {
363363 predicate isWeak ( ) { isWeakBlockMode ( this .getBlockMode ( ) ) }
364364}
365365
366- // Convenience methods for getting constant value arguments in cipher instantiation
367- private class CipherCallNode extends DataFlow:: CallNode {
368- string getStringArgument ( int i ) {
369- result = super .getArgument ( i ) .asExpr ( ) .getConstantValue ( ) .getStringOrSymbol ( )
370- }
366+ private string getStringArgument ( DataFlow:: CallNode call , int i ) {
367+ result = call .getArgument ( i ) .asExpr ( ) .getConstantValue ( ) .getStringOrSymbol ( )
368+ }
371369
372- int getIntArgument ( int i ) { result = super .getArgument ( i ) .asExpr ( ) .getConstantValue ( ) .getInt ( ) }
370+ private int getIntArgument ( DataFlow:: CallNode call , int i ) {
371+ result = call .getArgument ( i ) .asExpr ( ) .getConstantValue ( ) .getInt ( )
373372}
374373
375- /** A call to `OpenSSL::Cipher.new` or similar. */
376- private class CipherInstantiation extends CipherCallNode {
377- private OpenSSLCipher cipher ;
378- private CipherMode cipherMode ;
374+ /**
375+ * Holds if `call` is a call to `OpenSSL::Cipher.new` that instantiates a
376+ * `cipher` instance with mode `cipherMode`.
377+ */
378+ private predicate cipherInstantiationGeneric (
379+ DataFlow:: CallNode call , OpenSSLCipher cipher , CipherMode cipherMode
380+ ) {
381+ exists ( string cipherName | cipher .matchesName ( cipherName ) |
382+ // `OpenSSL::Cipher.new('<cipherName>')`
383+ call = cipherApi ( ) .getAnInstantiation ( ) and
384+ cipherName = getStringArgument ( call , 0 ) and
385+ // CBC is used by default
386+ cipherMode .isBlockMode ( "CBC" )
387+ )
388+ }
379389
380- CipherInstantiation ( ) {
381- exists ( string cipherName | cipher .matchesName ( cipherName ) |
382- // `OpenSSL::Cipher.new('<cipherName>')`
383- this = cipherApi ( ) .getAnInstantiation ( ) and
384- cipherName = this .getStringArgument ( 0 ) and
385- // CBC is used by default
386- cipherMode .isBlockMode ( "CBC" )
390+ /**
391+ * Holds if `call` is a call to `OpenSSL::Cipher::AES.new` or
392+ * `OpenSSL::Cipher::AES{128,192,256}.new` that instantiates an AES `cipher` instance
393+ * with mode `cipherMode`.
394+ */
395+ private predicate cipherInstantiationAES (
396+ DataFlow:: CallNode call , OpenSSLCipher cipher , CipherMode cipherMode
397+ ) {
398+ exists ( string cipherName | cipher .matchesName ( cipherName ) |
399+ // `OpenSSL::Cipher::AES` instantiations
400+ call = cipherApi ( ) .getMember ( "AES" ) .getAnInstantiation ( ) and
401+ exists ( string keyLength , string blockMode |
402+ // `OpenSSL::Cipher::AES.new('<keyLength-blockMode>')
403+ exists ( string arg0 |
404+ arg0 = getStringArgument ( call , 0 ) and
405+ keyLength = arg0 .splitAt ( "-" , 0 ) and
406+ blockMode = arg0 .splitAt ( "-" , 1 ) .toUpperCase ( )
407+ )
387408 or
388- // `OpenSSL::Cipher::AES` instantiations
389- this = cipherApi ( ) .getMember ( "AES" ) .getAnInstantiation ( ) and
390- exists ( string keyLength , string blockMode |
391- // `OpenSSL::Cipher::AES.new('<keyLength-blockMode>')
392- exists ( string arg0 |
393- arg0 = this .getStringArgument ( 0 ) and
394- keyLength = arg0 .splitAt ( "-" , 0 ) and
395- blockMode = arg0 .splitAt ( "-" , 1 ) .toUpperCase ( )
396- )
397- or
398- // `OpenSSL::Cipher::AES.new(<keyLength>, '<blockMode>')`
399- keyLength = this .getIntArgument ( 0 ) .toString ( ) and
400- blockMode = this .getStringArgument ( 1 ) .toUpperCase ( )
409+ // `OpenSSL::Cipher::AES.new(<keyLength>, '<blockMode>')`
410+ keyLength = getIntArgument ( call , 0 ) .toString ( ) and
411+ blockMode = getStringArgument ( call , 1 ) .toUpperCase ( )
412+ |
413+ cipherName = "AES-" + keyLength + "-" + blockMode and
414+ cipherMode .isBlockMode ( blockMode )
415+ )
416+ or
417+ // Modules for AES with specific key lengths
418+ exists ( string mod , string blockAlgo | mod = [ "AES128" , "AES192" , "AES256" ] |
419+ call = cipherApi ( ) .getMember ( mod ) .getAnInstantiation ( ) and
420+ // Canonical representation is `AES-<keyLength>`
421+ blockAlgo = "AES-" + mod .suffix ( 3 ) and
422+ exists ( string blockMode |
423+ if exists ( getStringArgument ( call , 0 ) )
424+ then
425+ // `OpenSSL::Cipher::<blockAlgo>.new('<blockMode>')`
426+ blockMode = getStringArgument ( call , 0 ) .toUpperCase ( )
427+ else
428+ // `OpenSSL::Cipher::<blockAlgo>.new` uses CBC by default
429+ blockMode = "CBC"
401430 |
402- cipherName = "AES-" + keyLength + "-" + blockMode and
431+ cipherName = blockAlgo + "-" + blockMode and
403432 cipherMode .isBlockMode ( blockMode )
404433 )
405- or
406- // RC4 stream cipher
407- this = cipherApi ( ) .getMember ( "RC4" ) .getAnInstantiation ( ) and
408- cipherMode = TStreamCipher ( ) and
409- (
410- if exists ( this .getStringArgument ( 0 ) )
411- then cipherName = "RC4-" + this .getStringArgument ( 0 ) .toUpperCase ( )
412- else cipherName = "RC4"
413- )
414- or
415- // Block ciphers with dedicated modules
416- exists ( string mod , string blockAlgo |
417- mod = [ "AES128" , "AES192" , "AES256" , "BF" , "CAST5" , "DES" , "IDEA" , "RC2" ]
434+ )
435+ )
436+ }
437+
438+ /**
439+ * Holds if `call` is a call that instantiates an OpenSSL cipher using a module
440+ * specific to a block encryption algorithm, e.g. Blowfish, DES, etc.
441+ */
442+ private predicate cipherInstantiationSpecific (
443+ DataFlow:: CallNode call , OpenSSLCipher cipher , CipherMode cipherMode
444+ ) {
445+ exists ( string cipherName | cipher .matchesName ( cipherName ) |
446+ // Block ciphers with dedicated modules
447+ exists ( string blockAlgo | blockAlgo = [ "BF" , "CAST5" , "DES" , "IDEA" , "RC2" ] |
448+ call = cipherApi ( ) .getMember ( blockAlgo ) .getAnInstantiation ( ) and
449+ exists ( string blockMode |
450+ if exists ( getStringArgument ( call , 0 ) )
451+ then
452+ // `OpenSSL::Cipher::<blockAlgo>.new('<blockMode>')`
453+ blockMode = getStringArgument ( call , 0 ) .toUpperCase ( )
454+ else
455+ // `OpenSSL::Cipher::<blockAlgo>.new` uses CBC by default
456+ blockMode = "CBC"
418457 |
419- this = cipherApi ( ) .getMember ( mod ) .getAnInstantiation ( ) and
420- (
421- // The `AES<keyLength>` modules are a special case in terms of naming
422- if mod = [ "AES128" , "AES192" , "AES256" ]
423- then blockAlgo = "AES-" + mod .suffix ( 3 )
424- else blockAlgo = mod
425- ) and
426- exists ( string blockMode |
427- if exists ( this .getStringArgument ( 0 ) )
428- then
429- // `OpenSSL::Cipher::<blockAlgo>.new('<blockMode>')`
430- blockMode = this .getStringArgument ( 0 ) .toUpperCase ( )
431- else
432- // `OpenSSL::Cipher::<blockAlgo>.new` uses CBC by default
433- blockMode = "CBC"
434- |
435- cipherName = blockAlgo + "-" + blockMode and
436- cipherMode .isBlockMode ( blockMode )
437- )
458+ cipherName = blockAlgo + "-" + blockMode and
459+ cipherMode .isBlockMode ( blockMode )
438460 )
439461 )
462+ )
463+ }
464+
465+ /**
466+ * Holds if `call` is a call to `OpenSSL::Cipher::RC4.new` or an RC4 `cipher`
467+ * instance with mode `cipherMode`.
468+ */
469+ private predicate cipherInstantiationRC4 (
470+ DataFlow:: CallNode call , OpenSSLCipher cipher , CipherMode cipherMode
471+ ) {
472+ exists ( string cipherName | cipher .matchesName ( cipherName ) |
473+ // RC4 stream cipher
474+ call = cipherApi ( ) .getMember ( "RC4" ) .getAnInstantiation ( ) and
475+ cipherMode = TStreamCipher ( ) and
476+ (
477+ if exists ( getStringArgument ( call , 0 ) )
478+ then cipherName = "RC4-" + getStringArgument ( call , 0 ) .toUpperCase ( )
479+ else cipherName = "RC4"
480+ )
481+ )
482+ }
483+
484+ /** A call to `OpenSSL::Cipher.new` or similar. */
485+ private class CipherInstantiation extends DataFlow:: CallNode {
486+ private OpenSSLCipher cipher ;
487+ private CipherMode cipherMode ;
488+
489+ CipherInstantiation ( ) {
490+ cipherInstantiationGeneric ( this , cipher , cipherMode ) or
491+ cipherInstantiationAES ( this , cipher , cipherMode ) or
492+ cipherInstantiationSpecific ( this , cipher , cipherMode ) or
493+ cipherInstantiationRC4 ( this , cipher , cipherMode )
440494 }
441495
442496 /** Gets the `OpenSSLCipher` associated with this instance. */
0 commit comments