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