Skip to content

Commit

Permalink
update tests
Browse files Browse the repository at this point in the history
Signed-off-by: Nicklas Körtge <nicklas.koertge1@ibm.com>
  • Loading branch information
n1ckl0sk0rtge committed Aug 29, 2024
1 parent 6cec400 commit d864bff
Show file tree
Hide file tree
Showing 14 changed files with 376 additions and 187 deletions.
4 changes: 4 additions & 0 deletions enricher/src/main/java/com/ibm/enricher/Enricher.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.ibm.enricher.algorithm.MacOrDigestEnricher;
import com.ibm.enricher.algorithm.PBKDF2Enricher;
import com.ibm.enricher.algorithm.RSAEnricher;
import com.ibm.enricher.algorithm.RSAoaepEnricher;
import com.ibm.enricher.algorithm.RSAssaPSSEnricher;
import com.ibm.enricher.algorithm.SHA2Enricher;
import com.ibm.enricher.algorithm.SHA3Enricher;
Expand Down Expand Up @@ -120,6 +121,9 @@ public INode enrich(@Nonnull INode node) {
if (node instanceof RSAssaPSS) {
node = new RSAssaPSSEnricher().enrich(node);
}
if (node instanceof RSA) {
node = new RSAoaepEnricher().enrich(node);
}

if (node instanceof Signature) {
node = new SignatureEnricher().enrich(node);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* SonarQube Cryptography Plugin
* Copyright (C) 2024 IBM
*
* 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.enricher.algorithm;

import com.ibm.enricher.IEnricher;
import com.ibm.mapper.model.INode;
import com.ibm.mapper.model.Oid;
import com.ibm.mapper.model.Padding;
import com.ibm.mapper.model.Signature;
import com.ibm.mapper.model.algorithms.RSA;
import com.ibm.mapper.model.padding.OAEP;
import java.util.Optional;
import org.jetbrains.annotations.NotNull;

public class RSAoaepEnricher implements IEnricher {

@Override
public @NotNull INode enrich(@NotNull INode node) {
if (node instanceof RSA rsa) {
final Optional<INode> padding = rsa.hasChildOfType(Padding.class);
if (padding.isEmpty()) {
return node;
}
if (padding.get() instanceof OAEP) {
final RSA newRSA = new RSA(Signature.class, rsa);
newRSA.put(new Oid("1.2.840.113549.1.1.7", rsa.getDetectionContext()));
return newRSA;
}
}
return node;
}
}
6 changes: 3 additions & 3 deletions mapper/src/main/java/com/ibm/mapper/ITranslator.java
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ protected abstract Optional<INode> translate(
*/
static class Traverser<R, T, S, P> {
@Nonnull final DetectionStore<R, T, S, P> rootDetectionStore;
@Nonnull final List<INode> newParents = new ArrayList<>();
@Nonnull final List<INode> newRoots = new ArrayList<>();
@Nonnull final Function<DetectionStore<R, T, S, P>, Map<Integer, List<INode>>> translator;

public Traverser(
Expand All @@ -131,7 +131,7 @@ public List<INode> translate() {
travers(rootDetectionStore, rootNodes);
final List<INode> translatedRootNodes =
new ArrayList<>(rootNodes.values().stream().flatMap(List::stream).toList());
translatedRootNodes.addAll(newParents);
translatedRootNodes.addAll(newRoots);
return translatedRootNodes;
}

Expand Down Expand Up @@ -196,7 +196,7 @@ private void append(
if (parentNode.hasChildOfType(childNode.getKind()).isPresent()) {
final INode newParent = parentNode.deepCopy();
newParent.put(childNode);
newParents.add(newParent);
newRoots.add(newParent);
} else {
parentNode.put(childNode);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import com.ibm.mapper.model.algorithms.ChaCha20;
import com.ibm.mapper.model.algorithms.ChaCha20Poly1305;
import com.ibm.mapper.model.algorithms.IDEA;
import com.ibm.mapper.model.algorithms.MGF1;
import com.ibm.mapper.model.algorithms.RC4;
import com.ibm.mapper.model.algorithms.RSA;
import com.ibm.mapper.model.algorithms.SEED;
Expand All @@ -48,7 +47,6 @@ public final class PycaCipherMapper implements IMapper {
}

return switch (str.toUpperCase().trim()) {
case "MGF1" -> Optional.of(new MGF1(detectionLocation));
case "AES" -> Optional.of(new AES(detectionLocation));
case "AES128" -> Optional.of(new AES(128, detectionLocation));
case "AES256" -> Optional.of(new AES(256, detectionLocation));
Expand Down
4 changes: 4 additions & 0 deletions mapper/src/main/java/com/ibm/mapper/model/algorithms/RSA.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,8 @@ public RSA(
super(NAME, asKind, detectionLocation);
this.put(new Oid(OID, detectionLocation));
}

public RSA(@Nonnull final Class<? extends IPrimitive> asKind, @NotNull RSA rsa) {
super(rsa, asKind);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* SonarQube Cryptography Plugin
* Copyright (C) 2024 IBM
*
* 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.mapper.reorganizer.rules;

import com.ibm.mapper.model.INode;
import com.ibm.mapper.model.Padding;
import com.ibm.mapper.model.PrivateKey;
import com.ibm.mapper.model.PublicKeyEncryption;
import com.ibm.mapper.model.functionality.Decrypt;
import com.ibm.mapper.model.padding.OAEP;
import com.ibm.mapper.reorganizer.IReorganizerRule;
import com.ibm.mapper.reorganizer.builder.ReorganizerRuleBuilder;
import java.util.Optional;

public final class PaddingReorganizer {

private PaddingReorganizer() {
// nothing
}

public static final IReorganizerRule MOVE_OAEP_UNDER_ALGORITHM =
new ReorganizerRuleBuilder()
.createReorganizerRule()
.forNodeKind(PrivateKey.class)
.withDetectionCondition(
(node, parent, roots) -> {
final Optional<INode> functionality =
node.hasChildOfType(Decrypt.class);
final Optional<INode> pke =
node.hasChildOfType(PublicKeyEncryption.class);
if (functionality.isEmpty()) {
return false;
}
if (pke.isEmpty()) {
return false;
}

return functionality
.get()
.hasChildOfType(Padding.class)
.map(OAEP.class::isInstance)
.orElse(false);
})
.perform(
(node, parent, roots) -> {
final Optional<INode> pke =
node.hasChildOfType(PublicKeyEncryption.class);
final Optional<INode> functionality =
node.hasChildOfType(Decrypt.class);
if (functionality.isEmpty()) {
return roots;
}
if (pke.isEmpty()) {
return roots;
}

functionality
.get()
.hasChildOfType(Padding.class)
.ifPresent(
p -> {
pke.get().put(p);
functionality
.get()
.removeChildOfType(p.getKind());
});
return roots;
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ private PycaRSA() {
.createDetectionRule()
.forObjectTypes(PADDING_TYPE)
.forMethods("MGF1")
.shouldBeDetectedAs(new ValueActionFactory<>("MGF1"))
.withMethodParameter(HASH_TYPE) // This "type" accepts both hashes
// and pre-hashes
.addDependingDetectionRules(PycaHash.rules())
Expand Down Expand Up @@ -101,7 +102,8 @@ private PycaRSA() {
.forMethods("OAEP")
.shouldBeDetectedAs(new ValueActionFactory<>("OAEP"))
.withMethodParameter(ANY)
.shouldBeDetectedAs(new AlgorithmFactory<>())
// .shouldBeDetectedAs(new AlgorithmFactory<>())
// .asChildOfParameterWithId(-1)
.addDependingDetectionRules(List.of(MGF1))
.withMethodParameter(HASH_TYPE) // This "type" accepts both hashes
// and pre-hashes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import com.ibm.mapper.reorganizer.IReorganizerRule;
import com.ibm.mapper.reorganizer.rules.KeyAgreementReorganizer;
import com.ibm.mapper.reorganizer.rules.PaddingReorganizer;
import com.ibm.mapper.reorganizer.rules.SignerReorganizer;
import java.util.List;
import java.util.stream.Stream;
Expand All @@ -37,7 +38,8 @@ public static List<IReorganizerRule> rules() {
return Stream.of(
SignerReorganizer.MOVE_DIGEST_FROM_SIGN_ACTION_UNDER_SIGNATURE,
SignerReorganizer.MERGE_SIGNATURE_WITH_PKE_UNDER_PRIVATE_KEY,
KeyAgreementReorganizer.MERGE_KEYAGREEMENT_WITH_PKE_UNDER_PRIVATE_KEY)
KeyAgreementReorganizer.MERGE_KEYAGREEMENT_WITH_PKE_UNDER_PRIVATE_KEY,
PaddingReorganizer.MOVE_OAEP_UNDER_ALGORITHM)
.toList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.ibm.mapper.IContextTranslation;
import com.ibm.mapper.mapper.pyca.PycaDigestMapper;
import com.ibm.mapper.model.INode;
import com.ibm.mapper.model.functionality.Digest;
import com.ibm.mapper.utils.DetectionLocation;
import java.util.Optional;
import org.jetbrains.annotations.NotNull;
Expand All @@ -42,7 +43,13 @@ public final class PycaDigestContextTranslator implements IContextTranslation<Tr
@NotNull DetectionLocation detectionLocation) {
if (value instanceof ValueAction<Tree>) {
final PycaDigestMapper pycaDigestMapper = new PycaDigestMapper();
return pycaDigestMapper.parse(value.asString(), detectionLocation).map(i -> i);
return pycaDigestMapper
.parse(value.asString(), detectionLocation)
.map(
hash -> {
hash.put(new Digest(detectionLocation));
return hash;
});
}
return Optional.empty();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,18 @@ public final class PycaSignatureContextTranslator implements IContextTranslation
case VERIFY -> Optional.of(new Verify(detectionLocation));
};
} else if (value instanceof ValueAction<Tree>
&& detectionContext instanceof DetectionContext context
&& context.get("kind").map(k -> k.equals("padding")).orElse(false) // padding case
) {
return switch (value.asString().toUpperCase().trim()) {
case "PKCS1V15" -> Optional.empty(); // TODO
default -> Optional.empty();
};
&& detectionContext instanceof DetectionContext context) {
if (context.get("kind").map(k -> k.equals("padding")).orElse(false)) { // padding case
return switch (value.asString().toUpperCase().trim()) {
case "PKCS1V15" -> Optional.empty(); // TODO
default -> Optional.empty();
};
} else {
return switch (value.asString().toUpperCase().trim()) {
case "MGF1" -> Optional.of(new MGF1(detectionLocation));
default -> Optional.empty();
};
}
}
return Optional.empty();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@

def verify(pubkey, signature, digest):
if isinstance(pubkey, ec.EllipticCurvePublicKey):
pubkey.verify(signature, digest, ec.ECDSA(hashes.SHA3_512())) # TODO: What should I detect here? Should I use `verify` as an entry point?
pubkey.verify(signature, digest, ec.ECDSA(hashes.SHA3_512()))
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def decrypt(ciphertext):
plaintext = private_key.decrypt(
ciphertext,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
mgf=padding.MGF1(algorithm=hashes.SHA384()),
algorithm=hashes.SHA256(),
label=None
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,23 @@
import com.ibm.plugin.TestBase;
import java.util.List;
import javax.annotation.Nonnull;
import org.junit.Test;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.sonar.plugins.python.api.PythonCheck;
import org.sonar.plugins.python.api.PythonVisitorContext;
import org.sonar.plugins.python.api.symbols.Symbol;
import org.sonar.plugins.python.api.tree.Tree;
import org.sonar.python.checks.utils.PythonCheckVerifier;

public class PycaEllipticCurveVerifyTest extends TestBase {
@Disabled // TODO: Reenable once we have an approach to detect `verify` (either make it an entry
// point, or better handle file imports for depending detection rule)

@Disabled(
"Reenable once we have an approach to detect `verify` (either make it an entry\n"
+ "point, or better handle file imports for depending detection rule)")
@Test
void test() {
public void test() {
PythonCheckVerifier.verify(
"src/test/files/rules/detection/asymmetric/EllipticCurve/CryptographyEllipticCurveVerifyTestFile.py",
"src/test/files/rules/detection/asymmetric/EllipticCurve/PycallipticCurveVerifyTestFile.py",
this);
}

Expand All @@ -47,6 +49,6 @@ public void asserts(
int findingId,
@Nonnull DetectionStore<PythonCheck, Tree, Symbol, PythonVisitorContext> detectionStore,
@Nonnull List<INode> nodes) {
// TODO:
// TODO
}
}
Loading

0 comments on commit d864bff

Please sign in to comment.