Self Signed X509 Certificate with Bouncy Castle in Java

X509 certificate signed with bouncy castle is not valid

I have a similar example working

Try replacing X500Name issuer = with the X500 name got from CA to avoid problems with characters

X500Name issuer = X500Name.getInstance(cacert.getSubjectX500Principal().getEncoded());

Also, I think you have need this part before PEM encoding

CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
signer = new JcaContentSignerBuilder("SHA1withRSA").build(cakey);
generator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build()).build(signer, cacert));
generator.addCertificate(new X509CertificateHolder(certencoded));
generator.addCertificate(new X509CertificateHolder(cacert.getEncoded()));
CMSTypedData content = new CMSProcessableByteArray(certencoded);
CMSSignedData signeddata = generator.generate(content, true);
byte signedCertificate[] = signeddata.getEncoded();

Generating X509Certificate with BouncyCastle with Java

You had all the code you needed to produce a self-signed certificate. You just needed to ensure your chain contained only one certificate.

public static void testKeyStore() throws Exception {
try {
String storeName = "path/to/store";
java.security.KeyPairGenerator keyPairGenerator = KeyPairGenerator
.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
X509Certificate selfCert = createCertificate("CN=Client", "CN=Client",
publicKey, privateKey);

// Note: if you just want to store this certificate then write the
// contents of selfCert.getEncoded() to file

java.security.cert.Certificate[] outChain = { selfCert };
KeyStore outStore = KeyStore.getInstance("PKCS12");
outStore.load(null, PASSWORD.toCharArray());
outStore.setKeyEntry("mykey", privateKey, PASSWORD.toCharArray(),
outChain);
OutputStream outputStream = new FileOutputStream(storeName);
outStore.store(outputStream, PASSWORD.toCharArray());
outputStream.flush();
outputStream.close();

KeyStore inStore = KeyStore.getInstance("PKCS12");
inStore.load(new FileInputStream(storeName), PASSWORD.toCharArray());
} catch (Exception e) {
e.printStackTrace();
throw new AssertionError(e.getMessage());
}
}

I would advise you don't throw an AssertionError. This should only be used by Java itself to indicate an assert statement is false.

Create x.509 certificate using bouncycastle with certificate path (cert chain)

I was able to find solution. Actually code works as expected. I didn't see chain of certificates because my caRoot certificate wasn't added to the trusted store. After I add my sel-signed certificate to the trusted root certified centers I see the whole certification chain as I expected.

Easy way to generate a self-signed certificate for java.security.Keystore using BouncyCastle

The solution I ended up using looks mostly like the following code (not pretty but it works):

import java.io.IOException;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPublicKey;
import java.sql.Date;

import javax.security.auth.x500.X500Principal;

import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v1CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;

public class SelfSignedCertificateGenerator {

private static final JcaX509CertificateConverter CONVERTER = new JcaX509CertificateConverter()
.setProvider(new BouncyCastleProvider());

private static final String SIGNATURE_ALGORITHM = "SHA1withRSA";

private static final X500Name ISSUER = new X500Name(new X500Principal("CN=Stupid CA Certificate").getName());
private static final X500Name SUBJECT = ISSUER;
private static final Date NOT_AFTER = Date.valueOf("3000-01-01");
private static final Date NOT_BEFORE = Date.valueOf("2000-01-01");
private static final BigInteger SERIAL = new BigInteger("1");

public static Certificate[] getCerts(KeyPair keys) {
return new Certificate[] { getCertificate(keys) };
}

private static X509Certificate getCertificate(KeyPair keys) {
try {
X509v1CertificateBuilder certificateBuilder = getCertificateBuilder(keys.getPublic());
X509CertificateHolder certificateHolder = certificateBuilder.build(getSigner(keys));
return CONVERTER.getCertificate(certificateHolder);
} catch (CertificateException e) {
throw new RuntimeException(e);
}
}

private static X509v1CertificateBuilder getCertificateBuilder(PublicKey publicKey) {
return new X509v1CertificateBuilder(ISSUER, SERIAL, NOT_BEFORE, NOT_AFTER, SUBJECT, getPublicKeyInfo(publicKey));
}

private static SubjectPublicKeyInfo getPublicKeyInfo(PublicKey publicKey) {
if (!(publicKey instanceof RSAPublicKey))
throw new RuntimeException("publicKey is not an RSAPublicKey");

RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;

try {
return SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(new RSAKeyParameters(false, rsaPublicKey
.getModulus(), rsaPublicKey.getPublicExponent()));
} catch (IOException e) {
throw new RuntimeException(e);
}
}

private static ContentSigner getSigner(KeyPair keys) {
try {
return new JcaContentSignerBuilder(SIGNATURE_ALGORITHM).setProvider(new BouncyCastleProvider()).build(
keys.getPrivate());
} catch (OperatorCreationException e) {
throw new RuntimeException(e);
}
}
}

Bouncy Castle: Signed Certificate with an existing CA

I have identified the problem: I was building the certificate chain in the opposite order that should be.

I had this order:

 certificateHolder = new X509CertificateHolder( cert.getEncoded() );
certificateHolder = new X509CertificateHolder( CAcert.getEncoded() );

And the right order is this:

certificateHolder = new X509CertificateHolder( CAcert.getEncoded() );
certificateHolder = new X509CertificateHolder( cert.getEncoded() );

I hope somebody can find this information useful!

How to sign a certificate using BouncyCastle or Java 11

As it is pointed out in comments by Boriss the Spider, certificate is not allowed to sign other certificates if any of the following conditions are not met:

  1. Certificate subject must be CA via Basic Constraints certificate extension. See my blog post on how basic constraints work in practice and how certificate chaining engine reacts to violation.
  2. Certificate must include certKeySign usage in Key Usage certificate extension

Validate the chain regardless of C1 not being a CA

it would be hard to disable basic constraints and key usage extension validation and retain other validation steps, this may require to disable client certificate validation at all. This is a simple PKI misuse that opens various vulnerabilities because you cannot implement proper certificate validation.

Creating an X509 Certificate in Java without BouncyCastle?

The ability to sign certificates is not part of a standard Java library or extension.

A lot of the code that is needed to do it yourself is part of the core. There are classes to encode and decode X.500 names, X.509 certificate extensions, public keys for various algorithms, and of course, for actually performing the digital signature.

Implementing this yourself is not trivial, but it is definitely doable—I probably spent 4 or 5 full days the first time I made a working prototype for certificate signing. It was a fantastic learning exercise for me, but it's hard to justify that expense when there are usable libraries available for free.



Related Topics



Leave a reply



Submit