]> cygwin.com Git - cygwin-apps/setup.git/blob - gpg-packet.cc
Use solver to check for problems and produce a list of package transactions
[cygwin-apps/setup.git] / gpg-packet.cc
1 /*
2 * Copyright (c) 2008, Dave Korn.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 * This module contains support utilities to assist in reading and
13 * parsing RFC4880-compliant OpenPGP format signature and key files,
14 * and related constant definitions.
15 *
16 *
17 * Written by Dave Korn <dave.korn.cygwin@gmail.com>
18 *
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include "win32.h"
25 #include "io_stream.h"
26 #include "gcrypt.h"
27 #include "gpg-packet.h"
28 #include "msg.h"
29 #include "LogSingleton.h"
30 #include "resource.h"
31
32 #define CRYPTODEBUGGING (0)
33
34 #if CRYPTODEBUGGING
35 #define ERRKIND __asm__ __volatile__ (".byte 0xcc"); note
36 #define MESSAGE LogBabblePrintf
37 #else /* !CRYPTODEBUGGING */
38 #define ERRKIND note
39 #define MESSAGE while (0) LogBabblePrintf
40 #endif /* CRYPTODEBUGGING */
41
42 #ifndef ARRAYSIZE
43 #define ARRAYSIZE(_ar) (sizeof (_ar) / sizeof (_ar[0]))
44 #endif
45
46 static const struct { char from; char to; } RFC4880HashCodesToGPGHashCodes[] =
47 {
48 { RFC4880_HC_MD5, GCRY_MD_MD5 },
49 { RFC4880_HC_SHA1, GCRY_MD_SHA1 },
50 { RFC4880_HC_RIPEMD160, GCRY_MD_RMD160 },
51 { RFC4880_HC_SHA256, GCRY_MD_SHA256 },
52 { RFC4880_HC_SHA384, GCRY_MD_SHA384 },
53 { RFC4880_HC_SHA512, GCRY_MD_SHA512 },
54 { RFC4880_HC_SHA224, GCRY_MD_SHA224 }
55 };
56
57 char
58 pkt_convert_hashcode (char rfc_hash)
59 {
60 for (unsigned int i = 0; i < ARRAYSIZE(RFC4880HashCodesToGPGHashCodes); i++)
61 if (RFC4880HashCodesToGPGHashCodes[i].from == rfc_hash)
62 return RFC4880HashCodesToGPGHashCodes[i].to;
63 return GCRY_MD_NONE;
64 }
65
66 /*
67 4.2.2. New Format Packet Lengths
68
69 New format packets have four possible ways of encoding length:
70
71 1. A one-octet Body Length header encodes packet lengths of up to 191
72 octets.
73
74 2. A two-octet Body Length header encodes packet lengths of 192 to
75 8383 octets.
76
77 3. A five-octet Body Length header encodes packet lengths of up to
78 4,294,967,295 (0xFFFFFFFF) octets in length. (This actually
79 encodes a four-octet scalar number.)
80
81 4. When the length of the packet body is not known in advance by the
82 issuer, Partial Body Length headers encode a packet of
83 indeterminate length, effectively making it a stream.
84
85 4.2.2.1. One-Octet Lengths
86
87 A one-octet Body Length header encodes a length of 0 to 191 octets.
88 This type of length header is recognized because the one octet value
89 is less than 192. The body length is equal to:
90
91 bodyLen = 1st_octet;
92
93 4.2.2.2. Two-Octet Lengths
94
95 A two-octet Body Length header encodes a length of 192 to 8383
96 octets. It is recognized because its first octet is in the range 192
97 to 223. The body length is equal to:
98
99 bodyLen = ((1st_octet - 192) << 8) + (2nd_octet) + 192
100
101 4.2.2.3. Five-Octet Lengths
102
103 A five-octet Body Length header consists of a single octet holding
104 the value 255, followed by a four-octet scalar. The body length is
105 equal to:
106
107 bodyLen = (2nd_octet << 24) | (3rd_octet << 16) |
108 (4th_octet << 8) | 5th_octet
109
110 This basic set of one, two, and five-octet lengths is also used
111 internally to some packets.
112
113 */
114 long
115 pkt_getlen (io_stream *file)
116 {
117 int ch1, ch2;
118
119 ch1 = pkt_getch (file);
120 // Obviously these two conditions fold into one, but since
121 // one is an error test and the other a range check it's
122 // nice to write them separately and let the compiler take
123 // care of it.
124 if (ch1 < 0)
125 return ch1;
126 if (ch1 < 192)
127 return ch1;
128
129 if (ch1 == 255)
130 return pkt_getdword (file);
131
132 ch2 = pkt_getch (file);
133 if (ch2 < 0)
134 return ch2;
135 if (ch1 < 224)
136 return ((ch1 - 192) << 8) + (ch2) + 192;
137 return -2;
138 }
139
140 /*
141 3.2. Multiprecision Integers
142
143 Multiprecision integers (also called MPIs) are unsigned integers used
144 to hold large integers such as the ones used in cryptographic
145 calculations.
146
147 An MPI consists of two pieces: a two-octet scalar that is the length
148 of the MPI in bits followed by a string of octets that contain the
149 actual integer.
150
151 These octets form a big-endian number; a big-endian number can be
152 made into an MPI by prefixing it with the appropriate length.
153
154 Examples:
155
156 (all numbers are in hexadecimal)
157
158 The string of octets [00 01 01] forms an MPI with the value 1. The
159 string [00 09 01 FF] forms an MPI with the value of 511.
160
161 Additional rules:
162
163 The size of an MPI is ((MPI.length + 7) / 8) + 2 octets.
164
165 The length field of an MPI describes the length starting from its
166 most significant non-zero bit. Thus, the MPI [00 02 01] is not
167 formed correctly. It should be [00 01 01].
168
169 Unused bits of an MPI MUST be zero.
170
171 Also note that when an MPI is encrypted, the length refers to the
172 plaintext MPI. It may be ill-formed in its ciphertext.
173
174 */
175 int
176 pkt_get_mpi (gcry_mpi_t *mpiptr, io_stream *file)
177 {
178 /* "An MPI consists of two pieces: a two-octet scalar that is the
179 length of the MPI in bits followed by a string of octets that contain
180 the actual integer." */
181
182 long nbits = pkt_getword (file);
183
184 if (nbits < 0)
185 return nbits;
186
187 size_t nbytes = ((nbits + 7) >> 3);
188
189 unsigned char *tmpbuf = new unsigned char [nbytes];
190
191 if (file->read (tmpbuf, nbytes) != (ssize_t)nbytes)
192 return -2;
193
194 gcry_error_t rv = gcry_mpi_scan (mpiptr, GCRYMPI_FMT_USG, tmpbuf, nbytes, 0UL);
195
196 delete[] tmpbuf;
197
198 if (rv != GPG_ERR_NO_ERROR)
199 return -3;
200
201 return 0;
202 }
203
204 /* Walk the packets in an io_stream. */
205 static void
206 walk_packets_1 (struct packet_walker *wlk)
207 {
208 long size_left = wlk->size_to_walk;
209 size_t ostartpos = wlk->startpos;
210 MESSAGE ("walk $%08x bytes at startpos $%08x\n", wlk->size_to_walk, wlk->startpos);
211 while (size_left)
212 {
213 char packet_type;
214 long packet_len;
215 enum pkt_cb_resp rv;
216 size_t newstartpos;
217
218 wlk->pfile->seek (wlk->startpos, IO_SEEK_SET);
219
220 if (wlk->is_subpackets)
221 packet_len = pkt_getlen (wlk->pfile) - 1;
222 else
223 packet_len = -1;
224
225 int tag = pkt_getch (wlk->pfile);
226 MESSAGE ("tag $%02x size $%08x\n", tag, size_left);
227
228 if (!wlk->is_subpackets && ((tag < 0) || !(tag & 0x80)))
229 {
230 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, tag, "illegal tag.");
231 return;
232 }
233
234 if (wlk->is_subpackets)
235 packet_type = tag;
236 else if (tag & 0x40)
237 {
238 packet_type = tag & 0x3f;
239 packet_len = pkt_getlen (wlk->pfile);
240 }
241 else
242 {
243 packet_type = (tag >> 2) & 0x0f;
244 switch (tag & 3)
245 {
246 case 0:
247 packet_len = pkt_getch (wlk->pfile);
248 break;
249 case 1:
250 packet_len = pkt_getword (wlk->pfile);
251 break;
252 case 2:
253 packet_len = pkt_getdword (wlk->pfile);
254 break;
255 case 3:
256 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, tag, "illegal old tag.");
257 return;
258 }
259 }
260
261 MESSAGE ("type $%02x len $%08x pos $%08x\n", packet_type, packet_len,
262 wlk->pfile->tell ());
263 if (packet_len < 0)
264 {
265 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, packet_len, "invalid packet");
266 return;
267 }
268 else if (packet_len > (size_left - (wlk->pfile->tell () - (long)wlk->startpos)))
269 {
270 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, packet_len, "malformed packet");
271 return;
272 }
273
274 newstartpos = wlk->pfile->tell () + packet_len;
275 rv = wlk->func ? wlk->func (wlk, packet_type, packet_len, wlk->startpos)
276 : pktCONTINUE;
277 if (rv == pktHALT)
278 break;
279
280 wlk->startpos = newstartpos;
281 wlk->pfile->seek (wlk->startpos, IO_SEEK_SET);
282 size_left = wlk->size_to_walk - (wlk->startpos - ostartpos);
283 MESSAGE ("remaining $%08x nextpos $%08x\n", size_left, wlk->startpos);
284 }
285 }
286
287 void *
288 pkt_walk_packets (io_stream *packet_file, packet_walk_cb func, HWND owner,
289 size_t startpos, size_t size_to_walk, void *userdata)
290 {
291 struct packet_walker wlk;
292 wlk.pfile = packet_file;
293 wlk.func = func;
294 wlk.owner = owner;
295 wlk.userdata = userdata;
296 wlk.startpos = startpos;
297 wlk.size_to_walk = size_to_walk;
298 wlk.is_subpackets = false;
299 walk_packets_1 (&wlk);
300 return wlk.userdata;
301 }
302
303 void *
304 pkt_walk_subpackets (io_stream *packet_file, packet_walk_cb func, HWND owner,
305 size_t startpos, size_t size_to_walk, void *userdata)
306 {
307 struct packet_walker wlk;
308 wlk.pfile = packet_file;
309 wlk.func = func;
310 wlk.owner = owner;
311 wlk.userdata = userdata;
312 wlk.startpos = startpos;
313 wlk.size_to_walk = size_to_walk;
314 wlk.is_subpackets = true;
315 walk_packets_1 (&wlk);
316 return wlk.userdata;
317 }
318
This page took 0.051509 seconds and 5 git commands to generate.