|
2 | 2 |
|
3 | 3 | import java.io.ByteArrayInputStream;
|
4 | 4 | import java.io.ByteArrayOutputStream;
|
| 5 | +import java.io.InputStreamReader; |
5 | 6 | import java.io.IOException;
|
6 | 7 | import java.io.ObjectInputStream;
|
7 | 8 | import java.io.ObjectOutputStream;
|
|
60 | 61 | import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
|
61 | 62 | import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
|
62 | 63 | import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
|
| 64 | +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; |
63 | 65 | import org.bouncycastle.asn1.pkcs.RSAPublicKey;
|
64 | 66 | import org.bouncycastle.asn1.x500.X500Name;
|
65 | 67 | import org.bouncycastle.asn1.x500.X500NameBuilder;
|
|
102 | 104 | import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
|
103 | 105 | import org.bouncycastle.jcajce.CompositePrivateKey;
|
104 | 106 | import org.bouncycastle.jcajce.CompositePublicKey;
|
| 107 | +import org.bouncycastle.jcajce.provider.asymmetric.compositesignatures.CompositeSignaturesConstants; |
105 | 108 | import org.bouncycastle.jcajce.spec.CompositeAlgorithmSpec;
|
106 | 109 | import org.bouncycastle.jce.X509KeyUsage;
|
107 | 110 | import org.bouncycastle.jce.interfaces.ECPointEncoder;
|
|
112 | 115 | import org.bouncycastle.jce.spec.ECPublicKeySpec;
|
113 | 116 | import org.bouncycastle.jce.spec.GOST3410ParameterSpec;
|
114 | 117 | import org.bouncycastle.math.ec.ECCurve;
|
| 118 | +import org.bouncycastle.openssl.PEMParser; |
115 | 119 | import org.bouncycastle.operator.ContentSigner;
|
116 | 120 | import org.bouncycastle.operator.ContentVerifierProvider;
|
117 | 121 | import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
|
118 | 122 | import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
|
| 123 | +import org.bouncycastle.operator.OperatorCreationException; |
119 | 124 | import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder;
|
120 | 125 | import org.bouncycastle.operator.bc.BcRSAContentVerifierProviderBuilder;
|
121 | 126 | import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
|
137 | 142 | import org.bouncycastle.util.encoders.Base64;
|
138 | 143 | import org.bouncycastle.util.encoders.Hex;
|
139 | 144 | import org.bouncycastle.util.test.SimpleTest;
|
| 145 | +import org.bouncycastle.util.test.TestFailedException; |
140 | 146 |
|
141 | 147 | public class CertTest
|
142 | 148 | extends SimpleTest
|
@@ -2953,7 +2959,7 @@ public void checkCRLCompositeCreation()
|
2953 | 2959 | // null comp test
|
2954 | 2960 | try
|
2955 | 2961 | {
|
2956 |
| - crl.verify(new CompositePublicKey(null, null)); |
| 2962 | + crl.verify(new CompositePublicKey(new PublicKey[]{null, null})); |
2957 | 2963 | }
|
2958 | 2964 | catch (InvalidKeyException e)
|
2959 | 2965 | {
|
@@ -4567,7 +4573,7 @@ public void checkCreationComposite()
|
4567 | 4573 | {
|
4568 | 4574 | vProv = new JcaContentVerifierProviderBuilder()
|
4569 | 4575 | .setProvider(BC)
|
4570 |
| - .build(new CompositePublicKey(null, null)); |
| 4576 | + .build(new CompositePublicKey(new PublicKey[]{null, null})); |
4571 | 4577 |
|
4572 | 4578 | certHldr.isSignatureValid(vProv);
|
4573 | 4579 | }
|
@@ -4596,7 +4602,7 @@ public void checkCreationComposite()
|
4596 | 4602 | // null comp test
|
4597 | 4603 | try
|
4598 | 4604 | {
|
4599 |
| - cert.verify(new CompositePublicKey(null, null)); |
| 4605 | + cert.verify(new CompositePublicKey(new PublicKey[]{null, null})); |
4600 | 4606 | }
|
4601 | 4607 | catch (InvalidKeyException e)
|
4602 | 4608 | {
|
@@ -5417,6 +5423,132 @@ private void checkSerialisation()
|
5417 | 5423 | doSerialize(attrHolder);
|
5418 | 5424 | }
|
5419 | 5425 |
|
| 5426 | + // TESTS REGARDING COMPOSITES https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html |
| 5427 | + private static String[] compositeSignaturesOIDs = { |
| 5428 | + "2.16.840.1.114027.80.8.1.1", //id-MLDSA44-RSA2048-PSS-SHA256 |
| 5429 | + "2.16.840.1.114027.80.8.1.2", //id-MLDSA44-RSA2048-PKCS15-SHA256 |
| 5430 | + "2.16.840.1.114027.80.8.1.3", //id-MLDSA44-Ed25519-SHA512 |
| 5431 | + "2.16.840.1.114027.80.8.1.4", //id-MLDSA44-ECDSA-P256-SHA256 |
| 5432 | + "2.16.840.1.114027.80.8.1.5", //id-MLDSA44-ECDSA-brainpoolP256r1-SHA256 |
| 5433 | + "2.16.840.1.114027.80.8.1.6", //id-MLDSA65-RSA3072-PSS-SHA512 |
| 5434 | + "2.16.840.1.114027.80.8.1.7", //id-MLDSA65-RSA3072-PKCS15-SHA512 |
| 5435 | + "2.16.840.1.114027.80.8.1.8", //id-MLDSA65-ECDSA-P256-SHA512 |
| 5436 | + "2.16.840.1.114027.80.8.1.9", //id-MLDSA65-ECDSA-brainpoolP256r1-SHA512 |
| 5437 | + "2.16.840.1.114027.80.8.1.10", //id-MLDSA65-Ed25519-SHA512 |
| 5438 | + "2.16.840.1.114027.80.8.1.11", //id-MLDSA87-ECDSA-P384-SHA512 |
| 5439 | + "2.16.840.1.114027.80.8.1.12", //id-MLDSA87-ECDSA-brainpoolP384r1-SHA512 |
| 5440 | + "2.16.840.1.114027.80.8.1.13", //id-MLDSA87-Ed448-SHA512 |
| 5441 | + // Falcon composites below were excluded from the draft. See MiscObjectIdentifiers for details. |
| 5442 | + "2.16.840.1.114027.80.8.1.14", //id-Falcon512-ECDSA-P256-SHA256 |
| 5443 | + "2.16.840.1.114027.80.8.1.15", //id-Falcon512-ECDSA-brainpoolP256r1-SHA256 |
| 5444 | + "2.16.840.1.114027.80.8.1.16", //id-Falcon512-Ed25519-SHA512 |
| 5445 | + }; |
| 5446 | + |
| 5447 | + private void checkCompositeSignatureCertificateCreation() |
| 5448 | + { |
| 5449 | + try |
| 5450 | + { |
| 5451 | + for (String oid : compositeSignaturesOIDs) |
| 5452 | + { |
| 5453 | + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(oid, "BC"); |
| 5454 | + KeyPair keyPair = keyPairGenerator.generateKeyPair(); |
| 5455 | + |
| 5456 | + String subjectName = "CN=ROOT CA"; |
| 5457 | + X500Name issuer = new X500Name(subjectName); |
| 5458 | + BigInteger serial = BigInteger.valueOf(5); |
| 5459 | + Date notBefore = new Date(); |
| 5460 | + Date notAfter = new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 365L); |
| 5461 | + X500Name subject = new X500Name(subjectName); |
| 5462 | + |
| 5463 | + JcaX509v3CertificateBuilder certificateBuilder = new JcaX509v3CertificateBuilder(issuer, serial, notBefore, notAfter, subject, keyPair.getPublic()); |
| 5464 | + X509CertificateHolder certHolder = certificateBuilder.build(new JcaContentSignerBuilder(oid).build(keyPair.getPrivate())); |
| 5465 | + X509Certificate cert = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certHolder); |
| 5466 | + |
| 5467 | + isEquals(oid, cert.getSigAlgOID()); |
| 5468 | + CompositePublicKey compositePublicKey = (CompositePublicKey) cert.getPublicKey(); |
| 5469 | + isEquals(CompositeSignaturesConstants.ASN1IdentifierAlgorithmNameMap.get(new ASN1ObjectIdentifier(oid)), compositePublicKey.getAlgorithm()); |
| 5470 | + |
| 5471 | + isEquals(subjectName, cert.getSubjectX500Principal().getName()); |
| 5472 | + |
| 5473 | + cert.verify(cert.getPublicKey()); |
| 5474 | + |
| 5475 | + } |
| 5476 | + } |
| 5477 | + catch (NoSuchAlgorithmException | NoSuchProviderException | CertificateException | OperatorCreationException | |
| 5478 | + SignatureException | InvalidKeyException | TestFailedException e) |
| 5479 | + { |
| 5480 | + fail("checkCompositeSignatureCertificateCreation failed: " + e.getMessage()); |
| 5481 | + } |
| 5482 | + } |
| 5483 | + |
| 5484 | + private void checkParseCompositePublicKey() |
| 5485 | + { |
| 5486 | + try |
| 5487 | + { |
| 5488 | + //compositePublicKeyExampleRFC.pem contains the sample public key from https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html |
| 5489 | + PEMParser pemParser = new PEMParser(new InputStreamReader(this.getClass().getResourceAsStream("compositePublicKeyExampleRFC.pem"))); |
| 5490 | + SubjectPublicKeyInfo subjectPublicKeyInfo = (SubjectPublicKeyInfo) pemParser.readObject(); |
| 5491 | + isEquals(subjectPublicKeyInfo.getAlgorithm().getAlgorithm(), MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256); |
| 5492 | + |
| 5493 | + CompositePublicKey compositePublicKey = new CompositePublicKey(subjectPublicKeyInfo); |
| 5494 | + |
| 5495 | + isEquals(compositePublicKey.getPublicKeys().get(0).getAlgorithm(), "DILITHIUM2"); |
| 5496 | + isEquals(compositePublicKey.getPublicKeys().get(1).getAlgorithm(), "ECDSA"); |
| 5497 | + } |
| 5498 | + catch (Exception e) |
| 5499 | + { |
| 5500 | + fail("checkParseCompositePublicKey failed: " + e.getMessage()); |
| 5501 | + } |
| 5502 | + } |
| 5503 | + |
| 5504 | + private void checkParseCompositePrivateKey() |
| 5505 | + { |
| 5506 | + try |
| 5507 | + { |
| 5508 | + //compositePrivateKeyExample.pem does NOT contain the sample private key from https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html |
| 5509 | + //because the at this moment, the Dilithium private key formats don't match. |
| 5510 | + //this sample was generated from this BC implementation |
| 5511 | + PEMParser pemParser = new PEMParser(new InputStreamReader(this.getClass().getResourceAsStream("compositePrivateKeyExample.pem"))); |
| 5512 | + PrivateKeyInfo privateKeyInfo = (PrivateKeyInfo) pemParser.readObject(); |
| 5513 | + |
| 5514 | + isEquals(privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm(), MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256); |
| 5515 | + |
| 5516 | + CompositePrivateKey compositePrivateKey = new CompositePrivateKey(privateKeyInfo); |
| 5517 | + |
| 5518 | + isEquals(compositePrivateKey.getPrivateKeys().get(0).getAlgorithm(), "DILITHIUM2"); |
| 5519 | + isEquals(compositePrivateKey.getPrivateKeys().get(1).getAlgorithm(), "ECDSA"); |
| 5520 | + } |
| 5521 | + catch (Exception e) |
| 5522 | + { |
| 5523 | + fail("checkParseCompositePrivateKey failed: " + e.getMessage()); |
| 5524 | + } |
| 5525 | + } |
| 5526 | + |
| 5527 | + private void checkParseAndVerifyCompositeCertificate() |
| 5528 | + { |
| 5529 | + try |
| 5530 | + { |
| 5531 | + //compositeCertificateExampleRFC.pem contains the sample certificate from https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html |
| 5532 | + PEMParser pemParser = new PEMParser(new InputStreamReader(this.getClass().getResourceAsStream("compositeCertificateExampleRFC.pem"))); |
| 5533 | + X509CertificateHolder certificateHolder = (X509CertificateHolder) pemParser.readObject(); |
| 5534 | + JcaX509CertificateConverter x509Converter = new JcaX509CertificateConverter().setProvider("BC"); |
| 5535 | + X509Certificate certificate = x509Converter.getCertificate(certificateHolder); |
| 5536 | + |
| 5537 | + isEquals(certificate.getSigAlgOID(), MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256.toString()); |
| 5538 | + |
| 5539 | + CompositePublicKey compositePublicKey = (CompositePublicKey) certificate.getPublicKey(); |
| 5540 | + |
| 5541 | + isEquals(compositePublicKey.getPublicKeys().get(0).getAlgorithm(), "DILITHIUM2"); |
| 5542 | + isEquals(compositePublicKey.getPublicKeys().get(1).getAlgorithm(), "ECDSA"); |
| 5543 | + |
| 5544 | + certificate.verify(compositePublicKey); |
| 5545 | + } |
| 5546 | + catch (Exception e) |
| 5547 | + { |
| 5548 | + fail("checkParseAndVerifyCompositeCertificate failed: " + e.getMessage()); |
| 5549 | + } |
| 5550 | + } |
| 5551 | + |
5420 | 5552 | private void doSerialize(Serializable encodable)
|
5421 | 5553 | throws Exception
|
5422 | 5554 | {
|
@@ -5565,6 +5697,11 @@ public void performTest()
|
5565 | 5697 | zeroDataTest();
|
5566 | 5698 |
|
5567 | 5699 | checkSerialisation();
|
| 5700 | + |
| 5701 | + checkCompositeSignatureCertificateCreation(); |
| 5702 | + checkParseCompositePublicKey(); |
| 5703 | + checkParseCompositePrivateKey(); |
| 5704 | + checkParseAndVerifyCompositeCertificate(); |
5568 | 5705 | }
|
5569 | 5706 |
|
5570 | 5707 | private Extensions generateExtensions(Vector oids, Vector values)
|
|
0 commit comments