Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[java] New security rule for finding hard-coded keys used for cryptographic operations #1046

Merged
merged 6 commits into from May 21, 2018

Conversation

sgorbaty
Copy link
Contributor

This change is to identify and report hard-coded keys used in HMAC and encryption/decryption operations.

@sgorbaty
Copy link
Contributor Author

@jsotuyod heads up, one more rule.

@adangel adangel added this to the 6.4.0 milestone Apr 28, 2018
@adangel adangel added the a:new-rule Proposal to add a new built-in rule label Apr 28, 2018
@sgorbaty
Copy link
Contributor Author

sgorbaty commented May 1, 2018

Hey @adangel @jsotuyod,

Just wondered when would be the next PMD release and if this PR would make it.
Thanks in advance!

Sergey

@jsotuyod
Copy link
Member

jsotuyod commented May 1, 2018

@sgorbaty the next release (PMD 6.4.0) is scheduled for May 27th. You can check all our next-release schedules (roughly once a month) on https://github.com/pmd/pmd/milestones

This PR will definitely be part of 6.4.0, Andreas already scheduled it.

Copy link
Member

@jsotuyod jsotuyod left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay, but I think I've some good feedback. We are still on plan to make it to the next release (6.4.0)


private <T> void extractPrimitiveTypesInner(Set<T> retVal, T field, List<ASTPrimitiveType> types) {
for (ASTPrimitiveType type : types) {
if (type.hasImageEqualTo("byte") || type.hasImageEqualTo("String")) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a primitive type can never be a string

ASTPrimaryPrefix prefix = init.getFirstChildOfType(ASTPrimaryPrefix.class);
if (prefix != null) {
ASTLiteral literal = prefix.getFirstChildOfType(ASTLiteral.class);
if (literal != null) {
Copy link
Member

@jsotuyod jsotuyod May 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this check seems too relaxed... maybe also check if literal.isStringLiteral()?

List<ASTAllocationExpression> allocations = node.findDescendantsOfType(ASTAllocationExpression.class);
for (ASTAllocationExpression allocation : allocations) {

ASTClassOrInterfaceType declClassName = allocation.getFirstDescendantOfType(ASTClassOrInterfaceType.class);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rather than ask the rulechain to visit all ASTClassOrInterfaceBodyDeclaration and then manually look for ASTAllocationExpression, you could ask the rulechain to visit ASTAllocationExpression for you and move this hole block to visit(ASTAllocationExpression node, Object data), which will probably be cleaner / easier to read

// intentionally
}

public static Set<String> findVariablesPassedToAnyParam(ASTClassOrInterfaceBodyDeclaration node,
Copy link
Member

@jsotuyod jsotuyod May 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this utility class a little troubling for a number of reasons

  1. The name Util is overly generic
  2. The name is misleading findVariablesPassedToAnyParam actually finds any variables passed to a constructor of the given type that's allocated anywhere within this node. I for one didn't expect that from the call in HardCodedCryptoKeyRule until I read this...
  3. I'm unsure this is common enough to require a utility or even considering moving it somewhere else (the AST?)

}

for (ASTLocalVariableDeclaration foundLocalVar : foundLocalVars) {
if (passedInIvVarNames.contains(foundLocalVar.getVariableName())) {
Copy link
Member

@jsotuyod jsotuyod May 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ASTLocalVariableDeclaration.getVariableName() returns the name of the first variable declarator id, but there may be more in the case of byte var1, var2, var3; and even the types may be slightly different thanks to arrays (ie: byte var1, var2[], var3[][];).

The Javadoc for getVariableName says this, but I fail to find a use-case where only the first one is going to be needed... I think ASTLocalVariableDeclaration should implement Iterable<ASTVariableDeclarator> and we should just use those...

Class<?> classToFind) {
Set<String> passedInIvVarNames = new HashSet<>();

// find new javax.crypto.spec.SecretKeySpec(...)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

left over from copy-paste?


public static Set<String> findVariablesPassedToAnyParam(ASTClassOrInterfaceBodyDeclaration node,
Class<?> classToFind) {
Set<String> passedInIvVarNames = new HashSet<>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the name remains too attached to a single case to be a generic utility

validateProperKey(data, var.getFirstDescendantOfType(ASTVariableInitializer.class));
}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these 3 for loops are somewhat redundant and fail to deal with nested scopes properly (specially in the presence of lambdas and nested classes).

I'd just keep this second loop, but making sure to also iterate over the parent scopes.

If reworking this to start directly from the allocation instead of ASTClassOrInterfaceBodyDeclaration you automatically start from the inner-most scope and can easily work your way up

@jsotuyod jsotuyod added the is:WIP For PRs that are not fully ready, or issues that are actively being tackled label May 12, 2018
@adangel adangel self-assigned this May 19, 2018
@adangel adangel changed the title [Java][Security] Finding hard-coded keys used for cryptographic operations. [java] New security rule for finding hard-coded keys used for cryptographic operations May 21, 2018
@adangel adangel removed the is:WIP For PRs that are not fully ready, or issues that are actively being tackled label May 21, 2018
@adangel adangel merged commit 98fe1d3 into pmd:master May 21, 2018
adangel added a commit that referenced this pull request May 21, 2018
@jsotuyod
Copy link
Member

Thanks @adangel for performing the changes. The code is way more succinct now, should be easier to maintain.

@sgorbaty thanks again for the contribution, as anticipated this will be part of 6.4.0 to be released next Sunday.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a:new-rule Proposal to add a new built-in rule
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants