Good morning Atanas, Thank you for your help, I have attempted to incorporate the solution you provided to construct detached revocation certificates.
Unfortunately, the C# library doesn't appear to have an equivalent to hashed.setRevocationReason(false, reason, description); I have incorporated everything else, and the revocation certificate verification still fails. I am guessing that that this is due to the lack of revocation reason, based on your earlier notes. Based on this, I guess I have two questions. The first is, is the revocation reason really required, given that the C# library doesn't appear to support it, or secondly, am I missing something in the C# implementation of PgpSignatureSubpacketGenerator.cs Using pgpdump to inspect the contents of the file which is created, I have the following : Old: Signature Packet(tag 2)(305 bytes) Ver 4 - new Sig type - Key revocation signature(0x20). Pub alg - RSA Encrypt or Sign(pub 1) Hash alg - SHA256(hash 8) Hashed Sub: signature creation time(sub 2)(4 bytes) Time - Sat Jun 30 09:48:54 MDT 2012 Sub: issuer key ID(sub 16)(8 bytes) Key ID - 0x1AEED5494B0BEB3F Sub: signer's User ID(sub 28)(19 bytes) User ID - 1940723000211663679 Hash left 2 bytes - 1d eb RSA m^d mod n(2045 bits) - ... -> PKCS-1 I also changed the headers as you had originally suggested as follows: string newHeaderline = "-----BEGIN PGP PUBLIC KEY BLOCK-----"; string oldHeaderLine = "-----BEGIN PGP SIGNATURE-----"; string oldFooterLine = "-----END PGP SIGNATURE-----"; string newFooterLine = "-----END PGP PUBLIC KEY BLOCK-----"; Thanks again for the help. Jim Treinen. On Fri, Jun 29, 2012 at 12:59 PM, Atanas Krachev <[email protected]> wrote: > Hi Jim, > > Please find below a short example that demonstrates how to append > signature subpackets. > > PGPSecretKeyRing certKey = ... > String privateKeyPassword = ... > > PGPSignatureSubpacketGenerator hashed = new > PGPSignatureSubpacketGenerator(); > hashed.setSignatureCreationTime(false, new Date()); > hashed.setRevocationReason(false, reason, description); > > PGPSignatureSubpacketGenerator unhashed = new > PGPSignatureSubpacketGenerator(); > unhashed.setIssuerKeyID(false, certKey.getPublicKey().getKeyID()); > > PGPSignatureGenerator sGen = new > PGPSignatureGenerator(certKey.getPublicKey().getAlgorithm(), > HashAlgorithmTags.SHA1, > > PGPLib.BOUNCY_CASTLE_PROVIDER); > sGen.initSign(PGPSignature.KEY_REVOCATION, > > certKey.getSecretKey().extractPrivateKey(privateKeyPassword.toCharArray(), > > "BC"); > > sGen.setHashedSubpackets(hashed.generate()); > sGen.setUnhashedSubpackets(unhashed.generate()); > > Cheers, > Atanas Krachev > > 2012/6/27 Jim Treinen <[email protected]> > >> Hi Atanas, >> >> Thank you very much for your advice on this topic. I am pretty new with >> BouncyCastle, and I haven't had much luck getting this to work, do you >> happen to have an example of creating hashed packets and adding them to the >> output? >> >> I appreciate your help, and thanks again, >> >> Jim. >> >> >> On Fri, Jun 15, 2012 at 3:38 AM, Atanas Krachev <[email protected]>wrote: >> >>> Hi Jim, >>> >>> In theory a revocation certificate is a text file that you use in the >>> case that you have lost either your private key or it's password >>> to revoke your public key. >>> >>> The text file is a signature created just like you do it: >>> sGen.InitSign(PgpSignature.KeyRevocation, pgpPrivKey); >>> >>> but you have to add additionally : >>> 1. two hashed packets: CreationTime and RevocationReason >>> 2. one unhashed packet : IssuerKeyID (in your case >>> pgpSec.GetPublicKey().KeyId) >>> >>> the signature does not have to be updated (sGen.Update is useless) >>> >>> and there is one final thing: >>> because ArmoredOutputStream has no way of producing correct revocation >>> certificate headers >>> you have to manually replace the generated ones with -----BEGIN PGP >>> PUBLIC KEY BLOCK----- and -----END PGP PUBLIC KEY BLOCK----- >>> >>> In short that's it. >>> >>> Cheers, >>> Atanas Krachev >>> >>> 2012/6/15 Jim Treinen <[email protected]> >>> >>>> Hello everyone, >>>> >>>> We are trying to create revocation certificates at key pair generation >>>> time. We have the following code working, which works great for signing >>>> and verifying challenge strings, however, when using it to create (what I >>>> thought) were revocation certificates, it creates another detached >>>> signature (adopted from the detached signature example), but the signature >>>> does not verify as a valid revocation cert. >>>> >>>> The stringToSign being passed in, is the public key, and the boolean, >>>> when set to true, is our attempt to generate a revocation cert. >>>> >>>> Thanks in advance, >>>> >>>> Jim T. >>>> >>>> >>>> private string _createSignature(KeyModel keyModel, string stringToSign, >>>> bool isRevocation) >>>> >>>> { >>>> >>>> >>>> Stream outputStream; >>>> >>>> PgpSecretKey pgpSec; >>>> >>>> PgpPrivateKey pgpPrivKey; >>>> >>>> MemoryStream privateKeyStream; >>>> >>>> outputStream = new MemoryStream(); >>>> >>>> >>>> ArmoredOutputStream armoredOutputStream >>>> = new ArmoredOutputStream(outputStream); >>>> >>>> >>>> byte[] toSignByteArray = Encoding.ASCII.GetBytes( >>>> stringToSign ); >>>> >>>> MemoryStream toSignStream >>>> = new MemoryStream(toSignByteArray); >>>> >>>> >>>> // Get the private key >>>> >>>> using (InsecureByteArray iba >>>> = new InsecureByteArray(KeyModel.PrivateKey, Encoding.ASCII)) >>>> >>>> { >>>> >>>> privateKeyStream = new MemoryStream(iba.Value); >>>> >>>> pgpSec = this.ReadSecretKey(privateKeyStream); >>>> >>>> privateKeyStream.Close(); >>>> >>>> } >>>> >>>> >>>> >>>> using (InsecureCharArray ica >>>> = new InsecureCharArray(KeyModel.Passphrase)) >>>> >>>> { >>>> >>>> pgpPrivKey = pgpSec.ExtractPrivateKey(ica.Value); >>>> >>>> } >>>> >>>> >>>> PgpSignatureGenerator sGen >>>> = new PgpSignatureGenerator(pgpSec.PublicKey.Algorithm, >>>> HashAlgorithmTag.Sha256); >>>> >>>> if (isRevocation) >>>> >>>> { >>>> >>>> sGen.InitSign(PgpSignature.KeyRevocation, pgpPrivKey); >>>> >>>> } >>>> >>>> else >>>> >>>> { >>>> >>>> sGen.InitSign(PgpSignature.BinaryDocument, pgpPrivKey); >>>> >>>> } >>>> >>>> >>>> BcpgOutputStream bOut >>>> = new BcpgOutputStream(armoredOutputStream); >>>> >>>> >>>> >>>> int ch = 0; >>>> >>>> while ((ch = toSignStream.ReadByte()) >= 0) >>>> >>>> { >>>> >>>> // lOut.WriteByte((byte)ch); >>>> >>>> sGen.Update((byte)ch); >>>> >>>> } >>>> >>>> >>>> >>>> >>>> // send the signature to the output stream >>>> >>>> sGen.Generate().Encode(bOut); >>>> >>>> >>>> // Clean up >>>> >>>> bOut.Close(); // BcpgOutputStream >>>> >>>> toSignStream.Close(); // input file stream >>>> >>>> >>>> outputStream.Position = 0; >>>> >>>> StreamReader reader = new StreamReader(outputStream); >>>> >>>> string signature = reader.ReadToEnd(); >>>> >>>> >>>> armoredOutputStream.Close(); // armored stream >>>> >>>> outputStream.Close(); // underlying stream >>>> >>>> >>>> >>>> reader.Close(); >>>> >>>> >>>> return signature; >>>> >>>> >>>> } >>>> >>> >>> >> >
