blob: 135e7910eb70091dbe427bd441ee7f238f1e5b99 [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001/*-
2 * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
3 * Redistribution and modifications are permitted subject to BSD license.
4 */
5#include <constr_TYPE.h>
6#include <assert.h>
7
8#define ADVANCE(num_bytes) do { \
9 size_t num = num_bytes; \
10 ptr += num; \
11 size -= num; \
12 consumed_myself += num; \
13 } while(0)
14#define RETURN(_code) do { \
15 ber_dec_rval_t rval; \
16 rval.code = _code; \
17 rval.consumed = consumed_myself; \
18 return rval; \
19 } while(0)
20
21/*
22 * The BER decoder of any type.
23 */
24ber_dec_rval_t
25ber_decode(asn1_TYPE_descriptor_t *type_descriptor,
26 void **struct_ptr, void *ptr, size_t size) {
27
28 /*
29 * Invoke type-specific decoder.
30 */
31 return type_descriptor->ber_decoder(type_descriptor,
32 struct_ptr, /* Pointer to the destination structure */
33 ptr, size, /* Buffer and its size */
34 0 /* Default tag mode is 0 */
35 );
36}
37
38/*
39 * Check the set of <TL<TL<TL...>>> tags matches the definition.
40 */
41ber_dec_rval_t
42ber_check_tags(asn1_TYPE_descriptor_t *head, ber_dec_ctx_t *ctx,
43 void *ptr, size_t size, int tag_mode,
44 ber_tlv_len_t *last_length, int *opt_tlv_form) {
45 ssize_t consumed_myself = 0;
46 ssize_t tag_len;
47 ssize_t len_len;
48 ber_tlv_tag_t tlv_tag;
49 ber_tlv_len_t tlv_len;
50 ber_tlv_len_t limit_len = -1;
51 int expect_00_terminators = 0;
52 int tlv_constr = -1; /* If CHOICE, opt_tlv_form is not given */
53 int tagno;
54
55 /*
56 * So what does all this tags_impl_skip stuff mean?
57 * Imagine two types,
58 * A ::= [5] IMPLICIT T
59 * B ::= [2] EXPLICIT T
60 * Where T is defined as
61 * T ::= [4] IMPLICIT SEQUENCE { ... }
62 *
63 * Let's say, we are starting to decode type A, given the
64 * following TLV stream: <5> <0>. What does this mean?
65 * It means that the type A contains type T which is,
66 * in turn, empty.
67 * Remember though, that we are still in A. We cannot
68 * just pass control to the type T decoder. Why? Because
69 * the type T decoder expects <4> <0>, not <5> <0>.
70 * So, we must make sure we are going to receive <5> while
71 * still in A, then pass control to the T decoder, indicating
72 * that the tag <4> was implicitly skipped. The decoder of T
73 * hence will be prepared to treat <4> as valid tag, and decode
74 * it appropriately.
75 */
76
77 /*
78 * We have a list of tags that must occur in the stream:
79 * {A,B,C}
80 * However, it may be indicated that the type is
81 * implicitly tagged in the caller, so it really boils down to the
82 * {I,B,C} or even {I,C}
83 * This is because the implicit tag at above structure may replace
84 * zero or more (or every) tags which follow it. We don't care
85 * about the precise number, as it is already computed for us
86 * by the ASN.1 compiler and placed into head->tags_impl_skip.
87 * So let's suppose the only tag left after implicit tagging is {I}.
88 * Yet, the table we have is {A,B,C} and head->tags_impl_skip=3.
89 * We need to check at least one tag in the loop, so the loop range
90 * is modified so it will be invoked at least one time.
91 */
92 tagno = ctx->step /* Continuing where left previously */
93 + (tag_mode==-1?(head->tags_impl_skip-1):0)
94 + (tag_mode==1?-1:0)
95 ;
96 //assert(head->tags_count >= 1); ?May not be the case for CHOICE!
97 assert(tagno < head->tags_count); /* At least one loop */
98 for((void)tagno; tagno < head->tags_count; tagno++, ctx->step++) {
99
100 /*
101 * Fetch and process T from TLV.
102 */
103 tag_len = ber_fetch_tag(ptr, size, &tlv_tag);
104 ASN_DEBUG("Fetching tag from {%p,%ld} %02X: "
105 "len %ld, tag %s",
106 ptr, (long)size,
107 *(uint8_t *)ptr, (long)tag_len,
108 ber_tlv_tag_string(tlv_tag));
109 switch(tag_len) {
110 case -1: RETURN(RC_FAIL);
111 case 0: RETURN(RC_WMORE);
112 }
113
114 tlv_constr = BER_TLV_CONSTRUCTED(ptr);
115
116 /*
117 * If {I}, don't check anything.
118 * If {I,B,C}, check B and C unless we're at I.
119 */
120 if(tag_mode != 0 && ctx->step == 0) {
121 /*
122 * We don't expect tag to match here.
123 * It's just because we don't know how the tag
124 * is supposed to look like.
125 */
126 } else {
127 assert(tagno >= 0); /* Guaranteed by the code above */
128 if(tlv_tag != head->tags[tagno]) {
129 /*
130 * Unexpected tag. Too bad.
131 */
132 ASN_DEBUG("Expected: %s, expectation failed",
133 ber_tlv_tag_string(head->tags[tagno]));
134 RETURN(RC_FAIL);
135 }
136 }
137
138 /*
139 * Attention: if there are more tags expected,
140 * ensure that the current tag is presented
141 * in constructed form (it contains other tags!).
142 * If this one is the last one, check that the tag form
143 * matches the one given in descriptor.
144 */
145 if(tagno < (head->tags_count - 1)) {
146 if(tlv_constr == 0) {
147 RETURN(RC_FAIL);
148 }
149 } else {
150 if(head->last_tag_form != tlv_constr
151 && head->last_tag_form != -1) {
152 RETURN(RC_FAIL);
153 }
154 }
155
156 /*
157 * Fetch and process L from TLV.
158 */
159 len_len = ber_fetch_length(tlv_constr,
160 ptr + tag_len, size - tag_len, &tlv_len);
161 switch(len_len) {
162 case -1: RETURN(RC_FAIL);
163 case 0: RETURN(RC_WMORE);
164 }
165
166 /*
167 * FIXME
168 * As of today, the chain of tags
169 * must either contain several indefinite length TLVs,
170 * or several definite length ones.
171 * No mixing is allowed.
172 */
173 if(tlv_len == -1) {
174 /*
175 * Indefinite length.
176 */
177 if(limit_len == -1) {
178 expect_00_terminators++;
179 } else {
180 ASN_DEBUG("Unexpected indefinite length "
181 "in a chain of definite lengths");
182 RETURN(RC_FAIL);
183 }
184 ADVANCE(tag_len + len_len);
185 continue;
186 } else {
187 if(expect_00_terminators) {
188 ASN_DEBUG("Unexpected definite length "
189 "in a chain of indefinite lengths");
190 RETURN(RC_FAIL);
191 }
192 }
193
194 /*
195 * Check that multiple TLVs specify ever decreasing length,
196 * which is consistent.
197 */
198 if(limit_len == -1) {
199 limit_len = tlv_len + tag_len + len_len;
200 } else if(limit_len != tlv_len + tag_len + len_len) {
201 /*
202 * Inner TLV specifies length which is inconsistent
203 * with the outer TLV's length value.
204 */
205 ASN_DEBUG("Outer TLV is %d and inner is %d",
206 limit_len, tlv_len);
207 RETURN(RC_FAIL);
208 }
209
210 ADVANCE(tag_len + len_len);
211
212 limit_len -= (tag_len + len_len);
213 if(size > limit_len) {
214 /*
215 * Make sure that we won't consume more bytes
216 * from the large buffer than the inferred limit.
217 */
218 size = limit_len;
219 }
220 }
221
222 if(opt_tlv_form)
223 *opt_tlv_form = tlv_constr;
224 if(expect_00_terminators)
225 *last_length = -expect_00_terminators;
226 else
227 *last_length = tlv_len;
228
229 RETURN(RC_OK);
230}