blob: 8ce0261b81c3123d6332cdd4855b06a5f3a8ce66 [file] [log] [blame]
Lev Walkin6d46bc32017-09-12 21:34:00 -07001/*
2 * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
3 * Redistribution and modifications are permitted subject to BSD license.
4 */
5#include <asn_internal.h>
6#include <asn_application.h>
7#include <errno.h>
8
Lev Walkin20696a42017-10-17 21:27:33 -07009static asn_enc_rval_t asn_encode_internal(const asn_codec_ctx_t *opt_codec_ctx,
10 enum asn_transfer_syntax syntax,
11 const asn_TYPE_descriptor_t *td,
12 const void *sptr,
13 asn_app_consume_bytes_f *callback,
14 void *callback_key);
Lev Walkin6d46bc32017-09-12 21:34:00 -070015
16
17struct callback_count_bytes_key {
18 asn_app_consume_bytes_f *callback;
19 void *callback_key;
20 size_t computed_size;
21};
22
23/*
24 * Encoder which just counts bytes that come through it.
25 */
26static int
27callback_count_bytes_cb(const void *data, size_t size, void *keyp) {
28 struct callback_count_bytes_key *key = keyp;
29 int ret;
30
31 ret = key->callback(data, size, key->callback_key);
32 if(ret >= 0) {
33 key->computed_size += size;
34 }
35
36 return ret;
37}
38
39struct overrun_encoder_key {
40 void *buffer;
41 size_t buffer_size;
42 size_t computed_size;
43};
44
Lev Walkin1fc5edb2017-11-06 01:58:49 -080045struct dynamic_encoder_key {
46 void *buffer;
47 size_t buffer_size;
48 size_t computed_size;
49};
50
Lev Walkin6d46bc32017-09-12 21:34:00 -070051struct callback_failure_catch_key {
52 asn_app_consume_bytes_f *callback;
53 void *callback_key;
54 int callback_failed;
55};
56
57/*
58 * Encoder which doesn't stop counting bytes
59 * even if it reaches the end of the buffer.
60 */
61static int
62overrun_encoder_cb(const void *data, size_t size, void *keyp) {
63 struct overrun_encoder_key *key = keyp;
64
65 if(key->computed_size + size > key->buffer_size) {
66 /*
67 * Avoid accident on the next call:
68 * stop adding bytes to the buffer.
69 */
70 key->buffer_size = 0;
71 } else {
72 memcpy((char *)key->buffer + key->computed_size, data, size);
Lev Walkin6d46bc32017-09-12 21:34:00 -070073 }
Lev Walkina5b02882017-10-01 22:48:44 -070074 key->computed_size += size;
Lev Walkin6d46bc32017-09-12 21:34:00 -070075
76 return 0;
77}
78
79/*
Lev Walkin1fc5edb2017-11-06 01:58:49 -080080 * Encoder which dynamically allocates output, and continues
81 * to count even if allocation failed.
82 */
83static int
84dynamic_encoder_cb(const void *data, size_t size, void *keyp) {
85 struct dynamic_encoder_key *key = keyp;
86
87 if(key->buffer) {
88 if(key->computed_size + size >= key->buffer_size) {
89 void *p;
90 size_t new_size = key->buffer_size;
91
92 do {
93 new_size *= 2;
94 } while(new_size <= key->computed_size + size);
95
96 p = REALLOC(key->buffer, new_size);
97 if(p) {
98 key->buffer = p;
99 key->buffer_size = new_size;
100 } else {
101 FREEMEM(key->buffer);
102 key->buffer = 0;
103 key->buffer_size = 0;
104 key->computed_size += size;
105 return 0;
106 }
107 }
108 memcpy((char *)key->buffer + key->computed_size, data, size);
109 }
110
111 key->computed_size += size;
112
113 return 0;
114}
115
116/*
Lev Walkin6d46bc32017-09-12 21:34:00 -0700117 * Encoder which help convert the application level encoder failure into EIO.
118 */
119static int
120callback_failure_catch_cb(const void *data, size_t size, void *keyp) {
121 struct callback_failure_catch_key *key = keyp;
122 int ret;
123
124 ret = key->callback(data, size, key->callback_key);
125 if(ret < 0) {
126 key->callback_failed = 1;
127 }
128
129 return ret;
130}
131
132asn_enc_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -0700133asn_encode(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin686f38b2017-11-14 22:00:57 -0800134 enum asn_transfer_syntax syntax, const asn_TYPE_descriptor_t *td,
135 const void *sptr, asn_app_consume_bytes_f *callback, void *callback_key) {
Lev Walkin6d46bc32017-09-12 21:34:00 -0700136 struct callback_failure_catch_key cb_key;
137 asn_enc_rval_t er;
138
139 if(!callback) {
140 errno = EINVAL;
141 ASN__ENCODE_FAILED;
142 }
143
144 cb_key.callback = callback;
145 cb_key.callback_key = callback_key;
146 cb_key.callback_failed = 0;
147
Lev Walkinafbf2a92017-09-12 23:30:27 -0700148 er = asn_encode_internal(opt_codec_ctx, syntax, td, sptr,
Lev Walkin6d46bc32017-09-12 21:34:00 -0700149 callback_failure_catch_cb, &cb_key);
150 if(cb_key.callback_failed) {
151 assert(er.encoded == -1);
152 assert(errno == EBADF);
153 errno = EIO;
154 }
155
156 return er;
157}
158
159asn_enc_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -0700160asn_encode_to_buffer(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin20696a42017-10-17 21:27:33 -0700161 enum asn_transfer_syntax syntax,
162 const asn_TYPE_descriptor_t *td, const void *sptr,
163 void *buffer, size_t buffer_size) {
Lev Walkin6d46bc32017-09-12 21:34:00 -0700164 struct overrun_encoder_key buf_key;
165 asn_enc_rval_t er;
166
167 if(buffer_size > 0 && !buffer) {
168 errno = EINVAL;
169 ASN__ENCODE_FAILED;
170 }
171
172 buf_key.buffer = buffer;
173 buf_key.buffer_size = buffer_size;
174 buf_key.computed_size = 0;
175
Lev Walkinafbf2a92017-09-12 23:30:27 -0700176 er = asn_encode_internal(opt_codec_ctx, syntax, td, sptr,
Lev Walkin6d46bc32017-09-12 21:34:00 -0700177 overrun_encoder_cb, &buf_key);
178
Lev Walkina5b02882017-10-01 22:48:44 -0700179 if(er.encoded >= 0 && (size_t)er.encoded != buf_key.computed_size) {
Lev Walkin1fc5edb2017-11-06 01:58:49 -0800180 ASN_DEBUG("asn_encode() returned %" ASN_PRI_SSIZE
181 " yet produced %" ASN_PRI_SIZE " bytes",
Lev Walkina5b02882017-10-01 22:48:44 -0700182 er.encoded, buf_key.computed_size);
Lev Walkinaa5838c2017-10-03 17:13:33 -0700183 assert(er.encoded < 0 || (size_t)er.encoded == buf_key.computed_size);
Lev Walkina5b02882017-10-01 22:48:44 -0700184 }
Lev Walkin6d46bc32017-09-12 21:34:00 -0700185
186 return er;
187}
188
Lev Walkin1fc5edb2017-11-06 01:58:49 -0800189asn_encode_to_new_buffer_result_t
190asn_encode_to_new_buffer(const asn_codec_ctx_t *opt_codec_ctx,
191 enum asn_transfer_syntax syntax,
192 const asn_TYPE_descriptor_t *td, const void *sptr) {
193 struct dynamic_encoder_key buf_key;
194 asn_encode_to_new_buffer_result_t res;
195
196 buf_key.buffer_size = 16;
197 buf_key.buffer = MALLOC(buf_key.buffer_size);
198 buf_key.computed_size = 0;
199
200 res.result = asn_encode_internal(opt_codec_ctx, syntax, td, sptr,
201 dynamic_encoder_cb, &buf_key);
202
203 if(res.result.encoded >= 0
204 && (size_t)res.result.encoded != buf_key.computed_size) {
205 ASN_DEBUG("asn_encode() returned %" ASN_PRI_SSIZE
206 " yet produced %" ASN_PRI_SIZE " bytes",
Bi-Ruei, Chiu8ae074c2017-11-09 11:55:06 +0800207 res.result.encoded, buf_key.computed_size);
Lev Walkin1fc5edb2017-11-06 01:58:49 -0800208 assert(res.result.encoded < 0
209 || (size_t)res.result.encoded == buf_key.computed_size);
210 }
211
212 res.buffer = buf_key.buffer;
213
214 /* 0-terminate just in case. */
215 if(res.buffer) {
216 assert(buf_key.computed_size < buf_key.buffer_size);
217 ((char *)res.buffer)[buf_key.computed_size] = '\0';
218 }
219
220 return res;
221}
222
Lev Walkin6d46bc32017-09-12 21:34:00 -0700223static asn_enc_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -0700224asn_encode_internal(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin20696a42017-10-17 21:27:33 -0700225 enum asn_transfer_syntax syntax,
226 const asn_TYPE_descriptor_t *td, const void *sptr,
227 asn_app_consume_bytes_f *callback, void *callback_key) {
Lev Walkin6d46bc32017-09-12 21:34:00 -0700228 asn_enc_rval_t er;
229 enum xer_encoder_flags_e xer_flags = XER_F_CANONICAL;
230
Lev Walkinafbf2a92017-09-12 23:30:27 -0700231 (void)opt_codec_ctx; /* Parameters are not checked on encode yet. */
Lev Walkin6d46bc32017-09-12 21:34:00 -0700232
233 if(!td || !sptr) {
234 errno = EINVAL;
235 ASN__ENCODE_FAILED;
236 }
237
238 switch(syntax) {
Lev Walkina5972be2017-09-29 23:15:58 -0700239 case ATS_NONSTANDARD_PLAINTEXT:
240 if(td->op->print_struct) {
241 struct callback_count_bytes_key cb_key;
242 cb_key.callback = callback;
243 cb_key.callback_key = callback_key;
244 cb_key.computed_size = 0;
245 if(td->op->print_struct(td, sptr, 1, callback_count_bytes_cb,
246 &cb_key)
247 < 0
248 || callback_count_bytes_cb("\n", 1, &cb_key) < 0) {
249 errno = EBADF; /* Structure has incorrect form. */
250 er.encoded = -1;
251 er.failed_type = td;
252 er.structure_ptr = sptr;
253 } else {
254 er.encoded = cb_key.computed_size;
255 er.failed_type = 0;
256 er.structure_ptr = 0;
257 }
258 } else {
259 errno = ENOENT; /* Transfer syntax is not defined for this type. */
260 ASN__ENCODE_FAILED;
261 }
262 break;
263
264 case ATS_RANDOM:
265 errno = ENOENT; /* Randomization doesn't make sense on output. */
266 ASN__ENCODE_FAILED;
267
Lev Walkin6d46bc32017-09-12 21:34:00 -0700268 case ATS_BER:
269 /* BER is a superset of DER. */
270 /* Fall through. */
271 case ATS_DER:
272 if(td->op->der_encoder) {
273 er = der_encode(td, sptr, callback, callback_key);
274 if(er.encoded == -1) {
275 if(er.failed_type && er.failed_type->op->der_encoder) {
276 errno = EBADF; /* Structure has incorrect form. */
277 } else {
278 errno = ENOENT; /* DER is not defined for this type. */
279 }
280 }
281 } else {
282 errno = ENOENT; /* Transfer syntax is not defined for this type. */
283 ASN__ENCODE_FAILED;
284 }
285 break;
286 case ATS_CER:
287 errno = ENOENT; /* Transfer syntax is not defined for any type. */
288 ASN__ENCODE_FAILED;
289
290#ifdef ASN_DISABLE_OER_SUPPORT
291 case ATS_BASIC_OER:
292 case ATS_CANONICAL_OER:
293 errno = ENOENT; /* PER is not defined. */
294 ASN__ENCODE_FAILED;
295 break;
296#else /* ASN_DISABLE_OER_SUPPORT */
297 case ATS_BASIC_OER:
298 /* CANONICAL-OER is a superset of BASIC-OER. */
299 /* Fall through. */
300 case ATS_CANONICAL_OER:
301 if(td->op->oer_encoder) {
302 er = oer_encode(td, sptr, callback, callback_key);
303 if(er.encoded == -1) {
304 if(er.failed_type && er.failed_type->op->oer_encoder) {
305 errno = EBADF; /* Structure has incorrect form. */
306 } else {
307 errno = ENOENT; /* OER is not defined for this type. */
308 }
309 }
310 } else {
311 errno = ENOENT; /* Transfer syntax is not defined for this type. */
312 ASN__ENCODE_FAILED;
313 }
314 break;
315#endif /* ASN_DISABLE_OER_SUPPORT */
316
317#ifdef ASN_DISABLE_PER_SUPPORT
318 case ATS_UNALIGNED_BASIC_PER:
319 case ATS_UNALIGNED_CANONICAL_PER:
320 errno = ENOENT; /* PER is not defined. */
321 ASN__ENCODE_FAILED;
322 break;
323#else /* ASN_DISABLE_PER_SUPPORT */
324 case ATS_UNALIGNED_BASIC_PER:
325 /* CANONICAL-UPER is a superset of BASIC-UPER. */
326 /* Fall through. */
327 case ATS_UNALIGNED_CANONICAL_PER:
328 if(td->op->uper_encoder) {
Lev Walkin56153042017-10-24 00:47:03 -0700329 er = uper_encode(td, 0, sptr, callback, callback_key);
Lev Walkin6d46bc32017-09-12 21:34:00 -0700330 if(er.encoded == -1) {
331 if(er.failed_type && er.failed_type->op->uper_encoder) {
332 errno = EBADF; /* Structure has incorrect form. */
333 } else {
334 errno = ENOENT; /* UPER is not defined for this type. */
335 }
336 } else {
337 ASN_DEBUG("Complete encoded in %ld bits", (long)er.encoded);
338 if(er.encoded == 0) {
339 /* Enforce "Complete Encoding" of X.691 #11.1 */
340 if(callback("\0", 1, callback_key) < 0) {
341 errno = EBADF;
342 ASN__ENCODE_FAILED;
343 }
344 er.encoded = 8; /* Exactly 8 zero bits is added. */
345 }
346 /* Convert bits into bytes */
347 er.encoded = (er.encoded + 7) >> 3;
348 }
349 } else {
350 errno = ENOENT; /* Transfer syntax is not defined for this type. */
351 ASN__ENCODE_FAILED;
352 }
353 break;
354#endif /* ASN_DISABLE_PER_SUPPORT */
355
356 case ATS_BASIC_XER:
357 /* CANONICAL-XER is a superset of BASIC-XER. */
358 xer_flags &= ~XER_F_CANONICAL;
359 xer_flags |= XER_F_BASIC;
360 /* Fall through. */
361 case ATS_CANONICAL_XER:
362 if(td->op->xer_encoder) {
363 er = xer_encode(td, sptr, xer_flags, callback, callback_key);
364 if(er.encoded == -1) {
365 if(er.failed_type && er.failed_type->op->xer_encoder) {
366 errno = EBADF; /* Structure has incorrect form. */
367 } else {
368 errno = ENOENT; /* XER is not defined for this type. */
369 }
370 }
371 } else {
372 errno = ENOENT; /* Transfer syntax is not defined for this type. */
373 ASN__ENCODE_FAILED;
374 }
375 break;
376
Lev Walkin6d46bc32017-09-12 21:34:00 -0700377 default:
378 errno = ENOENT;
379 ASN__ENCODE_FAILED;
380 }
381
382 return er;
383}
Lev Walkine8bbe932017-09-12 23:06:52 -0700384
385asn_dec_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -0700386asn_decode(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin20696a42017-10-17 21:27:33 -0700387 enum asn_transfer_syntax syntax, const asn_TYPE_descriptor_t *td,
Lev Walkine8bbe932017-09-12 23:06:52 -0700388 void **sptr, const void *buffer, size_t size) {
Lev Walkina5972be2017-09-29 23:15:58 -0700389 if(!td || !td->op || !sptr || (size && !buffer)) {
Lev Walkine8bbe932017-09-12 23:06:52 -0700390 ASN__DECODE_FAILED;
391 }
392
393 switch(syntax) {
394 case ATS_CER:
395 case ATS_NONSTANDARD_PLAINTEXT:
396 default:
397 errno = ENOENT;
398 ASN__DECODE_FAILED;
399
Lev Walkina5972be2017-09-29 23:15:58 -0700400 case ATS_RANDOM:
401 if(!td->op->random_fill) {
402 ASN__DECODE_FAILED;
403 } else {
404 if(asn_random_fill(td, sptr, 16000) == 0) {
405 asn_dec_rval_t ret = {RC_OK, 0};
406 return ret;
407 } else {
408 ASN__DECODE_FAILED;
409 }
410 }
411 break;
412
Lev Walkine8bbe932017-09-12 23:06:52 -0700413 case ATS_DER:
414 case ATS_BER:
Lev Walkinafbf2a92017-09-12 23:30:27 -0700415 return ber_decode(opt_codec_ctx, td, sptr, buffer, size);
Lev Walkine8bbe932017-09-12 23:06:52 -0700416
417 case ATS_BASIC_OER:
418 case ATS_CANONICAL_OER:
419#ifdef ASN_DISABLE_OER_SUPPORT
420 errno = ENOENT;
421 ASN__DECODE_FAILED;
422#else
Lev Walkinafbf2a92017-09-12 23:30:27 -0700423 return oer_decode(opt_codec_ctx, td, sptr, buffer, size);
Lev Walkine8bbe932017-09-12 23:06:52 -0700424#endif
425
426 case ATS_UNALIGNED_BASIC_PER:
427 case ATS_UNALIGNED_CANONICAL_PER:
428#ifdef ASN_DISABLE_PER_SUPPORT
429 errno = ENOENT;
430 ASN__DECODE_FAILED;
431#else
Lev Walkinafbf2a92017-09-12 23:30:27 -0700432 return uper_decode_complete(opt_codec_ctx, td, sptr, buffer, size);
Lev Walkine8bbe932017-09-12 23:06:52 -0700433#endif
434
435 case ATS_BASIC_XER:
436 case ATS_CANONICAL_XER:
Lev Walkinafbf2a92017-09-12 23:30:27 -0700437 return xer_decode(opt_codec_ctx, td, sptr, buffer, size);
Lev Walkine8bbe932017-09-12 23:06:52 -0700438 }
439}
440