Skip to content

Commit f05d60f

Browse files
SONARJAVA-4895: Add visitor for finding methods that securely produce IV byte arrays
1 parent 2b8782e commit f05d60f

File tree

1 file changed

+77
-0
lines changed

1 file changed

+77
-0
lines changed

java-checks/src/main/java/org/sonar/java/checks/security/CipherBlockChainingCheck.java

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
*/
1717
package org.sonar.java.checks.security;
1818

19+
import java.util.HashSet;
1920
import java.util.Objects;
21+
import java.util.Set;
2022
import java.util.stream.Stream;
2123
import javax.annotation.Nullable;
2224
import org.sonar.check.Rule;
@@ -30,7 +32,9 @@
3032
import org.sonar.plugins.java.api.tree.IdentifierTree;
3133
import org.sonar.plugins.java.api.tree.MemberSelectExpressionTree;
3234
import org.sonar.plugins.java.api.tree.MethodInvocationTree;
35+
import org.sonar.plugins.java.api.tree.MethodTree;
3336
import org.sonar.plugins.java.api.tree.NewClassTree;
37+
import org.sonar.plugins.java.api.tree.ReturnStatementTree;
3438
import org.sonar.plugins.java.api.tree.Tree;
3539
import org.sonar.plugins.java.api.tree.VariableTree;
3640

@@ -244,4 +248,77 @@ private static Stream<MethodInvocationTree> findConstructingMethods(ExpressionTr
244248
return Stream.concat(initializerStream, reassignments);
245249
}
246250
}
251+
252+
/**
253+
* Collects all methods that construct IV byte arrays in a secure way.
254+
* After applying this visitor to a class tree, {@link SecureByteArrayFactoryFinder#producesSecureBytesArray(MethodInvocationTree)} can
255+
* be used to check whether the invocation of a method belonging to that tree will return such a secure array.
256+
*/
257+
private static class SecureByteArrayFactoryFinder extends BaseTreeVisitor {
258+
private @Nullable MethodTree currentMethodTree = null;
259+
private final Set<String> secureByteArrayFactories = new HashSet<>();
260+
private final SecureByteArrayGeneratorDetector secureByteArrayGeneratorDetector = new SecureByteArrayGeneratorDetector();
261+
262+
public boolean producesSecureBytesArray(MethodInvocationTree methodInvocation) {
263+
return secureByteArrayFactories.contains(methodInvocation.methodSymbol().signature());
264+
}
265+
266+
public void clear() {
267+
secureByteArrayFactories.clear();
268+
}
269+
270+
@Override
271+
public void visitMethod(MethodTree tree) {
272+
// There is no need to explore methods that do not even produce IV byte arrays
273+
if (doesNotReturnByteArray(tree)
274+
// We do not track nested methods
275+
|| currentMethodTree != null) {
276+
return;
277+
}
278+
279+
currentMethodTree = tree;
280+
super.visitMethod(tree);
281+
currentMethodTree = null;
282+
}
283+
284+
@Override
285+
public void visitReturnStatement(ReturnStatementTree tree) {
286+
super.visitReturnStatement(tree);
287+
if (currentMethodTree == null) {
288+
return;
289+
}
290+
291+
var returnedExpression = tree.expression();
292+
if (returnedExpression == null) {
293+
return;
294+
}
295+
296+
if (secureByteArrayGeneratorDetector.isDynamicallyGenerated(returnedExpression)) {
297+
markAsSecureFactory();
298+
return;
299+
}
300+
301+
var isSecureBytesArray = SecureInitializationFinder
302+
.forIvBytesExpression(returnedExpression)
303+
.appliesSecureInitialization(currentMethodTree);
304+
305+
if (isSecureBytesArray) {
306+
markAsSecureFactory();
307+
}
308+
}
309+
310+
private void markAsSecureFactory() {
311+
Objects.requireNonNull(currentMethodTree);
312+
secureByteArrayFactories.add(currentMethodTree.symbol().signature());
313+
}
314+
315+
private static boolean doesNotReturnByteArray(MethodTree methodTree) {
316+
var returnType = methodTree.returnType();
317+
if (returnType == null) {
318+
return false;
319+
}
320+
321+
return !"byte[]".equals(returnType.symbolType().fullyQualifiedName());
322+
}
323+
}
247324
}

0 commit comments

Comments
 (0)