summaryrefslogtreecommitdiffstats
path: root/pickles/openpgp.pk
blob: 1f2b522f2fbc36e52de6380124ecc2aa612b2b73 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
//
// OpenPGP RFC 4880 pickle by apache2, april 2022
//
// This is incomplete, but may be of use, at least to people looking to
// *read* binary OpenPGP files.
//
// // Example:
// var r=open("real.pgp");
// var parse = pgp_file @ r : 0#B;
// printf("%v", parse);
// // ensure we only consumed the intended length:
// for (var p = 0; p < parse.packets'length; p++) {
//   assert(parse.packets[p].header.length() == parse.packets[p].payload'size'magnitude/8);
// }
//

fun packet_tag_to_a = (uint<8> tag)string:{
  if (tag == 1) { return "public-key-encrypted-session"; }
  else if (tag == 2) { return "signature"; }
  else if (tag == 3) { return "symmetric-key-encrypted-session-key"; }
  else if (tag == 4) { return "one-pass-signature"; }
  else if (tag == 5) { return "secret-key"; }
  else if (tag == 6) { return "public-key"; }
  else if (tag == 7) { return "secret-subkey"; }
  else if (tag == 8) { return "compressed-data-packet"; }
  else if (tag == 9) { return "symmetrically-encrypted-data"; }
  else if (tag == 10) { return "marker"; }
  else if (tag == 11) { return "literal-data"; }
  else if (tag == 12) { return "trust"; }
  else if (tag == 13) { return "uid"; }
  else if (tag == 14) { return "public-subkey"; }
  // 
  else if (tag == 17) { return "user-attribute"; }
  else if (tag == 18) { return "encrypted"; }
  else if (tag == 19) { return "modification-detection-code"; }
  else if (tag == 20) { return "encrypted-aead"; }
  return "UNKNOWN";
}
type pgp_version = union {
  char v3 == 3;
  char v4 == 4;
  char unknown;
  method _print=void:{
    try {v3;print("v3");return;}catch{}
    try {v4;print("v4");return;}catch{}
    printf("v%u8d", unknown);
  }
};
type pgp_v4_packet_length = union {
  struct uint<8> {
    uint<8> packed : packed <= 191;
  } uint8;
  struct uint<16> {
    uint<8> packed : 192 <= packed && packed <= 223;
    uint<8> shifted;
    method length = uint<32>: {
      return ((packed - 192) <<. 8) + shifted + 192;
    }
  } uint16;
  uint<8> partial : 224 <= partial && partial <= 254;
  struct uint<40> {
    uint<8> all == 0xff;
    big uint<32> length;
  } uint32;
  method length = uint<32>: {
  
    try { return uint8.packed; } catch {};
    try { return uint16.length(); } catch {};
    try { return uint32.length; } catch {};
    printf("WTF: %v\n", partial);
  }
};
type pgp_packet_header = struct {
  uint<1> bit_7 == 1; // MSB is ALWAYS set
  uint<1> v4_format; // 1 if "new"
  uint<4> old_packet_tag;
  uint<2> old_length_bits if v4_format;
  union {
    struct {
      uint<2> typ == 0;
      uint<8> length;
    } length_one;
    struct {
      uint<2> typ == 1;
      uint<16> length;
    } length_two;
    struct {
      uint<2> typ == 2;
      uint<32> length;
    } length_four;
    // TODO indeterminate length
  } v3_length if !v4_format;
  fun v3_length_calc = uint<32>: {
    try { return v3_length.length_one.length; } catch{}
    try { return v3_length.length_two.length; } catch{}
    try { return v3_length.length_four.length; } catch{}
  }
  pgp_v4_packet_length v4_length if v4_format;
  method length = uint<32>: {
    if (v4_format) {
      return v4_length.length();
    } else {
      return v3_length_calc();
    }
  }
  var packet_tag = v4_format
    ? (old_packet_tag <<. 2) | old_length_bits
    : old_packet_tag;
  method get_packet_tag = uint: { return packet_tag; }
  method _print = void:{
    printf("{packet=%s(%u8d),format:%s,length=%u32d}\n",
      packet_tag_to_a(packet_tag), packet_tag,
      v4_format ? "v4" : "v3",
      length()
    );
  }
};

type mpi = struct { // short for "multi-precision integer" aka bignum
  uint<16> bitlen;
  var bytelen = (bitlen + 7) / 8;
  byte[bytelen] num; // TODO I believe these are big-endian need to check RFC 4880
  method _print = void:{
    printf("mpi{bitlen=%u16d,num=", bitlen);
    if (bytelen > 16) {
      print("...");
    } else if (bytelen <=8) {
      printf("0x%u32x", num as uint<64> );
    } else {
      printf("###");
    }
    printf("}\n");
  }
};

type pgp_public_key = struct {
  pgp_version version;
  big uint<32> timestamp;
  uint<8> algo;
  union {
    struct {
      mpi n;
      mpi e;
    } rsa : algo in [1,2,3]; // rsa_encrypt_or_sign, rsa_encrypt, rsa_sign
    struct {
      mpi p; mpi g; mpi y;
    } elgamal : algo == 16;
    struct {
      mpi p;
      mpi q;
      mpi gg;
      mpi y;
    } dsa : algo == 17;
    byte[0] unknown; // the remainder is picked up in pgp_packet.extra below
  } asf; // algorithm-specific data
};

type pgp_subpacket_header = struct uint<8> { uint<1> critical; uint<7> tag; };
type pgp_signature_subpacket = struct {
  pgp_v4_packet_length len;
  pgp_subpacket_header hdr;
  union {
    big uint<32> signature_creation_time : hdr.tag == 2;
    big uint<32> key_expiration_time : hdr.tag == 9;
    byte[len.length()#B -hdr'size] preferred_symmetric_algos : hdr.tag == 11;
    byte[len.length()#B -hdr'size] preferred_hash_algos : hdr.tag == 21;
    byte[len.length()#B -hdr'size] preferred_compression_algos : hdr.tag == 22; //aka pref-zip-algos in gpg
    byte[len.length()#B -hdr'size] key_server_preferences : hdr.tag == 23;
    struct uint<8> {
      uint<2>; // bit 6..7: unsure
      uint<1> authentication; // bit 5
      uint<1>; // bit 4, unsure
      uint<1> encrypt_storage; // bit 3
      uint<1> encrypt_communications; // bit 2
      uint<1> sign_data;    // bit 1 
      uint<1> certify_keys; // bit 0
    } key_usage_flags: hdr.tag == 27; // aka "key flags" in gpg
    byte[len.length()#B -hdr'size] features : hdr.tag == 30; // 0x01 is "modification detection", ie supports MDC
    struct {pgp_version version; byte[20] hash;
      method _print = void:{
        printf("%v:", version);
        for(var i = 0; i < hash'length; i++){
	  printf("%u8x", hash[i]);
	}
      }
    } issuer_fingerprint: hdr.tag == 0x21; // and len.length() == 21
    byte[len.length()#B-hdr'size] unknown;
  } data;
};

// #!!# parse.packets[2].payload.signature.parse_hashed_subpackets()
type pgp_signature = struct {
  pgp_version version;
  uint<8> signature_type;
  uint<8> pk_algo;
  uint<8> hash_algo;
  offset<uint<16>,B> hashed_subpacket_len;
  byte[hashed_subpacket_len] hashed_subpackets;
  method parse_hashed_subpackets = pgp_signature_subpacket[]:{
    var consumed = 0#B;
    var ret = pgp_signature_subpacket[]();
    while (consumed < hashed_subpacket_len) {
      var this = pgp_signature_subpacket @ 0 // TODO pick right ios
      : (hashed_subpackets'offset + consumed);
      consumed += this'size;
      ret += [this];
    }
    return ret;
  }
  byte[hashed_subpacket_len - hashed_subpackets'size] what_the_fuck;
  // assert (hashed_subpacket_len == hashed_subpackets'size); // TODO
  uint<16> unhashed_subpacket_len;
  byte[unhashed_subpacket_len] unhashed_subpackets;

  uint<16> two_octet_checksum; // "begin of digest" in gpg --list-packets
  // this is the leftmost two bytes of the ${hash_algo}-digest of the
  // hash which gets signed in the algorithm-specific fields ("asf") below.

  union {
    struct {
      mpi m_pow_d_mod_n;
    } rsa : pk_algo in [1,3]; // rsa_encrypt_or_sign, rsa_sign
    struct {
      mpi r; mpi s;
    } dsa : pk_algo == 17;
    byte[0] unknown : pk_algo;
  } asf; // algorithm-specific fields containing the actual signature
};

type pgp_packet = struct {
  pgp_packet_header header;
  union {
    pgp_signature signature : header.get_packet_tag == 2;
    pgp_public_key public : header.get_packet_tag == 6;
    struct {
      byte[header.length()] uid;
      method _print = void: {
        for(var i=0;i < uid'length;i++){
          printf("%c", uid[i]);
        }
      }
    } uid : header.get_packet_tag() == 13;
    byte[header.length()] unknown;
  } payload;
  var extraneous = header.length()  - (payload'size'magnitude*payload'size'unit)/8;
  byte[extraneous] extra if payload'size'magnitude;
  method _print = void:{
    printf("%v", header);
    if (header.get_packet_tag == 6) {
      //printf("%v", payload.public);
    } else
    if (header.get_packet_tag() in [13]) {
      try { payload.uid;
        printf("\n%v", payload.uid);
      } catch {
        printf("unable to print payload.uid");
      }
    }
  }
};

// This is the main type that you'd want to map:
type pgp_file = struct {
  pgp_packet[] packets;
};
Generated by cgit on ageinghacker.net.
I am Luca Saiu. If you have reason to request commit access to one of these repositories please contact me. You may also send me patches by email.