mirrored from https://www.bouncycastle.org/repositories/bc-java
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Open
Description
Consider the following Java app, to be run with BC 1.83 and Java 21:
package com.example;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import java.io.FileOutputStream;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.Provider;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.util.Date;
import javax.security.auth.x500.X500Principal;
public class Test {
public static void main(final String[] args) throws Exception {
final String outFile = "example.p12";
final char[] password = "changeit".toCharArray();
final Provider provider = new BouncyCastleProvider();
//Security.addProvider(provider);
final KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", provider);
final KeyPair kp1 = kpg.generateKeyPair();
final X509Certificate cert1 =
selfSigned(kp1, "CN=RSA Key 1, O=Example, C=IT", Duration.ofDays(3650), provider);
final KeyStore ks = KeyStore.getInstance("PKCS12-AES256-AES128", provider);
ks.load(null, null);
ks.setKeyEntry("rsa-key-1", kp1.getPrivate(), password, new Certificate[] { cert1 });
try (final FileOutputStream fos = new FileOutputStream(outFile)) {
ks.store(fos, password);
}
System.out.println("Created: " + outFile);
System.out.println("Aliases: rsa-key-1, rsa-key-2");
}
private static X509Certificate selfSigned(final KeyPair keyPair, final String dn, final Duration validity,
final Provider provider) throws Exception {
final X500Principal subject = new X500Principal(dn);
final X500Principal issuer = subject;
final long now = System.currentTimeMillis();
final Date notBefore = new Date(now - 60_000L); // 1 min skew
final Date notAfter = new Date(now + validity.toMillis());
final BigInteger serial = new BigInteger(64, SecureRandom.getInstanceStrong()).abs().add(BigInteger.ONE);
final JcaX509v3CertificateBuilder builder =
new JcaX509v3CertificateBuilder(issuer, serial, notBefore, notAfter, subject, keyPair.getPublic());
final JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
builder.addExtension(Extension.basicConstraints, true, new BasicConstraints(false));
builder.addExtension(Extension.keyUsage, true,
new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment));
builder.addExtension(Extension.subjectKeyIdentifier, false,
extUtils.createSubjectKeyIdentifier(keyPair.getPublic()));
return new JcaX509CertificateConverter()
.setProvider(provider)
.getCertificate(builder.build(
new JcaContentSignerBuilder("SHA256withRSA").setProvider(provider).build(keyPair.getPrivate())));
}
}If you run it, it fails with:
Exception in thread "main" java.io.IOException: exception encrypting data - java.security.NoSuchAlgorithmException: 2.16.840.1.101.3.4.1.42 AlgorithmParameters not available
at org.bouncycastle.jcajce.provider.keystore.pkcs12.PKCS12KeyStoreSpi.wrapKey(Unknown Source)
at org.bouncycastle.jcajce.provider.keystore.pkcs12.PKCS12KeyStoreSpi.doStore(Unknown Source)
at org.bouncycastle.jcajce.provider.keystore.pkcs12.PKCS12KeyStoreSpi.engineStore(Unknown Source)
at org.bouncycastle.jcajce.provider.keystore.util.AdaptingKeyStoreSpi.engineStore(Unknown Source)
at java.base/java.security.KeyStore.store(KeyStore.java:1431)
at com.example.Test.main(Test.java:45)
Unless you uncomment line: //Security.addProvider(provider);
This is because PKCS12KeyStoreSpi.wrapKey(EncryptionScheme, Key, PBKDF2Params, char[]) does not specify the Bouncy Castle provider when getting an instance of AlgorithmParameters. This is unexpected: I don't want to be forced to add Bouncy Castle as a system provider, I'm just specifying it on every getInstance call that is under my control.
This sounds very similar to #2085.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels