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