23

I want to create a X509 certificate using Java language and then extract public key from it.

I have searched the internet and found many code examples, but all of them have errors (unknown variable or unknown type) or have many warnings that say something like : "the method ... from type ... is deprecated " etc.

For example, why the following code doesn't work:

PublicKey pk;
CertificateFactory cf = CertificateFactory.getInstance("X.509");
String PKstr = pk.toString();
InputStream PKstream = new ByteArrayInputStream(PKstr.getBytes());
X509Certificate pkcert = (X509Certificate)cf.generateCertificate(PKstream);


Can anyone show me how to create a certificate using pure Java or Bouncy Castle and then get a public key from that?

Thanks all.

3 Answers 3

26

For JDK versions <17, you can also generate a certificate using only JDK classes. The disadvantage is that you have to use two classes from the sun.security.x509 package. The code would be:

KeyStore keyStore = ... // your keystore

// generate the certificate
// first parameter  = Algorithm
// second parameter = signrature algorithm
// third parameter  = the provider to use to generate the keys (may be null or
//                    use the constructor without provider)
CertAndKeyGen certGen = new CertAndKeyGen("RSA", "SHA256WithRSA", null);
// generate it with 2048 bits
certGen.generate(2048);

// prepare the validity of the certificate
long validSecs = (long) 365 * 24 * 60 * 60; // valid for one year
// add the certificate information, currently only valid for one year.
X509Certificate cert = certGen.getSelfCertificate(
   // enter your details according to your application
   new X500Name("CN=My Application,O=My Organisation,L=My City,C=DE"), validSecs);

// set the certificate and the key in the keystore
keyStore.setKeyEntry(certAlias, certGen.getPrivateKey(), null, 
                        new X509Certificate[] { cert });

Retrieve the private key from the key store to encrypt or decrypt data. Based on the code is from http://www.pixelstech.net/article/1408524957-Generate-cetrificate-in-Java----3

Sign up to request clarification or add additional context in comments.

3 Comments

Unfortunately this does not work with Java 17 any more: annot access class sun.security.tools.keytool.CertAndKeyGen (in module java.base) because module java.base does not export sun.security.tools.keytool to unnamed module @0x1a5b6f42
Voting this down not because I don't like the solution, but because I guess it becomes less relevant as people upgrade their JDKs
E.g. sun.security.tools.keytool.CertAndKeyGen
10

For JDK >= 17, this is how to do it with BouncyCastle. The code example is in Kotlin, but it works exactly the same way in Java:

val keyPair = KeyPairGenerator.getInstance("RSA").genKeyPair()
val subPubKeyInfo = SubjectPublicKeyInfo.getInstance(keyPair.public.encoded)
val now = Instant.now()
val validFrom = Date.from(now)
val validTo = Date.from(now.plusSeconds(60L * 60 * 24 * 365))
val certBuilder = X509v3CertificateBuilder(
    X500Name("CN=My Application,O=My Organisation,L=My City,C=DE"),
    BigInteger.ONE,
    validFrom,
    validTo,
    X500Name("CN=My Application,O=My Organisation,L=My City,C=DE"),
    subPubKeyInfo
)
val signer = JcaContentSignerBuilder("SHA256WithRSA")
    .setProvider(BouncyCastleProvider())
    .build(keyPair.private)
val certificate = certBuilder.build(signer)

This is the gradledependency you need to pull:

implementation("org.bouncycastle:bcpkix-jdk18on:1.72")

Comments

8

Yes, with BouncyCastle, creating an X509 cert from 2 public keys (the key for the cert and the one for the CA) is done here.

I turn the resulting certificate into PEM here.

6 Comments

I have to add that the performance of BouncyCastle is pretty amazing. I had put this code being Jetty and could generate 8000 different certificates per second, from SSH public keys and (cached) LDAP information.
oh, no. I think that bad to say my question. I want to a simple code for create usual certificate.
Wow, I don't understand what you're looking for at all. You don't want to create a certificate from a key? Can you explain better? What's the input, what's the output?
the input is public key of the specified entity and the output is a certificate that certify that public key. for this purpose, why the above code doesn't work?
CertificateFactory.generateCertificate(x) reads an existing certificate in PKCS#7 format from x and returns a Certificate. That's documented on docs.oracle.com/javase/6/docs/api/java/security/cert/… . Creating one from a public key is harder and what my code does.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.