Line data Source code
1 : /* parsetlv.c - ASN.1 TLV functions
2 : * Copyright (C) 2005, 2007, 2008, 2012 g10 Code GmbH
3 : *
4 : * This file is free software; you can redistribute it and/or modify
5 : * it under the terms of the GNU Lesser General Public License as
6 : * published by the Free Software Foundation; either version 2.1 of
7 : * the License, or (at your option) any later version.
8 : *
9 : * This file is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU Lesser General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU Lesser General Public License
15 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
16 : */
17 :
18 : #ifdef HAVE_CONFIG_H
19 : # include <config.h>
20 : #endif
21 : #include <stdio.h>
22 : #include <stdlib.h>
23 : #include <string.h>
24 :
25 : #include "parsetlv.h"
26 :
27 :
28 : /* Simple but pretty complete ASN.1 BER parser. Parse the data at the
29 : address of BUFFER with a length given at the address of SIZE. On
30 : success return 0 and update BUFFER and SIZE to point to the value.
31 : Do not update them on error. The information about the object are
32 : stored in the caller allocated TI structure. */
33 : int
34 0 : _gpgme_parse_tlv (char const **buffer, size_t *size, tlvinfo_t *ti)
35 : {
36 : int c;
37 : unsigned long tag;
38 0 : const unsigned char *buf = (const unsigned char *)(*buffer);
39 0 : size_t length = *size;
40 :
41 0 : ti->cls = 0;
42 0 : ti->tag = 0;
43 0 : ti->is_cons = 0;
44 0 : ti->is_ndef = 0;
45 0 : ti->length = 0;
46 0 : ti->nhdr = 0;
47 :
48 0 : if (!length)
49 0 : return -1;
50 0 : c = *buf++; length--; ++ti->nhdr;
51 :
52 0 : ti->cls = (c & 0xc0) >> 6;
53 0 : ti->is_cons = !!(c & 0x20);
54 0 : tag = c & 0x1f;
55 :
56 0 : if (tag == 0x1f)
57 : {
58 0 : tag = 0;
59 : do
60 : {
61 0 : tag <<= 7;
62 0 : if (!length)
63 0 : return -1;
64 0 : c = *buf++; length--; ++ti->nhdr;
65 0 : tag |= c & 0x7f;
66 : }
67 0 : while (c & 0x80);
68 : }
69 0 : ti->tag = tag;
70 :
71 0 : if (!length)
72 0 : return -1;
73 0 : c = *buf++; length--; ++ti->nhdr;
74 :
75 0 : if ( !(c & 0x80) )
76 0 : ti->length = c;
77 0 : else if (c == 0x80)
78 0 : ti->is_ndef = 1;
79 0 : else if (c == 0xff)
80 0 : return -1;
81 : else
82 : {
83 0 : unsigned long len = 0;
84 0 : int count = (c & 0x7f);
85 :
86 0 : if (count > sizeof (len) || count > sizeof (size_t))
87 0 : return -1;
88 :
89 0 : for (; count; count--)
90 : {
91 0 : len <<= 8;
92 0 : if (!length)
93 0 : return -1;
94 0 : c = *buf++; length--; ++ti->nhdr;
95 0 : len |= c & 0xff;
96 : }
97 0 : ti->length = len;
98 : }
99 :
100 0 : *buffer = (void*)buf;
101 0 : *size = length;
102 0 : return 0;
103 : }
|