blob: 1c1762e0660ede453a1c969afb4410b1ff4e929c [file] [log] [blame]
package org.bouncycastle.pqc.jcajce.provider.test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import junit.framework.TestCase;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.Extensions;
import org.bouncycastle.asn1.x509.ExtensionsGenerator;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.TBSCertificate;
import org.bouncycastle.asn1.x509.Time;
import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
import org.bouncycastle.pqc.jcajce.spec.McElieceKeyGenParameterSpec;
import org.bouncycastle.pqc.jcajce.spec.SPHINCS256KeyGenParameterSpec;
import org.bouncycastle.pqc.jcajce.spec.XMSSMTParameterSpec;
public class KeyStoreTest
extends TestCase
{
private static final long ONE_DAY_IN_MILLIS = 24 * 60 * 60 * 1000;
private static final long TEN_YEARS_IN_MILLIS = 10l * 365 * ONE_DAY_IN_MILLIS;
private static Map algIds = new HashMap();
static
{
algIds.put("SHA512WITHSPHINCS256", new AlgorithmIdentifier(BCObjectIdentifiers.sphincs256_with_SHA512));
algIds.put("SHA256WITHXMSSMT", new AlgorithmIdentifier(BCObjectIdentifiers.xmss_mt_SHA256ph));
algIds.put("SHA512WITHXMSSMT", new AlgorithmIdentifier(BCObjectIdentifiers.xmss_mt_SHA512ph));
}
public void setUp()
{
Security.addProvider(new BouncyCastleProvider());
Security.addProvider(new BouncyCastlePQCProvider());
}
public void testPKCS12()
throws Exception
{
tryKeyStore("PKCS12");
tryKeyStore("PKCS12-DEF");
}
public void testBKS()
throws Exception
{
tryKeyStore("BKS");
tryKeyStore("UBER");
}
public void testBCFKS()
throws Exception
{
tryKeyStore("BCFKS-DEF");
}
private void tryKeyStore(String format)
throws Exception
{
// Keystore to store certificates and private keys
KeyStore store = KeyStore.getInstance(format, "BC");
store.load(null, null);
String password = "qwertz";
// XMSS
X500NameBuilder nameBuilder = new X500NameBuilder();
nameBuilder.addRDN(BCStyle.CN, "Root CA");
KeyPairGenerator kpg = KeyPairGenerator.getInstance("XMSSMT", "BCPQC");
kpg.initialize(new XMSSMTParameterSpec(20, 10, XMSSMTParameterSpec.SHA256), new SecureRandom());
KeyPair kp = kpg.generateKeyPair();
// root CA
X509Certificate rootCA = createPQSelfSignedCert(nameBuilder.build(), "SHA256WITHXMSSMT", kp);
X509Certificate[] chain = new X509Certificate[1];
chain[0] = rootCA;
// store root private key
String alias1 = "xmssmt private";
store.setKeyEntry(alias1, kp.getPrivate(), password.toCharArray(), chain);
// store root certificate
store.setCertificateEntry("root ca", rootCA);
// McEliece
kpg = KeyPairGenerator.getInstance("McEliece", "BCPQC");
McElieceKeyGenParameterSpec params = new McElieceKeyGenParameterSpec(9, 33);
kpg.initialize(params);
KeyPair mcelieceKp = kpg.generateKeyPair();
ExtensionsGenerator extGenerator = new ExtensionsGenerator();
extGenerator.addExtension(Extension.basicConstraints, false, new BasicConstraints(false));
extGenerator.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.encipherOnly));
X509Certificate cert1 = createCert(nameBuilder.build(), kp.getPrivate(), new X500Name("CN=meceliece"), "SHA256WITHXMSSMT",
extGenerator.generate(), mcelieceKp.getPublic());
X509Certificate[] chain1 = new X509Certificate[2];
chain1[1] = rootCA;
chain1[0] = cert1;
// SPHINCS-256
kpg = KeyPairGenerator.getInstance("SPHINCS256", "BCPQC");
kpg.initialize(new SPHINCS256KeyGenParameterSpec(SPHINCS256KeyGenParameterSpec.SHA512_256));
KeyPair sphincsKp = kpg.generateKeyPair();
extGenerator = new ExtensionsGenerator();
extGenerator.addExtension(Extension.basicConstraints, false, new BasicConstraints(false));
extGenerator.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature));
X509Certificate cert2 = createCert(nameBuilder.build(), sphincsKp.getPrivate(), new X500Name("CN=sphincs256"), "SHA512WITHSPHINCS256",
extGenerator.generate(), sphincsKp.getPublic());
X509Certificate[] chain2 = new X509Certificate[2];
chain2[1] = rootCA;
chain2[0] = cert2;
String alias2 = "private key 1";
String alias3 = "private key 2";
// store private keys
store.setKeyEntry(alias2, mcelieceKp.getPrivate(), password.toCharArray(), chain1);
store.setKeyEntry(alias3, sphincsKp.getPrivate(), password.toCharArray(), chain2);
// store certificates
store.setCertificateEntry("cert 1", cert1);
store.setCertificateEntry("cert 2", cert2);
// can't restore keys from keystore
Key k1 = store.getKey(alias1, password.toCharArray());
assertEquals(kp.getPrivate(), k1);
Key k2 = store.getKey(alias2, password.toCharArray());
assertEquals(mcelieceKp.getPrivate(), k2);
Key k3 = store.getKey(alias3, password.toCharArray());
assertEquals(sphincsKp.getPrivate(), k3);
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
store.store(bOut, "fred".toCharArray());
KeyStore bcStore = KeyStore.getInstance(format, "BC");
bcStore.load(new ByteArrayInputStream(bOut.toByteArray()), "fred".toCharArray());
k1 = store.getKey(alias1, password.toCharArray());
assertEquals(kp.getPrivate(), k1);
k2 = store.getKey(alias2, password.toCharArray());
assertEquals(mcelieceKp.getPrivate(), k2);
k3 = store.getKey(alias3, password.toCharArray());
assertEquals(sphincsKp.getPrivate(), k3);
}
private static X509Certificate createPQSelfSignedCert(X500Name dn, String sigName, KeyPair keyPair)
throws Exception
{
V3TBSCertificateGenerator certGen = new V3TBSCertificateGenerator();
long time = System.currentTimeMillis();
AtomicLong serialNumber = new AtomicLong(System.currentTimeMillis());
certGen.setSerialNumber(new ASN1Integer(serialNumber.getAndIncrement()));
certGen.setIssuer(dn);
certGen.setSubject(dn);
certGen.setStartDate(new Time(new Date(time - 5000)));
certGen.setEndDate(new Time(new Date(time + TEN_YEARS_IN_MILLIS)));
certGen.setSignature((AlgorithmIdentifier)algIds.get(sigName));
certGen.setSubjectPublicKeyInfo(SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded()));
ExtensionsGenerator extGenerator = new ExtensionsGenerator();
extGenerator.addExtension(Extension.basicConstraints, true, new BasicConstraints(true));
extGenerator.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.keyCertSign));
certGen.setExtensions(extGenerator.generate());
Signature sig = Signature.getInstance(sigName, BouncyCastlePQCProvider.PROVIDER_NAME);
sig.initSign(keyPair.getPrivate());
sig.update(certGen.generateTBSCertificate().getEncoded(ASN1Encoding.DER));
TBSCertificate tbsCert = certGen.generateTBSCertificate();
ASN1EncodableVector v = new ASN1EncodableVector();
// TBS
v.add(tbsCert);
// Algorithm Identifier
v.add((AlgorithmIdentifier)algIds.get(sigName));
// Signature
v.add(new DERBitString(sig.sign()));
return (X509Certificate)CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME)
.generateCertificate(new ByteArrayInputStream(new DERSequence(v).getEncoded(ASN1Encoding.DER)));
}
private static X509Certificate createCert(X500Name signerName, PrivateKey signerKey, X500Name dn, String sigName,
Extensions extensions, PublicKey pubKey)
throws Exception
{
V3TBSCertificateGenerator certGen = new V3TBSCertificateGenerator();
long time = System.currentTimeMillis();
AtomicLong serialNumber = new AtomicLong(System.currentTimeMillis());
certGen.setSerialNumber(new ASN1Integer(serialNumber.getAndIncrement()));
certGen.setIssuer(signerName);
certGen.setSubject(dn);
certGen.setStartDate(new Time(new Date(time - 5000)));
certGen.setEndDate(new Time(new Date(time + TEN_YEARS_IN_MILLIS)));
certGen.setSignature((AlgorithmIdentifier)algIds.get(sigName));
certGen.setSubjectPublicKeyInfo(SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()));
certGen.setExtensions(extensions);
Signature sig = Signature.getInstance(sigName, BouncyCastlePQCProvider.PROVIDER_NAME);
sig.initSign(signerKey);
sig.update(certGen.generateTBSCertificate().getEncoded(ASN1Encoding.DER));
TBSCertificate tbsCert = certGen.generateTBSCertificate();
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(tbsCert);
v.add((AlgorithmIdentifier)algIds.get(sigName));
v.add(new DERBitString(sig.sign()));
return (X509Certificate)CertificateFactory.getInstance("X.509", "BC")
.generateCertificate(new ByteArrayInputStream(new DERSequence(v).getEncoded(ASN1Encoding.DER)));
}
}