@@ -363,80 +363,134 @@ private class CipherMode extends TCipherMode {
363
363
predicate isWeak ( ) { isWeakBlockMode ( this .getBlockMode ( ) ) }
364
364
}
365
365
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
+ }
371
369
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 ( )
373
372
}
374
373
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
+ }
379
389
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
+ )
387
408
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"
401
430
|
402
- cipherName = "AES-" + keyLength + "-" + blockMode and
431
+ cipherName = blockAlgo + "-" + blockMode and
403
432
cipherMode .isBlockMode ( blockMode )
404
433
)
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"
418
457
|
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 )
438
460
)
439
461
)
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 )
440
494
}
441
495
442
496
/** Gets the `OpenSSLCipher` associated with this instance. */
0 commit comments