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 @@ -47,7 +47,6 @@
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.w3c.dom.Document;
Expand Down Expand Up @@ -131,23 +130,33 @@ void testMLDSASignAndVerify(String signatureAlgorithmURI, String alias) throws E
assertValidSignatureWithJcpApi(signedXml, false);
}

@Test
void testMLDSATamperedSignatureRejected() throws Exception {
@ParameterizedTest
@CsvSource({
XMLSignature.ALGO_ID_SIGNATURE_MLDSA_44 + ",ml-dsa-44",
XMLSignature.ALGO_ID_SIGNATURE_MLDSA_65 + ",ml-dsa-65",
XMLSignature.ALGO_ID_SIGNATURE_MLDSA_87 + ",ml-dsa-87",
})
void testMLDSATamperedSignatureRejected(String signatureAlgorithmURI, String alias) throws Exception {
Assumptions.assumeTrue(mlDsaAvailable, "ML-DSA requires BouncyCastle 1.81+");
byte[] signedXml = doSignWithJcpApi(XMLSignature.ALGO_ID_SIGNATURE_MLDSA_65, "ml-dsa-65", false);
byte[] signedXml = doSignWithJcpApi(signatureAlgorithmURI, alias, false);

byte[] tamperedXml = flipByteInSignatureValue(signedXml);

boolean coreValidity = validateSignatureWithJcpApi(tamperedXml, new KeySelectors.RawX509KeySelector());
Assertions.assertFalse(coreValidity, "A tampered SignatureValue must not validate");
}

@Test
void testMLDSAWrongPublicKeyRejected() throws Exception {
@ParameterizedTest
@CsvSource({
XMLSignature.ALGO_ID_SIGNATURE_MLDSA_44 + ",ml-dsa-44",
XMLSignature.ALGO_ID_SIGNATURE_MLDSA_65 + ",ml-dsa-65",
XMLSignature.ALGO_ID_SIGNATURE_MLDSA_87 + ",ml-dsa-87",
})
void testMLDSAWrongPublicKeyRejected(String signatureAlgorithmURI, String alias) throws Exception {
Assumptions.assumeTrue(mlDsaAvailable, "ML-DSA requires BouncyCastle 1.81+");
byte[] signedXml = doSignWithJcpApi(XMLSignature.ALGO_ID_SIGNATURE_MLDSA_65, "ml-dsa-65", false);
byte[] signedXml = doSignWithJcpApi(signatureAlgorithmURI, alias, false);

KeyPairGenerator kpg = KeyPairGenerator.getInstance("ML-DSA-65", "BC");
KeyPairGenerator kpg = KeyPairGenerator.getInstance(alias.toUpperCase(), "BC");
PublicKey wrongPublicKey = kpg.generateKeyPair().getPublic();

KeySelector wrongKeySelector = new KeySelector() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.w3c.dom.Document;
Expand Down Expand Up @@ -109,44 +108,54 @@ void testMLDSASign(String sigAlgorithm, String jcaAlgorithm) throws Exception {
verifyUsingDOM(document, kp.getPublic(), properties.getSignatureSecureParts());
}

@Test
void testMLDSAStaxTamperedSignatureRejected() throws Exception {
Assumptions.assumeTrue(isBcInstalled() && keyPairs.containsKey("ML-DSA-65"),
@ParameterizedTest
@CsvSource({
"http://www.w3.org/tbd#ml-dsa-44,ML-DSA-44",
"http://www.w3.org/tbd#ml-dsa-65,ML-DSA-65",
"http://www.w3.org/tbd#ml-dsa-87,ML-DSA-87"
})
void testMLDSAStaxTamperedSignatureRejected(String sigAlgorithm, String jcaAlgorithm) throws Exception {
Assumptions.assumeTrue(isBcInstalled() && keyPairs.containsKey(jcaAlgorithm),
"ML-DSA requires BouncyCastle 1.81+");

Document document = signWithMLDSA65();
Document document = signWith(sigAlgorithm, jcaAlgorithm);
Element sigElement = tamperSignatureValue(document);

XMLSignature signature = new XMLSignature(sigElement, "");
boolean coreValidity = signature.checkSignatureValue(keyPairs.get("ML-DSA-65").getPublic());
boolean coreValidity = signature.checkSignatureValue(keyPairs.get(jcaAlgorithm).getPublic());
Assertions.assertFalse(coreValidity, "A tampered SignatureValue must not validate");
}

@Test
void testMLDSAStaxWrongPublicKeyRejected() throws Exception {
Assumptions.assumeTrue(isBcInstalled() && keyPairs.containsKey("ML-DSA-65"),
@ParameterizedTest
@CsvSource({
"http://www.w3.org/tbd#ml-dsa-44,ML-DSA-44",
"http://www.w3.org/tbd#ml-dsa-65,ML-DSA-65",
"http://www.w3.org/tbd#ml-dsa-87,ML-DSA-87"
})
void testMLDSAStaxWrongPublicKeyRejected(String sigAlgorithm, String jcaAlgorithm) throws Exception {
Assumptions.assumeTrue(isBcInstalled() && keyPairs.containsKey(jcaAlgorithm),
"ML-DSA requires BouncyCastle 1.81+");

Document document = signWithMLDSA65();
Document document = signWith(sigAlgorithm, jcaAlgorithm);
Element sigElement = (Element) document.getElementsByTagNameNS(Constants.SignatureSpecNS, "Signature").item(0);

KeyPairGenerator kpg = KeyPairGenerator.getInstance("ML-DSA-65", "BC");
KeyPairGenerator kpg = KeyPairGenerator.getInstance(jcaAlgorithm, "BC");
PublicKey wrongPublicKey = kpg.generateKeyPair().getPublic();

XMLSignature signature = new XMLSignature(sigElement, "");
boolean coreValidity = signature.checkSignatureValue(wrongPublicKey);
Assertions.assertFalse(coreValidity, "Verification against the wrong public key must not validate");
}

private Document signWithMLDSA65() throws Exception {
private Document signWith(String sigAlgorithm, String jcaAlgorithm) throws Exception {
XMLSecurityProperties properties = new XMLSecurityProperties();
List<XMLSecurityConstants.Action> actions = new ArrayList<>();
actions.add(XMLSecurityConstants.SIGNATURE);
properties.setActions(actions);
properties.setSignatureKeyIdentifier(SecurityTokenConstants.KeyIdentifier_KeyValue);
properties.setSignatureAlgorithm("http://www.w3.org/tbd#ml-dsa-65");
properties.setSignatureAlgorithm(sigAlgorithm);

KeyPair kp = keyPairs.get("ML-DSA-65");
KeyPair kp = keyPairs.get(jcaAlgorithm);
properties.setSignatureKey(kp.getPrivate());
properties.setSignatureVerificationKey(kp.getPublic());

Expand Down