chiark / gitweb /
gnupg2 (2.1.17-3) unstable; urgency=medium
[gnupg2.git] / common / tlv.c
1 /* tlv.c - Tag-Length-Value Utilities
2  *      Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * This file is free software; you can redistribute it and/or modify
7  * it under the terms of either
8  *
9  *   - the GNU Lesser General Public License as published by the Free
10  *     Software Foundation; either version 3 of the License, or (at
11  *     your option) any later version.
12  *
13  * or
14  *
15  *   - the GNU General Public License as published by the Free
16  *     Software Foundation; either version 2 of the License, or (at
17  *     your option) any later version.
18  *
19  * or both in parallel, as here.
20  *
21  * This file is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, see <https://www.gnu.org/licenses/>.
28  */
29
30 #include <config.h>
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <assert.h>
36
37 #if GNUPG_MAJOR_VERSION == 1
38 #define GPG_ERR_EOF               (-1)
39 #define GPG_ERR_BAD_BER           (1)  /*G10ERR_GENERAL*/
40 #define GPG_ERR_INV_SEXP          (45) /*G10ERR_INV_ARG*/
41 typedef int gpg_error_t;
42 #define gpg_make_err(x,n) (n)
43 #else
44 #include <gpg-error.h>
45 #endif
46
47 #include "util.h"
48 #include "tlv.h"
49
50 static const unsigned char *
51 do_find_tlv (const unsigned char *buffer, size_t length,
52              int tag, size_t *nbytes, int nestlevel)
53 {
54   const unsigned char *s = buffer;
55   size_t n = length;
56   size_t len;
57   int this_tag;
58   int composite;
59
60   for (;;)
61     {
62       if (n < 2)
63         return NULL; /* Buffer definitely too short for tag and length. */
64       if (!*s || *s == 0xff)
65         { /* Skip optional filler between TLV objects. */
66           s++;
67           n--;
68           continue;
69         }
70       composite = !!(*s & 0x20);
71       if ((*s & 0x1f) == 0x1f)
72         { /* more tag bytes to follow */
73           s++;
74           n--;
75           if (n < 2)
76             return NULL; /* buffer definitely too short for tag and length. */
77           if ((*s & 0x1f) == 0x1f)
78             return NULL; /* We support only up to 2 bytes. */
79           this_tag = (s[-1] << 8) | (s[0] & 0x7f);
80         }
81       else
82         this_tag = s[0];
83       len = s[1];
84       s += 2; n -= 2;
85       if (len < 0x80)
86         ;
87       else if (len == 0x81)
88         { /* One byte length follows. */
89           if (!n)
90             return NULL; /* we expected 1 more bytes with the length. */
91           len = s[0];
92           s++; n--;
93         }
94       else if (len == 0x82)
95         { /* Two byte length follows. */
96           if (n < 2)
97             return NULL; /* We expected 2 more bytes with the length. */
98           len = ((size_t)s[0] << 8) | s[1];
99           s += 2; n -= 2;
100         }
101       else
102         return NULL; /* APDU limit is 65535, thus it does not make
103                         sense to assume longer length fields. */
104
105       if (composite && nestlevel < 100)
106         { /* Dive into this composite DO after checking for a too deep
107              nesting. */
108           const unsigned char *tmp_s;
109           size_t tmp_len;
110
111           tmp_s = do_find_tlv (s, len, tag, &tmp_len, nestlevel+1);
112           if (tmp_s)
113             {
114               *nbytes = tmp_len;
115               return tmp_s;
116             }
117         }
118
119       if (this_tag == tag)
120         {
121           *nbytes = len;
122           return s;
123         }
124       if (len > n)
125         return NULL; /* Buffer too short to skip to the next tag. */
126       s += len; n -= len;
127     }
128 }
129
130
131 /* Locate a TLV encoded data object in BUFFER of LENGTH and
132    return a pointer to value as well as its length in NBYTES.  Return
133    NULL if it was not found or if the object does not fit into the buffer. */
134 const unsigned char *
135 find_tlv (const unsigned char *buffer, size_t length,
136           int tag, size_t *nbytes)
137 {
138   const unsigned char *p;
139
140   p = do_find_tlv (buffer, length, tag, nbytes, 0);
141   if (p && *nbytes > (length - (p-buffer)))
142     p = NULL; /* Object longer than buffer. */
143   return p;
144 }
145
146
147
148 /* Locate a TLV encoded data object in BUFFER of LENGTH and
149    return a pointer to value as well as its length in NBYTES.  Return
150    NULL if it was not found.  Note, that the function does not check
151    whether the value fits into the provided buffer. */
152 const unsigned char *
153 find_tlv_unchecked (const unsigned char *buffer, size_t length,
154                     int tag, size_t *nbytes)
155 {
156   return do_find_tlv (buffer, length, tag, nbytes, 0);
157 }
158
159
160 /* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag
161    and the length part from the TLV triplet.  Update BUFFER and SIZE
162    on success. */
163 gpg_error_t
164 parse_ber_header (unsigned char const **buffer, size_t *size,
165                   int *r_class, int *r_tag,
166                   int *r_constructed, int *r_ndef,
167                   size_t *r_length, size_t *r_nhdr)
168 {
169   int c;
170   unsigned long tag;
171   const unsigned char *buf = *buffer;
172   size_t length = *size;
173
174   *r_ndef = 0;
175   *r_length = 0;
176   *r_nhdr = 0;
177
178   /* Get the tag. */
179   if (!length)
180     return gpg_err_make (default_errsource, GPG_ERR_EOF);
181   c = *buf++; length--; ++*r_nhdr;
182
183   *r_class = (c & 0xc0) >> 6;
184   *r_constructed = !!(c & 0x20);
185   tag = c & 0x1f;
186
187   if (tag == 0x1f)
188     {
189       tag = 0;
190       do
191         {
192           tag <<= 7;
193           if (!length)
194             return gpg_err_make (default_errsource, GPG_ERR_EOF);
195           c = *buf++; length--; ++*r_nhdr;
196           tag |= c & 0x7f;
197
198         }
199       while (c & 0x80);
200     }
201   *r_tag = tag;
202
203   /* Get the length. */
204   if (!length)
205     return gpg_err_make (default_errsource, GPG_ERR_EOF);
206   c = *buf++; length--; ++*r_nhdr;
207
208   if ( !(c & 0x80) )
209     *r_length = c;
210   else if (c == 0x80)
211     *r_ndef = 1;
212   else if (c == 0xff)
213     return gpg_err_make (default_errsource, GPG_ERR_BAD_BER);
214   else
215     {
216       unsigned long len = 0;
217       int count = c & 0x7f;
218
219       if (count > sizeof (len) || count > sizeof (size_t))
220         return gpg_err_make (default_errsource, GPG_ERR_BAD_BER);
221
222       for (; count; count--)
223         {
224           len <<= 8;
225           if (!length)
226             return gpg_err_make (default_errsource, GPG_ERR_EOF);
227           c = *buf++; length--; ++*r_nhdr;
228           len |= c & 0xff;
229         }
230       *r_length = len;
231     }
232
233   /* Without this kludge some example certs can't be parsed. */
234   if (*r_class == CLASS_UNIVERSAL && !*r_tag)
235     *r_length = 0;
236
237   *buffer = buf;
238   *size = length;
239   return 0;
240 }
241
242
243 /* FIXME: The following function should not go into this file but for
244    now it is easier to keep it here. */
245
246 /* Return the next token of an canonical encoded S-expression.  BUF
247    is the pointer to the S-expression and BUFLEN is a pointer to the
248    length of this S-expression (used to validate the syntax).  Both
249    are updated to reflect the new position.  The token itself is
250    returned as a pointer into the original buffer at TOK and TOKLEN.
251    If a parentheses is the next token, TOK will be set to NULL.
252    TOKLEN is checked to be within the bounds.  On error an error code
253    is returned and no pointer is not guaranteed to point to
254    a meaningful value.  DEPTH should be initialized to 0 and will
255    reflect on return the actual depth of the tree. To detect the end
256    of the S-expression it is advisable to check DEPTH after a
257    successful return.
258
259    depth = 0;
260    while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
261           && depth)
262      process_token (tok, toklen);
263    if (err)
264      handle_error ();
265  */
266 gpg_error_t
267 parse_sexp (unsigned char const **buf, size_t *buflen,
268             int *depth, unsigned char const **tok, size_t *toklen)
269 {
270   const unsigned char *s;
271   size_t n, vlen;
272
273   s = *buf;
274   n = *buflen;
275   *tok = NULL;
276   *toklen = 0;
277   if (!n)
278     return *depth ? gpg_err_make (default_errsource, GPG_ERR_INV_SEXP) : 0;
279   if (*s == '(')
280     {
281       s++; n--;
282       (*depth)++;
283       *buf = s;
284       *buflen = n;
285       return 0;
286     }
287   if (*s == ')')
288     {
289       if (!*depth)
290         return gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
291       *toklen = 1;
292       s++; n--;
293       (*depth)--;
294       *buf = s;
295       *buflen = n;
296       return 0;
297     }
298   for (vlen=0; n && *s && *s != ':' && (*s >= '0' && *s <= '9'); s++, n--)
299     vlen = vlen*10 + (*s - '0');
300   if (!n || *s != ':')
301     return gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
302   s++; n--;
303   if (vlen > n)
304     return gpg_err_make (default_errsource, GPG_ERR_INV_SEXP);
305   *tok = s;
306   *toklen = vlen;
307   s += vlen;
308   n -= vlen;
309   *buf = s;
310   *buflen = n;
311   return 0;
312 }