|
4 | 4 | import java.io.ByteArrayInputStream; |
5 | 5 | import java.io.InputStream; |
6 | 6 | import java.io.InputStreamReader; |
| 7 | +import java.security.InvalidKeyException; |
7 | 8 | import java.security.KeyFactory; |
8 | 9 | import java.security.KeyPair; |
9 | 10 | import java.security.KeyPairGenerator; |
|
37 | 38 | import org.bouncycastle.jcajce.CompositePrivateKey; |
38 | 39 | import org.bouncycastle.jcajce.CompositePublicKey; |
39 | 40 | import org.bouncycastle.jcajce.interfaces.MLDSAPrivateKey; |
| 41 | +import org.bouncycastle.jcajce.interfaces.MLDSAPublicKey; |
40 | 42 | import org.bouncycastle.jcajce.provider.asymmetric.compositesignatures.CompositeIndex; |
41 | 43 | import org.bouncycastle.jcajce.provider.asymmetric.mldsa.BCMLDSAPublicKey; |
42 | 44 | import org.bouncycastle.jcajce.spec.CompositeSignatureSpec; |
@@ -338,7 +340,70 @@ public void testMixedComposition() |
338 | 340 | signature.update(Strings.toUTF8ByteArray(messageToBeSigned)); |
339 | 341 | TestCase.assertTrue(signature.verify(signatureValue)); |
340 | 342 |
|
| 343 | + // |
| 344 | + // as COMPOSITE on sig creation |
| 345 | + // |
| 346 | + compPublicKey = CompositePublicKey.builder(BCObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256) |
| 347 | + .addPublicKey(mldsaKp.getPublic(), "BC") |
| 348 | + .addPublicKey(ecKp.getPublic(), "SunEC") |
| 349 | + .build(); |
| 350 | + compPrivateKey = CompositePrivateKey.builder(BCObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256) |
| 351 | + .addPrivateKey(mldsaKp.getPrivate(), "BC") |
| 352 | + .addPrivateKey(ecKp.getPrivate(), "SunEC") |
| 353 | + .build(); |
| 354 | + |
| 355 | + signature = Signature.getInstance("COMPOSITE", "BC"); |
| 356 | + |
| 357 | + signature.initSign(compPriv); |
| 358 | + signature.update(Strings.toUTF8ByteArray(messageToBeSigned)); |
| 359 | + signatureValue = signature.sign(); |
341 | 360 |
|
| 361 | + signature = Signature.getInstance(BCObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256.getId(), "BC"); |
| 362 | + signature.initVerify(compPub); |
| 363 | + signature.update(Strings.toUTF8ByteArray(messageToBeSigned)); |
| 364 | + TestCase.assertTrue(signature.verify(signatureValue)); |
| 365 | + } |
| 366 | + |
| 367 | + public void testMixedCompositionHSMStyle() |
| 368 | + throws Exception |
| 369 | + { |
| 370 | + if (Security.getProvider("SunEC") == null) |
| 371 | + { |
| 372 | + return; |
| 373 | + } |
| 374 | + KeyPairGenerator mldsaKpGen = KeyPairGenerator.getInstance("ML-DSA", "BC"); |
| 375 | + |
| 376 | + mldsaKpGen.initialize(MLDSAParameterSpec.ml_dsa_44); |
| 377 | + |
| 378 | + KeyPair mldsaKp = mldsaKpGen.generateKeyPair(); |
| 379 | + |
| 380 | + KeyPairGenerator ecKpGen = KeyPairGenerator.getInstance("EC", "SunEC"); |
| 381 | + |
| 382 | + ecKpGen.initialize(new ECGenParameterSpec("secp256r1")); |
| 383 | + |
| 384 | + KeyPair ecKp = ecKpGen.generateKeyPair(); |
| 385 | + |
| 386 | + CompositePublicKey compPublicKey = CompositePublicKey.builder(BCObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256) |
| 387 | + .addPublicKey(mldsaKp.getPublic(), "BC") |
| 388 | + .addPublicKey(ecKp.getPublic(), "SunEC") |
| 389 | + .build(); |
| 390 | + CompositePrivateKey compPrivateKey = CompositePrivateKey.builder(BCObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256) |
| 391 | + .addPrivateKey(new ProxyHSMPrivateKey((MLDSAPrivateKey)mldsaKp.getPrivate()), "BC") |
| 392 | + .addPrivateKey(ecKp.getPrivate(), "SunEC") |
| 393 | + .build(); |
| 394 | + |
| 395 | + Signature signature = Signature.getInstance("COMPOSITE", "BC"); |
| 396 | + |
| 397 | + try |
| 398 | + { |
| 399 | + signature.initSign(compPrivateKey); |
| 400 | + fail("proxy HSM key did not fail with BC"); |
| 401 | + } |
| 402 | + catch (InvalidKeyException e) |
| 403 | + { |
| 404 | + // we want to make sure it got at least as far as passing key to ML-DSA implementation |
| 405 | + assertEquals("unknown private key passed to ML-DSA", e.getMessage()); |
| 406 | + } |
342 | 407 | } |
343 | 408 |
|
344 | 409 | public void testMixedCompositionWithNull() |
@@ -808,4 +873,63 @@ private static String extractString(String json, String key) |
808 | 873 |
|
809 | 874 | return json.substring(start, end).replace("\\\"", "\""); |
810 | 875 | } |
| 876 | + |
| 877 | + private static class ProxyHSMPrivateKey |
| 878 | + implements MLDSAPrivateKey |
| 879 | + { |
| 880 | + private final MLDSAPrivateKey privateKey; |
| 881 | + |
| 882 | + ProxyHSMPrivateKey(MLDSAPrivateKey privateKey) |
| 883 | + { |
| 884 | + this.privateKey = privateKey; |
| 885 | + } |
| 886 | + |
| 887 | + @Override |
| 888 | + public String getAlgorithm() |
| 889 | + { |
| 890 | + return privateKey.getAlgorithm(); |
| 891 | + } |
| 892 | + |
| 893 | + @Override |
| 894 | + public String getFormat() |
| 895 | + { |
| 896 | + throw new IllegalStateException("getFormat() called"); |
| 897 | + } |
| 898 | + |
| 899 | + @Override |
| 900 | + public byte[] getEncoded() |
| 901 | + { |
| 902 | + throw new IllegalStateException("getEncoded() called"); |
| 903 | + } |
| 904 | + |
| 905 | + @Override |
| 906 | + public MLDSAParameterSpec getParameterSpec() |
| 907 | + { |
| 908 | + return privateKey.getParameterSpec(); |
| 909 | + } |
| 910 | + |
| 911 | + @Override |
| 912 | + public MLDSAPublicKey getPublicKey() |
| 913 | + { |
| 914 | + return privateKey.getPublicKey(); |
| 915 | + } |
| 916 | + |
| 917 | + @Override |
| 918 | + public byte[] getPrivateData() |
| 919 | + { |
| 920 | + throw new IllegalStateException("getPrivateData() called"); |
| 921 | + } |
| 922 | + |
| 923 | + @Override |
| 924 | + public byte[] getSeed() |
| 925 | + { |
| 926 | + throw new IllegalStateException("getSeed() called"); |
| 927 | + } |
| 928 | + |
| 929 | + @Override |
| 930 | + public MLDSAPrivateKey getPrivateKey(boolean preferSeedOnly) |
| 931 | + { |
| 932 | + throw new IllegalStateException("getPrivateKey() called"); |
| 933 | + } |
| 934 | + } |
811 | 935 | } |
0 commit comments