16
16
*/
17
17
package org.sonarsource.kotlin.checks
18
18
19
+ import org.jetbrains.kotlin.analysis.api.resolution.KaFunctionCall
20
+ import org.jetbrains.kotlin.analysis.api.resolution.successfulFunctionCallOrNull
19
21
import org.jetbrains.kotlin.psi.KtCallExpression
20
22
import org.jetbrains.kotlin.psi.KtExpression
21
- import org.jetbrains.kotlin.resolve.BindingContext
22
- import org.jetbrains.kotlin.resolve.calls.util.getCall
23
- import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
24
23
import org.sonar.check.Rule
25
24
import org.sonarsource.kotlin.api.checks.CallAbstractCheck
26
25
import org.sonarsource.kotlin.api.checks.ConstructorMatcher
@@ -32,8 +31,8 @@ import org.sonarsource.kotlin.api.checks.STRING_TYPE
32
31
import org.sonarsource.kotlin.api.checks.predictReceiverExpression
33
32
import org.sonarsource.kotlin.api.checks.predictRuntimeStringValue
34
33
import org.sonarsource.kotlin.api.checks.predictRuntimeValueExpression
35
-
36
34
import org.sonarsource.kotlin.api.frontend.KotlinFileContext
35
+ import org.sonarsource.kotlin.api.visiting.withKaSession
37
36
38
37
private val CIPHER_INIT_MATCHER = FunMatcher (qualifier = " javax.crypto.Cipher" , name = " init" ) {
39
38
withArguments(INT_TYPE , " java.security.Key" , " java.security.spec.AlgorithmParameterSpec" )
@@ -46,43 +45,48 @@ private val GET_INSTANCE_MATCHER = FunMatcher(qualifier = "javax.crypto.Cipher",
46
45
private val GET_BYTES_MATCHER = FunMatcher (qualifier = " kotlin.text" , name = " toByteArray" )
47
46
private val IV_PARAMETER_SPEC_MATCHER = ConstructorMatcher (" javax.crypto.spec.IvParameterSpec" )
48
47
49
- @org.sonarsource.kotlin.api.frontend.K1only
50
48
@Rule(key = " S3329" )
51
49
class CipherBlockChainingCheck : CallAbstractCheck () {
52
50
override val functionsToVisit = listOf (CIPHER_INIT_MATCHER )
53
51
54
52
override fun visitFunctionCall (
55
53
callExpression : KtCallExpression ,
56
- resolvedCall : ResolvedCall <* >,
54
+ resolvedCall : KaFunctionCall <* >,
55
+ matchedFun : FunMatcherImpl ,
57
56
kotlinFileContext : KotlinFileContext ,
58
57
) {
59
- val bindingContext = kotlinFileContext.bindingContext
60
58
val calleeExpression = callExpression.calleeExpression ? : return
61
- val receiverExpression = callExpression.predictReceiverExpression(bindingContext ) ? : return
59
+ val receiverExpression = callExpression.predictReceiverExpression() ? : return
62
60
val thirdArgument = callExpression.valueArguments[2 ].getArgumentExpression() ? : return
63
61
64
- if (receiverExpression.isCBC(bindingContext ) && thirdArgument.isInitializedWithToByteArray(bindingContext )) {
62
+ if (receiverExpression.isCBC() && thirdArgument.isInitializedWithToByteArray()) {
65
63
kotlinFileContext.reportIssue(calleeExpression, " Use a dynamically-generated, random IV." )
66
64
}
67
65
}
68
66
}
69
67
70
- private fun KtExpression.isInitializedWithToByteArray (bindingContext : BindingContext ) =
71
- firstArgumentOfInitializer(bindingContext, IV_PARAMETER_SPEC_MATCHER )
72
- ?.predictRuntimeValueExpression(bindingContext)
73
- ?.getCall(bindingContext)?.let { expr ->
74
- GET_BYTES_MATCHER .matches(expr, bindingContext)
68
+ private fun KtExpression.isInitializedWithToByteArray () = withKaSession {
69
+ firstArgumentOfInitializer(IV_PARAMETER_SPEC_MATCHER )
70
+ ?.predictRuntimeValueExpression()
71
+ ?.resolveToCall()
72
+ ?.successfulFunctionCallOrNull()
73
+ ?.let { expr ->
74
+ GET_BYTES_MATCHER .matches(expr)
75
75
} ? : false
76
+ }
76
77
77
- private fun KtExpression.isCBC (bindingContext : BindingContext ) =
78
- firstArgumentOfInitializer(bindingContext, GET_INSTANCE_MATCHER )
79
- ?.predictRuntimeStringValue(bindingContext )
78
+ private fun KtExpression.isCBC () =
79
+ firstArgumentOfInitializer(GET_INSTANCE_MATCHER )
80
+ ?.predictRuntimeStringValue()
80
81
?.contains(" CBC" , ignoreCase = true )
81
82
? : false
82
83
83
- private fun KtExpression.firstArgumentOfInitializer (bindingContext : BindingContext , matcher : FunMatcherImpl ) =
84
- predictRuntimeValueExpression(bindingContext)
85
- .getCall(bindingContext)?.let {
86
- if (matcher.matches(it, bindingContext)) it.valueArguments[0 ].getArgumentExpression()
87
- else null
84
+ private fun KtExpression.firstArgumentOfInitializer (matcher : FunMatcherImpl ) = withKaSession {
85
+ predictRuntimeValueExpression()
86
+ .resolveToCall()
87
+ ?.successfulFunctionCallOrNull()?.let {
88
+ if (matcher.matches(it)) {
89
+ it.argumentMapping.keys.elementAt(0 )
90
+ } else null
88
91
}
92
+ }
0 commit comments