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