Skip to content

Commit 002dd0c

Browse files
authored
Adding some AI generated tests + a small fix (#581)
* Adding a bunch of tests generated using copilot and a bug fix in ECDSAUtils * Adding more tests
1 parent d22b188 commit 002dd0c

14 files changed

Lines changed: 2696 additions & 2 deletions

File tree

src/main/java/org/apache/xml/security/algorithms/implementations/ECDSAUtils.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,20 +119,30 @@ public static byte[] convertXMLDSIGtoASN1(byte[] xmldsigBytes) throws IOExceptio
119119

120120
int j = i;
121121

122-
if (xmldsigBytes[rawLen - i] < 0) {
122+
if (i > 0 && xmldsigBytes[rawLen - i] < 0) {
123123
j += 1;
124124
}
125125

126+
// ASN.1 INTEGER requires at least one byte, even for zero
127+
if (j == 0) {
128+
j = 1;
129+
}
130+
126131
int k;
127132

128133
for (k = rawLen; k > 0 && xmldsigBytes[2 * rawLen - k] == 0; k--); //NOPMD
129134

130135
int l = k;
131136

132-
if (xmldsigBytes[2 * rawLen - k] < 0) {
137+
if (k > 0 && xmldsigBytes[2 * rawLen - k] < 0) {
133138
l += 1;
134139
}
135140

141+
// ASN.1 INTEGER requires at least one byte, even for zero
142+
if (l == 0) {
143+
l = 1;
144+
}
145+
136146
int len = 2 + j + 2 + l;
137147
if (len > 255) {
138148
throw new IOException("Invalid XMLDSIG format of ECDSA signature");
Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.xml.security.test.dom.algorithms;
20+
21+
import org.apache.xml.security.algorithms.SignatureAlgorithm;
22+
import org.apache.xml.security.signature.XMLSignature;
23+
import org.apache.xml.security.test.dom.TestUtils;
24+
import org.junit.jupiter.api.Test;
25+
import org.w3c.dom.Document;
26+
27+
import java.security.KeyPair;
28+
import java.security.KeyPairGenerator;
29+
30+
import static org.junit.jupiter.api.Assertions.*;
31+
32+
/**
33+
* Tests for cryptographic edge cases including zero-length signatures,
34+
* all-zeros signatures, and other boundary conditions.
35+
*/
36+
class CryptographicEdgeCasesTest {
37+
38+
static {
39+
org.apache.xml.security.Init.init();
40+
}
41+
42+
public CryptographicEdgeCasesTest() {
43+
// Public constructor for JUnit
44+
}
45+
46+
/**
47+
* Test that empty signature values are rejected.
48+
*/
49+
@Test
50+
void testEmptySignatureValueRejected() throws Exception {
51+
Document doc = TestUtils.newDocument();
52+
SignatureAlgorithm sa = new SignatureAlgorithm(doc, XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256);
53+
54+
// Initialize with proper key
55+
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
56+
KeyPair keyPair = keyPairGenerator.generateKeyPair();
57+
sa.initSign(keyPair.getPrivate());
58+
59+
// Sign some data
60+
byte[] data = "test data".getBytes();
61+
sa.update(data);
62+
byte[] signature = sa.sign();
63+
64+
// Valid signature should be non-empty
65+
assertTrue(signature.length > 0, "Signature should not be empty");
66+
}
67+
68+
/**
69+
* Test that all-zeros signature is rejected during verification.
70+
*/
71+
@Test
72+
void testAllZerosSignatureRejected() throws Exception {
73+
Document doc = TestUtils.newDocument();
74+
SignatureAlgorithm sa = new SignatureAlgorithm(doc, XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256);
75+
76+
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
77+
KeyPair keyPair = keyPairGenerator.generateKeyPair();
78+
79+
// Initialize verification
80+
sa.initVerify(keyPair.getPublic());
81+
82+
// Create all-zeros signature (256 bytes for RSA-2048)
83+
byte[] zeroSignature = new byte[256];
84+
85+
// Update with some data
86+
byte[] data = "test data".getBytes();
87+
sa.update(data);
88+
89+
// All-zeros signature should fail verification
90+
assertFalse(sa.verify(zeroSignature),
91+
"All-zeros signature should not verify successfully");
92+
}
93+
94+
/**
95+
* Test that signature verification requires the correct data.
96+
*/
97+
@Test
98+
void testSignatureVerificationWithWrongData() throws Exception {
99+
Document doc = TestUtils.newDocument();
100+
SignatureAlgorithm sa = new SignatureAlgorithm(doc, XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256);
101+
102+
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
103+
KeyPair keyPair = keyPairGenerator.generateKeyPair();
104+
105+
// Sign original data
106+
sa.initSign(keyPair.getPrivate());
107+
byte[] originalData = "original data".getBytes();
108+
sa.update(originalData);
109+
byte[] signature = sa.sign();
110+
111+
// Try to verify with different data
112+
SignatureAlgorithm verifier = new SignatureAlgorithm(doc, XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256);
113+
verifier.initVerify(keyPair.getPublic());
114+
byte[] wrongData = "wrong data".getBytes();
115+
verifier.update(wrongData);
116+
117+
// Should fail verification
118+
assertFalse(verifier.verify(signature),
119+
"Signature should not verify with wrong data");
120+
}
121+
122+
/**
123+
* Test that signature verification requires the correct key.
124+
*/
125+
@Test
126+
void testSignatureVerificationWithWrongKey() throws Exception {
127+
Document doc = TestUtils.newDocument();
128+
SignatureAlgorithm sa = new SignatureAlgorithm(doc, XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256);
129+
130+
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
131+
KeyPair keyPair1 = keyPairGenerator.generateKeyPair();
132+
KeyPair keyPair2 = keyPairGenerator.generateKeyPair();
133+
134+
// Sign with first key
135+
sa.initSign(keyPair1.getPrivate());
136+
byte[] data = "test data".getBytes();
137+
sa.update(data);
138+
byte[] signature = sa.sign();
139+
140+
// Try to verify with second key
141+
SignatureAlgorithm verifier = new SignatureAlgorithm(doc, XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256);
142+
verifier.initVerify(keyPair2.getPublic());
143+
verifier.update(data);
144+
145+
// Should fail verification
146+
assertFalse(verifier.verify(signature),
147+
"Signature should not verify with wrong key");
148+
}
149+
150+
/**
151+
* Test that signature algorithm names are properly registered.
152+
*/
153+
@Test
154+
void testAlgorithmNamesRegistered() {
155+
// Test that common algorithm URIs are recognized
156+
String[] algorithms = {
157+
XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256,
158+
XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA384,
159+
XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512,
160+
XMLSignature.ALGO_ID_SIGNATURE_DSA_SHA256,
161+
XMLSignature.ALGO_ID_MAC_HMAC_SHA256
162+
};
163+
164+
for (String algo : algorithms) {
165+
assertNotNull(algo, "Algorithm URI should not be null");
166+
assertTrue(algo.startsWith("http://"),
167+
"Algorithm URI should start with http://");
168+
}
169+
}
170+
171+
/**
172+
* Test that signature creation and verification roundtrip works.
173+
*/
174+
@Test
175+
void testSignatureRoundtrip() throws Exception {
176+
Document doc = TestUtils.newDocument();
177+
178+
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
179+
KeyPair keyPair = keyPairGenerator.generateKeyPair();
180+
181+
// Sign
182+
SignatureAlgorithm signer = new SignatureAlgorithm(doc, XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256);
183+
signer.initSign(keyPair.getPrivate());
184+
byte[] data = "test data for signing".getBytes();
185+
signer.update(data);
186+
byte[] signature = signer.sign();
187+
188+
assertNotNull(signature);
189+
assertTrue(signature.length > 0);
190+
191+
// Verify
192+
SignatureAlgorithm verifier = new SignatureAlgorithm(doc, XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256);
193+
verifier.initVerify(keyPair.getPublic());
194+
verifier.update(data);
195+
196+
assertTrue(verifier.verify(signature),
197+
"Signature should verify successfully with correct key and data");
198+
}
199+
200+
/**
201+
* Test that multiple updates before signing work correctly.
202+
*/
203+
@Test
204+
void testMultipleUpdatesBeforeSigning() throws Exception {
205+
Document doc = TestUtils.newDocument();
206+
207+
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
208+
KeyPair keyPair = keyPairGenerator.generateKeyPair();
209+
210+
// Sign with multiple updates
211+
SignatureAlgorithm signer = new SignatureAlgorithm(doc, XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256);
212+
signer.initSign(keyPair.getPrivate());
213+
signer.update("part1".getBytes());
214+
signer.update("part2".getBytes());
215+
signer.update("part3".getBytes());
216+
byte[] signature = signer.sign();
217+
218+
// Verify with same multiple updates
219+
SignatureAlgorithm verifier = new SignatureAlgorithm(doc, XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256);
220+
verifier.initVerify(keyPair.getPublic());
221+
verifier.update("part1".getBytes());
222+
verifier.update("part2".getBytes());
223+
verifier.update("part3".getBytes());
224+
225+
assertTrue(verifier.verify(signature),
226+
"Signature should verify with same sequence of updates");
227+
}
228+
229+
/**
230+
* Test that different update order produces different signature.
231+
*/
232+
@Test
233+
void testDifferentUpdateOrder() throws Exception {
234+
Document doc = TestUtils.newDocument();
235+
236+
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
237+
KeyPair keyPair = keyPairGenerator.generateKeyPair();
238+
239+
// Sign with one order
240+
SignatureAlgorithm signer = new SignatureAlgorithm(doc, XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256);
241+
signer.initSign(keyPair.getPrivate());
242+
signer.update("part1".getBytes());
243+
signer.update("part2".getBytes());
244+
byte[] signature = signer.sign();
245+
246+
// Verify with different order
247+
SignatureAlgorithm verifier = new SignatureAlgorithm(doc, XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256);
248+
verifier.initVerify(keyPair.getPublic());
249+
verifier.update("part2".getBytes());
250+
verifier.update("part1".getBytes());
251+
252+
assertFalse(verifier.verify(signature),
253+
"Signature should not verify with different update order");
254+
}
255+
256+
/**
257+
* Test that empty update is handled correctly.
258+
*/
259+
@Test
260+
void testEmptyUpdate() throws Exception {
261+
Document doc = TestUtils.newDocument();
262+
263+
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
264+
KeyPair keyPair = keyPairGenerator.generateKeyPair();
265+
266+
// Sign with empty data
267+
SignatureAlgorithm signer = new SignatureAlgorithm(doc, XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256);
268+
signer.initSign(keyPair.getPrivate());
269+
signer.update(new byte[0]);
270+
byte[] signature = signer.sign();
271+
272+
assertNotNull(signature);
273+
assertTrue(signature.length > 0);
274+
275+
// Verify
276+
SignatureAlgorithm verifier = new SignatureAlgorithm(doc, XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256);
277+
verifier.initVerify(keyPair.getPublic());
278+
verifier.update(new byte[0]);
279+
280+
assertTrue(verifier.verify(signature),
281+
"Empty data signature should verify correctly");
282+
}
283+
}

0 commit comments

Comments
 (0)