6
votes

I am using bouncycastle (JAVA) for signing, encryption, decryption and signatures' verification in implementation of SSO. I have raw PGP public and private keys and I need to store them in Java keystore. These PGP public keys have no certificate.

I understand that for public keys (according to javadoc of Keystore: http://docs.oracle.com/javase/6/docs/api/java/security/KeyStore.html) I have to create certificate. Once certificate is created I can import it to the keystore as KeyStore.TrustedCertificateEntry. However, I am not able to create certificate entry for type org.bouncycastle.openpgp.PGPPublicKey.

I have searched through the web but could not find any valid example:

  1. Bouncycastle documentation: http://www.bouncycastle.org/wiki/display/JA1/X.509+Public+Key+Certificate+and+Certification+Request+Generation Generates certificate for X.509 keys -
  2. Bouncycastle examples - org.bouncycastle.openpgp.examples.DirectKeySignature: Add certificat (object of type PGPSignature) directly to the PGPPublicKey. To conclude - I have signed (certified) PGPPublicKey but I am not able to store this type of Key into the java keystore.

    OutputStream out = new ByteArrayOutputStream();
    
    if (armor)
    {
        out = new ArmoredOutputStream(out);
    }
    
    PGPPrivateKey pgpPrivKey = secretKey.extractPrivateKey(secretKeyPass.toCharArray(), "BC");
    
    PGPSignatureGenerator       sGen = new PGPSignatureGenerator(secretKey.getPublicKey().getAlgorithm(), PGPUtil.SHA1, "BC");
    
    sGen.initSign(PGPSignature.DIRECT_KEY, pgpPrivKey);
    
    BCPGOutputStream            bOut = new BCPGOutputStream(out);
    
    sGen.generateOnePassVersion(false).encode(bOut);
    
    PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
    
    boolean isHumanReadable = true;
    
    spGen.setNotationData(true, isHumanReadable, notationName, notationValue);
    
    PGPSignatureSubpacketVector packetVector = spGen.generate();
    sGen.setHashedSubpackets(packetVector);
    
    bOut.flush();
    
    return PGPPublicKey.addCertification(keyToBeSigned, sGen.generate()).getEncoded();
    

I am mainly interested in programatic solution (java source code) but examples that use some tools will be helpful too.

Thanks!

2

2 Answers

0
votes

I think you should extract a java.security.PublicKey from your PGPPublicKey and use that to construct an X509Certificate which can be stored in a keystore.

JcaPGPKeyConverter c = new JcaPGPKeyConverter();
PublicKey publicKey = c.getPublicKey(pgpPublicKey);
// ... Use Bouncy's X509V3CertificateGenerator or X509v3CertificateBuilder
// ... to construct a self-signed cert
X509Certificate x509Certificate = // ...
// ... add cert to KeyStore

To create an X509Certificate from a PublicKey see: Generate random certificates.

0
votes

If you only want to save the public key, why cannot you just save the key content into Java keystore? Then retrieve the content and convert into a PGPPublicKey object when you need it.

Create a wrapper class first

public class PgpPublicKeyWrapper implements Key {
    private final String keyContent;
    public PgpPublicKeyWrapper(final String keyContent) {
        this.keyContent = keyContent;
    }
    @Override
    public String getAlgorithm() {
        return "PGP-PublicKey"; // you can call whatever you want
    }
    @Override
    public String getFormat() {
        return "RAW"; // has to be raw format
    }
    @Override
    public byte[] getEncoded() {
        return keyContent.getBytes();
    }
}

Then you can do this to save it

keyStore.setKeyEntry("think a name for alias", new PgpPublicKeyWrapper(key), PASSWORD, null);

When you want to retrieve it

Key key = this.keyStore.getKey(alias, PASSWORD);
InputStream is = new ByteArrayInputStream(key.getEncoded());
PGPPublicKey publicKey = readPublicKey(is); 

For readPublicKey(), you can find a lot of examples online about how to read InputStream to a PGPPublicKey object.