Imported Upstream version 1.3.4
[platform/upstream/libksba.git] / src / ber-help.c
1 /* ber-help.c - BER herlper functions
2  *      Copyright (C) 2001, 2012 g10 Code GmbH
3  *
4  * This file is part of KSBA.
5  *
6  * KSBA 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  * KSBA is distributed in the hope that it will be useful, but WITHOUT
22  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
24  * License for more details.
25  *
26  * You should have received a copies of the GNU General Public License
27  * and the GNU Lesser General Public License along with this program;
28  * if not, see <http://www.gnu.org/licenses/>.
29  */
30
31 #include <config.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <assert.h>
36 #include "util.h"
37
38 #include "asn1-func.h" /* need some constants */
39 #include "ber-help.h"
40
41 /* Fixme: The parser functions should check that primitive types don't
42    have the constructed bit set (which is not allowed).  This saves us
43    some work when using these parsers */
44
45 static int
46 read_byte (ksba_reader_t reader)
47 {
48   unsigned char buf;
49   size_t nread;
50   int rc;
51
52   do
53     rc = ksba_reader_read (reader, &buf, 1, &nread);
54   while (!rc && !nread);
55   return rc? -1: buf;
56 }
57
58
59 static int
60 premature_eof (struct tag_info *ti)
61 {
62   /* Note: We do an strcmp on this string at othyer places. */
63   ti->err_string = "premature EOF";
64   return gpg_error (GPG_ERR_BAD_BER);
65 }
66
67
68
69 static gpg_error_t
70 eof_or_error (ksba_reader_t reader, struct tag_info *ti, int premature)
71 {
72   gpg_error_t err;
73
74   err = ksba_reader_error (reader);
75   if (err)
76     {
77       ti->err_string = "read error";
78       return err;
79     }
80   if (premature)
81     return premature_eof (ti);
82
83   return gpg_error (GPG_ERR_EOF);
84 }
85
86
87
88 /*
89    Read the tag and the length part from the TLV triplet.
90  */
91 gpg_error_t
92 _ksba_ber_read_tl (ksba_reader_t reader, struct tag_info *ti)
93 {
94   int c;
95   unsigned long tag;
96
97   ti->length = 0;
98   ti->ndef = 0;
99   ti->nhdr = 0;
100   ti->err_string = NULL;
101   ti->non_der = 0;
102
103   /* Get the tag */
104   c = read_byte (reader);
105   if (c==-1)
106     return eof_or_error (reader, ti, 0);
107
108   ti->buf[ti->nhdr++] = c;
109   ti->class = (c & 0xc0) >> 6;
110   ti->is_constructed = !!(c & 0x20);
111   tag = c & 0x1f;
112
113   if (tag == 0x1f)
114     {
115       tag = 0;
116       do
117         {
118           /* We silently ignore an overflow in the tag value.  It is
119              not worth checking for it. */
120           tag <<= 7;
121           c = read_byte (reader);
122           if (c == -1)
123             return eof_or_error (reader, ti, 1);
124           if (ti->nhdr >= DIM (ti->buf))
125             {
126               ti->err_string = "tag+length header too large";
127               return gpg_error (GPG_ERR_BAD_BER);
128             }
129           ti->buf[ti->nhdr++] = c;
130           tag |= c & 0x7f;
131         }
132       while (c & 0x80);
133     }
134   ti->tag = tag;
135
136   /* Get the length */
137   c = read_byte (reader);
138   if (c == -1)
139     return eof_or_error (reader, ti, 1);
140   if (ti->nhdr >= DIM (ti->buf))
141     {
142       ti->err_string = "tag+length header too large";
143       return gpg_error (GPG_ERR_BAD_BER);
144     }
145   ti->buf[ti->nhdr++] = c;
146
147   if ( !(c & 0x80) )
148     ti->length = c;
149   else if (c == 0x80)
150     {
151       ti->ndef = 1;
152       ti->non_der = 1;
153     }
154   else if (c == 0xff)
155     {
156       ti->err_string = "forbidden length value";
157       return gpg_error (GPG_ERR_BAD_BER);
158     }
159   else
160     {
161       unsigned long len = 0;
162       int count = c & 0x7f;
163
164       if (count > sizeof (len) || count > sizeof (size_t))
165         return gpg_error (GPG_ERR_BAD_BER);
166
167       for (; count; count--)
168         {
169           len <<= 8;
170           c = read_byte (reader);
171           if (c == -1)
172             return eof_or_error (reader, ti, 1);
173           if (ti->nhdr >= DIM (ti->buf))
174             {
175               ti->err_string = "tag+length header too large";
176               return gpg_error (GPG_ERR_BAD_BER);
177             }
178           ti->buf[ti->nhdr++] = c;
179           len |= c & 0xff;
180         }
181       ti->length = len;
182     }
183
184   /* Without this kludge some example certs can't be parsed */
185   if (ti->class == CLASS_UNIVERSAL && !ti->tag)
186     ti->length = 0;
187
188   return 0;
189 }
190
191 /*
192    Parse the buffer at the address BUFFER which of SIZE and return
193    the tag and the length part from the TLV triplet.  Update BUFFER
194    and SIZE on success. */
195 gpg_error_t
196 _ksba_ber_parse_tl (unsigned char const **buffer, size_t *size,
197                     struct tag_info *ti)
198 {
199   int c;
200   unsigned long tag;
201   const unsigned char *buf = *buffer;
202   size_t length = *size;
203
204   ti->length = 0;
205   ti->ndef = 0;
206   ti->nhdr = 0;
207   ti->err_string = NULL;
208   ti->non_der = 0;
209
210   /* Get the tag */
211   if (!length)
212     return premature_eof (ti);
213   c = *buf++; length--;
214
215   ti->buf[ti->nhdr++] = c;
216   ti->class = (c & 0xc0) >> 6;
217   ti->is_constructed = !!(c & 0x20);
218   tag = c & 0x1f;
219
220   if (tag == 0x1f)
221     {
222       tag = 0;
223       do
224         {
225           /* We silently ignore an overflow in the tag value.  It is
226              not worth checking for it. */
227           tag <<= 7;
228           if (!length)
229             return premature_eof (ti);
230           c = *buf++; length--;
231           if (ti->nhdr >= DIM (ti->buf))
232             {
233               ti->err_string = "tag+length header too large";
234               return gpg_error (GPG_ERR_BAD_BER);
235             }
236           ti->buf[ti->nhdr++] = c;
237           tag |= c & 0x7f;
238         }
239       while (c & 0x80);
240     }
241   ti->tag = tag;
242
243   /* Get the length */
244   if (!length)
245     return premature_eof (ti);
246   c = *buf++; length--;
247   if (ti->nhdr >= DIM (ti->buf))
248     {
249       ti->err_string = "tag+length header too large";
250       return gpg_error (GPG_ERR_BAD_BER);
251     }
252   ti->buf[ti->nhdr++] = c;
253
254   if ( !(c & 0x80) )
255     ti->length = c;
256   else if (c == 0x80)
257     {
258       ti->ndef = 1;
259       ti->non_der = 1;
260     }
261   else if (c == 0xff)
262     {
263       ti->err_string = "forbidden length value";
264       return gpg_error (GPG_ERR_BAD_BER);
265     }
266   else
267     {
268       unsigned long len = 0;
269       int count = c & 0x7f;
270
271       if (count > sizeof (len) || count > sizeof (size_t))
272         return gpg_error (GPG_ERR_BAD_BER);
273
274       for (; count; count--)
275         {
276           len <<= 8;
277           if (!length)
278             return premature_eof (ti);
279           c = *buf++; length--;
280           if (ti->nhdr >= DIM (ti->buf))
281             {
282               ti->err_string = "tag+length header too large";
283               return gpg_error (GPG_ERR_BAD_BER);
284             }
285           ti->buf[ti->nhdr++] = c;
286           len |= c & 0xff;
287         }
288       /* Sanity check for the length: This is done so that we can take
289        * the value for malloc plus some additional bytes without
290        * risking an overflow.  */
291       if (len > (1 << 30))
292         return gpg_error (GPG_ERR_BAD_BER);
293       ti->length = len;
294     }
295
296
297   /* Without this kludge some example certs can't be parsed */
298   if (ti->class == CLASS_UNIVERSAL && !ti->tag)
299     ti->length = 0;
300
301   *buffer = buf;
302   *size = length;
303   return 0;
304 }
305
306
307 /* Write TAG of CLASS to WRITER.  constructed is a flag telling
308    whether the value is a constructed one.  length gives the length of
309    the value, if it is 0 undefinite length is assumed.  length is
310    ignored for the NULL tag. */
311 gpg_error_t
312 _ksba_ber_write_tl (ksba_writer_t writer,
313                     unsigned long tag,
314                     enum tag_class class,
315                     int constructed,
316                     unsigned long length)
317 {
318   unsigned char buf[50];
319   int buflen = 0;
320
321   if (tag < 0x1f)
322     {
323       *buf = (class << 6) | tag;
324       if (constructed)
325         *buf |= 0x20;
326       buflen++;
327     }
328   else
329     {
330       return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
331     }
332
333   if (!tag && !class)
334     buf[buflen++] = 0; /* end tag */
335   else if (tag == TYPE_NULL && !class)
336     buf[buflen++] = 0; /* NULL tag */
337   else if (!length)
338     buf[buflen++] = 0x80; /* indefinite length */
339   else if (length < 128)
340     buf[buflen++] = length;
341   else
342     {
343       int i;
344
345       /* fixme: if we know the sizeof an ulong we could support larger
346          objects - however this is pretty ridiculous */
347       i = (length <= 0xff ? 1:
348            length <= 0xffff ? 2:
349            length <= 0xffffff ? 3: 4);
350
351       buf[buflen++] = (0x80 | i);
352       if (i > 3)
353         buf[buflen++] = length >> 24;
354       if (i > 2)
355         buf[buflen++] = length >> 16;
356       if (i > 1)
357         buf[buflen++] = length >> 8;
358       buf[buflen++] = length;
359     }
360
361   return ksba_writer_write (writer, buf, buflen);
362 }
363
364 /* Encode TAG of CLASS in BUFFER.  CONSTRUCTED is a flag telling
365    whether the value is a constructed one.  LENGTH gives the length of
366    the value, if it is 0 undefinite length is assumed.  LENGTH is
367    ignored for the NULL tag. It is assumed that the provide buffer is
368    large enough for storing the result - this is usually achieved by
369    using _ksba_ber_count_tl() in advance.  Returns 0 in case of an
370    error or the length of the encoding.*/
371 size_t
372 _ksba_ber_encode_tl (unsigned char *buffer,
373                      unsigned long tag,
374                      enum tag_class class,
375                      int constructed,
376                      unsigned long length)
377 {
378   unsigned char *buf = buffer;
379
380   if (tag < 0x1f)
381     {
382       *buf = (class << 6) | tag;
383       if (constructed)
384         *buf |= 0x20;
385       buf++;
386     }
387   else
388     {
389       return 0; /*Not implemented*/
390     }
391
392   if (!tag && !class)
393     *buf++ = 0; /* end tag */
394   else if (tag == TYPE_NULL && !class)
395     *buf++ = 0; /* NULL tag */
396   else if (!length)
397     *buf++ = 0x80; /* indefinite length */
398   else if (length < 128)
399     *buf++ = length;
400   else
401     {
402       int i;
403
404       /* fixme: if we know the sizeof an ulong we could support larger
405          objetcs - however this is pretty ridiculous */
406       i = (length <= 0xff ? 1:
407            length <= 0xffff ? 2:
408            length <= 0xffffff ? 3: 4);
409
410       *buf++ = (0x80 | i);
411       if (i > 3)
412         *buf++ = length >> 24;
413       if (i > 2)
414         *buf++ = length >> 16;
415       if (i > 1)
416         *buf++ = length >> 8;
417       *buf++ = length;
418     }
419
420   return buf - buffer;
421 }
422
423
424 /* Calculate the length of the TL needed to encode a TAG of CLASS.
425    CONSTRUCTED is a flag telling whether the value is a constructed
426    one.  LENGTH gives the length of the value; if it is 0 an
427    indefinite length is assumed.  LENGTH is ignored for the NULL
428    tag. */
429 size_t
430 _ksba_ber_count_tl (unsigned long tag,
431                     enum tag_class class,
432                     int constructed,
433                     unsigned long length)
434 {
435   int buflen = 0;
436
437   (void)constructed;  /* Not used, but passed for uniformity of such calls.  */
438
439   if (tag < 0x1f)
440     {
441       buflen++;
442     }
443   else
444     {
445       buflen++; /* assume one and let the actual write function bail out */
446     }
447
448   if (!tag && !class)
449     buflen++; /* end tag */
450   else if (tag == TYPE_NULL && !class)
451     buflen++; /* NULL tag */
452   else if (!length)
453     buflen++; /* indefinite length */
454   else if (length < 128)
455     buflen++;
456   else
457     {
458       int i;
459
460       /* fixme: if we know the sizeof an ulong we could support larger
461          objetcs - however this is pretty ridiculous */
462       i = (length <= 0xff ? 1:
463            length <= 0xffff ? 2:
464            length <= 0xffffff ? 3: 4);
465
466       buflen++;
467       if (i > 3)
468         buflen++;
469       if (i > 2)
470         buflen++;
471       if (i > 1)
472         buflen++;
473       buflen++;
474     }
475
476   return buflen;
477 }