1
1
import java
2
2
import semmle.code.java.dataflow.DataFlow
3
+ import semmle.code.java.dataflow.TaintTracking
3
4
import semmle.code.java.controlflow.Dominance
4
5
5
6
module JCAModel {
@@ -43,6 +44,22 @@ module JCAModel {
43
44
.toUpperCase ( ) )
44
45
}
45
46
47
+ bindingset [ kdf]
48
+ predicate kdf_names ( string kdf ) {
49
+ kdf .toUpperCase ( ) .matches ( [ "PBKDF2With%" , "PBEWith%" ] .toUpperCase ( ) )
50
+ }
51
+
52
+ bindingset [ name]
53
+ Crypto:: TKeyDerivationType kdf_name_to_kdf_type ( string name , string withSubstring ) {
54
+ name .matches ( "PBKDF2With%" ) and
55
+ result instanceof Crypto:: PBKDF2 and
56
+ withSubstring = name .regexpCapture ( "PBKDF2With(.*)" , 1 )
57
+ or
58
+ name .matches ( "PBEWith%" ) and
59
+ result instanceof Crypto:: PBES and
60
+ withSubstring = name .regexpCapture ( "PBEWith(.*)" , 1 )
61
+ }
62
+
46
63
bindingset [ name]
47
64
Crypto:: THashType hash_name_to_hash_type ( string name , int digestLength ) {
48
65
name = "SHA-1" and result instanceof Crypto:: SHA1 and digestLength = 160
@@ -132,7 +149,7 @@ module JCAModel {
132
149
}
133
150
}
134
151
135
- module AlgorithmStringToFetchFlow = DataFlow :: Global< AlgorithmStringToFetchConfig > ;
152
+ module AlgorithmStringToFetchFlow = TaintTracking :: Global< AlgorithmStringToFetchConfig > ;
136
153
137
154
/**
138
155
* Note: padding and a mode of operation will only exist when the padding / mode (*and its type*) are determinable.
@@ -303,7 +320,7 @@ module JCAModel {
303
320
304
321
CipherGetInstanceAlgorithmArg ( ) { this = call .getAlgorithmArg ( ) }
305
322
306
- override DataFlow :: Node getInputNode ( ) { result .asExpr ( ) = this }
323
+ override Crypto :: ConsumerInputDataFlowNode getInputNode ( ) { result .asExpr ( ) = this }
307
324
308
325
CipherStringLiteral getOrigin ( string value ) {
309
326
AlgorithmStringToFetchFlow:: flow ( DataFlow:: exprNode ( result ) ,
@@ -447,13 +464,15 @@ module JCAModel {
447
464
448
465
override Crypto:: CipherOperationSubtype getCipherOperationSubtype ( ) { result = mode }
449
466
450
- override DataFlow :: Node getNonceConsumer ( ) {
467
+ override Crypto :: ConsumerInputDataFlowNode getNonceConsumer ( ) {
451
468
result .asExpr ( ) = sink .getState ( ) .( InitializedCipherModeFlowState ) .getInitCall ( ) .getNonceArg ( )
452
469
}
453
470
454
- override DataFlow:: Node getInputConsumer ( ) { result = doFinalize .getMessageArg ( ) }
471
+ override Crypto:: ConsumerInputDataFlowNode getInputConsumer ( ) {
472
+ result = doFinalize .getMessageArg ( )
473
+ }
455
474
456
- override DataFlow :: Node getKeyConsumer ( ) {
475
+ override Crypto :: ConsumerInputDataFlowNode getKeyConsumer ( ) {
457
476
result .asExpr ( ) = sink .getState ( ) .( InitializedCipherModeFlowState ) .getInitCall ( ) .getKeyArg ( )
458
477
}
459
478
@@ -611,7 +630,7 @@ module JCAModel {
611
630
class CipherInitCallKeyConsumer extends Crypto:: ArtifactConsumer {
612
631
CipherInitCallKeyConsumer ( ) { this = any ( CipherInitCall call ) .getKeyArg ( ) }
613
632
614
- override DataFlow :: Node getInputNode ( ) { result .asExpr ( ) = this }
633
+ override Crypto :: ConsumerInputDataFlowNode getInputNode ( ) { result .asExpr ( ) = this }
615
634
}
616
635
617
636
class CipherOperationCallOutput extends Crypto:: CipherOutputArtifactInstance {
@@ -659,7 +678,7 @@ module JCAModel {
659
678
660
679
MessageDigestAlgorithmValueConsumer ( ) { this = call .getAlgorithmArg ( ) }
661
680
662
- override DataFlow :: Node getInputNode ( ) { result .asExpr ( ) = this }
681
+ override Crypto :: ConsumerInputDataFlowNode getInputNode ( ) { result .asExpr ( ) = this }
663
682
664
683
override Crypto:: AlgorithmInstance getAKnownAlgorithmSource ( ) {
665
684
exists ( KnownHashAlgorithm l | l .getConsumer ( ) = this and result = l )
@@ -719,7 +738,7 @@ module JCAModel {
719
738
720
739
KeyGeneratorCallAlgorithmValueConsumer ( ) { this = call .getAlgorithmArg ( ) }
721
740
722
- override DataFlow :: Node getInputNode ( ) { result .asExpr ( ) = this }
741
+ override Crypto :: ConsumerInputDataFlowNode getInputNode ( ) { result .asExpr ( ) = this }
723
742
724
743
override Crypto:: AlgorithmInstance getAKnownAlgorithmSource ( ) {
725
744
result .( CipherStringLiteralAlgorithmInstance ) .getConsumer ( ) = this
@@ -780,6 +799,10 @@ module JCAModel {
780
799
Crypto:: AlgorithmInstance getAKnownAlgorithm ( ) {
781
800
result = this .getAnAlgorithmValueConsumer ( ) .getAKnownAlgorithmSource ( )
782
801
}
802
+
803
+ override Crypto:: ConsumerInputDataFlowNode getKeySizeConsumer ( ) { none ( ) }
804
+
805
+ override string getKeySizeFixed ( ) { none ( ) }
783
806
}
784
807
785
808
/*
@@ -845,7 +868,9 @@ module JCAModel {
845
868
846
869
module MACInitCallToMACOperationFlowConfig implements DataFlow:: ConfigSig {
847
870
// TODO: use flow state with one config
848
- predicate isSource ( DataFlow:: Node src ) { src .asExpr ( ) instanceof MACInitCall }
871
+ predicate isSource ( DataFlow:: Node src ) {
872
+ exists ( MACInitCall init | src .asExpr ( ) = init .getQualifier ( ) )
873
+ }
849
874
850
875
predicate isSink ( DataFlow:: Node sink ) {
851
876
exists ( MACOperationCall call | sink .asExpr ( ) = call .( MethodCall ) .getQualifier ( ) )
@@ -884,7 +909,7 @@ module JCAModel {
884
909
}
885
910
886
911
MACInitCall getInitCall ( ) {
887
- MACInitCallToMACOperationFlow :: flow ( DataFlow:: exprNode ( this ) ,
912
+ MACGetInstanceToMACOperationFlow :: flow ( DataFlow:: exprNode ( this ) ,
888
913
DataFlow:: exprNode ( result .getQualifier ( ) ) )
889
914
}
890
915
}
@@ -897,7 +922,7 @@ module JCAModel {
897
922
}
898
923
899
924
MACOperationCall getOperation ( ) {
900
- MACInitCallToMACOperationFlow:: flow ( DataFlow:: exprNode ( this ) ,
925
+ MACInitCallToMACOperationFlow:: flow ( DataFlow:: exprNode ( this . getQualifier ( ) ) ,
901
926
DataFlow:: exprNode ( result .( MethodCall ) .getQualifier ( ) ) )
902
927
}
903
928
}
@@ -907,7 +932,7 @@ module JCAModel {
907
932
908
933
MACGetInstanceAlgorithmValueConsumer ( ) { this = call .getAlgorithmArg ( ) }
909
934
910
- override DataFlow :: Node getInputNode ( ) { result .asExpr ( ) = this }
935
+ override Crypto :: ConsumerInputDataFlowNode getInputNode ( ) { result .asExpr ( ) = this }
911
936
912
937
override Crypto:: AlgorithmInstance getAKnownAlgorithmSource ( ) {
913
938
exists ( KnownMACAlgorithm l | l .getConsumer ( ) = this and result = l )
@@ -933,7 +958,7 @@ module JCAModel {
933
958
)
934
959
}
935
960
936
- override DataFlow :: Node getKeyConsumer ( ) {
961
+ override Crypto :: ConsumerInputDataFlowNode getKeyConsumer ( ) {
937
962
exists ( MACGetInstanceCall instantiation , MACInitCall initCall |
938
963
instantiation .getOperation ( ) = this and
939
964
initCall .getOperation ( ) = this and
@@ -942,9 +967,195 @@ module JCAModel {
942
967
)
943
968
}
944
969
945
- override DataFlow :: Node getMessageConsumer ( ) {
970
+ override Crypto :: ConsumerInputDataFlowNode getMessageConsumer ( ) {
946
971
result .asExpr ( ) = super .getArgument ( 0 ) and
947
972
super .getMethod ( ) .getParameterType ( 0 ) .hasName ( "byte[]" )
948
973
}
949
974
}
975
+
976
+ module SecretKeyFactoryGetInstanceToGenerateSecretFlowConfig implements DataFlow:: ConfigSig {
977
+ predicate isSource ( DataFlow:: Node src ) {
978
+ exists ( SecretKeyFactoryGetInstanceCall call | src .asExpr ( ) = call )
979
+ }
980
+
981
+ predicate isSink ( DataFlow:: Node sink ) {
982
+ exists ( SecretKeyFactoryGenerateSecretCall call |
983
+ sink .asExpr ( ) = call .( MethodCall ) .getQualifier ( )
984
+ )
985
+ }
986
+ }
987
+
988
+ module PBEKeySpecInstantiationToGenerateSecretFlowConfig implements DataFlow:: ConfigSig {
989
+ predicate isSource ( DataFlow:: Node src ) {
990
+ exists ( PBEKeySpecInstantiation call | src .asExpr ( ) = call )
991
+ }
992
+
993
+ predicate isSink ( DataFlow:: Node sink ) {
994
+ exists ( SecretKeyFactoryGenerateSecretCall call | sink .asExpr ( ) = call .getKeySpecArg ( ) )
995
+ }
996
+ }
997
+
998
+ module KDFAlgorithmStringToGetInstanceConfig implements DataFlow:: ConfigSig {
999
+ predicate isSource ( DataFlow:: Node src ) { kdf_names ( src .asExpr ( ) .( StringLiteral ) .getValue ( ) ) }
1000
+
1001
+ predicate isSink ( DataFlow:: Node sink ) {
1002
+ exists ( SecretKeyFactoryGetInstanceCall call | sink .asExpr ( ) = call .getAlgorithmArg ( ) )
1003
+ }
1004
+ }
1005
+
1006
+ module SecretKeyFactoryGetInstanceToGenerateSecretFlow =
1007
+ DataFlow:: Global< SecretKeyFactoryGetInstanceToGenerateSecretFlowConfig > ;
1008
+
1009
+ module PBEKeySpecInstantiationToGenerateSecretFlow =
1010
+ DataFlow:: Global< PBEKeySpecInstantiationToGenerateSecretFlowConfig > ;
1011
+
1012
+ module KDFAlgorithmStringToGetInstanceFlow =
1013
+ DataFlow:: Global< KDFAlgorithmStringToGetInstanceConfig > ;
1014
+
1015
+ class PBEKeySpecInstantiation extends ClassInstanceExpr {
1016
+ PBEKeySpecInstantiation ( ) {
1017
+ this .getConstructedType ( ) .hasQualifiedName ( "javax.crypto.spec" , "PBEKeySpec" )
1018
+ }
1019
+
1020
+ Expr getPasswordArg ( ) { result = this .getArgument ( 0 ) }
1021
+
1022
+ Expr getSaltArg ( ) { result = this .getArgument ( 1 ) }
1023
+
1024
+ Expr getIterationCountArg ( ) { result = this .getArgument ( 2 ) }
1025
+
1026
+ Expr getKeyLengthArg ( ) { result = this .getArgument ( 3 ) }
1027
+ }
1028
+
1029
+ class SecretKeyFactoryGetInstanceCall extends MethodCall {
1030
+ SecretKeyFactoryGetInstanceCall ( ) {
1031
+ this .getCallee ( ) .hasQualifiedName ( "javax.crypto" , "SecretKeyFactory" , "getInstance" )
1032
+ }
1033
+
1034
+ Expr getAlgorithmArg ( ) { result = this .getArgument ( 0 ) }
1035
+
1036
+ SecretKeyFactoryGenerateSecretCall getOperation ( ) {
1037
+ SecretKeyFactoryGetInstanceToGenerateSecretFlow:: flow ( DataFlow:: exprNode ( this ) ,
1038
+ DataFlow:: exprNode ( result .( MethodCall ) .getQualifier ( ) ) )
1039
+ }
1040
+ }
1041
+
1042
+ class KDFAlgorithmStringLiteral extends Crypto:: KeyDerivationAlgorithmInstance instanceof StringLiteral
1043
+ {
1044
+ SecretKeyFactoryKDFAlgorithmValueConsumer consumer ;
1045
+
1046
+ KDFAlgorithmStringLiteral ( ) {
1047
+ kdf_names ( this .getValue ( ) ) and
1048
+ KDFAlgorithmStringToGetInstanceFlow:: flow ( DataFlow:: exprNode ( this ) , consumer .getInputNode ( ) )
1049
+ }
1050
+
1051
+ override string getRawKDFAlgorithmName ( ) { result = super .getValue ( ) }
1052
+
1053
+ override Crypto:: TKeyDerivationType getKDFType ( ) {
1054
+ result = kdf_name_to_kdf_type ( super .getValue ( ) , _)
1055
+ }
1056
+
1057
+ SecretKeyFactoryKDFAlgorithmValueConsumer getConsumer ( ) { result = consumer }
1058
+ }
1059
+
1060
+ class PBKDF2AlgorithmStringLiteral extends KDFAlgorithmStringLiteral ,
1061
+ Crypto:: PBKDF2AlgorithmInstance , Crypto:: HMACAlgorithmInstance , Crypto:: HashAlgorithmInstance ,
1062
+ Crypto:: AlgorithmValueConsumer
1063
+ {
1064
+ PBKDF2AlgorithmStringLiteral ( ) { super .getKDFType ( ) instanceof Crypto:: PBKDF2 }
1065
+
1066
+ override Crypto:: ConsumerInputDataFlowNode getInputNode ( ) { none ( ) }
1067
+
1068
+ override Crypto:: AlgorithmInstance getAKnownAlgorithmSource ( ) { result = this }
1069
+
1070
+ override Crypto:: THashType getHashFamily ( ) {
1071
+ result = hash_name_to_hash_type ( this .getRawHashAlgorithmName ( ) , _)
1072
+ }
1073
+
1074
+ override int getDigestLength ( ) {
1075
+ exists ( hash_name_to_hash_type ( this .getRawHashAlgorithmName ( ) , result ) )
1076
+ }
1077
+
1078
+ override string getRawMACAlgorithmName ( ) {
1079
+ result = super .getRawKDFAlgorithmName ( ) .splitAt ( "PBKDF2With" , 1 )
1080
+ }
1081
+
1082
+ override string getRawHashAlgorithmName ( ) {
1083
+ result = super .getRawKDFAlgorithmName ( ) .splitAt ( "WithHmac" , 1 )
1084
+ }
1085
+
1086
+ override Crypto:: TMACType getMACType ( ) { result instanceof Crypto:: THMAC }
1087
+
1088
+ override Crypto:: AlgorithmValueConsumer getHMACAlgorithmValueConsumer ( ) { result = this }
1089
+
1090
+ override Crypto:: AlgorithmValueConsumer getHashAlgorithmValueConsumer ( ) { result = this }
1091
+ }
1092
+
1093
+ class SecretKeyFactoryKDFAlgorithmValueConsumer extends Crypto:: AlgorithmValueConsumer instanceof Expr
1094
+ {
1095
+ SecretKeyFactoryGetInstanceCall call ;
1096
+
1097
+ SecretKeyFactoryKDFAlgorithmValueConsumer ( ) { this = call .getAlgorithmArg ( ) }
1098
+
1099
+ override Crypto:: ConsumerInputDataFlowNode getInputNode ( ) { result .asExpr ( ) = this }
1100
+
1101
+ override Crypto:: AlgorithmInstance getAKnownAlgorithmSource ( ) {
1102
+ exists ( KDFAlgorithmStringLiteral l | l .getConsumer ( ) = this and result = l )
1103
+ }
1104
+
1105
+ SecretKeyFactoryGetInstanceCall getInstantiation ( ) { result = call }
1106
+ }
1107
+
1108
+ class SecretKeyFactoryGenerateSecretCall extends Crypto:: KeyDerivationOperationInstance instanceof MethodCall
1109
+ {
1110
+ SecretKeyFactoryGenerateSecretCall ( ) {
1111
+ super .getCallee ( ) .hasQualifiedName ( "javax.crypto" , "SecretKeyFactory" , "generateSecret" )
1112
+ }
1113
+
1114
+ Expr getKeySpecArg ( ) {
1115
+ result = super .getArgument ( 0 ) and
1116
+ super .getMethod ( ) .getParameterType ( 0 ) .hasName ( "KeySpec" )
1117
+ }
1118
+
1119
+ PBEKeySpecInstantiation getInstantiation ( ) {
1120
+ PBEKeySpecInstantiationToGenerateSecretFlow:: flow ( DataFlow:: exprNode ( result ) ,
1121
+ DataFlow:: exprNode ( this .getKeySpecArg ( ) ) )
1122
+ }
1123
+
1124
+ override Crypto:: AlgorithmValueConsumer getAnAlgorithmValueConsumer ( ) {
1125
+ exists ( SecretKeyFactoryGetInstanceCall instantiation |
1126
+ instantiation .getOperation ( ) = this and result = instantiation .getAlgorithmArg ( )
1127
+ )
1128
+ }
1129
+
1130
+ override Crypto:: ConsumerInputDataFlowNode getSaltConsumer ( ) {
1131
+ result .asExpr ( ) = this .getInstantiation ( ) .getSaltArg ( )
1132
+ }
1133
+
1134
+ override Crypto:: ConsumerInputDataFlowNode getInputConsumer ( ) {
1135
+ result .asExpr ( ) = this .getInstantiation ( ) .getPasswordArg ( )
1136
+ }
1137
+
1138
+ override Crypto:: ConsumerInputDataFlowNode getIterationCountConsumer ( ) {
1139
+ result .asExpr ( ) = this .getInstantiation ( ) .getIterationCountArg ( )
1140
+ }
1141
+
1142
+ override DataFlow:: Node getOutputKeyArtifact ( ) {
1143
+ result .asExpr ( ) = this and
1144
+ super .getMethod ( ) .getReturnType ( ) .hasName ( "SecretKey" )
1145
+ }
1146
+
1147
+ override Crypto:: ConsumerInputDataFlowNode getOutputKeySizeConsumer ( ) {
1148
+ result .asExpr ( ) = this .getInstantiation ( ) .getKeyLengthArg ( )
1149
+ }
1150
+
1151
+ override Crypto:: ConsumerInputDataFlowNode getKeySizeConsumer ( ) {
1152
+ result .asExpr ( ) = this .getInstantiation ( ) .getKeyLengthArg ( )
1153
+ }
1154
+
1155
+ override string getKeySizeFixed ( ) { none ( ) }
1156
+
1157
+ override string getOutputKeySizeFixed ( ) { none ( ) }
1158
+
1159
+ override string getIterationCountFixed ( ) { none ( ) }
1160
+ }
950
1161
}
0 commit comments