3

I need to generate a public X509 Certificate but I have very little experience with Security in Java. I just want to make sure that what I am currently doing will work. First, I have already generated a public and private key with the following code:

public static void generateKeys() {
        try {
            KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
            SecureRandom random = SecureRandom.getInstanceStrong();
            keyGen.initialize(2048, random);

            KeyPair pair = keyGen.generateKeyPair();
            PrivateKey priv = pair.getPrivate();
            PublicKey pub = pair.getPublic();
            byte[] encPriv = priv.getEncoded();
            FileOutputStream privfos = new FileOutputStream(PRIVATE_KEY_FILENAME);
            privfos.write(encPriv);
            privfos.close();

            byte[] encPub = pub.getEncoded();
            FileOutputStream pubfos = new FileOutputStream(PUBLIC_KEY_FILENAME);
            pubfos.write(encPub);
            pubfos.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

And here is the code used for generating the X509Certificate:

public static PrivateKey getPrivateKey() throws Exception {
    byte[] pkcs8EncodedBytes = Files.readAllBytes(PRIVATE_KEY_FILENAME);
    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pkcs8EncodedBytes);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    return kf.generatePrivate(keySpec);
}

public static PublicKey getPublicKey() throws Exception {
    byte[] publicEncodedBytes = Files.readAllBytes(PUBLIC_KEY_FILENAME);
    X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicEncodedBytes);
    KeyFactory factory = KeyFactory.getInstance("RSA");
    return factory.generatePublic(publicKeySpec);
}

public static X509Certificate generateX509Certificate() throws Exception {
    PrivateKey privateKey = getPrivateKey();
    PublicKey publicKey = getPublicKey();
    KeyPair keyPair = new KeyPair(publicKey, privateKey);
    final Instant now = Instant.now();
    final Date notBefore = Date.from(now);
    final Date until = LocalDate.now().plusYears(100).toDate();
    final ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256WITHRSA").build(keyPair.getPrivate());
    final X500Name x500Name = new X500Name("CN=Common Name,O=Organization,L=City,ST=State");
    final X509v3CertificateBuilder certificateBuilder = new JcaX509v3CertificateBuilder(x500Name,
            BigInteger.valueOf(now.toEpochMilli()), notBefore, until, x500Name, keyPair.getPublic());
    return new JcaX509CertificateConverter().setProvider(new BouncyCastleProvider())
            .getCertificate(certificateBuilder.build(contentSigner));
}

Can someone clarify if this is the correct way to create a X509Certificate in Java? Thanks!

1

1 Answer 1

3

I haven't seen your loading a Key Store. Your method of retrieving the private/public key doesn't seem right.
A working example looks like this:

    public static Certificate generateCertificate(KeyPair keyPair) throws CertificateException, OperatorCreationException 
    {
        X500Name x500Name = new X500Name("CN=***.com, OU=Security&Defense, O=*** Crypto., L=Ottawa, ST=Ontario, C=CA");
        SubjectPublicKeyInfo pubKeyInfo = SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded());
        final Date start = new Date();
        final Date until = Date.from(LocalDate.now().plus(365, ChronoUnit.DAYS).atStartOfDay().toInstant(ZoneOffset.UTC));
        final X509v3CertificateBuilder certificateBuilder = new X509v3CertificateBuilder(x500Name,
                new BigInteger(10, new SecureRandom()), start,   until,  x500Name,  pubKeyInfo
        );
        ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256WithRSA").build(keyPair.getPrivate());

        Certificate certificate = new JcaX509CertificateConverter().setProvider(new BouncyCastleProvider()).getCertificate(certificateBuilder.build(contentSigner));
        
        System.out.println("x.509 certificate is successfully generated!");
        
        return certificate;
           
    }

Generate certificate logging:

Generating certificate in KeyStore /security/keystore/Andante-x509.jks

Encapsulating KeyPair with password in KeyStore... 

x.509 certificate is successfully generated!

Sitzung beendet wird. 

Extract and validate certificate from KeyStore:

If certificate doesn’t exist:

Certificate API Exception: The system cannot find the path specified. 

If KeyStore alias doesn’t match:

KeyStore Exception: Key cannot be retrieved. 

If KeyStore password doesn’t match:

KeyStore Exception: Keystore was tampered with, or password was incorrect. 

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

7 Comments

While KeyStore is (intentionally) suitable and convenient for storing keys in most cases, it is not the only way; the write(key.getEncoded())) and readAllBytes+KeyFactory method in the Q works -- although keeping the unencrypted privatekey in a file is often insecure
Yes, the mainspring of Java Security fabric is to lend both veracity and validity to the certificate. If ever the hacker intercepts or replaces data, key pairs or signature, the encoded keys render useless. After the certificate is encrypted in KeyStore, an alias permits of genuine certificate existence. While the encryption permits of no keystore tampering…That is my understanding…
Substituting a public key and compromising a private key are different threats (but both important). The private key is encrypted in file-based keystores (JKS, JCEKS, PKCS12) and expected to have equivalent protection in others (like PKCS11/HSM); the certificate does not need to be and usually isn't encrypted, but is protected by integrity measures like a PBMAC on the file-based stores.
I added an Extraction output in Answer... What might have safeguarded the certificate better based on that Extraction and validation logic? I'm all ears.
I don't know what you're asking. If you have a certificate in a usual file-based Java keystore, it is protected against substitution (or alteration) by the (PB)MAC; the alias helps organize the keystore but does not protect it (an attacker can easily enumerate aliases, even in PKCS12). For some formats the cert is not encrypted and thus not protected against exposure, but that's not a problem because certs (and publickeys generally) are defined to be public. OTOH the privatekey is always encrypted (as well as included in the MAC).
|

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.