Repository navigation
SONARJAVA-6939 Make S4426 key sizes configurable via rule property #6147
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 |
|---|---|---|
|
|
@@ -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; | ||
|
|
@@ -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; | ||
|
|
@@ -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; | ||
|
|
||
| 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; | ||
| } | ||
|
gitar-bot[bot] marked this conversation as resolved.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Checked |
||
|
|
||
| private static final MethodMatchers KEY_GEN = MethodMatchers.or( | ||
| MethodMatchers.create() | ||
|
|
@@ -69,7 +73,7 @@ public class CryptographicKeySizeCheck extends AbstractMethodDetection { | |
| .names("initialize") | ||
| .addParametersMatcher("int") | ||
| .addParametersMatcher("int", "java.security.SecureRandom") | ||
| .build()) ; | ||
| .build()); | ||
|
|
||
| @Override | ||
| protected MethodMatchers getMethodInvocationMatchers() { | ||
|
|
@@ -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."); | ||
| } | ||
| }); | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -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; | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.