Search code examples
javax509certificatepublic-key-encryption

How to get Certificate for encrypting mail into Java without private key?


I want to send an encrypted mail in java. BouncyCastle (Release 1.6.4) seems to be popular to do so. In their example "CreateLargeEncryptedMail.java" you find:

/**
 * a simple example that creates a single encrypted mail message.
 * <p>
 * The key store can be created using the class in
 * org.bouncycastle.jce.examples.PKCS12Example - the program expects only one
 * key to be present in the key file.
 * <p>
 * Note: while this means that both the private key is available to
 * the program, the private key is retrieved from the keystore only for
 * the purposes of locating the corresponding public key, in normal circumstances
 * you would only be doing this with a certificate available.
 */
public class CreateLargeEncryptedMail
{
    public static void main(
        String args[])
        throws Exception
    {
        if (args.length != 3)
        {
            System.err.println("usage: CreateLargeEncryptedMail pkcs12Keystore password inputFile");
            System.exit(0);
        }

        //
        // Open the key store
        //
        KeyStore    ks = KeyStore.getInstance("PKCS12", "BC");
        String      keyAlias = ExampleUtils.findKeyAlias(ks, args[0], args[1].toCharArray());

        Certificate[]   chain = ks.getCertificateChain(keyAlias);

But ks.getCertificateChain() does not work without the private key and usually I do not have the private key of a recipient. In my tries it returned null. From documentation

Returns the certificate chain associated with the given alias. The certificate chain must have been associated with the alias by a call to setKeyEntry, or by a call to setEntry with a PrivateKeyEntry.

But I do not have the private key.

An other way would be to use CertificateFactory.getInstance("X.509"); is there a way to decrypt smime public key data.

But I only come to java.security.cert.CertificateParsingException: signed fields invalid

Found stackoverflow to that exception, but the solution uses KeyStore.getCertificate() again.

I have: A certificat suitable for SMIME in Windows trust store. The certificat works in outlook. I can export the certificat to a file.

I want: A java object of type Certificate (X509Certificate) working for SMIME with BounceCastle.

So what kind of file do I have to create with which tool and what to do in Java to get this X509Certificate initialized? Do I need the single certificat or a chain in that file? The certificat is self signed.


Solution

  • BouncyCastle not only supports SMIME encryption but also contains a CertificateFactory which can load a p7b-file I exported from Windows certmgr. For export I chose without private key and with key-chain. That file worked for me using:

    import org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory;
    ...
    
        /**
         * Reads the Certificate from the file with filename.
         * Works for p7b-files.
         * @param filename the name and path of a key-file.
         * @return a Certificate
         */
        public static Certificate getCertificate(String filename) {
            Certificate cert = null;
            try (InputStream is = new FileInputStream(filename)) {
                CertificateFactory fact = new CertificateFactory();
                cert = fact.engineGenerateCertificate(is);
            }
            catch (Exception ex) {
                ex.printStackTrace();
            }
            return cert;
        }