Skip to content

Commit 1752dbf

Browse files
committed
CMS: Basic tests for ML-DSA SignedData examples
1 parent 07ba85d commit 1752dbf

File tree

5 files changed

+219
-2
lines changed

5 files changed

+219
-2
lines changed

pkix/src/main/java/org/bouncycastle/cms/SignerInformation.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,8 @@ private boolean doVerify(
341341
SignerInformationVerifier verifier)
342342
throws CMSException
343343
{
344+
// TODO[cms] For pure signature algorithms, restrict digest algorithm to permitted set
345+
344346
String encName = CMSSignedHelper.INSTANCE.getEncryptionAlgName(this.getEncryptionAlgOID());
345347
AlgorithmIdentifier realDigestAlgorithm = signedAttributeSet != null ?
346348
info.getDigestAlgorithm() : translateBrokenRSAPkcs7(encryptionAlgorithm, info.getDigestAlgorithm());

pkix/src/test/java/org/bouncycastle/cert/test/AllTests.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,20 @@ public void setUp()
2323

2424
public void testSimpleTests()
2525
{
26-
org.bouncycastle.util.test.Test[] tests = new org.bouncycastle.util.test.Test[] { new CertTest(), new DANETest(), new PKCS10Test(), new AttrCertSelectorTest(), new AttrCertTest(), new X509ExtensionUtilsTest(),
27-
new CertPathLoopTest(), new GOST3410_2012CMSTest(), new ExternalKeyTest() };
26+
org.bouncycastle.util.test.Test[] tests = new org.bouncycastle.util.test.Test[]
27+
{
28+
new AttrCertSelectorTest(),
29+
new AttrCertTest(),
30+
new CertPathLoopTest(),
31+
new CertTest(),
32+
new DANETest(),
33+
new ExternalKeyTest(),
34+
new GOST3410_2012CMSTest(),
35+
new GOSTR3410_2012_256GenerateCertificate(),
36+
new MLDSACredentialsTest(),
37+
new PKCS10Test(),
38+
new X509ExtensionUtilsTest(),
39+
};
2840

2941
for (int i = 0; i != tests.length; i++)
3042
{
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package org.bouncycastle.cert.test;
2+
3+
import java.security.GeneralSecurityException;
4+
import java.security.PublicKey;
5+
import java.security.Security;
6+
import java.security.cert.X509Certificate;
7+
8+
import org.bouncycastle.jce.provider.BouncyCastleProvider;
9+
import org.bouncycastle.util.test.SimpleTest;
10+
11+
public class MLDSACredentialsTest
12+
extends SimpleTest
13+
{
14+
public String getName()
15+
{
16+
return "MLDSACredentials";
17+
}
18+
19+
public void performTest()
20+
throws Exception
21+
{
22+
checkSampleCredentials(SampleCredentials.ML_DSA_44);
23+
checkSampleCredentials(SampleCredentials.ML_DSA_65);
24+
checkSampleCredentials(SampleCredentials.ML_DSA_87);
25+
}
26+
27+
private static void checkSampleCredentials(SampleCredentials creds)
28+
throws GeneralSecurityException
29+
{
30+
X509Certificate cert = creds.getCertificate();
31+
PublicKey pubKey = cert.getPublicKey();
32+
cert.verify(pubKey, BouncyCastleProvider.PROVIDER_NAME);
33+
}
34+
35+
public static void main(String[] args)
36+
{
37+
Security.addProvider(new BouncyCastleProvider());
38+
39+
runTest(new MLDSACredentialsTest());
40+
}
41+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package org.bouncycastle.cert.test;
2+
3+
import java.io.BufferedInputStream;
4+
import java.io.ByteArrayInputStream;
5+
import java.io.IOException;
6+
import java.io.InputStream;
7+
import java.io.InputStreamReader;
8+
import java.io.Reader;
9+
import java.security.KeyFactory;
10+
import java.security.KeyPair;
11+
import java.security.PrivateKey;
12+
import java.security.PublicKey;
13+
import java.security.Security;
14+
import java.security.cert.CertificateFactory;
15+
import java.security.cert.X509Certificate;
16+
import java.security.spec.PKCS8EncodedKeySpec;
17+
import java.security.spec.X509EncodedKeySpec;
18+
19+
import org.bouncycastle.jce.provider.BouncyCastleProvider;
20+
import org.bouncycastle.test.TestResourceFinder;
21+
import org.bouncycastle.util.io.pem.PemObject;
22+
import org.bouncycastle.util.io.pem.PemReader;
23+
import org.junit.Assert;
24+
25+
public class SampleCredentials
26+
{
27+
public static final SampleCredentials ML_DSA_44 = load("ML-DSA-44", "pkix/cert/mldsa", "ML-DSA-44.pem");
28+
public static final SampleCredentials ML_DSA_65 = load("ML-DSA-65", "pkix/cert/mldsa", "ML-DSA-65.pem");
29+
public static final SampleCredentials ML_DSA_87 = load("ML-DSA-87", "pkix/cert/mldsa", "ML-DSA-87.pem");
30+
31+
private static PemObject expectPemObject(PemReader pemReader, String type)
32+
throws IOException
33+
{
34+
PemObject result = pemReader.readPemObject();
35+
if (!type.equals(result.getType()))
36+
{
37+
throw new IllegalStateException();
38+
}
39+
return result;
40+
}
41+
42+
private static SampleCredentials load(String algorithm, String path, String name)
43+
{
44+
try
45+
{
46+
if (Security.getProvider("BC") == null)
47+
{
48+
Security.addProvider(new BouncyCastleProvider());
49+
}
50+
51+
InputStream input = new BufferedInputStream(TestResourceFinder.findTestResource(path, name));
52+
Reader reader = new InputStreamReader(input);
53+
54+
PemReader pemReader = new PemReader(reader);
55+
PemObject pemPub = expectPemObject(pemReader, "PRIVATE KEY");
56+
PemObject pemPriv = expectPemObject(pemReader, "PUBLIC KEY");
57+
PemObject pemCert = expectPemObject(pemReader, "CERTIFICATE");
58+
pemReader.close();
59+
60+
KeyFactory kf = KeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME);
61+
CertificateFactory cf = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
62+
63+
PrivateKey privateKey = kf.generatePrivate(new PKCS8EncodedKeySpec(pemPub.getContent()));
64+
PublicKey publicKey = kf.generatePublic(new X509EncodedKeySpec(pemPriv.getContent()));
65+
KeyPair keyPair = new KeyPair(publicKey, privateKey);
66+
67+
X509Certificate certificate = (X509Certificate)cf.generateCertificate(
68+
new ByteArrayInputStream(pemCert.getContent()));
69+
70+
Assert.assertEquals(publicKey, certificate.getPublicKey());
71+
72+
return new SampleCredentials(keyPair, certificate);
73+
}
74+
catch (Exception e)
75+
{
76+
throw new RuntimeException(e);
77+
}
78+
}
79+
80+
private final KeyPair keyPair;
81+
private final X509Certificate certificate;
82+
83+
private SampleCredentials(KeyPair keyPair, X509Certificate certificate)
84+
{
85+
this.keyPair = keyPair;
86+
this.certificate = certificate;
87+
}
88+
89+
public X509Certificate getCertificate()
90+
{
91+
return certificate;
92+
}
93+
94+
public KeyPair getKeyPair()
95+
{
96+
return keyPair;
97+
}
98+
}

pkix/src/test/java/org/bouncycastle/cms/test/NewSignedDataTest.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
package org.bouncycastle.cms.test;
22

3+
import java.io.BufferedInputStream;
34
import java.io.ByteArrayInputStream;
45
import java.io.IOException;
6+
import java.io.InputStream;
7+
import java.io.InputStreamReader;
58
import java.io.OutputStream;
9+
import java.io.Reader;
610
import java.security.KeyFactory;
711
import java.security.KeyPair;
812
import java.security.MessageDigest;
@@ -68,6 +72,7 @@
6872
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
6973
import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
7074
import org.bouncycastle.cert.ocsp.OCSPResp;
75+
import org.bouncycastle.cert.test.SampleCredentials;
7176
import org.bouncycastle.cms.CMSAbsentContent;
7277
import org.bouncycastle.cms.CMSAlgorithm;
7378
import org.bouncycastle.cms.CMSAttributeTableGenerationException;
@@ -106,10 +111,13 @@
106111
import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder;
107112
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
108113
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
114+
import org.bouncycastle.test.TestResourceFinder;
109115
import org.bouncycastle.util.CollectionStore;
110116
import org.bouncycastle.util.Store;
111117
import org.bouncycastle.util.encoders.Base64;
112118
import org.bouncycastle.util.io.Streams;
119+
import org.bouncycastle.util.io.pem.PemObject;
120+
import org.bouncycastle.util.io.pem.PemReader;
113121

114122
public class NewSignedDataTest
115123
extends TestCase
@@ -689,6 +697,29 @@ public class NewSignedDataTest
689697
"CiwhMCLDeeEBOdxWZHVbIiFnnRTQqyIDGAOSSIUmjE/pMPKpPvumkCGq2r9GxPV9\n" +
690698
"YlpnThaYbDCnWg8tbWYAAAAAAAA=");
691699

700+
private static byte[] signedData_mldsa44 = loadPemContents("pkix/cms/mldsa", "SignedData_ML-DSA-44.pem");
701+
private static byte[] signedData_mldsa65 = loadPemContents("pkix/cms/mldsa", "SignedData_ML-DSA-65.pem");
702+
private static byte[] signedData_mldsa87 = loadPemContents("pkix/cms/mldsa", "SignedData_ML-DSA-87.pem");
703+
704+
private static byte[] loadPemContents(String path, String name)
705+
{
706+
try
707+
{
708+
InputStream input = new BufferedInputStream(TestResourceFinder.findTestResource(path, name));
709+
Reader reader = new InputStreamReader(input);
710+
711+
PemReader pemReader = new PemReader(reader);
712+
PemObject pemObject = pemReader.readPemObject();
713+
pemReader.close();
714+
715+
return pemObject.getContent();
716+
}
717+
catch (Exception e)
718+
{
719+
throw new RuntimeException(e);
720+
}
721+
}
722+
692723
static
693724
{
694725
noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
@@ -3447,6 +3478,24 @@ public void testForMultipleCounterSignatures()
34473478
}
34483479
}
34493480

3481+
public void testVerifySignedDataMLDsa44()
3482+
throws Exception
3483+
{
3484+
implTestVerifySignedData(signedData_mldsa44, SampleCredentials.ML_DSA_44);
3485+
}
3486+
3487+
public void testVerifySignedDataMLDsa65()
3488+
throws Exception
3489+
{
3490+
implTestVerifySignedData(signedData_mldsa65, SampleCredentials.ML_DSA_65);
3491+
}
3492+
3493+
public void testVerifySignedDataMLDsa87()
3494+
throws Exception
3495+
{
3496+
implTestVerifySignedData(signedData_mldsa87, SampleCredentials.ML_DSA_87);
3497+
}
3498+
34503499
private void verifySignatures(CMSSignedDataParser sp)
34513500
throws Exception
34523501
{
@@ -3468,6 +3517,21 @@ private void verifySignatures(CMSSignedDataParser sp)
34683517
}
34693518
}
34703519

3520+
private static void implTestVerifySignedData(byte[] signedData, SampleCredentials credentials)
3521+
throws Exception
3522+
{
3523+
CMSSignedData sd = new CMSSignedData(signedData);
3524+
3525+
assertTrue(sd.verifySignatures(new SignerInformationVerifierProvider()
3526+
{
3527+
public SignerInformationVerifier get(SignerId signerId)
3528+
throws OperatorCreationException
3529+
{
3530+
return new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(credentials.getCertificate());
3531+
}
3532+
}));
3533+
}
3534+
34713535
private static class TestCMSSignatureAlgorithmNameGenerator
34723536
extends DefaultCMSSignatureAlgorithmNameGenerator
34733537
{

0 commit comments

Comments
 (0)