This is an automated email from the ASF dual-hosted git repository. chrisdutz pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/plc4x.git
commit d7616bb6b79beaaf86d6a945c67a2e660a641298 Author: Christofer Dutz <[email protected]> AuthorDate: Fri Aug 14 17:37:53 2026 +0200 fix(plc4j/opcua): Make the test certificate serial a fixed DER length ChunkFactoryTest failed intermittently on off-by-one size assertions, in clusters of 20-40 cases at a time. The cause was the certificate serial: BigInteger.valueOf(new Random().nextLong()) usually encodes to 8 DER bytes but sometimes fewer, since DER strips redundant leading bytes. One byte less in the serial means one byte less in the certificate, and the expected securityHeaderSize embeds that length - so every asymmetric row for the affected key size failed at once. Measured over 400 certificates per key size: 412x3 / 413x397 at 1024 bit, 673x2 / 674x398 at 2048 bit. The serial is now a random 63-bit value, which always encodes to 8 bytes while staying unique (PinnedCertificateVerifierTest distinguishes a pinned certificate from an impostor). Keys are still generated per run; only the encoded length is deterministic, and the resulting lengths are the ones the chunk-calculation CSVs were authored against, so no expectation changed. --- .../plc4x/java/opcua/TestCertificateGenerator.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/TestCertificateGenerator.java b/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/TestCertificateGenerator.java index a633479cb9..e9e5392e89 100644 --- a/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/TestCertificateGenerator.java +++ b/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/TestCertificateGenerator.java @@ -30,7 +30,6 @@ import java.security.cert.X509Certificate; import java.util.Date; import java.util.Map; import java.util.Map.Entry; -import java.util.Random; import java.util.concurrent.TimeUnit; import javax.security.auth.x500.X500Principal; import org.bouncycastle.cert.X509CertificateHolder; @@ -42,6 +41,20 @@ import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; public class TestCertificateGenerator { + /** + * A random serial number that always encodes to the same number of DER bytes. + * <p> + * DER drops redundant leading bytes of an INTEGER, so a plain {@code Random.nextLong()} serial + * encodes to 8 bytes most of the time but occasionally to 7 or fewer - which changes the + * certificate's total DER length. Test expectations that contain a certificate's size (the + * OPC UA asymmetric security header, see ChunkFactoryTest) then fail by one byte every few + * hundred runs. Forcing the value to exactly 63 bits keeps it random and unique while pinning + * the encoded length at 8 bytes. + */ + private static BigInteger serialNumber() { + return new BigInteger(62, new SecureRandom()).setBit(62); + } + public static Entry<PrivateKey, X509Certificate> generate(int keySize, String dn, long validitySec) { try { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); @@ -50,7 +63,7 @@ public class TestCertificateGenerator { X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder( new X500Principal(dn), - BigInteger.valueOf(new Random().nextLong()), + serialNumber(), new Date(), new Date(System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(validitySec)), new X500Principal(dn),
