blob: 88d7a2a1b4a0d2b57c5ad0fd3e0067faa7986a4f [file] [log] [blame]
Lev Walkinc6bd3592017-08-30 17:36:23 -07001/*
2 * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
3 * All rights reserved.
4 * Redistribution and modifications are permitted subject to BSD license.
5 */
6#ifndef ASN_DISABLE_OER_SUPPORT
7
8#include <asn_internal.h>
9#include <constr_SET_OF.h>
10#include <asn_SET_OF.h>
11#include <errno.h>
12
13/*
14 * This macro "eats" the part of the buffer which is definitely "consumed",
15 * i.e. was correctly converted into local representation or rightfully skipped.
16 */
17#undef ADVANCE
18#define ADVANCE(num_bytes) \
19 do { \
20 size_t num = num_bytes; \
21 ptr = ((const char *)ptr) + num; \
22 size -= num; \
23 consumed_myself += num; \
24 } while(0)
25
26/*
27 * Switch to the next phase of parsing.
28 */
29#undef NEXT_PHASE
30#define NEXT_PHASE(ctx) \
31 do { \
32 ctx->phase++; \
33 ctx->step = 0; \
34 } while(0)
35#undef SET_PHASE
36#define SET_PHASE(ctx, value) \
37 do { \
38 ctx->phase = value; \
39 ctx->step = 0; \
40 } while(0)
41
42/*
43 * Return a standardized complex structure.
44 */
45#undef RETURN
46#define RETURN(_code) \
47 do { \
48 asn_dec_rval_t rval; \
49 rval.code = _code; \
50 rval.consumed = consumed_myself; \
51 return rval; \
52 } while(0)
53
54/*
55 * The SEQUENCE OF and SET OF values utilize a "quantity field".
56 * It is is a pointless combination of #8.6 (length determinant, capable
57 * of encoding tiny and huge numbers in the shortest possible number of octets)
58 * and the variable sized integer. What could have been encoded by #8.6 alone
59 * is required to be encoded by #8.6 followed by that number of unsigned octets.
60 * This doesn't make too much sense. It seems that the original version of OER
61 * standard have been using the unconstrained unsigned integer as a quantity
62 * field, and this legacy have gone through ISO/ITU-T standardization process.
63 */
64static ssize_t
65oer_fetch_quantity(const void *ptr, size_t size, size_t *qty_r) {
Lev Walkineff98a52017-09-13 22:24:35 +000066 const uint8_t *b;
67 const uint8_t *bend;
Lev Walkinc6bd3592017-08-30 17:36:23 -070068 size_t len = 0;
69 size_t qty;
70
71 ssize_t len_len = oer_fetch_length(ptr, size, &len);
72 if(len_len <= 0) {
73 *qty_r = 0;
74 return len_len;
75 }
76
77 if((len_len + len) > size) {
78 *qty_r = 0;
79 return 0;
80 }
81
Lev Walkineff98a52017-09-13 22:24:35 +000082 b = (const uint8_t *)ptr + len_len;
83 bend = b + len;
Lev Walkinc6bd3592017-08-30 17:36:23 -070084
85 /* Skip the leading 0-bytes */
86 for(; b < bend && *b == 0; b++) {
87 }
88
Lev Walkinc6bd3592017-08-30 17:36:23 -070089 if((bend - b) > (ssize_t)sizeof(size_t)) {
90 /* Length is not representable by the native size_t type */
91 *qty_r = 0;
92 return -1;
93 }
94
95 for(qty = 0; b < bend; b++) {
96 qty = (qty << 8) + *b;
97 }
98
99 if(qty > RSIZE_MAX) { /* A bit of C11 validation */
100 *qty_r = 0;
101 return -1;
102 }
103
104 *qty_r = qty;
105 assert((size_t)len_len + len == (size_t)(bend - (const uint8_t *)ptr));
106 return len_len + len;
107}
108
109asn_dec_rval_t
Lev Walkin20696a42017-10-17 21:27:33 -0700110SET_OF_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
111 const asn_TYPE_descriptor_t *td,
112 const asn_oer_constraints_t *constraints, void **struct_ptr,
113 const void *ptr, size_t size) {
Lev Walkind84f6032017-10-03 16:33:59 -0700114 const asn_SET_OF_specifics_t *specs = (const asn_SET_OF_specifics_t *)td->specifics;
Lev Walkinc6bd3592017-08-30 17:36:23 -0700115 asn_dec_rval_t rval = {RC_OK, 0};
116 void *st = *struct_ptr; /* Target structure */
117 asn_struct_ctx_t *ctx; /* Decoder context */
118 size_t consumed_myself = 0; /* Consumed bytes from ptr. */
119
Lev Walkinc6bd3592017-08-30 17:36:23 -0700120 (void)constraints;
121
Lev Walkin62155df2017-10-21 01:16:17 -0700122 if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx))
123 ASN__DECODE_FAILED;
124
Lev Walkinc6bd3592017-08-30 17:36:23 -0700125 /*
126 * Create the target structure if it is not present already.
127 */
128 if(st == 0) {
129 st = *struct_ptr = CALLOC(1, specs->struct_size);
130 if(st == 0) {
131 RETURN(RC_FAIL);
132 }
133 }
134
135 /*
136 * Restore parsing context.
137 */
138 ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
139
140 /*
141 * Start to parse where left previously.
142 */
143 switch(ctx->phase) {
144 case 0: {
145 /*
146 * Fetch number of elements to decode.
147 */
148 size_t length = 0;
149 size_t len_size = oer_fetch_quantity(ptr, size, &length);
150 switch(len_size) {
151 case 0:
152 RETURN(RC_WMORE);
153 case -1:
154 RETURN(RC_FAIL);
155 default:
Lev Walkinc6bd3592017-08-30 17:36:23 -0700156 ADVANCE(len_size);
157 ctx->left = length;
158 }
159 }
160 NEXT_PHASE(ctx);
161 /* FALL THROUGH */
162 case 1: {
163 /* Decode components of the extension root */
164 asn_TYPE_member_t *elm = td->elements;
165 asn_anonymous_set_ *list = _A_SET_FROM_VOID(st);
Lev Walkin52b88e12017-10-24 03:03:46 -0700166 const void *base_ptr = ptr;
167 ber_tlv_len_t base_ctx_left = ctx->left;
Lev Walkinc6bd3592017-08-30 17:36:23 -0700168
169 assert(td->elements_count == 1);
170
171 ASN_DEBUG("OER SET OF %s Decoding PHASE 1", td->name);
172
173 for(; ctx->left > 0; ctx->left--) {
174 asn_dec_rval_t rv = elm->type->op->oer_decoder(
Lev Walkina5972be2017-09-29 23:15:58 -0700175 opt_codec_ctx, elm->type,
176 elm->encoding_constraints.oer_constraints, &ctx->ptr, ptr,
Lev Walkinc6bd3592017-08-30 17:36:23 -0700177 size);
178 ADVANCE(rv.consumed);
179 switch(rv.code) {
180 case RC_OK:
181 if(ASN_SET_ADD(list, ctx->ptr) != 0) {
182 RETURN(RC_FAIL);
183 } else {
184 ctx->ptr = 0;
Lev Walkin52b88e12017-10-24 03:03:46 -0700185 /*
186 * This check is to avoid compression bomb with
187 * specs like SEQUENCE/SET OF NULL which don't
188 * consume data at all.
189 */
190 if(rv.consumed == 0 && base_ptr == ptr
191 && (base_ctx_left - ctx->left) > 200) {
192 ASN__DECODE_FAILED;
193 }
Lev Walkinc6bd3592017-08-30 17:36:23 -0700194 break;
195 }
196 case RC_WMORE:
197 RETURN(RC_WMORE);
198 case RC_FAIL:
199 ASN_STRUCT_FREE(*elm->type, ctx->ptr);
200 ctx->ptr = 0;
201 SET_PHASE(ctx, 3);
202 RETURN(RC_FAIL);
203 }
204 }
205 /* Decoded decently. */
206 NEXT_PHASE(ctx);
207 }
208 /* Fall through */
209 case 2:
210 /* Ignore fully decoded */
211 assert(ctx->left == 0);
212 RETURN(RC_OK);
213 case 3:
214 /* Failed to decode. */
215 RETURN(RC_FAIL);
216 }
217
218 return rval;
219}
220
Lev Walkinfc89b9d2017-08-31 00:54:38 -0700221static ssize_t
222oer_put_quantity(size_t qty, asn_app_consume_bytes_f *cb, void *app_key) {
223 uint8_t buf[1 + sizeof(size_t)];
224 uint8_t *b = &buf[sizeof(size_t)]; /* Last addressable */
225 size_t encoded;
226
227 do {
228 *b-- = qty;
229 qty >>= 8;
230 } while(qty);
231
232 *b = sizeof(buf) - (b-buf) - 1;
233 encoded = sizeof(buf) - (b-buf);
234 if(cb(b, encoded, app_key) < 0)
235 return -1;
236 return encoded;
237}
238
Lev Walkinc6bd3592017-08-30 17:36:23 -0700239/*
240 * Encode as Canonical OER.
241 */
242asn_enc_rval_t
Lev Walkin20696a42017-10-17 21:27:33 -0700243SET_OF_encode_oer(const asn_TYPE_descriptor_t *td,
244 const asn_oer_constraints_t *constraints, const void *sptr,
245 asn_app_consume_bytes_f *cb, void *app_key) {
246 const asn_TYPE_member_t *elm;
247 const asn_anonymous_set_ *list;
Lev Walkinc6bd3592017-08-30 17:36:23 -0700248 size_t computed_size = 0;
Lev Walkinfc89b9d2017-08-31 00:54:38 -0700249 ssize_t qty_len;
Lev Walkin71191ba2017-08-31 01:00:00 -0700250 int n;
Lev Walkinc6bd3592017-08-30 17:36:23 -0700251
252 (void)constraints;
Lev Walkinfc89b9d2017-08-31 00:54:38 -0700253
254 if(!sptr) ASN__ENCODE_FAILED;
255
256 elm = td->elements;
Lev Walkin20696a42017-10-17 21:27:33 -0700257 list = _A_CSET_FROM_VOID(sptr);
Lev Walkinfc89b9d2017-08-31 00:54:38 -0700258
259 qty_len = oer_put_quantity(list->count, cb, app_key);
260 if(qty_len < 0) {
261 ASN__ENCODE_FAILED;
262 }
263 computed_size += qty_len;
264
265 for(n = 0; n < list->count; n++) {
266 void *memb_ptr = list->array[n];
267 asn_enc_rval_t er;
Lev Walkina5972be2017-09-29 23:15:58 -0700268 er = elm->type->op->oer_encoder(
269 elm->type, elm->encoding_constraints.oer_constraints, memb_ptr, cb,
270 app_key);
Lev Walkinfc89b9d2017-08-31 00:54:38 -0700271 if(er.encoded < 0) {
272 return er;
273 } else {
274 computed_size += er.encoded;
275 }
276 }
Lev Walkinc6bd3592017-08-30 17:36:23 -0700277
278 {
Lev Walkineff98a52017-09-13 22:24:35 +0000279 asn_enc_rval_t erval;
280 erval.encoded = computed_size;
281 ASN__ENCODED_OK(erval);
Lev Walkinc6bd3592017-08-30 17:36:23 -0700282 }
283}
284
285#endif /* ASN_DISABLE_OER_SUPPORT */