2

I've got a doubt.. I have to sign a pgp public key using bouncycastle api supposedly. Now: to my understanding signing a key with another means ultimately adding to this public key a "certificate". Thus lacking any other way, I've gone blind searching in the library. my only find so far has been method generateCertification inside PGPSignatureGenerator. But this method generate a certification between a master PgpPublicKey and another PgpPublicKey.. And this strikes me as strange: I assumed that in order to trust another public key, that has to be signed with your own private pgp key just like in regular x.509 with CA certification in a manner.. This was assumption by some methods that I saw when trying to get some ideas from other library: didisoft for example has a similar method on a keystore where you have to provide the PgpPrivatekey keyuid...

Anyone has any hint or a piece of code to propose? Thanks in advance.

witchedwiz
  • 295
  • 2
  • 10
  • Why are you signing a public key? Usually you either use your private key to sign a message (or file) (to prove that you sent it and it hasn't been altered) or use the recipient's public key to encrypt a message (or file) that you're sending to him (that only his private key can decrypt.) – Duston Feb 18 '15 at 19:59
  • Uhm maybe it's me not having exactly clear the pgp concepts... I mean, you want to trust someone key and say that for you their key is "okay" basically sort of a CA concept equivalent.. in this case you sign their public key.. a value of "trust" of an identity is given by who/how many recipients have signed that pgp public key.. that's why I assume you need to sign a key. – witchedwiz Feb 18 '15 at 22:15

2 Answers2

2

This can be used to check that one key gave default certification to another

  /**
 * Signs a public key
 *
 * @param publicKeyRing a public key ring containing the single public key to sign
 * @param id the id we are certifying against the public key
 * @param secretKey the signing key
 * @param secretKeyPassword the signing key password
 *
 * @return a public key ring with the signed public key
 */
public static PGPPublicKeyRing signPublicKey( PGPPublicKeyRing publicKeyRing, String id, PGPSecretKey secretKey,
                                              String secretKeyPassword ) throws PGPException
{
    try
    {
        PGPPublicKey oldKey = publicKeyRing.getPublicKey();

        PGPPrivateKey pgpPrivKey = secretKey.extractPrivateKey(
                new JcePBESecretKeyDecryptorBuilder().setProvider( provider )
                                                     .build( secretKeyPassword.toCharArray() ) );

        PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(
                new JcaPGPContentSignerBuilder( secretKey.getPublicKey().getAlgorithm(), PGPUtil.SHA1 ) );

        signatureGenerator.init( PGPSignature.DEFAULT_CERTIFICATION, pgpPrivKey );

        PGPSignature signature = signatureGenerator.generateCertification( id, oldKey );

        PGPPublicKey newKey = PGPPublicKey.addCertification( oldKey, signature );

        PGPPublicKeyRing newPublicKeyRing = PGPPublicKeyRing.removePublicKey( publicKeyRing, oldKey );

        return PGPPublicKeyRing.insertPublicKey( newPublicKeyRing, newKey );
    }
    catch ( Exception e )
    {
        //throw custom  exception
        throw new PGPException( "Error signing public key", e );
    }
}


/**
 * Verifies that a public key is signed with another public key
 *
 * @param keyToVerify the public key to verify
 * @param id the id we are verifying against the public key
 * @param keyToVerifyWith the key to verify with
 *
 * @return true if verified, false otherwise
 */
public static boolean verifyPublicKey( PGPPublicKey keyToVerify, String id, PGPPublicKey keyToVerifyWith )
        throws PGPException
{
    try
    {
        Iterator<PGPSignature> signIterator = keyToVerify.getSignatures();
        while ( signIterator.hasNext() )
        {
            PGPSignature signature = signIterator.next();
            signature.init( new JcaPGPContentVerifierBuilderProvider().setProvider( provider ), keyToVerifyWith );
            if ( signature.verifyCertification( id.getBytes(), keyToVerify ) )
            {
                return true;
            }
        }
        return false;
    }
    catch ( Exception e )
    {
        //throw custom  exception
        throw new PGPException( "Error verifying public key", e );
    }
}
SoL
  • 21
  • 4
1

Here's a Codeexample to sign a public Key:

    PGPSecretKey mySecretKey;
    PGPPublicKey publicKeyToBeSigned; 
    PGPPrivateKey pgpPrivKey = mySecretKey
            .extractPrivateKey(new JcePBESecretKeyDecryptorBuilder()
                    .setProvider("BC").build("password for your private key"));
    PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(
            new JcaPGPContentSignerBuilder(mySecretKey.getPublicKey()
                    .getAlgorithm(), PGPUtil.SHA512));
    signatureGenerator.init(PGPSignature.DIRECT_KEY, pgpPrivKey);

    PGPSignature signature = signatureGenerator.generateCertification(
            id, publicKeyToBeSigned);

This piece of code just creates the signature. You need to add it to your the public key then:

PGPPublicKey.addCertification(publicKeyToBeSigned, signature);

Hope that helps you :)

Jan
  • 1,004
  • 6
  • 23
  • I'll check this later tomorrow most likely.. I already surmised a code that is pretty much like this, with the only difference that I've not run an init first.. (which i notice is compulsory for other action as well, like when verifying a revocation certificate)... I'll let you know. – witchedwiz Feb 18 '15 at 22:18
  • Now... if I want to go the other way around it: I have the key2 that has been signed by key1.. I tried something along these lines [code] BcPGPContentVerifierBuilderProvider verifierBuilderProvider = new BcPGPContentVerifierBuilderProvider(); signature.init(verifierBuilderProvider, signedKey); boolean resultOfMatching = signature.verifyCertification(authorKey, signedKey); [/code] but unfortunately it doesn't work.. any suggestion on this? – witchedwiz Feb 19 '15 at 11:20
  • Funny thing: you're doing the exact same failure I did ;). Don't have the code with me but to verify a signature you need TWO public Keys. Signer and signed! One goes to the init the other to the verifyCertification. If you can't figure it out I could post an example today or tomorrow evening. If my code example works for you it would be nice of you if you mark my answer as accepted. – Jan Feb 19 '15 at 14:21
  • Of course I'm marking your answer as accepted! Thanks for taking your time answering me! A code sample for the second point would be most welcome, but as is you helped me aplenty.. I'm really appaled by the amount of (or should i say the lack of..) sample of pgp along with the bouncycastle api.. I mean, bouncycasatle is great as far as X509 goes, but as for pgp, given the complexity of some thematics (web of trust, etc) I'd really expect much more details given along with the code either in form of in-depth javadoc or in form of documentation... But it's a free api, so there's that.. – witchedwiz Feb 23 '15 at 11:35
  • Yeah I know what you mean... Had to deal with the same problems ;). Here is a short code snippet but it should show how it works. `pgpSignature.init(new JcaPGPContentVerifierBuilderProvider() .setProvider("BC"), publicKeyOfSigner); boolean result = pgpSignature.verifyCertification(signedPublicKey);` – Jan Feb 23 '15 at 23:32
  • Uhm I think that this cannot work.. the verifyCertification method will only work for this.getSignatureType() == KEY_REVOCATION or this.getSignatureType() == SUBKEY_REVOCATION.. in every other case it will raise "throw new PGPException("signature is not a key signature");".. But, a key signing a key, is a DIRECT_KEY type of signature.. maybe you mean to use pgpSignature.verifyCertification(publicKeyOfSigner, signedPublicKey) ? but doing this way, will always give me false :| – witchedwiz Feb 24 '15 at 10:23
  • Hmm you're right. Saw it [here](http://grepcode.com/file/repo1.maven.org/maven2/org.bouncycastle/bcpg-jdk16/1.44/org/bouncycastle/openpgp/PGPSignature.java#PGPSignature.verifyCertification%28org.bouncycastle.openpgp.PGPPublicKey%29) (But I was using another version of BC). Maybe I made some mistake copying the code together. I'll check my code this later and let you know... – Jan Feb 24 '15 at 10:31
  • Hmm sorry but I am using bcpg-jdk15on-1.51. Seems like it's different in this version of bc – Jan Feb 24 '15 at 21:21