Rework InsecureCryptoIvRule to use RuleChain on AllocationExpression

No need for Util. Use Symbol Table instead.
This commit is contained in:
Andreas Dangel
2018-05-21 12:46:29 +02:00
parent e9f6668c9b
commit f14fbd02b5
2 changed files with 42 additions and 117 deletions

View File

@ -4,22 +4,19 @@
package net.sourceforge.pmd.lang.java.rule.security;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;
import net.sourceforge.pmd.lang.java.ast.ASTArgumentList;
import net.sourceforge.pmd.lang.java.ast.ASTArguments;
import net.sourceforge.pmd.lang.java.ast.ASTArrayInitializer;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
import net.sourceforge.pmd.lang.java.ast.ASTLiteral;
import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType;
import net.sourceforge.pmd.lang.java.ast.ASTReferenceType;
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;
import net.sourceforge.pmd.lang.java.ast.ASTName;
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
import net.sourceforge.pmd.lang.java.ast.ASTVariableInitializer;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration;
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper;
/**
* Finds hardcoded static Initialization Vectors vectors used with cryptographic
@ -38,73 +35,56 @@ import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
public class InsecureCryptoIvRule extends AbstractJavaRule {
public InsecureCryptoIvRule() {
addRuleChainVisit(ASTClassOrInterfaceBodyDeclaration.class);
addRuleChainVisit(ASTAllocationExpression.class);
}
@Override
public Object visit(ASTClassOrInterfaceBodyDeclaration node, Object data) {
Set<ASTLocalVariableDeclaration> foundLocalVars = new HashSet<>();
// find new javax.crypto.spec.IvParameterSpec(...)
Set<String> passedInIvVarNames = Util.findVariablesPassedToAnyParam(node, javax.crypto.spec.IvParameterSpec.class);
public Object visit(ASTAllocationExpression node, Object data) {
ASTClassOrInterfaceType declClassName = node.getFirstChildOfType(ASTClassOrInterfaceType.class);
if (declClassName != null && TypeHelper.isA(declClassName, javax.crypto.spec.IvParameterSpec.class)) {
Node firstArgument = null;
List<ASTLocalVariableDeclaration> localVars = node.findDescendantsOfType(ASTLocalVariableDeclaration.class);
for (ASTLocalVariableDeclaration localVar : localVars) {
foundLocalVars.addAll(extractPrimitiveTypes(localVar));
ASTArguments arguments = node.getFirstChildOfType(ASTArguments.class);
if (arguments.getArgumentCount() > 0) {
firstArgument = arguments.getFirstChildOfType(ASTArgumentList.class).jjtGetChild(0);
}
if (firstArgument != null) {
ASTPrimaryPrefix prefix = firstArgument.getFirstDescendantOfType(ASTPrimaryPrefix.class);
validateProperIv(data, prefix);
}
}
return super.visit(node, data);
}
private void validateProperIv(Object data, ASTPrimaryPrefix firstArgumentExpression) {
if (firstArgumentExpression == null) {
return;
}
Map<VariableNameDeclaration, List<NameOccurrence>> globalDecls = node.getScope()
.getDeclarations(VariableNameDeclaration.class);
for (VariableNameDeclaration fieldVar : globalDecls.keySet()) {
if (passedInIvVarNames.contains(fieldVar.getNode().getImage())) {
ASTVariableDeclarator var = fieldVar.getNode().getFirstParentOfType(ASTVariableDeclarator.class);
if (var != null) {
validateProperIv(data, var.getFirstDescendantOfType(ASTVariableInitializer.class));
// named variable
ASTName namedVar = firstArgumentExpression.getFirstDescendantOfType(ASTName.class);
if (namedVar != null) {
// find where it's declared, if possible
if (namedVar != null && namedVar.getNameDeclaration() instanceof VariableNameDeclaration) {
VariableNameDeclaration varDecl = (VariableNameDeclaration) namedVar.getNameDeclaration();
ASTVariableInitializer initializer = varDecl.getAccessNodeParent().getFirstDescendantOfType(ASTVariableInitializer.class);
if (initializer != null) {
validateProperIv(data, initializer.getFirstDescendantOfType(ASTPrimaryPrefix.class));
}
}
}
for (ASTLocalVariableDeclaration foundLocalVar : foundLocalVars) {
if (passedInIvVarNames.contains(foundLocalVar.getVariableName())) {
validateProperIv(data, foundLocalVar.getFirstDescendantOfType(ASTVariableInitializer.class));
}
}
return data;
}
private Set<ASTLocalVariableDeclaration> extractPrimitiveTypes(ASTLocalVariableDeclaration localVar) {
List<ASTPrimitiveType> types = localVar.findDescendantsOfType(ASTPrimitiveType.class);
Set<ASTLocalVariableDeclaration> retVal = new HashSet<>();
extractPrimitiveTypesInner(retVal, localVar, types);
return retVal;
}
private <T> void extractPrimitiveTypesInner(Set<T> retVal, T field, List<ASTPrimitiveType> types) {
for (ASTPrimitiveType type : types) {
if (type.hasImageEqualTo("byte")) {
ASTReferenceType parent = type.getFirstParentOfType(ASTReferenceType.class);
if (parent != null) {
retVal.add(field);
}
}
}
}
private void validateProperIv(Object data, ASTVariableInitializer varInit) {
// hard coded array
ASTArrayInitializer arrayInit = varInit.getFirstDescendantOfType(ASTArrayInitializer.class);
ASTArrayInitializer arrayInit = firstArgumentExpression.getFirstDescendantOfType(ASTArrayInitializer.class);
if (arrayInit != null) {
addViolation(data, varInit);
addViolation(data, firstArgumentExpression);
}
// string literal
ASTLiteral literal = varInit.getFirstDescendantOfType(ASTLiteral.class);
ASTLiteral literal = firstArgumentExpression.getFirstDescendantOfType(ASTLiteral.class);
if (literal != null && literal.isStringLiteral()) {
addViolation(data, varInit);
addViolation(data, firstArgumentExpression);
}
}
}

View File

@ -1,55 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.rule.security;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
import net.sourceforge.pmd.lang.java.ast.ASTName;
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
/**
* @author sergeygorbaty
*
*/
public final class Util {
private Util() {
// intentionally
}
public static Set<String> findVariablesPassedToAnyParam(ASTClassOrInterfaceBodyDeclaration node,
Class<?> classToFind) {
Set<String> passedInIvVarNames = new HashSet<>();
// find new javax.crypto.spec.SecretKeySpec(...)
List<ASTAllocationExpression> allocations = node.findDescendantsOfType(ASTAllocationExpression.class);
for (ASTAllocationExpression allocation : allocations) {
ASTClassOrInterfaceType declClassName = allocation.getFirstDescendantOfType(ASTClassOrInterfaceType.class);
if (declClassName != null) {
Class<?> foundClass = declClassName.getType();
if (foundClass != null && classToFind.isAssignableFrom(foundClass)) {
ASTPrimaryExpression init = allocation.getFirstDescendantOfType(ASTPrimaryExpression.class);
if (init != null) {
ASTName name = init.getFirstDescendantOfType(ASTName.class);
if (name != null) {
if (name.getNameDeclaration() != null) {
passedInIvVarNames.add(name.getNameDeclaration().getName());
}
}
}
}
}
}
return passedInIvVarNames;
}
}