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:
- 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.
- 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
Multiple Runwith Statements in Junit
Eclipse Reading Stdin (System.In) from a File
How to Get Subnet Mask of Local System Using Java
What Is the Jvm Thread Scheduling Algorithm
Why Does Collections.Sort Use Mergesort But Arrays.Sort Does Not
Creating a Custom Jbutton in Java
How to Unit Test Abstract Classes: Extend with Stubs
How to Use Classloader.Getresources() Correctly
Why Never Change the Notifier in Receiving a Change Event
JPA @Onetoone with Shared Id -- How to Do This Better
Dynamically Find the Class That Represents a Primitive Java Type
Setting Outer Variable from Anonymous Inner Class
How to Get the Unique Id of an Object Which Overrides Hashcode()
Prevent Swing Gui Locking Up During a Background Task