blob: cd40728358537aaa5de9857193fb65b7aec55d48 [file] [log] [blame]
vlmfa67ddc2004-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 */
vlm39ba4c42004-09-22 16:06:28 +00005#include <asn_internal.h>
vlmfa67ddc2004-06-03 03:38:44 +00006#include <constr_TYPE.h>
7#include <assert.h>
8
9#define ADVANCE(num_bytes) do { \
10 size_t num = num_bytes; \
vlmd86c9252004-08-25 01:34:11 +000011 ptr = ((char *)ptr) + num; \
vlmfa67ddc2004-06-03 03:38:44 +000012 size -= num; \
13 consumed_myself += num; \
14 } while(0)
15#define RETURN(_code) do { \
16 ber_dec_rval_t rval; \
17 rval.code = _code; \
18 rval.consumed = consumed_myself; \
19 return rval; \
20 } while(0)
21
22/*
23 * The BER decoder of any type.
24 */
25ber_dec_rval_t
26ber_decode(asn1_TYPE_descriptor_t *type_descriptor,
27 void **struct_ptr, void *ptr, size_t size) {
28
29 /*
30 * Invoke type-specific decoder.
31 */
32 return type_descriptor->ber_decoder(type_descriptor,
33 struct_ptr, /* Pointer to the destination structure */
34 ptr, size, /* Buffer and its size */
35 0 /* Default tag mode is 0 */
36 );
37}
38
39/*
40 * Check the set of <TL<TL<TL...>>> tags matches the definition.
41 */
42ber_dec_rval_t
vlm796c1da2004-07-21 03:55:44 +000043ber_check_tags(asn1_TYPE_descriptor_t *td, ber_dec_ctx_t *ctx,
vlmfa67ddc2004-06-03 03:38:44 +000044 void *ptr, size_t size, int tag_mode,
45 ber_tlv_len_t *last_length, int *opt_tlv_form) {
46 ssize_t consumed_myself = 0;
47 ssize_t tag_len;
48 ssize_t len_len;
49 ber_tlv_tag_t tlv_tag;
50 ber_tlv_len_t tlv_len;
51 ber_tlv_len_t limit_len = -1;
52 int expect_00_terminators = 0;
53 int tlv_constr = -1; /* If CHOICE, opt_tlv_form is not given */
54 int tagno;
55
56 /*
vlm1308d2b2004-09-10 15:49:15 +000057 * So what does all this implicit skip stuff mean?
vlm9bb9a252004-06-06 07:59:35 +000058 * Imagine two types,
vlmfa67ddc2004-06-03 03:38:44 +000059 * A ::= [5] IMPLICIT T
60 * B ::= [2] EXPLICIT T
61 * Where T is defined as
62 * T ::= [4] IMPLICIT SEQUENCE { ... }
63 *
64 * Let's say, we are starting to decode type A, given the
65 * following TLV stream: <5> <0>. What does this mean?
66 * It means that the type A contains type T which is,
67 * in turn, empty.
68 * Remember though, that we are still in A. We cannot
69 * just pass control to the type T decoder. Why? Because
70 * the type T decoder expects <4> <0>, not <5> <0>.
71 * So, we must make sure we are going to receive <5> while
72 * still in A, then pass control to the T decoder, indicating
73 * that the tag <4> was implicitly skipped. The decoder of T
74 * hence will be prepared to treat <4> as valid tag, and decode
75 * it appropriately.
76 */
77
vlmfa67ddc2004-06-03 03:38:44 +000078 tagno = ctx->step /* Continuing where left previously */
vlmfa67ddc2004-06-03 03:38:44 +000079 + (tag_mode==1?-1:0)
80 ;
vlm796c1da2004-07-21 03:55:44 +000081 ASN_DEBUG("ber_check_tags(%s, size=%ld, tm=%d, step=%d, tagno=%d)",
82 td->name, (long)size, tag_mode, ctx->step, tagno);
vlm463dc5a2004-09-04 04:44:30 +000083 //assert(td->tags_count >= 1); ?May not be the case for CHOICE or ANY.
84
vlm1308d2b2004-09-10 15:49:15 +000085 if(tag_mode == 0 && tagno == td->tags_count) {
vlm463dc5a2004-09-04 04:44:30 +000086 /*
87 * This must be the _untagged_ ANY type,
88 * which outermost tag isn't known in advance.
89 * Fetch the tag and length separately.
90 */
91 tag_len = ber_fetch_tag(ptr, size, &tlv_tag);
92 switch(tag_len) {
93 case -1: RETURN(RC_FAIL);
94 case 0: RETURN(RC_WMORE);
95 }
96 tlv_constr = BER_TLV_CONSTRUCTED(ptr);
97 len_len = ber_fetch_length(tlv_constr,
98 (char *)ptr + tag_len, size - tag_len, &tlv_len);
99 switch(len_len) {
100 case -1: RETURN(RC_FAIL);
101 case 0: RETURN(RC_WMORE);
102 }
103 } else {
104 assert(tagno < td->tags_count); /* At least one loop */
105 }
vlm796c1da2004-07-21 03:55:44 +0000106 for((void)tagno; tagno < td->tags_count; tagno++, ctx->step++) {
vlmfa67ddc2004-06-03 03:38:44 +0000107
108 /*
109 * Fetch and process T from TLV.
110 */
111 tag_len = ber_fetch_tag(ptr, size, &tlv_tag);
vlm796c1da2004-07-21 03:55:44 +0000112 ASN_DEBUG("Fetching tag from {%p,%ld} %02X..%02X: "
vlmfa67ddc2004-06-03 03:38:44 +0000113 "len %ld, tag %s",
114 ptr, (long)size,
vlm796c1da2004-07-21 03:55:44 +0000115 size?*(uint8_t *)ptr:0,
vlm1e9e0b92004-07-21 04:03:14 +0000116 ((size_t)tag_len<size&&tag_len>0)
vlm796c1da2004-07-21 03:55:44 +0000117 ?*((uint8_t *)ptr + tag_len):0,
118 (long)tag_len,
vlmfa67ddc2004-06-03 03:38:44 +0000119 ber_tlv_tag_string(tlv_tag));
120 switch(tag_len) {
121 case -1: RETURN(RC_FAIL);
122 case 0: RETURN(RC_WMORE);
123 }
124
125 tlv_constr = BER_TLV_CONSTRUCTED(ptr);
126
127 /*
128 * If {I}, don't check anything.
129 * If {I,B,C}, check B and C unless we're at I.
130 */
131 if(tag_mode != 0 && ctx->step == 0) {
132 /*
133 * We don't expect tag to match here.
134 * It's just because we don't know how the tag
135 * is supposed to look like.
136 */
137 } else {
138 assert(tagno >= 0); /* Guaranteed by the code above */
vlm796c1da2004-07-21 03:55:44 +0000139 if(tlv_tag != td->tags[tagno]) {
vlmfa67ddc2004-06-03 03:38:44 +0000140 /*
141 * Unexpected tag. Too bad.
142 */
143 ASN_DEBUG("Expected: %s, expectation failed",
vlm796c1da2004-07-21 03:55:44 +0000144 ber_tlv_tag_string(td->tags[tagno]));
vlmfa67ddc2004-06-03 03:38:44 +0000145 RETURN(RC_FAIL);
146 }
147 }
148
149 /*
150 * Attention: if there are more tags expected,
151 * ensure that the current tag is presented
152 * in constructed form (it contains other tags!).
153 * If this one is the last one, check that the tag form
154 * matches the one given in descriptor.
155 */
vlm796c1da2004-07-21 03:55:44 +0000156 if(tagno < (td->tags_count - 1)) {
vlmfa67ddc2004-06-03 03:38:44 +0000157 if(tlv_constr == 0) {
158 RETURN(RC_FAIL);
159 }
160 } else {
vlm796c1da2004-07-21 03:55:44 +0000161 if(td->last_tag_form != tlv_constr
162 && td->last_tag_form != -1) {
vlmfa67ddc2004-06-03 03:38:44 +0000163 RETURN(RC_FAIL);
164 }
165 }
166
167 /*
168 * Fetch and process L from TLV.
169 */
170 len_len = ber_fetch_length(tlv_constr,
vlm1ff928d2004-08-11 08:10:13 +0000171 (char *)ptr + tag_len, size - tag_len, &tlv_len);
vlmfa67ddc2004-06-03 03:38:44 +0000172 switch(len_len) {
173 case -1: RETURN(RC_FAIL);
174 case 0: RETURN(RC_WMORE);
175 }
176
177 /*
178 * FIXME
179 * As of today, the chain of tags
180 * must either contain several indefinite length TLVs,
181 * or several definite length ones.
182 * No mixing is allowed.
183 */
184 if(tlv_len == -1) {
185 /*
186 * Indefinite length.
187 */
188 if(limit_len == -1) {
189 expect_00_terminators++;
190 } else {
191 ASN_DEBUG("Unexpected indefinite length "
192 "in a chain of definite lengths");
193 RETURN(RC_FAIL);
194 }
195 ADVANCE(tag_len + len_len);
196 continue;
197 } else {
198 if(expect_00_terminators) {
199 ASN_DEBUG("Unexpected definite length "
200 "in a chain of indefinite lengths");
201 RETURN(RC_FAIL);
202 }
203 }
204
205 /*
206 * Check that multiple TLVs specify ever decreasing length,
207 * which is consistent.
208 */
209 if(limit_len == -1) {
210 limit_len = tlv_len + tag_len + len_len;
211 } else if(limit_len != tlv_len + tag_len + len_len) {
212 /*
213 * Inner TLV specifies length which is inconsistent
214 * with the outer TLV's length value.
215 */
216 ASN_DEBUG("Outer TLV is %d and inner is %d",
217 limit_len, tlv_len);
218 RETURN(RC_FAIL);
219 }
220
221 ADVANCE(tag_len + len_len);
222
223 limit_len -= (tag_len + len_len);
vlmb42843a2004-06-05 08:17:50 +0000224 if((ssize_t)size > limit_len) {
vlmfa67ddc2004-06-03 03:38:44 +0000225 /*
226 * Make sure that we won't consume more bytes
227 * from the large buffer than the inferred limit.
228 */
229 size = limit_len;
230 }
231 }
232
233 if(opt_tlv_form)
234 *opt_tlv_form = tlv_constr;
235 if(expect_00_terminators)
236 *last_length = -expect_00_terminators;
237 else
238 *last_length = tlv_len;
239
240 RETURN(RC_OK);
241}