Handle TTN_GETDISPINFOW
[cygwin-setup.git] / gpg-packet.cc
blob114d07dbe705a0b38a22790976298c13eaa34214
1 /*
2 * Copyright (c) 2008, Dave Korn.
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.
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
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.
17 * Written by Dave Korn <dave.korn.cygwin@gmail.com>
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"
32 #ifndef RFC4880DEBUGGING
33 #define RFC4880DEBUGGING (0)
34 #endif
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 */
44 #ifndef ARRAYSIZE
45 #define ARRAYSIZE(_ar) (sizeof (_ar) / sizeof (_ar[0]))
46 #endif
48 static const struct { char from; char to; } RFC4880HashCodesToGPGHashCodes[] =
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 }
59 char
60 pkt_convert_hashcode (char rfc_hash)
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;
69 4.2.2. New Format Packet Lengths
71 New format packets have four possible ways of encoding length:
73 1. A one-octet Body Length header encodes packet lengths of up to 191
74 octets.
76 2. A two-octet Body Length header encodes packet lengths of 192 to
77 8383 octets.
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.)
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.
87 4.2.2.1. One-Octet Lengths
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:
93 bodyLen = 1st_octet;
95 4.2.2.2. Two-Octet Lengths
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:
101 bodyLen = ((1st_octet - 192) << 8) + (2nd_octet) + 192
103 4.2.2.3. Five-Octet Lengths
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:
109 bodyLen = (2nd_octet << 24) | (3rd_octet << 16) |
110 (4th_octet << 8) | 5th_octet
112 This basic set of one, two, and five-octet lengths is also used
113 internally to some packets.
116 long
117 pkt_getlen (io_stream *file)
119 int ch1, ch2;
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;
131 if (ch1 == 255)
132 return pkt_getdword (file);
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;
143 3.2. Multiprecision Integers
145 Multiprecision integers (also called MPIs) are unsigned integers used
146 to hold large integers such as the ones used in cryptographic
147 calculations.
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.
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.
156 Examples:
158 (all numbers are in hexadecimal)
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.
163 Additional rules:
165 The size of an MPI is ((MPI.length + 7) / 8) + 2 octets.
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].
171 Unused bits of an MPI MUST be zero.
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.
178 pkt_get_mpi (gcry_mpi_t *mpiptr, io_stream *file)
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." */
184 long nbits = pkt_getword (file);
186 if (nbits < 0)
187 return nbits;
189 size_t nbytes = ((nbits + 7) >> 3);
191 unsigned char *tmpbuf = new unsigned char [nbytes];
193 if (file->read (tmpbuf, nbytes) != (ssize_t)nbytes)
194 return -2;
196 gcry_error_t rv = gcry_mpi_scan (mpiptr, GCRYMPI_FMT_USG, tmpbuf, nbytes, 0UL);
198 delete[] tmpbuf;
200 if (rv != GPG_ERR_NO_ERROR)
201 return -3;
203 return 0;
206 /* Walk the packets in an io_stream. */
207 static void
208 walk_packets_1 (struct packet_walker *wlk)
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)
215 char packet_type;
216 long packet_len;
217 enum pkt_cb_resp rv;
218 size_t newstartpos;
220 wlk->pfile->seek (wlk->startpos, IO_SEEK_SET);
222 if (wlk->is_subpackets)
223 packet_len = pkt_getlen (wlk->pfile) - 1;
224 else
225 packet_len = -1;
227 int tag = pkt_getch (wlk->pfile);
228 MESSAGE ("tag $%02x size $%08x\n", tag, size_left);
230 if (!wlk->is_subpackets && ((tag < 0) || !(tag & 0x80)))
232 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, tag, "illegal tag.");
233 return;
236 if (wlk->is_subpackets)
237 packet_type = tag;
238 else if (tag & 0x40)
240 packet_type = tag & 0x3f;
241 packet_len = pkt_getlen (wlk->pfile);
243 else
245 packet_type = (tag >> 2) & 0x0f;
246 switch (tag & 3)
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;
263 MESSAGE ("type $%02x len $%08x pos $%08x\n", packet_type, packet_len,
264 wlk->pfile->tell ());
265 if (packet_len < 0)
267 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, packet_len, "invalid packet");
268 return;
270 else if (packet_len > (size_left - (wlk->pfile->tell () - (long)wlk->startpos)))
272 ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, packet_len, "malformed packet");
273 return;
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;
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);
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)
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;
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)
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;