b3187fbfe1b3c98d6380d82d503b1953d8c863dd
[gnupg.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 <http://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++;
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 /* Find the first tuple with tag TAG.  On success return a pointer to
147    its value and store the length of the value at R_LENGTH.  If no
148    tuple was found return NULL.  For use by next_tuple, the last
149    position is stored in the descriptor.  */
150 const void *
151 find_tuple (tupledesc_t tupledesc, unsigned int tag, size_t *r_length)
152 {
153   const unsigned char *s;
154   const unsigned char *s_end; /* Points right behind the data. */
155   unsigned int t;
156   size_t n;
157
158   s = tupledesc->data;
159   if (!s)
160     return NULL;
161   s_end = s + tupledesc->datalen;
162   while (s < s_end)
163     {
164       /* We use addresses for the overflow check to avoid undefined
165          behaviour.  size_t should work with all flat memory models.  */
166       if ((size_t)s+3 >= (size_t)s_end || (size_t)s + 3 < (size_t)s)
167         break;
168       t  = s[0] << 8;
169       t |= s[1];
170       n  = s[2] << 8;
171       n |= s[3];
172       s += 4;
173       if ((size_t)s + n > (size_t)s_end || (size_t)s + n < (size_t)s)
174         break;
175       if (t == tag)
176         {
177           tupledesc->pos = (s + n) - tupledesc->data;
178           *r_length = n;
179           return s;
180         }
181       s += n;
182     }
183   return NULL;
184 }
185
186
187 /* Helper for find_tuple_uint and others.  */
188 static gpg_error_t
189 convert_uint (const unsigned char *s, size_t n, unsigned long long *r_value)
190 {
191   unsigned long long value = 0;
192
193   *r_value = 0;
194
195   if (!s)
196     return gpg_error (GPG_ERR_NOT_FOUND);
197   if (!n || (*s & 0x80)) /* No bytes or negative.  */
198     return gpg_error (GPG_ERR_ERANGE);
199   if (n && !*s) /* Skip a leading zero.  */
200     {
201       n--;
202       s++;
203     }
204   if (n > sizeof value)
205     return gpg_error (GPG_ERR_ERANGE);
206   for (; n; n--, s++)
207     {
208       value <<= 8;
209       value |= *s;
210     }
211   *r_value = value;
212   return 0;
213 }
214
215
216 /* Similar to find-tuple but expects an unsigned int value and stores
217  * that at R_VALUE.  If the tag was not found GPG_ERR_NOT_FOUND is
218  * returned and 0 stored at R_VALUE.  If the value cannot be converted
219  * to an unsigned integer GPG_ERR_ERANGE is returned.  */
220 gpg_error_t
221 find_tuple_uint (tupledesc_t tupledesc, unsigned int tag,
222                  unsigned long long *r_value)
223 {
224   const unsigned char *s;
225   size_t n;
226
227   s = find_tuple (tupledesc, tag, &n);
228   return convert_uint (s, n, r_value);
229 }
230
231
232 const void *
233 next_tuple (tupledesc_t tupledesc, unsigned int *r_tag, size_t *r_length)
234 {
235   const unsigned char *s;
236   const unsigned char *s_end; /* Points right behind the data.  */
237   unsigned int t;
238   size_t n;
239
240   s = tupledesc->data;
241   if (!s)
242     return NULL;
243   s_end = s + tupledesc->datalen;
244   s += tupledesc->pos;
245   if (s < s_end
246       && !((size_t)s + 3 >= (size_t)s_end || (size_t)s + 3 < (size_t)s))
247     {
248       t  = s[0] << 8;
249       t |= s[1];
250       n  = s[2] << 8;
251       n |= s[3];
252       s += 4;
253       if (!((size_t)s + n > (size_t)s_end || (size_t)s + n < (size_t)s))
254         {
255           tupledesc->pos = (s + n) - tupledesc->data;
256           *r_tag = t;
257           *r_length = n;
258           return s;
259         }
260     }
261
262   return NULL;
263 }
264
265
266 /* Return true if BUF has only printable characters.  */
267 static int
268 all_printable (const void *buf, size_t buflen)
269 {
270   const unsigned char *s;
271
272   for (s=buf ; buflen; s++, buflen--)
273     if (*s < 32 && *s > 126)
274       return 0;
275   return 1;
276 }
277
278
279 /* Print information about TUPLES to the log stream.  */
280 void
281 dump_tupledesc (tupledesc_t tuples)
282 {
283   size_t n;
284   unsigned int tag;
285   const void *value;
286   unsigned long long uint;
287
288   log_info ("keyblob dump:\n");
289   tag = KEYBLOB_TAG_BLOBVERSION;
290   value = find_tuple (tuples, tag, &n);
291   while (value)
292     {
293       log_info ("   tag: %-5u len: %-2u value: ", tag, (unsigned int)n);
294       if (!n)
295         log_printf ("[none]\n");
296       else
297         {
298           switch (tag)
299             {
300             case KEYBLOB_TAG_ENCKEY:
301             case KEYBLOB_TAG_MACKEY:
302               log_printf ("[confidential]\n");
303               break;
304
305             case KEYBLOB_TAG_ALGOSTR:
306               if (n < 100 && all_printable (value, n))
307                 log_printf ("%.*s\n", (int)n, (const char*)value);
308               else
309                 log_printhex ("", value, n);
310               break;
311
312             case KEYBLOB_TAG_CONT_NSEC:
313             case KEYBLOB_TAG_ENC_NSEC:
314             case KEYBLOB_TAG_ENC_OFF:
315               if (!convert_uint (value, n, &uint))
316                 log_printf ("%llu\n", uint);
317               else
318                 log_printhex ("", value, n);
319               break;
320
321             default:
322               log_printhex ("", value, n);
323               break;
324             }
325         }
326       value = next_tuple (tuples, &tag, &n);
327     }
328 }