Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,15 @@ public void key_variable_compliant() throws NoSuchAlgorithmException {
}
}

class CryptographicKeySizeCheckECInt {
public void key_variable() throws NoSuchAlgorithmException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
keyGen.initialize(192); // Noncompliant {{Use a key length of at least 224 bits for EC cipher algorithm.}}
// ^^^^^^^^^^^^^^^^^^^^^^
keyGen.initialize(224); // Compliant
}
}

class CryptographicKeySizeCheckEC {
public void key_EC() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException {
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("EC");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package checks.security;

import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.KeyGenerator;

class CryptographicKeySizeCheckCustom {
public void rsa() throws NoSuchAlgorithmException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048); // Noncompliant {{Use a key length of at least 4096 bits for RSA cipher algorithm.}}
keyGen.initialize(4096); // Compliant
}

public void aes() throws NoSuchAlgorithmException {
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(64); // Compliant - threshold lowered to 64
keyGen.init(128); // Compliant
}

public void dh() throws NoSuchAlgorithmException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH");
keyGen.initialize(1024); // Noncompliant {{Use a key length of at least 2048 bits for DH cipher algorithm.}}
keyGen.initialize(2048); // Compliant
}

public void diffieHellman() throws NoSuchAlgorithmException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DiffieHellman");
keyGen.initialize(1024); // Noncompliant {{Use a key length of at least 2048 bits for DiffieHellman cipher algorithm.}}
keyGen.initialize(2048); // Compliant
}

public void dsa() throws NoSuchAlgorithmException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
keyGen.initialize(1024, new SecureRandom()); // Noncompliant {{Use a key length of at least 2048 bits for DSA cipher algorithm.}}
keyGen.initialize(2048, new SecureRandom()); // Compliant
}

public void ec() throws NoSuchAlgorithmException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
keyGen.initialize(192); // Noncompliant {{Use a key length of at least 224 bits for EC cipher algorithm.}}
keyGen.initialize(224); // Compliant
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,10 @@
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
import org.sonar.check.Rule;
import org.sonar.check.RuleProperty;
import org.sonar.java.checks.helpers.ExpressionsHelper;
import org.sonarsource.analyzer.commons.collections.MapBuilder;
import org.sonar.java.checks.methods.AbstractMethodDetection;
import org.sonar.java.model.ExpressionUtils;
import org.sonar.java.model.LiteralUtils;
Expand All @@ -34,6 +32,7 @@
import org.sonar.plugins.java.api.tree.MethodInvocationTree;
import org.sonar.plugins.java.api.tree.MethodTree;
import org.sonar.plugins.java.api.tree.NewClassTree;
import org.sonarsource.analyzer.commons.appsec.CryptographicKeySizeConfiguration;

import static org.sonar.java.model.ExpressionUtils.getAssignedSymbol;
import static org.sonar.java.model.ExpressionUtils.isInvocationOnVariable;
Expand All @@ -47,16 +46,21 @@ public class CryptographicKeySizeCheck extends AbstractMethodDetection {
private static final String GET_INSTANCE_METHOD = "getInstance";
private static final String STRING = "java.lang.String";

private static final int EC_MIN_KEY = 224;
private static final Pattern EC_KEY_PATTERN = Pattern.compile("^(secp|prime|sect|c2tnb)(\\d+)");
@RuleProperty(
key = "minimumKeySizes",
description = "Comma-separated list of algorithm:minKeySize pairs (e.g. \"RSA:4096,AES:256\"). " +
"Patches the default minimum key sizes — only the listed algorithms are overridden; others keep their defaults.",
defaultValue = CryptographicKeySizeConfiguration.DEFAULT_KEY_SIZES)
public String minimumKeySizes = CryptographicKeySizeConfiguration.DEFAULT_KEY_SIZES;
Comment thread
asya-vorobeva marked this conversation as resolved.

private static final Map<String, Integer> ALGORITHM_KEY_SIZE_MAP = MapBuilder.<String, Integer>newMap()
.put("RSA", 2048)
.put("DH", 2048)
.put("DIFFIEHELLMAN", 2048)
.put("DSA", 2048)
.put("AES", 128)
.build();
private Map<String, Integer> effectiveKeySizeMap;

private Map<String, Integer> getEffectiveKeySizeMap() {
if (effectiveKeySizeMap == null) {
effectiveKeySizeMap = CryptographicKeySizeConfiguration.effectiveKeySizes(minimumKeySizes);
}
return effectiveKeySizeMap;
}
Comment thread
gitar-bot[bot] marked this conversation as resolved.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Checked CryptographicKeySizeConfiguration.parseKeySizes in analyzer-commons — you're right. Malformed pairs like RSA:abc or RSA=4096 are caught internally (NumberFormatException is swallowed, and entries that don't split into exactly 2 parts are just skipped), so nothing ever throws out of the visitor. The "throws per file" part of the finding doesn't hold. The remaining point — invalid entries are silently dropped with no diagnostic — is a deliberate design choice in analyzer-commons rather than a bug here, so no code change needed on this point.


private static final MethodMatchers KEY_GEN = MethodMatchers.or(
MethodMatchers.create()
Expand All @@ -69,7 +73,7 @@ public class CryptographicKeySizeCheck extends AbstractMethodDetection {
.names("initialize")
.addParametersMatcher("int")
.addParametersMatcher("int", "java.security.SecureRandom")
.build()) ;
.build());

@Override
protected MethodMatchers getMethodInvocationMatchers() {
Expand Down Expand Up @@ -101,9 +105,13 @@ protected void onMethodInvocationFound(MethodInvocationTree mit) {
protected void onConstructorFound(NewClassTree newClassTree) {
String firstArgument = ExpressionsHelper.getConstantValueAsString(newClassTree.arguments().get(0)).value();
if (firstArgument != null) {
Matcher matcher = EC_KEY_PATTERN.matcher(firstArgument);
if (matcher.find() && Integer.valueOf(matcher.group(2)) < EC_MIN_KEY) {
reportIssue(newClassTree, "Use a key length of at least " + EC_MIN_KEY + " bits for EC cipher algorithm.");
Integer ecMinKey = getEffectiveKeySizeMap().get("EC");
if (ecMinKey != null) {
CryptographicKeySizeConfiguration.extractEcKeySize(firstArgument).ifPresent(keySize -> {
if (keySize < ecMinKey) {
reportIssue(newClassTree, "Use a key length of at least " + ecMinKey + " bits for EC cipher algorithm.");
}
});
}
}
}
Expand All @@ -116,7 +124,7 @@ private class MethodVisitor extends BaseTreeVisitor {

public MethodVisitor(String getInstanceArg, @Nullable Symbol variable) {
this.algorithm = getInstanceArg;
this.minKeySize = ALGORITHM_KEY_SIZE_MAP.get(this.algorithm.toUpperCase(Locale.ENGLISH));
this.minKeySize = getEffectiveKeySizeMap().get(this.algorithm.toUpperCase(Locale.ROOT));
this.variable = variable;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,14 @@ void test_without_semantic() {
.withoutSemantic()
.verifyIssues();
}

@Test
void test_custom_key_sizes() {
CryptographicKeySizeCheck check = new CryptographicKeySizeCheck();
check.minimumKeySizes = "RSA:4096,AES:64";
CheckVerifier.newVerifier()
.onFile(mainCodeSourcesPath("checks/security/CryptographicKeySizeCheckCustom.java"))
.withCheck(check)
.verifyIssues();
}
}
Loading