diff --git a/java/pom.xml b/java/pom.xml index 0e14af2a3..af6e865e7 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -60,6 +60,13 @@ 1.83 test + + + com.google.crypto.tink + tink + 1.21.0 + test + com.google.guava guava diff --git a/java/src/main/java/com/ibm/plugin/rules/detection/JavaDetectionRules.java b/java/src/main/java/com/ibm/plugin/rules/detection/JavaDetectionRules.java index 061cf4457..00ebe12f6 100644 --- a/java/src/main/java/com/ibm/plugin/rules/detection/JavaDetectionRules.java +++ b/java/src/main/java/com/ibm/plugin/rules/detection/JavaDetectionRules.java @@ -23,6 +23,7 @@ import com.ibm.plugin.rules.detection.bc.BouncyCastleDetectionRules; import com.ibm.plugin.rules.detection.jca.JcaDetectionRules; import com.ibm.plugin.rules.detection.ssl.SSLDetectionRules; +import com.ibm.plugin.rules.detection.tink.TinkDetectionRules; import java.util.List; import java.util.stream.Stream; import javax.annotation.Nonnull; @@ -38,7 +39,8 @@ public static List> rules() { return Stream.of( JcaDetectionRules.rules().stream(), BouncyCastleDetectionRules.rules().stream(), - SSLDetectionRules.rules().stream()) + SSLDetectionRules.rules().stream(), + TinkDetectionRules.rules().stream()) .flatMap(i -> i) .toList(); } diff --git a/java/src/main/java/com/ibm/plugin/rules/detection/tink/TinkAead.java b/java/src/main/java/com/ibm/plugin/rules/detection/tink/TinkAead.java new file mode 100644 index 000000000..8af2a06b1 --- /dev/null +++ b/java/src/main/java/com/ibm/plugin/rules/detection/tink/TinkAead.java @@ -0,0 +1,133 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.tink; + +import com.ibm.engine.detection.MethodMatcher; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import java.util.List; +import javax.annotation.Nonnull; +import org.sonar.plugins.java.api.tree.Tree; + +/** + * Detection rules for Google Tink AEAD. + * + *

Detects key generation and encrypt/decrypt operations: + * + *

+ */ +@SuppressWarnings("java:S1192") +public final class TinkAead { + + private TinkAead() { + // nothing + } + + // aead.encrypt(plaintext, aad) + private static final IDetectionRule AEAD_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("com.google.crypto.tink.Aead") + .forMethods("encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("ENCRYPT")) + .withMethodParameter(MethodMatcher.ANY) + .withMethodParameter(MethodMatcher.ANY) + .buildForContext(new CipherContext()) + .inBundle(() -> "Tink") + .withoutDependingDetectionRules(); + + // aead.decrypt(ciphertext, aad) + private static final IDetectionRule AEAD_DECRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("com.google.crypto.tink.Aead") + .forMethods("decrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("DECRYPT")) + .withMethodParameter(MethodMatcher.ANY) + .withMethodParameter(MethodMatcher.ANY) + .buildForContext(new CipherContext()) + .inBundle(() -> "Tink") + .withoutDependingDetectionRules(); + + private static final List> AEAD_OP_RULES = + List.of(AEAD_ENCRYPT, AEAD_DECRYPT); + + // KeysetHandle.generateNew(AeadKeyTemplates.AES128_GCM) + private static final IDetectionRule AES128_GCM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("com.google.crypto.tink.KeysetHandle") + .forMethods("generateNew") + .shouldBeDetectedAs(new ValueActionFactory<>("AES128_GCM")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> "Tink") + .withDependingDetectionRules(AEAD_OP_RULES); + + // KeysetHandle.generateNew(AeadKeyTemplates.AES256_GCM) + private static final IDetectionRule AES256_GCM = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("com.google.crypto.tink.KeysetHandle") + .forMethods("generateNew") + .shouldBeDetectedAs(new ValueActionFactory<>("AES256_GCM")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> "Tink") + .withDependingDetectionRules(AEAD_OP_RULES); + + // KeysetHandle.generateNew(AeadKeyTemplates.AES128_CTR_HMAC_SHA256) + private static final IDetectionRule AES128_CTR_HMAC_SHA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("com.google.crypto.tink.KeysetHandle") + .forMethods("generateNew") + .shouldBeDetectedAs(new ValueActionFactory<>("AES128_CTR_HMAC_SHA256")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> "Tink") + .withDependingDetectionRules(AEAD_OP_RULES); + + // KeysetHandle.generateNew(AeadKeyTemplates.AES256_CTR_HMAC_SHA256) + private static final IDetectionRule AES256_CTR_HMAC_SHA256 = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("com.google.crypto.tink.KeysetHandle") + .forMethods("generateNew") + .shouldBeDetectedAs(new ValueActionFactory<>("AES256_CTR_HMAC_SHA256")) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> "Tink") + .withDependingDetectionRules(AEAD_OP_RULES); + + @Nonnull + public static List> rules() { + return List.of(AES128_GCM, AES256_GCM, AES128_CTR_HMAC_SHA256, AES256_CTR_HMAC_SHA256); + } +} diff --git a/java/src/main/java/com/ibm/plugin/rules/detection/tink/TinkDetectionRules.java b/java/src/main/java/com/ibm/plugin/rules/detection/tink/TinkDetectionRules.java new file mode 100644 index 000000000..c144bef97 --- /dev/null +++ b/java/src/main/java/com/ibm/plugin/rules/detection/tink/TinkDetectionRules.java @@ -0,0 +1,45 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.tink; + +import com.ibm.engine.rule.IDetectionRule; +import java.util.List; +import java.util.stream.Stream; +import javax.annotation.Nonnull; +import org.sonar.plugins.java.api.tree.Tree; + +/** Aggregates all Google Tink detection rule lists. */ +public final class TinkDetectionRules { + + private TinkDetectionRules() { + // nothing + } + + @Nonnull + public static List> rules() { + return Stream.of( + TinkAead.rules().stream(), + TinkMac.rules().stream(), + TinkSignature.rules().stream(), + TinkHybrid.rules().stream()) + .flatMap(i -> i) + .toList(); + } +} diff --git a/java/src/main/java/com/ibm/plugin/rules/detection/tink/TinkHybrid.java b/java/src/main/java/com/ibm/plugin/rules/detection/tink/TinkHybrid.java new file mode 100644 index 000000000..459d61460 --- /dev/null +++ b/java/src/main/java/com/ibm/plugin/rules/detection/tink/TinkHybrid.java @@ -0,0 +1,99 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.tink; + +import com.ibm.engine.detection.MethodMatcher; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import java.util.List; +import javax.annotation.Nonnull; +import org.sonar.plugins.java.api.tree.Tree; + +/** + * Detection rules for Google Tink hybrid encryption primitive. + * + *
    + *
  • {@code KeysetHandle.generateNew(HybridKeyTemplates.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM)} + *
  • {@code hybridEncrypt.encrypt(plaintext, contextInfo)} + *
  • {@code hybridDecrypt.decrypt(ciphertext, contextInfo)} + *
+ */ +@SuppressWarnings("java:S1192") +public final class TinkHybrid { + + private TinkHybrid() { + // nothing + } + + // hybridEncrypt.encrypt(byte[] plaintext, byte[] contextInfo) + private static final IDetectionRule HYBRID_ENCRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("com.google.crypto.tink.HybridEncrypt") + .forMethods("encrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("ENCRYPT")) + .withMethodParameter(MethodMatcher.ANY) + .withMethodParameter(MethodMatcher.ANY) + .buildForContext(new CipherContext()) + .inBundle(() -> "Tink") + .withoutDependingDetectionRules(); + + // hybridDecrypt.decrypt(byte[] ciphertext, byte[] contextInfo) + private static final IDetectionRule HYBRID_DECRYPT = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("com.google.crypto.tink.HybridDecrypt") + .forMethods("decrypt") + .shouldBeDetectedAs(new ValueActionFactory<>("DECRYPT")) + .withMethodParameter(MethodMatcher.ANY) + .withMethodParameter(MethodMatcher.ANY) + .buildForContext(new CipherContext()) + .inBundle(() -> "Tink") + .withoutDependingDetectionRules(); + + private static final List> HYBRID_OP_RULES = + List.of(HYBRID_ENCRYPT, HYBRID_DECRYPT); + + private static IDetectionRule hybridKeyRule(String value) { + return new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("com.google.crypto.tink.KeysetHandle") + .forMethods("generateNew") + .shouldBeDetectedAs(new ValueActionFactory<>(value)) + .withAnyParameters() + .buildForContext(new CipherContext()) + .inBundle(() -> "Tink") + .withDependingDetectionRules(HYBRID_OP_RULES); + } + + private static final IDetectionRule ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM = + hybridKeyRule("ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM"); + private static final IDetectionRule ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256 = + hybridKeyRule("ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256"); + + @Nonnull + public static List> rules() { + return List.of( + ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM, + ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256); + } +} diff --git a/java/src/main/java/com/ibm/plugin/rules/detection/tink/TinkMac.java b/java/src/main/java/com/ibm/plugin/rules/detection/tink/TinkMac.java new file mode 100644 index 000000000..bcc469f60 --- /dev/null +++ b/java/src/main/java/com/ibm/plugin/rules/detection/tink/TinkMac.java @@ -0,0 +1,111 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.tink; + +import com.ibm.engine.detection.MethodMatcher; +import com.ibm.engine.model.context.MacContext; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import java.util.List; +import javax.annotation.Nonnull; +import org.sonar.plugins.java.api.tree.Tree; + +/** + * Detection rules for Google Tink MAC primitive. + * + *

Detects key generation and MAC operations: + * + *

    + *
  • {@code KeysetHandle.generateNew(MacKeyTemplates.HMAC_SHA256_128BITTAG)} + *
  • {@code KeysetHandle.generateNew(MacKeyTemplates.HMAC_SHA256_256BITTAG)} + *
  • {@code KeysetHandle.generateNew(MacKeyTemplates.HMAC_SHA512_256BITTAG)} + *
  • {@code KeysetHandle.generateNew(MacKeyTemplates.HMAC_SHA512_512BITTAG)} + *
  • {@code KeysetHandle.generateNew(MacKeyTemplates.AES_CMAC)} + *
  • {@code mac.computeMac(data)} + *
  • {@code mac.verifyMac(tag, data)} + *
+ */ +@SuppressWarnings("java:S1192") +public final class TinkMac { + + private TinkMac() { + // nothing + } + + // mac.computeMac(byte[] data) + private static final IDetectionRule MAC_COMPUTE = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("com.google.crypto.tink.Mac") + .forMethods("computeMac") + .shouldBeDetectedAs(new ValueActionFactory<>("COMPUTE")) + .withMethodParameter(MethodMatcher.ANY) + .buildForContext(new MacContext()) + .inBundle(() -> "Tink") + .withoutDependingDetectionRules(); + + // mac.verifyMac(byte[] tag, byte[] data) + private static final IDetectionRule MAC_VERIFY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("com.google.crypto.tink.Mac") + .forMethods("verifyMac") + .shouldBeDetectedAs(new ValueActionFactory<>("VERIFY")) + .withMethodParameter(MethodMatcher.ANY) + .withMethodParameter(MethodMatcher.ANY) + .buildForContext(new MacContext()) + .inBundle(() -> "Tink") + .withoutDependingDetectionRules(); + + private static final List> MAC_OP_RULES = List.of(MAC_COMPUTE, MAC_VERIFY); + + private static IDetectionRule macKeyRule(String value) { + return new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("com.google.crypto.tink.KeysetHandle") + .forMethods("generateNew") + .shouldBeDetectedAs(new ValueActionFactory<>(value)) + .withAnyParameters() + .buildForContext(new MacContext()) + .inBundle(() -> "Tink") + .withDependingDetectionRules(MAC_OP_RULES); + } + + private static final IDetectionRule HMAC_SHA256_128BITTAG = + macKeyRule("HMAC_SHA256_128BITTAG"); + private static final IDetectionRule HMAC_SHA256_256BITTAG = + macKeyRule("HMAC_SHA256_256BITTAG"); + private static final IDetectionRule HMAC_SHA512_256BITTAG = + macKeyRule("HMAC_SHA512_256BITTAG"); + private static final IDetectionRule HMAC_SHA512_512BITTAG = + macKeyRule("HMAC_SHA512_512BITTAG"); + private static final IDetectionRule AES_CMAC = macKeyRule("AES_CMAC"); + + @Nonnull + public static List> rules() { + return List.of( + HMAC_SHA256_128BITTAG, + HMAC_SHA256_256BITTAG, + HMAC_SHA512_256BITTAG, + HMAC_SHA512_512BITTAG, + AES_CMAC); + } +} diff --git a/java/src/main/java/com/ibm/plugin/rules/detection/tink/TinkSignature.java b/java/src/main/java/com/ibm/plugin/rules/detection/tink/TinkSignature.java new file mode 100644 index 000000000..2c95ada9b --- /dev/null +++ b/java/src/main/java/com/ibm/plugin/rules/detection/tink/TinkSignature.java @@ -0,0 +1,98 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.tink; + +import com.ibm.engine.detection.MethodMatcher; +import com.ibm.engine.model.context.SignatureContext; +import com.ibm.engine.model.factory.ValueActionFactory; +import com.ibm.engine.rule.IDetectionRule; +import com.ibm.engine.rule.builder.DetectionRuleBuilder; +import java.util.List; +import javax.annotation.Nonnull; +import org.sonar.plugins.java.api.tree.Tree; + +/** + * Detection rules for Google Tink digital signature primitive. + * + *
    + *
  • {@code KeysetHandle.generateNew(SignatureKeyTemplates.ECDSA_P256)} + *
  • {@code KeysetHandle.generateNew(SignatureKeyTemplates.ED25519)} + *
  • {@code signer.sign(data)} + *
  • {@code verifier.verify(signature, data)} + *
+ */ +@SuppressWarnings("java:S1192") +public final class TinkSignature { + + private TinkSignature() { + // nothing + } + + // signer.sign(byte[] data) + private static final IDetectionRule SIGN = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("com.google.crypto.tink.PublicKeySign") + .forMethods("sign") + .shouldBeDetectedAs(new ValueActionFactory<>("SIGN")) + .withMethodParameter(MethodMatcher.ANY) + .buildForContext(new SignatureContext()) + .inBundle(() -> "Tink") + .withoutDependingDetectionRules(); + + // verifier.verify(byte[] signature, byte[] data) + private static final IDetectionRule VERIFY = + new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("com.google.crypto.tink.PublicKeyVerify") + .forMethods("verify") + .shouldBeDetectedAs(new ValueActionFactory<>("VERIFY")) + .withMethodParameter(MethodMatcher.ANY) + .withMethodParameter(MethodMatcher.ANY) + .buildForContext(new SignatureContext()) + .inBundle(() -> "Tink") + .withoutDependingDetectionRules(); + + private static final List> SIGN_OP_RULES = List.of(SIGN, VERIFY); + + private static IDetectionRule signKeyRule(String value) { + return new DetectionRuleBuilder() + .createDetectionRule() + .forObjectTypes("com.google.crypto.tink.KeysetHandle") + .forMethods("generateNew") + .shouldBeDetectedAs(new ValueActionFactory<>(value)) + .withAnyParameters() + .buildForContext(new SignatureContext()) + .inBundle(() -> "Tink") + .withDependingDetectionRules(SIGN_OP_RULES); + } + + private static final IDetectionRule ECDSA_P256 = signKeyRule("ECDSA_P256"); + private static final IDetectionRule ECDSA_P384 = signKeyRule("ECDSA_P384"); + private static final IDetectionRule ECDSA_P521 = signKeyRule("ECDSA_P521"); + private static final IDetectionRule ED25519 = signKeyRule("ED25519"); + private static final IDetectionRule RSA_SSA_PKCS1_3072_SHA256_F4 = + signKeyRule("RSA_SSA_PKCS1_3072_SHA256_F4"); + + @Nonnull + public static List> rules() { + return List.of(ECDSA_P256, ECDSA_P384, ECDSA_P521, ED25519, RSA_SSA_PKCS1_3072_SHA256_F4); + } +} diff --git a/java/src/main/java/com/ibm/plugin/translation/translator/contexts/JavaAbstractLibraryTranslator.java b/java/src/main/java/com/ibm/plugin/translation/translator/contexts/JavaAbstractLibraryTranslator.java index 9246b8765..dadb381d6 100644 --- a/java/src/main/java/com/ibm/plugin/translation/translator/contexts/JavaAbstractLibraryTranslator.java +++ b/java/src/main/java/com/ibm/plugin/translation/translator/contexts/JavaAbstractLibraryTranslator.java @@ -42,6 +42,7 @@ public Optional translate( return switch (bundleIdentifier.getIdentifier()) { case "Jca" -> translateJCA(value, detectionContext, detectionLocation); case "Bc" -> translateBC(value, detectionContext, detectionLocation); + case "Tink" -> translateTink(value, detectionContext, detectionLocation); default -> Optional.of(new Unknown(detectionLocation)); }; } @@ -57,4 +58,12 @@ protected abstract Optional translateBC( @Nonnull IValue value, @Nonnull IDetectionContext detectionContext, @Nonnull DetectionLocation detectionLocation); + + @Nonnull + protected Optional translateTink( + @Nonnull IValue value, + @Nonnull IDetectionContext detectionContext, + @Nonnull DetectionLocation detectionLocation) { + return Optional.empty(); + } } diff --git a/java/src/main/java/com/ibm/plugin/translation/translator/contexts/JavaCipherContextTranslator.java b/java/src/main/java/com/ibm/plugin/translation/translator/contexts/JavaCipherContextTranslator.java index 7bfed2e84..92e362915 100644 --- a/java/src/main/java/com/ibm/plugin/translation/translator/contexts/JavaCipherContextTranslator.java +++ b/java/src/main/java/com/ibm/plugin/translation/translator/contexts/JavaCipherContextTranslator.java @@ -202,4 +202,24 @@ public Optional translateBC( } return Optional.empty(); } + + @Nonnull + @Override + protected Optional translateTink( + @Nonnull IValue value, + @Nonnull IDetectionContext detectionContext, + @Nonnull DetectionLocation detectionLocation) { + if (value instanceof ValueAction) { + return switch (value.asString()) { + case "AES128_GCM", "AES256_GCM" -> + Optional.of( + new com.ibm.mapper.model.algorithms.AES( + AuthenticatedEncryption.class, detectionLocation)); + case "AES128_CTR_HMAC_SHA256", "AES256_CTR_HMAC_SHA256" -> + Optional.of(new com.ibm.mapper.model.algorithms.AES(detectionLocation)); + default -> Optional.empty(); + }; + } + return Optional.empty(); + } } diff --git a/java/src/test/files/rules/detection/tink/TinkAeadTestFile.java b/java/src/test/files/rules/detection/tink/TinkAeadTestFile.java new file mode 100644 index 000000000..821d31071 --- /dev/null +++ b/java/src/test/files/rules/detection/tink/TinkAeadTestFile.java @@ -0,0 +1,21 @@ +import com.google.crypto.tink.Aead; +import com.google.crypto.tink.KeysetHandle; +import com.google.crypto.tink.aead.AeadConfig; +import com.google.crypto.tink.aead.AeadKeyTemplates; + +public class TinkAeadTestFile { + + public void testAes128Gcm() throws Exception { + AeadConfig.register(); + KeysetHandle keysetHandle = + KeysetHandle.generateNew(AeadKeyTemplates.AES128_GCM); // Noncompliant 4 + Aead aead = keysetHandle.getPrimitive(Aead.class); + } + + public void testAes256Gcm() throws Exception { + AeadConfig.register(); + KeysetHandle keysetHandle = + KeysetHandle.generateNew(AeadKeyTemplates.AES256_GCM); // Noncompliant 4 + Aead aead = keysetHandle.getPrimitive(Aead.class); + } +} \ No newline at end of file diff --git a/java/src/test/files/rules/detection/tink/TinkHybridTestFile.java b/java/src/test/files/rules/detection/tink/TinkHybridTestFile.java new file mode 100644 index 000000000..2ddaac349 --- /dev/null +++ b/java/src/test/files/rules/detection/tink/TinkHybridTestFile.java @@ -0,0 +1,18 @@ +import com.google.crypto.tink.HybridDecrypt; +import com.google.crypto.tink.HybridEncrypt; +import com.google.crypto.tink.KeysetHandle; +import com.google.crypto.tink.hybrid.HybridConfig; +import com.google.crypto.tink.hybrid.HybridKeyTemplates; + +public class TinkHybridTestFile { + + public void testEciesP256() throws Exception { + HybridConfig.register(); + KeysetHandle keysetHandle = KeysetHandle.generateNew(HybridKeyTemplates.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM); // Noncompliant 4 + } + + public void testEciesP256Ctr() throws Exception { + HybridConfig.register(); + KeysetHandle keysetHandle = KeysetHandle.generateNew(HybridKeyTemplates.ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256); // Noncompliant 4 + } +} diff --git a/java/src/test/files/rules/detection/tink/TinkMacTestFile.java b/java/src/test/files/rules/detection/tink/TinkMacTestFile.java new file mode 100644 index 000000000..b535c4304 --- /dev/null +++ b/java/src/test/files/rules/detection/tink/TinkMacTestFile.java @@ -0,0 +1,19 @@ +import com.google.crypto.tink.KeysetHandle; +import com.google.crypto.tink.Mac; +import com.google.crypto.tink.mac.MacConfig; +import com.google.crypto.tink.mac.MacKeyTemplates; + +public class TinkMacTestFile { + + public void testHmacSha256() throws Exception { + MacConfig.register(); + KeysetHandle keysetHandle = + KeysetHandle.generateNew(MacKeyTemplates.HMAC_SHA256_128BITTAG); // Noncompliant 4 + } + + public void testHmacSha512() throws Exception { + MacConfig.register(); + KeysetHandle keysetHandle = + KeysetHandle.generateNew(MacKeyTemplates.HMAC_SHA512_256BITTAG); // Noncompliant 4 + } +} \ No newline at end of file diff --git a/java/src/test/files/rules/detection/tink/TinkSignatureTestFile.java b/java/src/test/files/rules/detection/tink/TinkSignatureTestFile.java new file mode 100644 index 000000000..580b42bbc --- /dev/null +++ b/java/src/test/files/rules/detection/tink/TinkSignatureTestFile.java @@ -0,0 +1,19 @@ +import com.google.crypto.tink.KeysetHandle; +import com.google.crypto.tink.PublicKeySign; +import com.google.crypto.tink.signature.SignatureConfig; +import com.google.crypto.tink.signature.SignatureKeyTemplates; + +public class TinkSignatureTestFile { + + public void testEcdsaP256() throws Exception { + SignatureConfig.register(); + KeysetHandle keysetHandle = + KeysetHandle.generateNew(SignatureKeyTemplates.ECDSA_P256); // Noncompliant 4 + } + + public void testEd25519() throws Exception { + SignatureConfig.register(); + KeysetHandle keysetHandle = + KeysetHandle.generateNew(SignatureKeyTemplates.ED25519); // Noncompliant 4 + } +} \ No newline at end of file diff --git a/java/src/test/java/com/ibm/plugin/rules/detection/tink/TinkAeadTest.java b/java/src/test/java/com/ibm/plugin/rules/detection/tink/TinkAeadTest.java new file mode 100644 index 000000000..681bc5f84 --- /dev/null +++ b/java/src/test/java/com/ibm/plugin/rules/detection/tink/TinkAeadTest.java @@ -0,0 +1,98 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.tink; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.engine.model.context.MacContext; +import com.ibm.engine.model.context.SignatureContext; +import com.ibm.mapper.model.AuthenticatedEncryption; +import com.ibm.mapper.model.BlockCipher; +import com.ibm.mapper.model.INode; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.java.checks.verifier.CheckVerifier; +import org.sonar.plugins.java.api.JavaCheck; +import org.sonar.plugins.java.api.JavaFileScannerContext; +import org.sonar.plugins.java.api.semantic.Symbol; +import org.sonar.plugins.java.api.tree.Tree; + +class TinkAeadTest extends TestBase { + + @Test + void test() { + CheckVerifier.newVerifier() + .onFile("src/test/files/rules/detection/tink/TinkAeadTestFile.java") + .withChecks(this) + .withClassPath( + com.google.common.collect.ImmutableList.of( + new java.io.File( + System.getProperty("user.home") + + "/.m2/repository/com/google/crypto/tink/tink/1.21.0/tink-1.21.0.jar"))) + .verifyIssues(); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + + /* + * Detection Store + */ + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOfAny(CipherContext.class, MacContext.class, SignatureContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()) + .isIn( + "AES128_GCM", + "AES256_GCM", + "AES128_CTR_HMAC_SHA256", + "AES256_CTR_HMAC_SHA256", + "HMAC_SHA256_128BITTAG", + "HMAC_SHA256_256BITTAG", + "HMAC_SHA512_256BITTAG", + "HMAC_SHA512_512BITTAG", + "AES_CMAC", + "ECDSA_P256", + "ECDSA_P384", + "ECDSA_P521", + "ED25519", + "RSA_SSA_PKCS1_3072_SHA256_F4", + "ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM", + "ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256"); + + // Translation only implemented for AEAD templates — Mac/Hybrid/Signature return empty nodes + if (!nodes.isEmpty()) { + INode node = nodes.get(0); + assertThat(node.getKind()).isIn(AuthenticatedEncryption.class, BlockCipher.class); + assertThat(node.asString()).isEqualTo("AES"); + } + } +} diff --git a/java/src/test/java/com/ibm/plugin/rules/detection/tink/TinkHybridTest.java b/java/src/test/java/com/ibm/plugin/rules/detection/tink/TinkHybridTest.java new file mode 100644 index 000000000..dd7158d77 --- /dev/null +++ b/java/src/test/java/com/ibm/plugin/rules/detection/tink/TinkHybridTest.java @@ -0,0 +1,89 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.tink; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.engine.model.context.MacContext; +import com.ibm.engine.model.context.SignatureContext; +import com.ibm.mapper.model.INode; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.java.checks.verifier.CheckVerifier; +import org.sonar.plugins.java.api.JavaCheck; +import org.sonar.plugins.java.api.JavaFileScannerContext; +import org.sonar.plugins.java.api.semantic.Symbol; +import org.sonar.plugins.java.api.tree.Tree; + +class TinkHybridTest extends TestBase { + + @Test + void test() { + CheckVerifier.newVerifier() + .onFile("src/test/files/rules/detection/tink/TinkHybridTestFile.java") + .withChecks(this) + .withClassPath( + com.google.common.collect.ImmutableList.of( + new java.io.File( + System.getProperty("user.home") + + "/.m2/repository/com/google/crypto/tink/tink/1.21.0/tink-1.21.0.jar"))) + .verifyIssues(); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + + /* + * Detection Store + */ + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOfAny(CipherContext.class, MacContext.class, SignatureContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()) + .isIn( + "AES128_GCM", + "AES256_GCM", + "AES128_CTR_HMAC_SHA256", + "AES256_CTR_HMAC_SHA256", + "HMAC_SHA256_128BITTAG", + "HMAC_SHA256_256BITTAG", + "HMAC_SHA512_256BITTAG", + "HMAC_SHA512_512BITTAG", + "AES_CMAC", + "ECDSA_P256", + "ECDSA_P384", + "ECDSA_P521", + "ED25519", + "RSA_SSA_PKCS1_3072_SHA256_F4", + "ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM", + "ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256"); + } +} diff --git a/java/src/test/java/com/ibm/plugin/rules/detection/tink/TinkMacTest.java b/java/src/test/java/com/ibm/plugin/rules/detection/tink/TinkMacTest.java new file mode 100644 index 000000000..abef704f9 --- /dev/null +++ b/java/src/test/java/com/ibm/plugin/rules/detection/tink/TinkMacTest.java @@ -0,0 +1,89 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.tink; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.engine.model.context.MacContext; +import com.ibm.engine.model.context.SignatureContext; +import com.ibm.mapper.model.INode; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.java.checks.verifier.CheckVerifier; +import org.sonar.plugins.java.api.JavaCheck; +import org.sonar.plugins.java.api.JavaFileScannerContext; +import org.sonar.plugins.java.api.semantic.Symbol; +import org.sonar.plugins.java.api.tree.Tree; + +class TinkMacTest extends TestBase { + + @Test + void test() { + CheckVerifier.newVerifier() + .onFile("src/test/files/rules/detection/tink/TinkMacTestFile.java") + .withChecks(this) + .withClassPath( + com.google.common.collect.ImmutableList.of( + new java.io.File( + System.getProperty("user.home") + + "/.m2/repository/com/google/crypto/tink/tink/1.21.0/tink-1.21.0.jar"))) + .verifyIssues(); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + + /* + * Detection Store + */ + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOfAny(CipherContext.class, MacContext.class, SignatureContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()) + .isIn( + "AES128_GCM", + "AES256_GCM", + "AES128_CTR_HMAC_SHA256", + "AES256_CTR_HMAC_SHA256", + "HMAC_SHA256_128BITTAG", + "HMAC_SHA256_256BITTAG", + "HMAC_SHA512_256BITTAG", + "HMAC_SHA512_512BITTAG", + "AES_CMAC", + "ECDSA_P256", + "ECDSA_P384", + "ECDSA_P521", + "ED25519", + "RSA_SSA_PKCS1_3072_SHA256_F4", + "ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM", + "ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256"); + } +} diff --git a/java/src/test/java/com/ibm/plugin/rules/detection/tink/TinkSignatureTest.java b/java/src/test/java/com/ibm/plugin/rules/detection/tink/TinkSignatureTest.java new file mode 100644 index 000000000..8d428cb85 --- /dev/null +++ b/java/src/test/java/com/ibm/plugin/rules/detection/tink/TinkSignatureTest.java @@ -0,0 +1,89 @@ +/* + * Sonar Cryptography Plugin + * Copyright (C) 2024 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ibm.plugin.rules.detection.tink; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.ibm.engine.detection.DetectionStore; +import com.ibm.engine.model.IValue; +import com.ibm.engine.model.ValueAction; +import com.ibm.engine.model.context.CipherContext; +import com.ibm.engine.model.context.MacContext; +import com.ibm.engine.model.context.SignatureContext; +import com.ibm.mapper.model.INode; +import com.ibm.plugin.TestBase; +import java.util.List; +import javax.annotation.Nonnull; +import org.junit.jupiter.api.Test; +import org.sonar.java.checks.verifier.CheckVerifier; +import org.sonar.plugins.java.api.JavaCheck; +import org.sonar.plugins.java.api.JavaFileScannerContext; +import org.sonar.plugins.java.api.semantic.Symbol; +import org.sonar.plugins.java.api.tree.Tree; + +class TinkSignatureTest extends TestBase { + + @Test + void test() { + CheckVerifier.newVerifier() + .onFile("src/test/files/rules/detection/tink/TinkSignatureTestFile.java") + .withChecks(this) + .withClassPath( + com.google.common.collect.ImmutableList.of( + new java.io.File( + System.getProperty("user.home") + + "/.m2/repository/com/google/crypto/tink/tink/1.21.0/tink-1.21.0.jar"))) + .verifyIssues(); + } + + @Override + public void asserts( + int findingId, + @Nonnull DetectionStore detectionStore, + @Nonnull List nodes) { + + /* + * Detection Store + */ + assertThat(detectionStore.getDetectionValues()).hasSize(1); + assertThat(detectionStore.getDetectionValueContext()) + .isInstanceOfAny(CipherContext.class, MacContext.class, SignatureContext.class); + IValue value = detectionStore.getDetectionValues().get(0); + assertThat(value).isInstanceOf(ValueAction.class); + assertThat(value.asString()) + .isIn( + "AES128_GCM", + "AES256_GCM", + "AES128_CTR_HMAC_SHA256", + "AES256_CTR_HMAC_SHA256", + "HMAC_SHA256_128BITTAG", + "HMAC_SHA256_256BITTAG", + "HMAC_SHA512_256BITTAG", + "HMAC_SHA512_512BITTAG", + "AES_CMAC", + "ECDSA_P256", + "ECDSA_P384", + "ECDSA_P521", + "ED25519", + "RSA_SSA_PKCS1_3072_SHA256_F4", + "ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM", + "ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256"); + } +}