Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create encrypting/signing integration test for example/key_from_raw_data.cpp #58

Open
vicsn opened this issue Jun 9, 2020 · 22 comments
Assignees

Comments

@vicsn
Copy link
Contributor

vicsn commented Jun 9, 2020

No description provided.

@skaht
Copy link

skaht commented Jun 10, 2020

Here is a proposal for using blinded deterministic Test Driven Development (TDD) that is to fully mimic results of what gpg batch mode or gpg interactive mode that can be produced by extending https://github.com/summitto/pgp-packet-library/blob/master/examples/key_from_raw_data.cpp as follows to produce a gold standard two tier 9 packet PGP certificate. The pgp-packet-library has the bones to take on what will be called the sally_0E68D9A4-allkeys.asc test that was created during

% date -r 1578020795
Thu Jan  2 22:06:35 EST 2020

What follows frames a smoke test that includes three subkeys, For readers following this thread desiring to better understand, examine https://wiki.debian.org/Subkeys and https://davesteele.github.io/gpg/2014/09/20/anatomy-of-a-gpg-key/.

@skaht
Copy link

skaht commented Jun 10, 2020

The proposed test below has four signature packets.

Purpose is to create PGP packets associated with these two tier hierarchical key types:

 1. master  
 2. sign
 3. encrypt
 4. auth

PGP packet classes required:

 1. secret_key
 2. secret_subkey
 3. signature
 4. user_id

Test vector keys:

Master keys:
% echo f06e15698057a4801fdb8d7008f97abac7b51ce1c2e779a403e9ecf02f65bb4b | ./25519
9fb050155ff5ea4d3fce0c2121945a4447004218d3e7df3d01d5a904573dfddb

Signature subkeys:
% echo 51222405cc982d8b1f6868d6116728409e6a2cc2b43523697345b27315271727 | ./25519
7f4d5eb234a4e5e0185af3e6fd20584b3874e3bd176928b31976b809aee14005

Encryption subkeys:
% echo 462b74948bf3d7c0f1eb35fa21ab3b6138faa61d6e0e1281a9583949494c48a0 | ./endian32 | ./25519 --curve25519
85a437ffa288e779afdcb060bb4068c08bf5404eeafe4272e3400495b4502143

Authentication subkeys:
% echo 559692d22e734ae8d94e142ecee459b1b0279cc31e8f1863ceababd4f21a96bd | ./25519
2c43aa7d8440b04552bc3fd206e8e2ed9b527a94c1e90e2bf59deb16060e749a

Convention for naming important variables inside the sally_0E68D9A4-test.cpp.

const char*          user_id     = "sally <pumpkin@peanuts.com>";
std::time_t          unix_time   = 1578020795;

uint32_t             creation    = unix_time;
uint32_t             expiration  = 157680000;

const char          *master_secret_key_ed25519     = "f06e15698057a4801fdb8d7008f97abac7b51ce1c2e779a403e9ecf02f65bb4b",
                    *master_public_key_ed25519     = "9fb050155ff5ea4d3fce0c2121945a4447004218d3e7df3d01d5a904573dfddb",

                    *sign_secret_subkey_ed25519    = "51222405cc982d8b1f6868d6116728409e6a2cc2b43523697345b27315271727",
                    *sign_public_subkey_ed25519    = "7f4d5eb234a4e5e0185af3e6fd20584b3874e3bd176928b31976b809aee14005",

                    *encrypt_secret_subkey_cv25519 = "462b74948bf3d7c0f1eb35fa21ab3b6138faa61d6e0e1281a9583949494c48a0",
                    *encrypt_public_subkey_cv25519 = "85a437ffa288e779afdcb060bb4068c08bf5404eeafe4272e3400495b4502143",

                    *auth_secret_subkey_ed25519    = "559692d22e734ae8d94e142ecee459b1b0279cc31e8f1863ceababd4f21a96bd",
                    *auth_public_subkey_ed25519    = "2c43aa7d8440b04552bc3fd206e8e2ed9b527a94c1e90e2bf59deb16060e749a";


pgp::vector<uint8_t> master_secret_key,
                     master_public_key,

                     sign_secret_subkey,
                     sign_public_subkey,

                     encrypt_secret_subkey,
                     encrypt_public_subkey,

                     auth_secret_subkey,
                     auth_public_subkey;

pgp::packet          master_secret_key_packet,
                     user_id_packet,
                     master_signature_packet,

                     sign_secret_subkey_packet,
                     sign_signature_packet,

                     encrypt_secret_subkey_packet,
                     encrypt_signature_packet,

                     auth_secret_subkey_packet,
                     auth_signature_packet;

@skaht
Copy link

skaht commented Jun 11, 2020

Starting to code from the spec above.

@vicsn
Copy link
Contributor Author

vicsn commented Jun 11, 2020

Starting to code from the spec above.

If you are interested, we already have a set of integration tests here (without test vectors though): https://github.com/summitto/pgp-key-generation/blob/master/tests/integration_test.py

@skaht
Copy link

skaht commented Jun 12, 2020

The following GNUv3 code builds off key_from_raw_data.cpp to perform a smoke test of the depth and breadth of pgp-packet-library for generating realistic set of nine PGP packets that aggregate into a PGP certificate with a master key and three associated subkeys. This integration smoke test will exercise four different signatures.

The supplied code compiles fine and executes as expected. However, if lines 204 through 225 are uncommented for Packet#6, the code will not compile. This is a breadth issue.

Also having depth issues commented out sections of Packet #3, examine lines commented out from 166 through 181.

  1 #include <iostream>
  2 #include <fstream>
  3 #include <vector>
  4 #include <ctime>
  5 
  6 #include <sodium.h>
  7 
  8 #include <pgp-packet/packet.h>
  9 
 10 using namespace std;
 11 
 12 
 13 int main()
 14 {
 15    std::time_t          unix_time   = 1578020795;  // "date -r 1578020795" yields "Thu Jan  2 22:06:35 EST 2020"
 16    uint32_t             creation    = unix_time;   // "date +%s" yielded 1591556393 at one prior instant of time
 17    uint32_t             expiration  =  157680000;  // "date -r 157680000"  yields "Mon Dec 30 19:00:00 EST 1974"
 18 
 19    const char          *filename = "sally_0E68D9A4-allkeys",
 20                        *email_ID = "sally <pumpkin@peanuts.com>"; // From ./parse.csh sally_0E68D9A4-allkeys.asc
 21 
 22    const char          *master_secret_key_ed25519     = "f06e15698057a4801fdb8d7008f97abac7b51ce1c2e779a403e9ecf02f65bb4b",
 23                        *master_public_key_ed25519     = "9fb050155ff5ea4d3fce0c2121945a4447004218d3e7df3d01d5a904573dfddb",
 24 
 25                        *sign_secret_subkey_ed25519    = "51222405cc982d8b1f6868d6116728409e6a2cc2b43523697345b27315271727",
 26                        *sign_public_subkey_ed25519    = "7f4d5eb234a4e5e0185af3e6fd20584b3874e3bd176928b31976b809aee14005",
 27 
 28                        *encrypt_secret_subkey_cv25519 = "462b74948bf3d7c0f1eb35fa21ab3b6138faa61d6e0e1281a9583949494c48a0",
 29                        *encrypt_public_subkey_cv25519 = "85a437ffa288e779afdcb060bb4068c08bf5404eeafe4272e3400495b4502143",
 30 
 31                        *auth_secret_subkey_ed25519    = "559692d22e734ae8d94e142ecee459b1b0279cc31e8f1863ceababd4f21a96bd",
 32                        *auth_public_subkey_ed25519    = "2c43aa7d8440b04552bc3fd206e8e2ed9b527a94c1e90e2bf59deb16060e749a";
 33 
 34    pgp::vector<uint8_t> master_secret_key,
 35                         master_public_key,
 36 
 37                         sign_secret_subkey,
 38                         sign_public_subkey,
 39 
 40                         encrypt_secret_subkey,
 41                         encrypt_public_subkey,
 42 
 43                         auth_secret_subkey,
 44                         auth_public_subkey;
 45 
 46 
 47    // initialize libsodium
 48    if (sodium_init() == -1)
 49    {
 50        return 1;
 51    }
 52 
 53 
 54    // allocate and initialize binary encoded memory for the keys
 55    master_secret_key.resize(32);
 56    master_public_key.resize(32+1);                                        // extra leading byte to accomodate canonical ed25519 public key prefix
 57 
 58    sign_secret_subkey.resize(32);
 59    sign_public_subkey.resize(32+1);                                       // extra leading byte to accomodate canonical ed25519 public key prefix
 60 
 61    encrypt_secret_subkey.resize(32);
 62    encrypt_public_subkey.resize(32+1);                                    // extra leading byte to accomodate canonical cv25519 public key prefix
 63 
 64    auth_secret_subkey.resize(32);
 65    auth_public_subkey.resize(32+1);                                       // extra leading byte to accomodate canonical ed25519 public key prefix
 66 
 67    sodium_hex2bin( (unsigned char*)&master_secret_key[0],     32, (const char*)master_secret_key_ed25519,     64, NULL, NULL, NULL );
 68    sodium_hex2bin( (unsigned char*)&master_public_key[1],     32, (const char*)master_public_key_ed25519,     64, NULL, NULL, NULL );
 69                                     master_public_key[0]     = 0x40;      // per https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#appendix-B
 70 
 71    sodium_hex2bin( (unsigned char*)&sign_secret_subkey[0],    32, (const char*)sign_secret_subkey_ed25519,    64, NULL, NULL, NULL );
 72    sodium_hex2bin( (unsigned char*)&sign_public_subkey[1],    32, (const char*)sign_public_subkey_ed25519,    64, NULL, NULL, NULL );
 73                                     sign_public_subkey[0]    = 0x40;      // per https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#appendix-B
 74 
 75    sodium_hex2bin( (unsigned char*)&encrypt_secret_subkey[0], 32, (const char*)encrypt_secret_subkey_cv25519, 64, NULL, NULL, NULL );
 76    sodium_hex2bin( (unsigned char*)&encrypt_public_subkey[1], 32, (const char*)encrypt_public_subkey_cv25519, 64, NULL, NULL, NULL );
 77                                     encrypt_public_subkey[0] = 0x40;      // per https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#appendix-B
 78 
 79    sodium_hex2bin( (unsigned char*)&auth_secret_subkey[0],    32, (const char*)auth_secret_subkey_ed25519,    64, NULL, NULL, NULL );
 80    sodium_hex2bin( (unsigned char*)&auth_public_subkey[1],    32, (const char*)auth_public_subkey_ed25519,    64, NULL, NULL, NULL );
 81                                     auth_public_subkey[0]    = 0x40;      // per https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#appendix-B
 82 
 83    /**
 84       Packet #,     Packet Object Name        Packet Class
 85          #1      master_secret_key_packet      secret_key
 86          #2      user_id_packetR               user_id
 87          #3      master_signature_packet       signature
 88 
 89          #4      sign_secret_subkey_packet     secret_subkey
 90          #5      sign_signature_packet         signature
 91 
 92          #6      encrypt_secret_subkey_packet  secret_subkey
 93          #7      encrypt_signature_packet      signature
 94 
 95          #8      auth_secret_subkey_packet     secret_subkey
 96          #9      auth_signature_packet         signature
 97    **/
 98 
 99    // Create the Master secret_key packet
100    pgp::packet master_secret_key_packet                                  // Build the Master "secret_key" Packet #1
101    {
102        pgp::in_place_type_t<pgp::secret_key>{},
103        creation,                                                         // https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-5.2.3.4
104        pgp::key_algorithm::eddsa,                                        // https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-9.1
105        pgp::in_place_type_t<pgp::secret_key::eddsa_key_t>{},             // create a key of the eddsa type
106        std::forward_as_tuple
107        (                                                                 // arguments for the public key
108            pgp::curve_oid::ed25519(),                                    // curve to use, ed25519 for master ed25519 secret_key
109                                                                          // https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-9.2
110                                                                          // https://github.com/summitto/pgp-packet-library/blob/master/include/curve_oid.h#L66
111            pgp::multiprecision_integer{ std::move(master_public_key) }   // append public key
112        ),
113        std::forward_as_tuple
114        (                                                                 // arguments for the secret key
115            pgp::multiprecision_integer{ std::move(master_secret_key) }   // append secret key
116        )
117    };
118 
119 
120    // Create the user_id packet
121    pgp::packet user_id_packet                                            // Build the "user_id" Packet #2
122    {
123        pgp::in_place_type_t<pgp::user_id>{},
124        std::string{ email_ID }
125    };
126 
127 
128    // Create the signature_packet that binds the user_id to the the master_secret_key_packet
129    // along with emamail PGP certificate creation/expiration dates, flags, and preferences
130 
131    const auto& master_signature_key = pgp::get<pgp::secret_key>(master_secret_key_packet.body());
132 
131    const auto& master_signature_key = pgp::get<pgp::secret_key>(master_secret_key_packet.body());
132 
133    pgp::packet master_signature_packet                                   // Build the Master "signature" Packet #3
134    {
135        pgp::in_place_type_t<pgp::signature>{},                           // creates a signature
136        master_signature_key,                                             // with this key
137        pgp::get<pgp::user_id>(user_id_packet.body()),                    // for this given user
138        pgp::signature_subpacket_set
139        {{  // hashed subpackets
140            pgp::signature_subpacket::issuer_fingerprint                                      // https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-5.2.3.28
141            {
142                master_signature_key.fingerprint()
143            },
144 
145            pgp::signature_subpacket::signature_creation_time          { creation         },  // https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-5.2.3.4
146            pgp::signature_subpacket::key_expiration_time              { expiration       },  // https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-5.2.3.6
147            pgp::signature_subpacket::key_flags
148                                                      { pgp::key_flag::certification,         // https://github.com/summitto/pgp-packet-library/blob/master/include/key_flag.h#L13
149                                                        pgp::key_flag::signing            },  // https://github.com/summitto/pgp-packet-library/blob/master/include/key_flag.h#L14
150 //         pgp::signature_subpacket::key_flags                        { 0x01, 0x02       },  // https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-5.2.3.22
151 /**
152                                                                                                  First octet:
153                                                                                                     0x01 - This key may be used to certify other keys.
154                                                                                                     0x02 - This key may be used to sign data.
155                                                                                                     0x04 - This key may be used to encrypt communications.
156                                                                                                     0x08 - This key may be used to encrypt storage.
157                                                                                                     0x10 - The private component of this key may have been split by a
158                                                                                                            secret-sharing mechanism.
159                                                                                                     0x20 - This key may be used for authentication.
160                                                                                                     0x80 - The private component of this key may be in the possession
161                                                                                                            of more than one person.
162                                                                                                  Second octet:
163 
164                                                                                                     0x04 - This key may be used as an additional decryption subkey (ADSK).
165                                                                                                     0x08 - This key may be used for timestamping.
166 **/
167 //         pgp::signature_subpacket::preferred_symmetric_algorithms
168 //                                      { pgp::symmetric_key_algorithm::aes256           },  // https://github.com/summitto/pgp-packet-library/blob/master/include/symmetric_key_algorithm.h#L20
169 //                                        pgp::symmetric_key_algorithm::aes192,              // https://github.com/summitto/pgp-packet-library/blob/master/include/symmetric_key_algorithm.h#L19
170 //                                        pgp::symmetric_key_algorithm::aes128           },  // https://github.com/summitto/pgp-packet-library/blob/master/include/symmetric_key_algorithm.h#L18
171 //         pgp::signature_subpacket::preferred_symmetric_algorithms   { 9, 8, 7 }            // https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-9.3
172 //         pgp::signature_subpacket::preferred_symmetric_algorithms   { 0x090807         },  // https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-9.3
173 
174 /**
175 //         pgp::signature_subpacket::exportable_certification         {                  },  // https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-5.2.3.12
176 //         pgp::signature_subpacket::key_server_preferences           { 0x80             },  // https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-5.2.3.18
177 //         pgp::signature_subpacket::preferred_key_server             {                  },  // https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-5.2.3.19
178 //         pgp::signature_subpacket::preferred_hash_algorithms        { 0x0a, 0x09, 0x08 },  // https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-9.5
179 //         pgp::signature_subpacket::preferred_compression_algorithms { 0x02, 0x03, 0x01 },  // https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-9.4
180 //         pgp::signature_subpacket::features                         { 0x01             },  // https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-5.2.3.25
181 **/
182        }},
183 
184        pgp::signature_subpacket_set
185        {{                                                                                    // unhashed subpackets
186            pgp::signature_subpacket::issuer
187            {
188                 master_signature_key.key_id()
189            }
190        }}
191    };
192 
193 
194 /**
195    pgp::packet sign_secret_subkey_packet                                    // Build Signing "secret_subkey" Packet #4
196    {
197    }
198 
199    pgp::packet sign_signature_packet                                        // Build Signing "signature" Packet #5
200    {
201    }
202 **/
203 
204 /*** DOES-NOT-COMPILE
205    pgp::packet encrypt_secret_subkey_packet                                 // Build Encryption "secret_subkey" Packet #6
206    {
207       pgp::in_place_type_t<pgp::secret_subkey>{},
208       creation,                                                             // create a unix timestamp per
209                                                                             // https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-5.2.3.4
210       pgp::key_algorithm::ecdh,                                             // use the ecdh key algorithm per
211                                                                             // https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-9.1
212       pgp::in_place_type_t<pgp::secret_subkey::ecdh_key_t>{},               // create a secret_subkey of the ecdh type
213       std::forward_as_tuple
214       (                                                                     // arguments for the public key
215         pgp::curve_oid::curve_25519(),                                      // which curve to use, curve_25519 for encrypt_secret_subkey_packet
216                                                                             // https://github.com/summitto/pgp-packet-library/blob/master/include/curve_oid.h#L67
217                                                                             // https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-9.2
218         pgp::multiprecision_integer{ std::move(encrypt_public_subkey) }     // append public key
219       ),
220       std::forward_as_tuple
221       (                                                                     // secret arguments
222         pgp::multiprecision_integer{ std::move(encrypt_secret_subkey) }     // append secret key
223       )
224    };
225 ***/
226 
227 
228 /**
229    pgp::packet encrypt_signature_packet                                     // Build Encryption "signature" Packet #7
230    {
231    }
232 
233    pgp::packet auth_secret_subkey_packet                                    // Build Authentication "secret_subkey" Packet #8
234    {
235    }
236 
237    pgp::packet auth_signature_packet                                        // Build Authentication "signature" Packet #9
238    {
239    }
240 **/
241 
242   // we now have a set of packets, which, when encoded to a file, can
243   // be imported into a compatible pgp implementation (such as gnupg)
244   pgp::vector<uint8_t> data;
245 
246   data.resize
247   (
248     master_secret_key_packet.size() +
249     user_id_packet.size() +
250     master_signature_packet.size()
251 //  encrypt_secret_subkey_packet.size()
252   );
253 
254   // create an encoder writing in the vectors range
255   pgp::range_encoder encoder{ data };
256 
257   // encode all the packets into the encoder
258   master_secret_key_packet.encode(encoder);
259   user_id_packet.encode(encoder);
260   master_signature_packet.encode(encoder);
261 //encrypt_secret_subkey_packet.encode(encoder);
262 
263 
264   // the encoder has now filled the vector with data, which can be written
265   std::ofstream   output{ filename };
266 
267   output.write(reinterpret_cast<const char*>(data.data()), data.size());
268 
269   return 0;
270 }

@skaht
Copy link

skaht commented Jun 12, 2020

The sally_0E68D9A4-allkeys.asc smoke test has traceability to the two GPG batch mode generated files below. The suffix master was added to the filename. The code above does not yet address the synthesis of a PGP revocation certificate.

% cat sally_0E68D9A4-allkeys.asc.master

-----BEGIN PGP PRIVATE KEY BLOCK-----

lFgEXg6vuxYJKwYBBAHaRw8BAQdAn7BQFV/16k0/zgwhIZRaREcAQhjT5989AdWp
BFc9/dsAAQDwbhVpgFekgB/bjXAI+Xq6x7Uc4cLneaQD6ezwL2W7SxGltBtzYWxs
eSA8cHVtcGtpbkBwZWFudXRzLmNvbT6IkwQTFgoAOxYhBCRzVv7G3xDbuWLI2Wrw
u8wOaNmkBQJeDq+7AhsDBQkJZgGABAsJCAcEFQoJCAQWAgMBAh4BAheAAAoJEGrw
u8wOaNmknFABALV7dYOgqf+D0E7ulXyJGD0N2ht5R4XFi97oBcJTypBQAQDlNmZ5
jtSeWsyhAd5BC2aO8u2WIXOGNkg5XOXNpLnZAZxYBF4OsNsWCSsGAQQB2kcPAQEH
QH9NXrI0pOXgGFrz5v0gWEs4dOO9F2kosxl2uAmu4UAFAAD/USIkBcyYLYsfaGjW
EWcoQJ5qLMK0NSNpc0WycxUnFycMHoj1BBgWCgAmFiEEJHNW/sbfENu5YsjZavC7
zA5o2aQFAl4OsNsCGwIFCQHhM4AAgQkQavC7zA5o2aR2IAQZFgoAHRYhBBNOMMJv
NRug9mrC1Sxdo1SrmWLnBQJeDrDbAAoJECxdo1SrmWLnMa4BAKYqXIkPMqCwzzgJ
J+Fbeeq75SLbW5qca6Nm1bgonkL9AP4uaig+U4ukJT5LUhXDQ5z6zzU0IVdOdQKi
1GJoZLiBAiDGAPsGpDI85gnGjCk7Ak1OzrJE/05KALlClYeldMV8Y49W0AD+OeMe
Uc7RkJWafLgEOwdazXXRM6YSvEEFw3F5jXrG1AKcXQReDrEWEgorBgEEAZdVAQUB
AQdAhaQ3/6KI53mv3LBgu0BowIv1QE7q/kJy40AElbRQIUMDAQgHAAD/Rit0lIvz
18Dx6zX6Ias7YTj6ph1uDhKBqVg5SUlMSKAQBIh+BBgWCgAmFiEEJHNW/sbfENu5
YsjZavC7zA5o2aQFAl4OsRYCGwwFCQHhM4AACgkQavC7zA5o2aR54wEA3Zo8P+P9
/uNXc93il5HtmsmJd4sxr4ZLz/mqZ8eqTCYA/11gyVAwUulwrWN6ToCYfb/T/Uvu
LegSqUrZ0ksOz8EFnFgEXg6xRRYJKwYBBAHaRw8BAQdALEOqfYRAsEVSvD/SBuji
7ZtSepTB6Q4r9Z3rFgYOdJoAAP9VlpLSLnNK6NlOFC7O5FmxsCecwx6PGGPOq6vU
8hqWvRH7iH4EGBYKACYWIQQkc1b+xt8Q27liyNlq8LvMDmjZpAUCXg6xRQIbIAUJ
AeEzgAAKCRBq8LvMDmjZpAa5AQDyjLSvRx0v4+UkSuWIoM4hKoAMwE1vWjIHclfq
GkZP+AD/WzZy5hNUHx4AZ9+71D7+kXKT1/9YltuuGcDl75hvBww=
=FX9m
-----END PGP PRIVATE KEY BLOCK-----

% cat sally_0E68D9A4-allkeys.asc.master | sed 's/-----BEGIN PGP PRIVATE KEY BLOCK-----//' | sed 's/-----END PGP PRIVATE KEY BLOCK-----//' | sed '/^$/d' | sed '/^=.*$/d' | tr -d '\n' | bx base64-decode | bx base16-encode

9458045e0eafbb16092b06010401da470f010107409fb050155ff5ea4d3fce0c2121945a4447004218d3e7df3d01d5a904573dfddb000100f06e15698057a4801fdb8d7008f97abac7b51ce1c2e779a403e9ecf02f65bb4b11a5b41b73616c6c79203c70756d706b696e407065616e7574732e636f6d3e88930413160a003b162104247356fec6df10dbb962c8d96af0bbcc0e68d9a405025e0eafbb021b03050909660180040b09080704150a09080416020301021e01021780000a09106af0bbcc0e68d9a49c500100b57b7583a0a9ff83d04eee957c89183d0dda1b794785c58bdee805c253ca90500100e53666798ed49e5acca101de410b668ef2ed962173863648395ce5cda4b9d9019c58045e0eb0db16092b06010401da470f010107407f4d5eb234a4e5e0185af3e6fd20584b3874e3bd176928b31976b809aee140050000ff51222405cc982d8b1f6868d6116728409e6a2cc2b43523697345b273152717270c1e88f50418160a0026162104247356fec6df10dbb962c8d96af0bbcc0e68d9a405025e0eb0db021b02050901e13380008109106af0bbcc0e68d9a476200419160a001d162104134e30c26f351ba0f66ac2d52c5da354ab9962e705025e0eb0db000a09102c5da354ab9962e731ae0100a62a5c890f32a0b0cf380927e15b79eabbe522db5b9a9c6ba366d5b8289e42fd00fe2e6a283e538ba4253e4b5215c3439cfacf353421574e7502a2d4626864b8810220c600fb06a4323ce609c68c293b024d4eceb244ff4e4a00b9429587a574c57c638f56d000fe39e31e51ced190959a7cb8043b075acd75d133a612bc4105c371798d7ac6d4029c5d045e0eb116120a2b06010401975501050101074085a437ffa288e779afdcb060bb4068c08bf5404eeafe4272e3400495b4502143030108070000ff462b74948bf3d7c0f1eb35fa21ab3b6138faa61d6e0e1281a9583949494c48a01004887e0418160a0026162104247356fec6df10dbb962c8d96af0bbcc0e68d9a405025e0eb116021b0c050901e13380000a09106af0bbcc0e68d9a479e30100dd9a3c3fe3fdfee35773dde29791ed9ac989778b31af864bcff9aa67c7aa4c2600ff5d60c9503052e970ad637a4e80987dbfd3fd4bee2de812a94ad9d24b0ecfc1059c58045e0eb14516092b06010401da470f010107402c43aa7d8440b04552bc3fd206e8e2ed9b527a94c1e90e2bf59deb16060e749a0000ff559692d22e734ae8d94e142ecee459b1b0279cc31e8f1863ceababd4f21a96bd11fb887e0418160a0026162104247356fec6df10dbb962c8d96af0bbcc0e68d9a405025e0eb145021b20050901e13380000a09106af0bbcc0e68d9a406b90100f28cb4af471d2fe3e5244ae588a0ce212a800cc04d6f5a32077257ea1a464ff800ff5b3672e613541f1e0067dfbbd43efe917293d7ff5896dbae19c0e5ef986f070c

% cat 247356FEC6DF10DBB962C8D96AF0BBCC0E68D9A4.rev.master

This is a revocation certificate for the OpenPGP key:

pub   ed25519 2020-01-03 [SC] [expires: 2025-01-01]
      247356FEC6DF10DBB962C8D96AF0BBCC0E68D9A4
uid          sally <pumpkin@peanuts.com>

A revocation certificate is a kind of "kill switch" to publicly
declare that a key shall not anymore be used.  It is not possible
to retract such a revocation certificate once it has been published.

Use it to revoke this key in case of a compromise or loss of
the secret key.  However, if the secret key is still accessible,
it is better to generate a new revocation certificate and give
a reason for the revocation.  For details see the description of
of the gpg command "--generate-revocation" in the GnuPG manual.

To avoid an accidental use of this file, a colon has been inserted
before the 5 dashes below.  Remove this colon with a text editor
before importing and publishing this revocation certificate.

:-----BEGIN PGP PUBLIC KEY BLOCK-----
Comment: This is a revocation certificate

iHgEIBYKACAWIQQkc1b+xt8Q27liyNlq8LvMDmjZpAUCXg6vuwIdAAAKCRBq8LvM
DmjZpDVqAP9QSQnSHzJXt+ub4WYW2kkxQ61uOCrUAT88YF5PxOiqeAEA0woZJlwW
taOCSVZ/Sf3pJCQGAXmxL+f1xum54TWvDgo=
=uS5G
-----END PGP PUBLIC KEY BLOCK-----

% echo iHgEIBYKACAWIQQkc1b+xt8Q27liyNlq8LvMDmjZpAUCXg6vuwIdAAAKCRBq8LvMDmjZpDVqAP9QSQnSHzJXt+ub4WYW2kkxQ61uOCrUAT88YF5PxOiqeAEA0woZJlwWtaOCSVZ/Sf3pJCQGAXmxL+f1xum54TWvDgo= | bx base64-decode | bx base16-encode

88780420160a0020162104247356fec6df10dbb962c8d96af0bbcc0e68d9a405025e0eafbb021d00000a09106af0bbcc0e68d9a4356a00ff504909d21f3257b7eb9be16616da493143ad6e382ad4013f3c605e4fc4e8aa780100d30a19265c16b5a38249567f49fde92424060179b12fe7f5c6e9b9e135af0e0a

@skaht
Copy link

skaht commented Jun 12, 2020

The parsing script is an ugly duckling not meant for distribution but here are its results for the nine packet certificate.

% ./parse.csh sally_0E68D9A4-allkeys.asc.master

9458045e0eafbb16092b06010401da470f010107409fb050155ff5ea4d3fce0c2121945a4447004218d3e7df3d01d5a904573dfddb000100f06e15698057a4801fdb8d7008f97abac7b51ce1c2e779a403e9ecf02f65bb4b11a5b41b73616c6c79203c70756d706b696e407065616e7574732e636f6d3e88930413160a003b162104247356fec6df10dbb962c8d96af0bbcc0e68d9a405025e0eafbb021b03050909660180040b09080704150a09080416020301021e01021780000a09106af0bbcc0e68d9a49c500100b57b7583a0a9ff83d04eee957c89183d0dda1b794785c58bdee805c253ca90500100e53666798ed49e5acca101de410b668ef2ed962173863648395ce5cda4b9d9019c58045e0eb0db16092b06010401da470f010107407f4d5eb234a4e5e0185af3e6fd20584b3874e3bd176928b31976b809aee140050000ff51222405cc982d8b1f6868d6116728409e6a2cc2b43523697345b273152717270c1e88f50418160a0026162104247356fec6df10dbb962c8d96af0bbcc0e68d9a405025e0eb0db021b02050901e13380008109106af0bbcc0e68d9a476200419160a001d162104134e30c26f351ba0f66ac2d52c5da354ab9962e705025e0eb0db000a09102c5da354ab9962e731ae0100a62a5c890f32a0b0cf380927e15b79eabbe522db5b9a9c6ba366d5b8289e42fd00fe2e6a283e538ba4253e4b5215c3439cfacf353421574e7502a2d4626864b8810220c600fb06a4323ce609c68c293b024d4eceb244ff4e4a00b9429587a574c57c638f56d000fe39e31e51ced190959a7cb8043b075acd75d133a612bc4105c371798d7ac6d4029c5d045e0eb116120a2b06010401975501050101074085a437ffa288e779afdcb060bb4068c08bf5404eeafe4272e3400495b4502143030108070000ff462b74948bf3d7c0f1eb35fa21ab3b6138faa61d6e0e1281a9583949494c48a01004887e0418160a0026162104247356fec6df10dbb962c8d96af0bbcc0e68d9a405025e0eb116021b0c050901e13380000a09106af0bbcc0e68d9a479e30100dd9a3c3fe3fdfee35773dde29791ed9ac989778b31af864bcff9aa67c7aa4c2600ff5d60c9503052e970ad637a4e80987dbfd3fd4bee2de812a94ad9d24b0ecfc1059c58045e0eb14516092b06010401da470f010107402c43aa7d8440b04552bc3fd206e8e2ed9b527a94c1e90e2bf59deb16060e749a0000ff559692d22e734ae8d94e142ecee459b1b0279cc31e8f1863ceababd4f21a96bd11fb887e0418160a0026162104247356fec6df10dbb962c8d96af0bbcc0e68d9a405025e0eb145021b20050901e13380000a09106af0bbcc0e68d9a406b90100f28cb4af471d2fe3e5244ae588a0ce212a800cc04d6f5a32077257ea1a464ff800ff5b3672e613541f1e0067dfbbd43efe917293d7ff5896dbae19c0e5ef986f070c


1) ECC Secret-Key Packet (Tag 5): 0x94
   Raw Packet: 9458045e0eafbb16092b06010401da470f010107409fb050155ff5ea4d3fce0c2121945a4447004218d3e7df3d01d5a904573dfddb000100f06e15698057a4801fdb8d7008f97abac7b51ce1c2e779a403e9ecf02f65bb4b11a5
   Packet size in bytes         : 90
   Packet body size in bytes    : 0x58 or 88
   Packet Version               : 0x04
             UNIX Epoch Time    : 0x5e0eafbb  or  Thu Jan 2 22:06:35 EST 2020
             Pubkey Algo index  : 0x16 -> EdDSA [RFC8032]
             OID Size in bytes  : 0x09 or 9
             Object Identifier  : 0x2b06010401da470f01 -> 1.3.6.1.4.1.11591.15.1, Ed25519
             KDF Size in bytes  : 0x01 or 1
             KDF Details        : 0x07 -> SHA2-256
             Canonical Prefix   : 0x40 -> Native point format of the curve follows, compressed
           ECC Public Key       : 9fb050155ff5ea4d3fce0c2121945a4447004218d3e7df3d01d5a904573dfddb
           ECC Fingerprint Basis: 990033045e0eafbb16092b06010401da470f010107409fb050155ff5ea4d3fce0c2121945a4447004218d3e7df3d01d5a904573dfddb
           ECC Fingerprint      : 247356fec6df10dbb962c8d96af0bbcc0e68d9a4
    BROKEN ECC Keygrip          : ab9324727165481151cae86271d8506ecf6c3e15
           S2K Hash Header      : 0x00 -> Simple S2K
           S2K Hash Algorithm   : 0x01 -> SHA-1
           S2K Cipher Header    : 0x00 -> No S2K Cipher, No encryption, Cleartext
               Secret Key       : f06e15698057a4801fdb8d7008f97abac7b51ce1c2e779a403e9ecf02f65bb4b
               Checksum         : 0x11a5

2) User ID Packet       (Tag 13): 0xb4
   Raw Packet: b41b73616c6c79203c70756d706b696e407065616e7574732e636f6d3e
   Packet size in bytes         : 29
   Packet body size in bytes    : 0x1b or 27
                 User ID String : sally <pumpkin@peanuts.com>

3) ECC Signature Packet  (Tag 2): 0x88
   Raw Packet: 88930413160a003b162104247356fec6df10dbb962c8d96af0bbcc0e68d9a405025e0eafbb021b03050909660180040b09080704150a09080416020301021e01021780000a09106af0bbcc0e68d9a49c500100b57b7583a0a9ff83d04eee957c89183d0dda1b794785c58bdee805c253ca90500100e53666798ed49e5acca101de410b668ef2ed962173863648395ce5cda4b9d901
   Packet size in bytes         : 149
   Packet body size in bytes    : 0x93 or 147
   Packet Version               : 0x04
                 Signature Type : 0x13 -> Positive certification of a User ID and Public-Key packet.
           Public Key Algorithm : 0x16 -> EdDSA [RFC8032]
                 Hash Algorithm : 0x0a -> SHA2-512 [FIPS180] or SHA512
              HASHED DATA COUNT : 0x003b or 59
   Subpacket #1 Length in bytes : 0x16 or 22
                 Subpacket Type : 0x21 -> Issuer Fingerprint - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-5.2.3.28
             Fingerprint Prefix : 0x04
           Issuer's Fingerprint : 0x247356fec6df10dbb962c8d96af0bbcc0e68d9a4
   Subpacket #2 Length in bytes : 0x05 or 5
                 Subpacket Type : 0x02 -> Issuer Signature Creation Time - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-5.2.3.4
                UNIX Epoch Time : 0x5e0eafbb  or  Thu Jan 2 22:06:35 EST 2020
   Subpacket #3 Length in bytes : 0x02 or 2
                 Subpacket Type : 0x1b -> Key Flags - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-5.2.3.22
                    Hashed Data : 0x03
   Subpacket #4 Length in bytes : 0x05 or 5
                 Subpacket Type : 0x09 -> Key Expiration Time - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-5.2.3.6
                UNIX Epoch Time : 0x09660180  or  Mon Dec 30 19:00:00 EST 1974
   Subpacket #5 Length in bytes : 0x04 or 4
                 Subpacket Type : 0x0b -> Preferred Symmetric Algorithms - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-9.3
                    Hashed Data : 0x090807
   Subpacket #6 Length in bytes : 0x04 or 4
                 Subpacket Type : 0x15 -> Preferred Hash Algorithms - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-9.5
                    Hashed Data : 0x0a0908
   Subpacket #7 Length in bytes : 0x04 or 4
                 Subpacket Type : 0x16 -> Preferred Compression Algorithms - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-9.4
                    Hashed Data : 0x020301
   Subpacket #8 Length in bytes : 0x02 or 2
                 Subpacket Type : 0x1e -> Features - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-5.2.3.25
                    Hashed Data : 0x01
   Subpacket #9 Length in bytes : 0x02 or 2
                 Subpacket Type : 0x17 -> Key Server Preference - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-5.2.3.18
                    Hashed Data : 0x80
            UNHASHED DATA COUNT : 0x000a or 10
   Subpacket #10 Length in bytes : 0x09 or 9
                 Subpacket Type : 0x10 -> Issuer - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-5.2.3.5
                  Unhashed Data : 0x6af0bbcc0e68d9a4
          signedHashValuePrefix : 0x9c50
                   Delimiter #1 : 0x0100
         R Portion of Signature : b57b7583a0a9ff83d04eee957c89183d0dda1b794785c58bdee805c253ca9050
                   Delimiter #2 : 0x0100
         S Portion of Signature : e53666798ed49e5acca101de410b668ef2ed962173863648395ce5cda4b9d901

4) ECC Secret-Subkey Packet (Tag 7): 0x9c
   Raw Packet: 9c58045e0eb0db16092b06010401da470f010107407f4d5eb234a4e5e0185af3e6fd20584b3874e3bd176928b31976b809aee140050000ff51222405cc982d8b1f6868d6116728409e6a2cc2b43523697345b273152717270c1e
   Packet size in bytes         : 90
   Packet body size in bytes    : 0x58 or 88
   Packet Version               : 0x04
             UNIX Epoch Time    : 0x5e0eb0db  or  Thu Jan 2 22:11:23 EST 2020
             Pubkey Algo index  : 0x16 -> EdDSA [RFC8032]
             OID Size in bytes  : 0x09 or 9
             Object Identifier  : 0x2b06010401da470f01 -> 1.3.6.1.4.1.11591.15.1, Ed25519
             KDF Size in bytes  : 0x01 or 1
             KDF Details        : 0x07 -> SHA2-256
             Canonical Prefix   : 0x40 -> Native point format of the curve follows, compressed
           ECC Public Key       : 7f4d5eb234a4e5e0185af3e6fd20584b3874e3bd176928b31976b809aee14005
           ECC Fingerprint Basis: 990033045e0eb0db16092b06010401da470f010107407f4d5eb234a4e5e0185af3e6fd20584b3874e3bd176928b31976b809aee14005
           ECC Fingerprint      : 134e30c26f351ba0f66ac2d52c5da354ab9962e7
    BROKEN ECC Keygrip          : cc6370da82eed8a525984da1a2af15d7bd8dea2c
           S2K Hash Header      : 0x00 -> Simple S2K
           S2K Hash Algorithm   : 0x00 -> MD5 [HAC]
           S2K Cipher Header    : 0xff -> No S2K Cipher, No encryption, Cleartext
               Secret Key       : 51222405cc982d8b1f6868d6116728409e6a2cc2b43523697345b27315271727
               Checksum         : 0x0c1e

5) ECC Signature Packet  (Tag 2): 0x88
   Raw Packet: 88f50418160a0026162104247356fec6df10dbb962c8d96af0bbcc0e68d9a405025e0eb0db021b02050901e13380008109106af0bbcc0e68d9a476200419160a001d162104134e30c26f351ba0f66ac2d52c5da354ab9962e705025e0eb0db000a09102c5da354ab9962e731ae0100a62a5c890f32a0b0cf380927e15b79eabbe522db5b9a9c6ba366d5b8289e42fd00fe2e6a283e538ba4253e4b5215c3439cfacf353421574e7502a2d4626864b8810220c600fb06a4323ce609c68c293b024d4eceb244ff4e4a00b9429587a574c57c638f56d000fe39e31e51ced190959a7cb8043b075acd75d133a612bc4105c371798d7ac6d402
   Packet size in bytes         : 247
   Packet body size in bytes    : 0xf5 or 245
   Packet Version               : 0x04
                 Signature Type : 0x18 -> Subkey Binding Signature.
           Public Key Algorithm : 0x16 -> EdDSA [RFC8032]
                 Hash Algorithm : 0x0a -> SHA2-512 [FIPS180] or SHA512
              HASHED DATA COUNT : 0x0026 or 38
   Subpacket #1 Length in bytes : 0x16 or 22
                 Subpacket Type : 0x21 -> Issuer Fingerprint - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-5.2.3.28
             Fingerprint Prefix : 0x04
           Issuer's Fingerprint : 0x247356fec6df10dbb962c8d96af0bbcc0e68d9a4
   Subpacket #2 Length in bytes : 0x05 or 5
                 Subpacket Type : 0x02 -> Issuer Signature Creation Time - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-5.2.3.4
                UNIX Epoch Time : 0x5e0eb0db  or  Thu Jan 2 22:11:23 EST 2020
   Subpacket #3 Length in bytes : 0x02 or 2
                 Subpacket Type : 0x1b -> Key Flags - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-5.2.3.22
                    Hashed Data : 0x02
   Subpacket #4 Length in bytes : 0x05 or 5
                 Subpacket Type : 0x09 -> Key Expiration Time - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-5.2.3.6
                UNIX Epoch Time : 0x01e13380  or  Thu Dec 31 19:00:00 EST 1970
            UNHASHED DATA COUNT : 0x0081 or 129
   Subpacket #5 Length in bytes : 0x09 or 9
                 Subpacket Type : 0x10 -> Issuer - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-5.2.3.5
                  Unhashed Data : 0x6af0bbcc0e68d9a4
   Subpacket #6 Length in bytes : 0x76 or 118
                 Subpacket Type : 0x20 -> Embedded Signature - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-5.2.3.27
                  Unhashed Data : 0x0419160a001d162104134e30c26f351ba0f66ac2d52c5da354ab9962e705025e0eb0db000a09102c5da354ab9962e731ae0100a62a5c890f32a0b0cf380927e15b79eabbe522db5b9a9c6ba366d5b8289e42fd00fe2e6a283e538ba4253e4b5215c3439cfacf353421574e7502a2d4626864b88102
          signedHashValuePrefix : 0x20c6
                   Delimiter #1 : 0x00fb
         R Portion of Signature : 06a4323ce609c68c293b024d4eceb244ff4e4a00b9429587a574c57c638f56d0
                   Delimiter #2 : 0x00fe
         S Portion of Signature : 39e31e51ced190959a7cb8043b075acd75d133a612bc4105c371798d7ac6d402

6) ECC Secret-Subkey Packet (Tag 7): 0x9c
   Raw Packet: 9c5d045e0eb116120a2b06010401975501050101074085a437ffa288e779afdcb060bb4068c08bf5404eeafe4272e3400495b4502143030108070000ff462b74948bf3d7c0f1eb35fa21ab3b6138faa61d6e0e1281a9583949494c48a01004
   Packet size in bytes         : 95
   Packet body size in bytes    : 0x5d or 93
   Packet Version               : 0x04
             UNIX Epoch Time    : 0x5e0eb116  or  Thu Jan 2 22:12:22 EST 2020
             Pubkey Algo index  : 0x12 -> ECDH public key algorithm
             OID Size in bytes  : 0x0a or 10
             Object Identifier  : 0x2b060104019755010501 -> 1.3.6.1.4.1.3029.1.5.1, Curve25519
             KDF Size in bytes  : 0x01 or 1
             KDF Details        : 0x07 -> SHA2-256
             Canonical Prefix   : 0x40 -> Native point format of the curve follows, compressed
           ECC Public Key       : 85a437ffa288e779afdcb060bb4068c08bf5404eeafe4272e3400495b4502143
           ECC Mystery Field    : 0x03010807
           ECC Fingerprint Basis: 990038045e0eb116120a2b06010401975501050101074085a437ffa288e779afdcb060bb4068c08bf5404eeafe4272e3400495b450214303010807
           ECC Fingerprint      : ebc8e84eda8bfbcde085c976c18ddc38afe302cc
    BROKEN ECC Keygrip          : f08043e987e1b3dc077ce8b7d272450d7265cded
           S2K Hash Header      : 0x00 -> Simple S2K
           S2K Hash Algorithm   : 0x00 -> MD5 [HAC]
           S2K Cipher Header    : 0xff -> No S2K Cipher, No encryption, Cleartext
               Secret Key       : 462b74948bf3d7c0f1eb35fa21ab3b6138faa61d6e0e1281a9583949494c48a0
               Checksum         : 0x1004

7) ECC Signature Packet  (Tag 2): 0x88
   Raw Packet: 887e0418160a0026162104247356fec6df10dbb962c8d96af0bbcc0e68d9a405025e0eb116021b0c050901e13380000a09106af0bbcc0e68d9a479e30100dd9a3c3fe3fdfee35773dde29791ed9ac989778b31af864bcff9aa67c7aa4c2600ff5d60c9503052e970ad637a4e80987dbfd3fd4bee2de812a94ad9d24b0ecfc105
   Packet size in bytes         : 128
   Packet body size in bytes    : 0x7e or 126
   Packet Version               : 0x04
                 Signature Type : 0x18 -> Subkey Binding Signature.
           Public Key Algorithm : 0x16 -> EdDSA [RFC8032]
                 Hash Algorithm : 0x0a -> SHA2-512 [FIPS180] or SHA512
              HASHED DATA COUNT : 0x0026 or 38
   Subpacket #1 Length in bytes : 0x16 or 22
                 Subpacket Type : 0x21 -> Issuer Fingerprint - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-5.2.3.28
             Fingerprint Prefix : 0x04
           Issuer's Fingerprint : 0x247356fec6df10dbb962c8d96af0bbcc0e68d9a4
   Subpacket #2 Length in bytes : 0x05 or 5
                 Subpacket Type : 0x02 -> Issuer Signature Creation Time - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-5.2.3.4
                UNIX Epoch Time : 0x5e0eb116  or  Thu Jan 2 22:12:22 EST 2020
   Subpacket #3 Length in bytes : 0x02 or 2
                 Subpacket Type : 0x1b -> Key Flags - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-5.2.3.22
                    Hashed Data : 0x0c
   Subpacket #4 Length in bytes : 0x05 or 5
                 Subpacket Type : 0x09 -> Key Expiration Time - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-5.2.3.6
                UNIX Epoch Time : 0x01e13380  or  Thu Dec 31 19:00:00 EST 1970
            UNHASHED DATA COUNT : 0x000a or 10
   Subpacket #5 Length in bytes : 0x09 or 9
                 Subpacket Type : 0x10 -> Issuer - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-5.2.3.5
                  Unhashed Data : 0x6af0bbcc0e68d9a4
          signedHashValuePrefix : 0x79e3
                   Delimiter #1 : 0x0100
         R Portion of Signature : dd9a3c3fe3fdfee35773dde29791ed9ac989778b31af864bcff9aa67c7aa4c26
                   Delimiter #2 : 0x00ff
         S Portion of Signature : 5d60c9503052e970ad637a4e80987dbfd3fd4bee2de812a94ad9d24b0ecfc105

8) ECC Secret-Subkey Packet (Tag 7): 0x9c
   Raw Packet: 9c58045e0eb14516092b06010401da470f010107402c43aa7d8440b04552bc3fd206e8e2ed9b527a94c1e90e2bf59deb16060e749a0000ff559692d22e734ae8d94e142ecee459b1b0279cc31e8f1863ceababd4f21a96bd11fb
   Packet size in bytes         : 90
   Packet body size in bytes    : 0x58 or 88
   Packet Version               : 0x04
             UNIX Epoch Time    : 0x5e0eb145  or  Thu Jan 2 22:13:09 EST 2020
             Pubkey Algo index  : 0x16 -> EdDSA [RFC8032]
             OID Size in bytes  : 0x09 or 9
             Object Identifier  : 0x2b06010401da470f01 -> 1.3.6.1.4.1.11591.15.1, Ed25519
             KDF Size in bytes  : 0x01 or 1
             KDF Details        : 0x07 -> SHA2-256
             Canonical Prefix   : 0x40 -> Native point format of the curve follows, compressed
           ECC Public Key       : 2c43aa7d8440b04552bc3fd206e8e2ed9b527a94c1e90e2bf59deb16060e749a
           ECC Fingerprint Basis: 990033045e0eb14516092b06010401da470f010107402c43aa7d8440b04552bc3fd206e8e2ed9b527a94c1e90e2bf59deb16060e749a
           ECC Fingerprint      : f468a64bcadfe4fb31c3e9cbae40cce81e41a4ca
    BROKEN ECC Keygrip          : 2c078091f57d93d58caede50074b7cc5ad9ae46a
           S2K Hash Header      : 0x00 -> Simple S2K
           S2K Hash Algorithm   : 0x00 -> MD5 [HAC]
           S2K Cipher Header    : 0xff -> No S2K Cipher, No encryption, Cleartext
               Secret Key       : 559692d22e734ae8d94e142ecee459b1b0279cc31e8f1863ceababd4f21a96bd
               Checksum         : 0x11fb

9) ECC Signature Packet  (Tag 2): 0x88
   Raw Packet: 887e0418160a0026162104247356fec6df10dbb962c8d96af0bbcc0e68d9a405025e0eb145021b20050901e13380000a09106af0bbcc0e68d9a406b90100f28cb4af471d2fe3e5244ae588a0ce212a800cc04d6f5a32077257ea1a464ff800ff5b3672e613541f1e0067dfbbd43efe917293d7ff5896dbae19c0e5ef986f070c
   Packet size in bytes         : 128
   Packet body size in bytes    : 0x7e or 126
   Packet Version               : 0x04
                 Signature Type : 0x18 -> Subkey Binding Signature.
           Public Key Algorithm : 0x16 -> EdDSA [RFC8032]
                 Hash Algorithm : 0x0a -> SHA2-512 [FIPS180] or SHA512
              HASHED DATA COUNT : 0x0026 or 38
   Subpacket #1 Length in bytes : 0x16 or 22
                 Subpacket Type : 0x21 -> Issuer Fingerprint - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-5.2.3.28
             Fingerprint Prefix : 0x04
           Issuer's Fingerprint : 0x247356fec6df10dbb962c8d96af0bbcc0e68d9a4
   Subpacket #2 Length in bytes : 0x05 or 5
                 Subpacket Type : 0x02 -> Issuer Signature Creation Time - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-5.2.3.4
                UNIX Epoch Time : 0x5e0eb145  or  Thu Jan 2 22:13:09 EST 2020
   Subpacket #3 Length in bytes : 0x02 or 2
                 Subpacket Type : 0x1b -> Key Flags - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-5.2.3.22
                    Hashed Data : 0x20
   Subpacket #4 Length in bytes : 0x05 or 5
                 Subpacket Type : 0x09 -> Key Expiration Time - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-5.2.3.6
                UNIX Epoch Time : 0x01e13380  or  Thu Dec 31 19:00:00 EST 1970
            UNHASHED DATA COUNT : 0x000a or 10
   Subpacket #5 Length in bytes : 0x09 or 9
                 Subpacket Type : 0x10 -> Issuer - https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-5.2.3.5
                  Unhashed Data : 0x6af0bbcc0e68d9a4
          signedHashValuePrefix : 0x06b9
                   Delimiter #1 : 0x0100
         R Portion of Signature : f28cb4af471d2fe3e5244ae588a0ce212a800cc04d6f5a32077257ea1a464ff8
                   Delimiter #2 : 0x00ff
         S Portion of Signature : 5b3672e613541f1e0067dfbbd43efe917293d7ff5896dbae19c0e5ef986f070c

@skaht
Copy link

skaht commented Jun 16, 2020

Worth noting the signature types for the smoke test above are of types described at https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-5.2.1:

3) Signature Type : 0x13 -> Positive certification of a User ID and Public-Key packet.
5) Signature Type : 0x18 -> Subkey Binding Signature.  (subkey used for signing)
7) Signature Type : 0x18 -> Subkey Binding Signature.  (subkey used for encryption)
9) Signature Type : 0x18 -> Subkey Binding Signature.  (subkey used for authentication)

The revocation signature packet above is of type 0x20.

0x20  -> "Key revocation signature." applies to the master key. 
0x28  -> "Subkey revocation signature."  will apply to subkeys. (hunting for any of these)

It is worth noting that from an analysis of the g10/keygen.c: write_keybinding() function reveals that an authentication subkey really requires two signatures to be made.

err = make_keysig_packet (ctrl, &sig, pri_pk, NULL, sub_pk, pri_psk, 
                                               0x18, 0, timestamp, 0, 
                                              keygen_add_key_flags_and_expire, &oduap, cache_nonce);

err = make_backsig (ctrl, sig, pri_pk, sub_pk, sub_psk, timestamp, cache_nonce); 

The make_backsig then performs a make_keysig_packet(...) call requiring a 0x19 signature.

The way signatures are created for 0x13, 0x18, 0x19, and 0x20 are different according to https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#section-5.2.4. How those signatures are created in the RFC appear to lack sufficient detail.

From https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#appendix-A.2, the second packet
885e040016080006050255f95f95000a09108cfde12197965a9af622010056f90cca98e2102637bd983fdb16c131dfd27ed82bf4dde5606e0d756aed33660100d09c4fa11527f038e0f57f22 01d82f2ea2c9033265fa6ceb489e854bae61b404
is non-normative of

Signature Type : 0x00 -> Signature of a binary document.

@skaht
Copy link

skaht commented Jun 18, 2020

Added a post at https://www.reddit.com/r/pgp/comments/hb6jxp/analysis_of_a_raw_pgp_signature_packet_0x13/ for how to compute the R&S signature components for packet #3 above.

I'm confident the ./sign program used works properly because it produced identical test vector results to https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09#appendix-A.2.

% echo 4f70656e504750040016080006050255f95f9504ff0000000c | bx sha256

f6220a3f757814f4c2176ffbb68b00249cd4ccdc059c4b34ad871f30b1740280

% ./sign -k 1a8b1ff05ded48e18bf50166c664ab023ea70003d78d9e41f5758a91d850f8d2 -m f6220a3f757814f4c2176ffbb68b00249cd4ccdc059c4b34ad871f30b1740280

            ED25519 R Signature Component : 56f90cca98e2102637bd983fdb16c131dfd27ed82bf4dde5606e0d756aed3366                                            
            ED25519 S Signature Component : d09c4fa11527f038e0f57f2201d82f2ea2c9033265fa6ceb489e854bae61b404

@skaht
Copy link

skaht commented Jun 20, 2020

https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=g10/sign.c;h=6e9f68ec041b8adf3c197a70aa4bf93cad57b5e3;hb=refs/heads/STABLE-BRANCH-2-2#l1569 is relevant to https://www.rfc-editor.org/rfc/rfc2440.html#section-5.2.4 "Computing Signatures"

After examining https://docs.sequoia-pgp.org/src/sequoia_openpgp/serialize.rs.htm, the following concerning certificate building also looks promising:

  1. sequoia/openpgp/src/cert/builder.rs
  2. sequoia/openpgp/src/crypto/hash.rs
  3. sequoia/openpgp/src/types/mod.rs

The main issue is the references above is they were not designed for creating deterministic/recoverable PGP certificates, neither public nor private.

@vicsn
Copy link
Contributor Author

vicsn commented Jun 25, 2020

Thanks for the research @skaht, are you happy with the preliminary results? May I ask where the parse.csh and sign programs are from?

@skaht
Copy link

skaht commented Jun 25, 2020

Both parse.csh and sign.cpp are exploratory code I wrote to provide feedback when trying to understand RFC 4880 and using gpg as the reference PGP implementation. https://dump.sequoia-pgp.org/ will be more useful than parse.csh. The sign.cpp code uses uses libsodium's crypto_sign_detached() function.

Was really hoping to utilize the pgp-packet-library package to deterministically create PGP certificates, but this package does not yet have enough implemented depth and breadth as the use-case driven code up top demonstrates. I'm on a tight schedule and will continue to press forward to develop a less functional (easier to audit) but immediately practicable PGP certificate synthesis package to mitigate schedule risks.

@skaht
Copy link

skaht commented Jun 25, 2020

Any estimates as too when subkey signature support for packets no. 5, no. 7, no. 9 mentioned as inline code comments in line 83 through 97?

@vicsn
Copy link
Contributor Author

vicsn commented Jul 1, 2020

Hi @skaht, unfortunately we can't give any estimates at the moment. We'll notify you when we continue with the topic!

@skaht
Copy link

skaht commented Aug 17, 2020

Figured how to use gpg libraries to compute keygrips directly from both ed25519 and cv25519 public key s expressions. Moving on to computing deterministic certificates using gpg libraries.

@skaht
Copy link

skaht commented Sep 2, 2020

GPGME is nothing more than a native "C/C++/Python" wrapper around gpg. This became obvious when I dug down through the GPGME Library source code used to synthesize keys corresponding to my top-level ikc.c source code I wrote that linked to the GPGME Library.

  1. vi +2601 gpgme-1.14.0/src/engine-gpg.c -> Synthesizes PGP primary/master keys
  2. vi +2527 gpgme-1.14.0/src/engine-gpg.c -> Synthesizes PGP subkeys (e.g., sign, encrypt, authenticate )

@skaht
Copy link

skaht commented Dec 9, 2020

Okay guys there is now working C++ code (not pgp-packet-library) to synthesize deterministic OpenPGP master, sign, encr, auth keys and associated certs/keyblocks.

The major issue I have is there no dependable means I've identified to determine the two byte field delimiters separating secret keys and signature values from other fields. Other than that, I'm 97% of the way there...

Not apparent how sections of https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-10#section-5.2.4 and https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-10#section-5.5.3 are useful concerning determining the delimiter rules.

Delimiters tend to be 0x0100, 0x00ff, 0x00fe, 0x00fc, 0x00fb. Just need to understand the method to the madness...

If delimiters are replaced with those created by gpg, the same certificates can be synthesized. If the delimiters are not replaced, it appears gpg can still import the externally generated certs and functions.

@skaht
Copy link

skaht commented Dec 29, 2020

C++ constructor overloading can be applied for synthesizing Primary and Secondary secret keys and different signature types such 0x13 (primary cert), 0x18 (subkey certs), 0x19 (sign subkey backsignature), 0x20 (primary revocation cert), contextually sensitive keychain 0x28 (subkey revocation certs).

GPG has no batch capability for generating subkey revocation certs in advance, requires being in the interactive mode.

@skaht
Copy link

skaht commented Feb 14, 2021

It is interesting to contrast the output results of June 12th, 2020 results above to:

% cat sally_0E68D9A4_ikop.asc | gpg --list-packets --verbose

# off=0 ctb=94 tag=5 hlen=2 plen=88
:secret key packet:
version 4, algo 22, created 1578020795, expires 0
pkey[0]: 092B06010401DA470F01 ed25519 (1.3.6.1.4.1.11591.15.1)
pkey[1]: 409FB050155FF5EA4D3FCE0C2121945A4447004218D3E7DF3D01D5A904573DFDDB
skey[2]: F06E15698057A4801FDB8D7008F97ABAC7B51CE1C2E779A403E9ECF02F65BB4B
checksum: 11a5
keyid: 6AF0BBCC0E68D9A4

# off=90 ctb=b4 tag=13 hlen=2 plen=27
:user ID packet: "sally pumpkin@peanuts.com"

# off=119 ctb=88 tag=2 hlen=2 plen=147
:signature packet: algo 22, keyid 6AF0BBCC0E68D9A4
version 4, created 1578020795, md5len 0, sigclass 0x13
digest algo 10, begin of digest 9c 50
hashed subpkt 33 len 21 (issuer fpr v4 247356FEC6DF10DBB962C8D96AF0BBCC0E68D9A4)
hashed subpkt 2 len 4 (sig created 2020-01-03)
hashed subpkt 27 len 1 (key flags: 03)
hashed subpkt 9 len 4 (key expires after 5y0d0h0m)
hashed subpkt 11 len 3 (pref-sym-algos: 9 8 7)
hashed subpkt 21 len 3 (pref-hash-algos: 10 9 8)
hashed subpkt 22 len 3 (pref-zip-algos: 2 3 1)
hashed subpkt 30 len 1 (features: 01)
hashed subpkt 23 len 1 (keyserver preferences: 80)
subpkt 16 len 8 (issuer key ID 6AF0BBCC0E68D9A4)
data: B57B7583A0A9FF83D04EEE957C89183D0DDA1B794785C58BDEE805C253CA9050
data: E53666798ED49E5ACCA101DE410B668EF2ED962173863648395CE5CDA4B9D901

# off=268 ctb=9c tag=7 hlen=2 plen=88
:secret sub key packet:
version 4, algo 22, created 1578021083, expires 0
pkey[0]: 092B06010401DA470F01 ed25519 (1.3.6.1.4.1.11591.15.1)
pkey[1]: 407F4D5EB234A4E5E0185AF3E6FD20584B3874E3BD176928B31976B809AEE14005
skey[2]: 51222405CC982D8B1F6868D6116728409E6A2CC2B43523697345B27315271727
checksum: 0c1e
keyid: 2C5DA354AB9962E7

# off=358 ctb=88 tag=2 hlen=2 plen=245
:signature packet: algo 22, keyid 6AF0BBCC0E68D9A4
version 4, created 1578021083, md5len 0, sigclass 0x18
digest algo 10, begin of digest 20 c6
hashed subpkt 33 len 21 (issuer fpr v4 247356FEC6DF10DBB962C8D96AF0BBCC0E68D9A4)
hashed subpkt 2 len 4 (sig created 2020-01-03)
hashed subpkt 27 len 1 (key flags: 02)
hashed subpkt 9 len 4 (key expires after 1y0d0h0m)
subpkt 16 len 8 (issuer key ID 6AF0BBCC0E68D9A4)
subpkt 32 len 117 (signature: v4, class 0x19, algo 22, digest algo 10)
data: 06A4323CE609C68C293B024D4ECEB244FF4E4A00B9429587A574C57C638F56D0
data: 39E31E51CED190959A7CB8043B075ACD75D133A612BC4105C371798D7AC6D402

# off=605 ctb=9c tag=7 hlen=2 plen=93
:secret sub key packet:
version 4, algo 18, created 1578021142, expires 0
pkey[0]: 0A2B060104019755010501 cv25519 (1.3.6.1.4.1.3029.1.5.1)
pkey[1]: 4085A437FFA288E779AFDCB060BB4068C08BF5404EEAFE4272E3400495B4502143
pkey[2]: 03010807
skey[3]: 462B74948BF3D7C0F1EB35FA21AB3B6138FAA61D6E0E1281A9583949494C48A0
checksum: 1004
keyid: C18DDC38AFE302CC

# off=700 ctb=88 tag=2 hlen=2 plen=126
:signature packet: algo 22, keyid 6AF0BBCC0E68D9A4
version 4, created 1578021142, md5len 0, sigclass 0x18
digest algo 10, begin of digest 79 e3
hashed subpkt 33 len 21 (issuer fpr v4 247356FEC6DF10DBB962C8D96AF0BBCC0E68D9A4)
hashed subpkt 2 len 4 (sig created 2020-01-03)
hashed subpkt 27 len 1 (key flags: 0C)
hashed subpkt 9 len 4 (key expires after 1y0d0h0m)
subpkt 16 len 8 (issuer key ID 6AF0BBCC0E68D9A4)
data: DD9A3C3FE3FDFEE35773DDE29791ED9AC989778B31AF864BCFF9AA67C7AA4C26
data: 5D60C9503052E970AD637A4E80987DBFD3FD4BEE2DE812A94AD9D24B0ECFC105

# off=828 ctb=9c tag=7 hlen=2 plen=88
:secret sub key packet:
version 4, algo 22, created 1578021189, expires 0
pkey[0]: 092B06010401DA470F01 ed25519 (1.3.6.1.4.1.11591.15.1)
pkey[1]: 402C43AA7D8440B04552BC3FD206E8E2ED9B527A94C1E90E2BF59DEB16060E749A
skey[2]: 559692D22E734AE8D94E142ECEE459B1B0279CC31E8F1863CEABABD4F21A96BD
checksum: 11fb
keyid: AE40CCE81E41A4CA

# off=918 ctb=88 tag=2 hlen=2 plen=126
:signature packet: algo 22, keyid 6AF0BBCC0E68D9A4
version 4, created 1578021189, md5len 0, sigclass 0x18
digest algo 10, begin of digest 06 b9
hashed subpkt 33 len 21 (issuer fpr v4 247356FEC6DF10DBB962C8D96AF0BBCC0E68D9A4)
hashed subpkt 2 len 4 (sig created 2020-01-03)
hashed subpkt 27 len 1 (key flags: 20)
hashed subpkt 9 len 4 (key expires after 1y0d0h0m)
subpkt 16 len 8 (issuer key ID 6AF0BBCC0E68D9A4)
data: F28CB4AF471D2FE3E5244AE588A0CE212A800CC04D6F5A32077257EA1A464FF8
data: 5B3672E613541F1E0067DFBBD43EFE917293D7FF5896DBAE19C0E5EF986F070C

The net result is not all fields are shown with the gpg command, for example:

  1. Secret Key and Secret Subkey Packets don't show the 3 bytes prior to the secret keys
  2. Signature Packets don't show the two 2-byte R and S field delimiters ( Delimiter #1 and Delimiter #2 )

@skaht
Copy link

skaht commented Feb 14, 2021

  1. For Secret Key and Secret Subkey Packets, https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-10#section-3.7 appears to have applicability to the 3 bytes prior to secret keys.
  2. For Signature Packets, It is unclear what the rule sets are for computing the two bytes for Delimiter #1 and Delimiter #2 above.

Not clear if gnupg-2.2.*/doc/DETAILS is useful for resolving the the details for Delimeter #1 and Delimiter #2 above.

@skaht
Copy link

skaht commented Feb 20, 2021

Turned out that the 2-byte signature headers are nothing more than libgcrypt artifacts that store the bits required to contain the R and S signatures. This detail was not documented in RFC 4880bis10.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants