chiark / gitweb /
dirmngr: Drop useless housekeeping.
[gnupg2.git] / g13 / g13tuple.c
1 /* g13tuple.c - Tuple handling
2  * Copyright (C) 2009 Free Software Foundation, Inc.
3  * Copyright (C) 2009, 2015, 2016  Werner Koch
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <https://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <assert.h>
27
28 #include "g13.h"
29 #include "g13tuple.h"
30 #include "keyblob.h"  /* Required for dump_tupledesc.  */
31
32
33 /* Definition of the tuple descriptor object.  */
34 struct tupledesc_s
35 {
36   unsigned char *data; /* The tuple data.  */
37   size_t datalen;      /* The length of the data.  */
38   size_t pos;          /* The current position as used by next_tuple.  */
39   int refcount;        /* Number of references hold. */
40 };
41
42
43
44 /* Append the TAG and the VALUE to the MEMBUF.  There is no error
45    checking here; this is instead done while getting the value back
46    from the membuf. */
47 void
48 append_tuple (membuf_t *membuf, int tag, const void *value, size_t length)
49 {
50   unsigned char buf[2];
51
52   assert (tag >= 0 && tag <= 0xffff);
53   assert (length <= 0xffff);
54
55   buf[0] = tag >> 8;
56   buf[1] = tag;
57   put_membuf (membuf, buf, 2);
58   buf[0] = length >> 8;
59   buf[1] = length;
60   put_membuf (membuf, buf, 2);
61   if (length)
62     put_membuf (membuf, value, length);
63 }
64
65
66 /* Append the unsigned integer VALUE under TAG to MEMBUF.  We make
67  * sure that the most significant bit is always cleared to explicitly
68  * flag the value as unsigned.  */
69 void
70 append_tuple_uint (membuf_t *membuf, int tag, unsigned long long value)
71 {
72   unsigned char buf[16];
73   unsigned char *p;
74   unsigned int len;
75
76   p = buf + sizeof buf;
77   len = 0;
78   do
79     {
80       if (p == buf)
81         BUG () ;
82       *--p = (value & 0xff);
83       value >>= 8;
84       len++;
85     }
86   while (value);
87
88   /* Prepend a zero byte if the first byte has its MSB set.  */
89   if ((*p & 0x80))
90     {
91       if (p == buf)
92         BUG () ;
93       *--p = 0;
94       len++;
95     }
96
97   append_tuple (membuf, tag, p, len);
98 }
99
100
101 /* Create a tuple object by moving the ownership of (DATA,DATALEN) to
102  * a new object.  Returns 0 on success and stores the new object at
103  * R_TUPLEHD.  The return object must be released using
104  * destroy_tuples().  */
105 gpg_error_t
106 create_tupledesc (tupledesc_t *r_desc, void *data, size_t datalen)
107 {
108   if (datalen < 5 || memcmp (data, "\x00\x00\x00\x01\x01", 5))
109     return gpg_error (GPG_ERR_NOT_SUPPORTED);
110
111   *r_desc = xtrymalloc (sizeof **r_desc);
112   if (!*r_desc)
113     return gpg_error_from_syserror ();
114   (*r_desc)->data = data;
115   (*r_desc)->datalen = datalen;
116   (*r_desc)->pos = 0;
117   (*r_desc)->refcount = 1;
118   return 0;
119 }
120
121 /* Unref a tuple descriptor and if the refcount is down to 0 release
122    its allocated storage.  */
123 void
124 destroy_tupledesc (tupledesc_t tupledesc)
125 {
126   if (!tupledesc)
127     return;
128
129   if (!--tupledesc->refcount)
130     {
131       xfree (tupledesc->data);
132       xfree (tupledesc);
133     }
134 }
135
136
137 tupledesc_t
138 ref_tupledesc (tupledesc_t tupledesc)
139 {
140   if (tupledesc)
141     tupledesc->refcount++;
142   return tupledesc;
143 }
144
145
146 /* Return a pointer to the memory used to store the tuples.  This is
147  * the data originally provided to create_tupledesc.  It is higly
148  * recommended that the callers uses ref_tupledesc before calling this
149  * function and unref_tupledesc when the return data will not anymore
150  * be used.  */
151 const void *
152 get_tupledesc_data (tupledesc_t tupledesc, size_t *r_datalen)
153 {
154   *r_datalen = tupledesc->datalen;
155   return tupledesc->data;
156 }
157
158 /* Find the first tuple with tag TAG.  On success return a pointer to
159    its value and store the length of the value at R_LENGTH.  If no
160    tuple was found return NULL.  For use by next_tuple, the last
161    position is stored in the descriptor.  */
162 const void *
163 find_tuple (tupledesc_t tupledesc, unsigned int tag, size_t *r_length)
164 {
165   const unsigned char *s;
166   const unsigned char *s_end; /* Points right behind the data. */
167   unsigned int t;
168   size_t n;
169
170   s = tupledesc->data;
171   if (!s)
172     return NULL;
173   s_end = s + tupledesc->datalen;
174   while (s < s_end)
175     {
176       /* We use addresses for the overflow check to avoid undefined
177          behaviour.  size_t should work with all flat memory models.  */
178       if ((size_t)s+3 >= (size_t)s_end || (size_t)s + 3 < (size_t)s)
179         break;
180       t  = s[0] << 8;
181       t |= s[1];
182       n  = s[2] << 8;
183       n |= s[3];
184       s += 4;
185       if ((size_t)s + n > (size_t)s_end || (size_t)s + n < (size_t)s)
186         break;
187       if (t == tag)
188         {
189           tupledesc->pos = (s + n) - tupledesc->data;
190           *r_length = n;
191           return s;
192         }
193       s += n;
194     }
195   return NULL;
196 }
197
198
199 /* Helper for find_tuple_uint and others.  */
200 static gpg_error_t
201 convert_uint (const unsigned char *s, size_t n, unsigned long long *r_value)
202 {
203   unsigned long long value = 0;
204
205   *r_value = 0;
206
207   if (!s)
208     return gpg_error (GPG_ERR_NOT_FOUND);
209   if (!n || (*s & 0x80)) /* No bytes or negative.  */
210     return gpg_error (GPG_ERR_ERANGE);
211   if (n && !*s) /* Skip a leading zero.  */
212     {
213       n--;
214       s++;
215     }
216   if (n > sizeof value)
217     return gpg_error (GPG_ERR_ERANGE);
218   for (; n; n--, s++)
219     {
220       value <<= 8;
221       value |= *s;
222     }
223   *r_value = value;
224   return 0;
225 }
226
227
228 /* Similar to find-tuple but expects an unsigned int value and stores
229  * that at R_VALUE.  If the tag was not found GPG_ERR_NOT_FOUND is
230  * returned and 0 stored at R_VALUE.  If the value cannot be converted
231  * to an unsigned integer GPG_ERR_ERANGE is returned.  */
232 gpg_error_t
233 find_tuple_uint (tupledesc_t tupledesc, unsigned int tag,
234                  unsigned long long *r_value)
235 {
236   const unsigned char *s;
237   size_t n;
238
239   s = find_tuple (tupledesc, tag, &n);
240   return convert_uint (s, n, r_value);
241 }
242
243
244 const void *
245 next_tuple (tupledesc_t tupledesc, unsigned int *r_tag, size_t *r_length)
246 {
247   const unsigned char *s;
248   const unsigned char *s_end; /* Points right behind the data.  */
249   unsigned int t;
250   size_t n;
251
252   s = tupledesc->data;
253   if (!s)
254     return NULL;
255   s_end = s + tupledesc->datalen;
256   s += tupledesc->pos;
257   if (s < s_end
258       && !((size_t)s + 3 >= (size_t)s_end || (size_t)s + 3 < (size_t)s))
259     {
260       t  = s[0] << 8;
261       t |= s[1];
262       n  = s[2] << 8;
263       n |= s[3];
264       s += 4;
265       if (!((size_t)s + n > (size_t)s_end || (size_t)s + n < (size_t)s))
266         {
267           tupledesc->pos = (s + n) - tupledesc->data;
268           *r_tag = t;
269           *r_length = n;
270           return s;
271         }
272     }
273
274   return NULL;
275 }
276
277
278 /* Return true if BUF has only printable characters.  */
279 static int
280 all_printable (const void *buf, size_t buflen)
281 {
282   const unsigned char *s;
283
284   for (s=buf ; buflen; s++, buflen--)
285     if (*s < 32 && *s > 126)
286       return 0;
287   return 1;
288 }
289
290
291 /* Print information about TUPLES to the log stream.  */
292 void
293 dump_tupledesc (tupledesc_t tuples)
294 {
295   size_t n;
296   unsigned int tag;
297   const void *value;
298   unsigned long long uint;
299
300   log_info ("keyblob dump:\n");
301   tag = KEYBLOB_TAG_BLOBVERSION;
302   value = find_tuple (tuples, tag, &n);
303   while (value)
304     {
305       log_info ("   tag: %-5u len: %-2u value: ", tag, (unsigned int)n);
306       if (!n)
307         log_printf ("[none]\n");
308       else
309         {
310           switch (tag)
311             {
312             case KEYBLOB_TAG_ENCKEY:
313             case KEYBLOB_TAG_MACKEY:
314               log_printf ("[confidential]\n");
315               break;
316
317             case KEYBLOB_TAG_ALGOSTR:
318               if (n < 100 && all_printable (value, n))
319                 log_printf ("%.*s\n", (int)n, (const char*)value);
320               else
321                 log_printhex ("", value, n);
322               break;
323
324             case KEYBLOB_TAG_CONT_NSEC:
325             case KEYBLOB_TAG_ENC_NSEC:
326             case KEYBLOB_TAG_ENC_OFF:
327               if (!convert_uint (value, n, &uint))
328                 log_printf ("%llu\n", uint);
329               else
330                 log_printhex ("", value, n);
331               break;
332
333             default:
334               log_printhex ("", value, n);
335               break;
336             }
337         }
338       value = next_tuple (tuples, &tag, &n);
339     }
340 }