blob: 6704dd843cff0840dd2acd569f773e5cd20f37c4 [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001/*-
2 * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
3 * Redistribution and modifications are permitted subject to BSD license.
4 */
5#include <constr_SEQUENCE.h>
6
7/*
8 * Number of bytes left for this structure.
9 * (ctx->left) indicates the number of bytes _transferred_ for the structure.
10 * (size) contains the number of bytes in the buffer passed.
11 */
12#define LEFT ((size<ctx->left)?size:ctx->left)
13
14/*
15 * If the subprocessor function returns with an indication that it wants
16 * more data, it may well be a fatal decoding problem, because the
17 * size is constrained by the <TLV>'s L, even if the buffer size allows
18 * reading more data.
19 * For example, consider the buffer containing the following TLVs:
20 * <T:5><L:1><V> <T:6>...
21 * The TLV length clearly indicates that one byte is expected in V, but
22 * if the V processor returns with "want more data" even if the buffer
23 * contains way more data than the V processor have seen.
24 */
25#define SIZE_VIOLATION (ctx->left >= 0 && ctx->left <= size)
26
27/*
28 * This macro "eats" the part of the buffer which is definitely "consumed",
29 * i.e. was correctly converted into local representation or rightfully skipped.
30 */
31#define ADVANCE(num_bytes) do { \
32 size_t num = num_bytes; \
33 ptr += num; \
34 size -= num; \
35 if(ctx->left >= 0) \
36 ctx->left -= num; \
37 consumed_myself += num; \
38 } while(0)
39
40/*
41 * Switch to the next phase of parsing.
42 */
43#define NEXT_PHASE(ctx) do { \
44 ctx->phase++; \
45 ctx->step = 0; \
46 } while(0)
47#define PHASE_OUT(ctx) do { ctx->phase = 10; } while(0)
48
49/*
50 * Return a standardized complex structure.
51 */
52#define RETURN(_code) do { \
53 rval.code = _code; \
54 rval.consumed = consumed_myself;\
55 return rval; \
56 } while(0)
57
58/*
59 * Check whether we are inside the extensions group.
60 */
61#define IN_EXTENSION_GROUP(specs, memb_idx) \
62 ( ((memb_idx) > (specs)->ext_after) \
63 &&((memb_idx) < (specs)->ext_before))
64
65/*
66 * The decoder of the SEQUENCE type.
67 */
68ber_dec_rval_t
69SEQUENCE_decode_ber(asn1_TYPE_descriptor_t *sd,
70 void **struct_ptr, void *ptr, size_t size, int tag_mode) {
71 /*
72 * Bring closer parts of structure description.
73 */
74 asn1_SEQUENCE_specifics_t *specs = sd->specifics;
75 asn1_SEQUENCE_element_t *elements = specs->elements;
76
77 /*
78 * Parts of the structure being constructed.
79 */
80 void *st = *struct_ptr; /* Target structure. */
81 ber_dec_ctx_t *ctx; /* Decoder context */
82
83 ber_tlv_tag_t tlv_tag; /* T from TLV */
84 //ber_tlv_len_t tlv_len; /* L from TLV */
85 ber_dec_rval_t rval; /* Return code from subparsers */
86
87 ssize_t consumed_myself = 0; /* Consumed bytes from ptr */
88 int edx; /* SEQUENCE element's index */
89
90 ASN_DEBUG("Decoding %s as SEQUENCE", sd->name);
91
92 /*
93 * Create the target structure if it is not present already.
94 */
95 if(st == 0) {
96 st = *struct_ptr = CALLOC(1, specs->struct_size);
97 if(st == 0) {
98 RETURN(RC_FAIL);
99 }
100 }
101
102 /*
103 * Restore parsing context.
104 */
105 ctx = (st + specs->ctx_offset);
106
107 /*
108 * Start to parse where left previously
109 */
110 switch(ctx->phase) {
111 case 0:
112 /*
113 * PHASE 0.
114 * Check that the set of tags associated with given structure
115 * perfectly fits our expectations.
116 */
117
118 rval = ber_check_tags(sd, ctx, ptr, size,
119 tag_mode, &ctx->left, 0);
120 if(rval.code != RC_OK) {
121 ASN_DEBUG("%s tagging check failed: %d",
122 sd->name, rval.code);
123 consumed_myself += rval.consumed;
124 RETURN(rval.code);
125 }
126
127 if(ctx->left >= 0)
128 ctx->left += rval.consumed; /* ?Substracted below! */
129 ADVANCE(rval.consumed);
130
131 NEXT_PHASE(ctx);
132
133 ASN_DEBUG("Structure consumes %ld bytes, buffer %ld",
134 (long)ctx->left, (long)size);
135
136 /* Fall through */
137 case 1:
138 /*
139 * PHASE 1.
140 * From the place where we've left it previously,
141 * try to decode the next member from the list of
142 * this structure's elements.
143 * (ctx->step) stores the member being processed
144 * between invocations and the microphase {0,1} of parsing
145 * that member:
146 * step = (<member_number> * 2 + <microphase>).
147 */
148 for(edx = (ctx->step >> 1); edx < specs->elements_count;
149 edx++, ctx->step = (ctx->step & ~1) + 2) {
150 void *memb_ptr; /* Pointer to the member */
151 void *memb_ptr2; /* Pointer to that pointer */
152 ssize_t tag_len; /* Length of TLV's T */
153 int opt_edx_end; /* Next non-optional element */
154 int n;
155
156 if(ctx->step & 1)
157 goto microphase2;
158
159 /*
160 * MICROPHASE 1: Synchronize decoding.
161 */
162 ASN_DEBUG("In %s SEQUENCE left %d, edx=%d opt=%d ec=%d",
163 sd->name, (int)ctx->left,
164 edx, elements[edx].optional, specs->elements_count);
165
166 if(ctx->left == 0 /* No more stuff is expected */
167 && (
168 /* Explicit OPTIONAL specification reaches the end */
169 (edx + elements[edx].optional == specs->elements_count)
170 ||
171 /* All extensions are optional */
172 (IN_EXTENSION_GROUP(specs, edx)
173 && specs->ext_before > specs->elements_count)
174 )
175 ) {
176 ASN_DEBUG("End of SEQUENCE %s", sd->name);
177 /*
178 * Found the legitimate end of the structure.
179 */
180 PHASE_OUT(ctx);
181 RETURN(RC_OK);
182 }
183
184 /*
185 * Fetch the T from TLV.
186 */
187 tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag);
188 ASN_DEBUG("In %s SEQUENCE for %d %s next tag length %d",
189 sd->name, edx, elements[edx].name, (int)tag_len);
190 switch(tag_len) {
191 case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
192 /* Fall through */
193 case -1: RETURN(RC_FAIL);
194 }
195
196 /*
197 * Find the next available type with this tag.
198 */
199 opt_edx_end = edx + elements[edx].optional + 1;
200 if(opt_edx_end > specs->elements_count)
201 opt_edx_end = specs->elements_count; /* Cap */
202 for(n = edx; n < opt_edx_end; n++) {
203 if(BER_TAGS_EQUAL(tlv_tag, elements[n].tag)) {
204 /*
205 * Found element corresponding to the tag
206 * being looked at.
207 * Reposition over the right element.
208 */
209 edx = n;
210 ctx->step = 2 * edx; /* Remember! */
211 break;
212 }
213 }
214 if(n == opt_edx_end) {
215 /*
216 * If tag is unknown, it may be either
217 * an unknown (thus, incorrect) tag,
218 * or an extension (...),
219 * or an end of the indefinite-length structure.
220 */
221
222 if(!IN_EXTENSION_GROUP(specs, edx)) {
223 ASN_DEBUG("Unexpected tag %s",
224 ber_tlv_tag_string(tlv_tag));
225 ASN_DEBUG("Expected tag %s%s",
226 ber_tlv_tag_string(elements[edx].tag),
227 elements[edx].optional
228 ?" or alternatives":"");
229 RETURN(RC_FAIL);
230 }
231
232 if(ctx->left < 0
233 && ((uint8_t *)ptr)[0] == 0) {
234 if(LEFT < 2) {
235 if(SIZE_VIOLATION)
236 RETURN(RC_FAIL);
237 else
238 RETURN(RC_WMORE);
239 } else if(((uint8_t *)ptr)[1] == 0) {
240 /*
241 * Yeah, baby! Found the terminator
242 * of the indefinite length structure.
243 */
244 /*
245 * Proceed to the canonical
246 * finalization function.
247 * No advancing is necessary.
248 */
249 goto phase3;
250 }
251 } else {
252 /* Skip this tag */
253 ssize_t skip;
254
255 skip = ber_skip_length(
256 BER_TLV_CONSTRUCTED(ptr),
257 ptr + tag_len, LEFT - tag_len);
258 ASN_DEBUG("Skip length %d in %s",
259 (int)skip, sd->name);
260 switch(skip) {
261 case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
262 /* Fall through */
263 case -1: RETURN(RC_FAIL);
264 }
265
266 ADVANCE(skip + tag_len);
267 ctx->step -= 2;
268 edx--;
269 continue; /* Try again with the next tag */
270 }
271 }
272
273 /*
274 * MICROPHASE 2: Invoke the member-specific decoder.
275 */
276 ctx->step |= 1; /* Confirm entering next microphase */
277 microphase2:
278 ASN_DEBUG("Inside SEQUENCE %s MF2", sd->name);
279
280 /*
281 * Compute the position of the member inside a structure,
282 * and also a type of containment (it may be contained
283 * as pointer or using inline inclusion).
284 */
285 if(elements[edx].optional) {
286 /* Optional member, hereby, a simple pointer */
287 memb_ptr2 = (char *)st + elements[edx].memb_offset;
288 } else {
289 /*
290 * A pointer to a pointer
291 * holding the start of the structure
292 */
293 memb_ptr = (char *)st + elements[edx].memb_offset;
294 memb_ptr2 = &memb_ptr;
295 }
296 /*
297 * Invoke the member fetch routine according to member's type
298 */
299 rval = elements[edx].type->ber_decoder(
300 (void *)elements[edx].type,
301 memb_ptr2, ptr, LEFT,
302 elements[edx].tag_mode);
303 ASN_DEBUG("In %s SEQUENCE decoded %d %s in %d bytes code %d",
304 sd->name, edx, elements[edx].type->name,
305 (int)rval.consumed, rval.code);
306 switch(rval.code) {
307 case RC_OK:
308 break;
309 case RC_WMORE: /* More data expected */
310 if(!SIZE_VIOLATION) {
311 ADVANCE(rval.consumed);
312 RETURN(RC_WMORE);
313 }
314 /* Fall through */
315 case RC_FAIL: /* Fatal error */
316 RETURN(RC_FAIL);
317 } /* switch(rval) */
318
319 ADVANCE(rval.consumed);
320 } /* for(all structure members) */
321
322 phase3:
323 ctx->phase = 3;
324 case 3: /* 00 and other tags expected */
325 case 4: /* only 00's expected */
326
327 ASN_DEBUG("SEQUENCE %s Leftover: %ld, size = %ld",
328 sd->name, (long)ctx->left, (long)size);
329
330 /*
331 * Skip everything until the end of the SEQUENCE.
332 */
333 while(ctx->left) {
334 ssize_t tl, ll;
335
336 tl = ber_fetch_tag(ptr, LEFT, &tlv_tag);
337 switch(tl) {
338 case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
339 /* Fall through */
340 case -1: RETURN(RC_FAIL);
341 }
342
343 /*
344 * If expected <0><0>...
345 */
346 if(ctx->left < 0
347 && ((uint8_t *)ptr)[0] == 0) {
348 if(LEFT < 2) {
349 if(SIZE_VIOLATION)
350 RETURN(RC_FAIL);
351 else
352 RETURN(RC_WMORE);
353 } else if(((uint8_t *)ptr)[1] == 0) {
354 /*
355 * Correctly finished with <0><0>.
356 */
357 ADVANCE(2);
358 ctx->left++;
359 ctx->phase = 4;
360 continue;
361 }
362 }
363
364 if(!IN_EXTENSION_GROUP(specs, specs->elements_count)
365 || ctx->phase == 4) {
366 ASN_DEBUG("Unexpected continuation "
367 "of a non-extensible type "
368 "%s (SEQUENCE): %s",
369 sd->name,
370 ber_tlv_tag_string(tlv_tag));
371 RETURN(RC_FAIL);
372 }
373
374 ll = ber_skip_length(
375 BER_TLV_CONSTRUCTED(ptr),
376 ptr + tl, LEFT - tl);
377 switch(ll) {
378 case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
379 /* Fall through */
380 case -1: RETURN(RC_FAIL);
381 }
382
383 ADVANCE(tl + ll);
384 }
385
386 PHASE_OUT(ctx);
387 }
388
389 RETURN(RC_OK);
390}
391
392/*
393 * The DER encoder of the SEQUENCE type.
394 */
395der_enc_rval_t
396SEQUENCE_encode_der(asn1_TYPE_descriptor_t *sd,
397 void *ptr, int tag_mode, ber_tlv_tag_t tag,
398 asn_app_consume_bytes_f *cb, void *app_key) {
399 asn1_SEQUENCE_specifics_t *specs = sd->specifics;
400 size_t computed_size = 0;
401 der_enc_rval_t erval;
402 ssize_t ret;
403 int edx;
404
405 ASN_DEBUG("%s %s as SEQUENCE",
406 cb?"Encoding":"Estimating", sd->name);
407
408 /*
409 * Gather the length of the underlying members sequence.
410 */
411 for(edx = 0; edx < specs->elements_count; edx++) {
412 asn1_SEQUENCE_element_t *elm = &specs->elements[edx];
413 void *memb_ptr;
414 if(elm->optional) {
415 memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
416 if(!memb_ptr) continue;
417 } else {
418 memb_ptr = (void *)((char *)ptr + elm->memb_offset);
419 }
420 erval = elm->type->der_encoder(elm->type, memb_ptr,
421 elm->tag_mode, elm->tag,
422 0, 0);
423 if(erval.encoded == -1)
424 return erval;
425 computed_size += erval.encoded;
426 ASN_DEBUG("Member %d %s estimated %ld bytes",
427 edx, elm->name, (long)erval.encoded);
428 }
429
430 /*
431 * Encode the TLV for the sequence itself.
432 */
433 ret = der_write_tags(sd, computed_size, tag_mode, tag, cb, app_key);
434 ASN_DEBUG("Wrote tags: %ld (+%ld)", (long)ret, (long)computed_size);
435 if(ret == -1) {
436 erval.encoded = -1;
437 erval.failed_type = sd;
438 erval.structure_ptr = ptr;
439 return erval;
440 }
441 erval.encoded = computed_size + ret;
442
443 if(!cb) return erval;
444
445 /*
446 * Encode all members.
447 */
448 for(edx = 0; edx < specs->elements_count; edx++) {
449 asn1_SEQUENCE_element_t *elm = &specs->elements[edx];
450 der_enc_rval_t tmperval;
451 void *memb_ptr;
452
453 if(elm->optional) {
454 memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
455 if(!memb_ptr) continue;
456 } else {
457 memb_ptr = (void *)((char *)ptr + elm->memb_offset);
458 }
459 tmperval = elm->type->der_encoder(elm->type, memb_ptr,
460 elm->tag_mode, elm->tag,
461 cb, app_key);
462 if(tmperval.encoded == -1)
463 return tmperval;
464 computed_size -= tmperval.encoded;
465 ASN_DEBUG("Member %d %s of SEQUENCE %s encoded in %d bytes",
466 edx, elm->name, sd->name, tmperval.encoded);
467 }
468
469 if(computed_size != 0) {
470 /*
471 * Encoded size is not equal to the computed size.
472 */
473 erval.encoded = -1;
474 erval.failed_type = sd;
475 erval.structure_ptr = ptr;
476 }
477
478 return erval;
479}
480
481int
482SEQUENCE_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
483 asn_app_consume_bytes_f *cb, void *app_key) {
484 asn1_SEQUENCE_specifics_t *specs = td->specifics;
485 int edx;
486 int ret;
487
488 if(!sptr) return cb("<absent>", 8, app_key);
489
490 /* Dump preamble */
491 if(cb(td->name, strlen(td->name), app_key)
492 || cb(" ::= {\n", 7, app_key))
493 return -1;
494
495 for(edx = 0; edx < specs->elements_count; edx++) {
496 asn1_SEQUENCE_element_t *elm = &specs->elements[edx];
497 const void *memb_ptr;
498
499 if(elm->optional) {
500 memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
501 if(!memb_ptr) continue;
502 } else {
503 memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
504 }
505
506 /* Indentation */
507 for(ret = 0; ret < ilevel; ret++) cb(" ", 1, app_key);
508
509 /* Print the member's name and stuff */
510 if(cb(elm->name, strlen(elm->name), app_key)
511 || cb(": ", 2, app_key))
512 return -1;
513
514 /* Print the member itself */
515 ret = elm->type->print_struct(elm->type, memb_ptr, ilevel + 4,
516 cb, app_key);
517 if(ret) return ret;
518
519 /* Print out the terminator */
520 ret = cb("\n", 1, app_key);
521 if(ret) return ret;
522 }
523
524 /* Indentation */
525 for(ret = 0; ret < ilevel - 4; ret++) cb(" ", 1, app_key);
526
527 return cb("}", 1, app_key);
528}
529
530void
531SEQUENCE_free(asn1_TYPE_descriptor_t *td, void *sptr, int contents_only) {
532 asn1_SEQUENCE_specifics_t *specs = td->specifics;
533 int edx;
534
535 if(!td || !sptr)
536 return;
537
538 ASN_DEBUG("Freeing %s as SEQUENCE", td->name);
539
540 for(edx = 0; edx < specs->elements_count; edx++) {
541 asn1_SEQUENCE_element_t *elm = &specs->elements[edx];
542 void *memb_ptr;
543 if(elm->optional) {
544 memb_ptr = *(void **)((char *)sptr + elm->memb_offset);
545 if(memb_ptr)
546 elm->type->free_struct(elm->type, memb_ptr, 0);
547 } else {
548 memb_ptr = (void *)((char *)sptr + elm->memb_offset);
549 elm->type->free_struct(elm->type, memb_ptr, 1);
550 }
551 }
552
553 if(!contents_only) {
554 FREEMEM(sptr);
555 }
556}
557
558int
559SEQUENCE_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,
560 asn_app_consume_bytes_f *app_errlog, void *app_key) {
561 asn1_SEQUENCE_specifics_t *specs = td->specifics;
562 int edx;
563
564 if(!sptr) {
565 _ASN_ERRLOG("%s: value not given", td->name);
566 return -1;
567 }
568
569 /*
570 * Iterate over structure members and check their validity.
571 */
572 for(edx = 0; edx < specs->elements_count; edx++) {
573 asn1_SEQUENCE_element_t *elm = &specs->elements[edx];
574 const void *memb_ptr;
575
576 if(elm->optional) {
577 memb_ptr = *(const void **)((const char *)sptr + elm->memb_offset);
578 if(!memb_ptr) continue;
579 } else {
580 memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
581 }
582
583 return elm->type->check_constraints(elm->type, memb_ptr,
584 app_errlog, app_key);
585 }
586
587 return 0;
588}