blob: 2cb9b1936c95fe7ea29a8998dba95f547c6ff308 [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
9static asn_enc_rval_t asn_encode_internal(
Lev Walkinafbf2a92017-09-12 23:30:27 -070010 const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin6d46bc32017-09-12 21:34:00 -070011 enum asn_transfer_syntax syntax, asn_TYPE_descriptor_t *td,
12 void *sptr, asn_app_consume_bytes_f *callback, void *callback_key);
13
14
15struct callback_count_bytes_key {
16 asn_app_consume_bytes_f *callback;
17 void *callback_key;
18 size_t computed_size;
19};
20
21/*
22 * Encoder which just counts bytes that come through it.
23 */
24static int
25callback_count_bytes_cb(const void *data, size_t size, void *keyp) {
26 struct callback_count_bytes_key *key = keyp;
27 int ret;
28
29 ret = key->callback(data, size, key->callback_key);
30 if(ret >= 0) {
31 key->computed_size += size;
32 }
33
34 return ret;
35}
36
37struct overrun_encoder_key {
38 void *buffer;
39 size_t buffer_size;
40 size_t computed_size;
41};
42
43struct callback_failure_catch_key {
44 asn_app_consume_bytes_f *callback;
45 void *callback_key;
46 int callback_failed;
47};
48
49/*
50 * Encoder which doesn't stop counting bytes
51 * even if it reaches the end of the buffer.
52 */
53static int
54overrun_encoder_cb(const void *data, size_t size, void *keyp) {
55 struct overrun_encoder_key *key = keyp;
56
57 if(key->computed_size + size > key->buffer_size) {
58 /*
59 * Avoid accident on the next call:
60 * stop adding bytes to the buffer.
61 */
62 key->buffer_size = 0;
63 } else {
64 memcpy((char *)key->buffer + key->computed_size, data, size);
Lev Walkin6d46bc32017-09-12 21:34:00 -070065 }
Lev Walkina5b02882017-10-01 22:48:44 -070066 key->computed_size += size;
Lev Walkin6d46bc32017-09-12 21:34:00 -070067
68 return 0;
69}
70
71/*
72 * Encoder which help convert the application level encoder failure into EIO.
73 */
74static int
75callback_failure_catch_cb(const void *data, size_t size, void *keyp) {
76 struct callback_failure_catch_key *key = keyp;
77 int ret;
78
79 ret = key->callback(data, size, key->callback_key);
80 if(ret < 0) {
81 key->callback_failed = 1;
82 }
83
84 return ret;
85}
86
87asn_enc_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -070088asn_encode(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin6d46bc32017-09-12 21:34:00 -070089 enum asn_transfer_syntax syntax, asn_TYPE_descriptor_t *td,
90 void *sptr, asn_app_consume_bytes_f *callback, void *callback_key) {
91 struct callback_failure_catch_key cb_key;
92 asn_enc_rval_t er;
93
94 if(!callback) {
95 errno = EINVAL;
96 ASN__ENCODE_FAILED;
97 }
98
99 cb_key.callback = callback;
100 cb_key.callback_key = callback_key;
101 cb_key.callback_failed = 0;
102
Lev Walkinafbf2a92017-09-12 23:30:27 -0700103 er = asn_encode_internal(opt_codec_ctx, syntax, td, sptr,
Lev Walkin6d46bc32017-09-12 21:34:00 -0700104 callback_failure_catch_cb, &cb_key);
105 if(cb_key.callback_failed) {
106 assert(er.encoded == -1);
107 assert(errno == EBADF);
108 errno = EIO;
109 }
110
111 return er;
112}
113
114asn_enc_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -0700115asn_encode_to_buffer(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin6d46bc32017-09-12 21:34:00 -0700116 enum asn_transfer_syntax syntax, asn_TYPE_descriptor_t *td,
117 void *sptr, void *buffer, size_t buffer_size) {
118 struct overrun_encoder_key buf_key;
119 asn_enc_rval_t er;
120
121 if(buffer_size > 0 && !buffer) {
122 errno = EINVAL;
123 ASN__ENCODE_FAILED;
124 }
125
126 buf_key.buffer = buffer;
127 buf_key.buffer_size = buffer_size;
128 buf_key.computed_size = 0;
129
Lev Walkinafbf2a92017-09-12 23:30:27 -0700130 er = asn_encode_internal(opt_codec_ctx, syntax, td, sptr,
Lev Walkin6d46bc32017-09-12 21:34:00 -0700131 overrun_encoder_cb, &buf_key);
132
Lev Walkina5b02882017-10-01 22:48:44 -0700133 if(er.encoded >= 0 && (size_t)er.encoded != buf_key.computed_size) {
Lev Walkinaa5838c2017-10-03 17:13:33 -0700134 ASN_DEBUG("asn_encode() returned %zd yet produced %zu bytes",
Lev Walkina5b02882017-10-01 22:48:44 -0700135 er.encoded, buf_key.computed_size);
Lev Walkinaa5838c2017-10-03 17:13:33 -0700136 assert(er.encoded < 0 || (size_t)er.encoded == buf_key.computed_size);
Lev Walkina5b02882017-10-01 22:48:44 -0700137 }
Lev Walkin6d46bc32017-09-12 21:34:00 -0700138
139 return er;
140}
141
142static asn_enc_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -0700143asn_encode_internal(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin6d46bc32017-09-12 21:34:00 -0700144 enum asn_transfer_syntax syntax, asn_TYPE_descriptor_t *td,
145 void *sptr, asn_app_consume_bytes_f *callback,
146 void *callback_key) {
147 asn_enc_rval_t er;
148 enum xer_encoder_flags_e xer_flags = XER_F_CANONICAL;
149
Lev Walkinafbf2a92017-09-12 23:30:27 -0700150 (void)opt_codec_ctx; /* Parameters are not checked on encode yet. */
Lev Walkin6d46bc32017-09-12 21:34:00 -0700151
152 if(!td || !sptr) {
153 errno = EINVAL;
154 ASN__ENCODE_FAILED;
155 }
156
157 switch(syntax) {
Lev Walkina5972be2017-09-29 23:15:58 -0700158 case ATS_NONSTANDARD_PLAINTEXT:
159 if(td->op->print_struct) {
160 struct callback_count_bytes_key cb_key;
161 cb_key.callback = callback;
162 cb_key.callback_key = callback_key;
163 cb_key.computed_size = 0;
164 if(td->op->print_struct(td, sptr, 1, callback_count_bytes_cb,
165 &cb_key)
166 < 0
167 || callback_count_bytes_cb("\n", 1, &cb_key) < 0) {
168 errno = EBADF; /* Structure has incorrect form. */
169 er.encoded = -1;
170 er.failed_type = td;
171 er.structure_ptr = sptr;
172 } else {
173 er.encoded = cb_key.computed_size;
174 er.failed_type = 0;
175 er.structure_ptr = 0;
176 }
177 } else {
178 errno = ENOENT; /* Transfer syntax is not defined for this type. */
179 ASN__ENCODE_FAILED;
180 }
181 break;
182
183 case ATS_RANDOM:
184 errno = ENOENT; /* Randomization doesn't make sense on output. */
185 ASN__ENCODE_FAILED;
186
Lev Walkin6d46bc32017-09-12 21:34:00 -0700187 case ATS_BER:
188 /* BER is a superset of DER. */
189 /* Fall through. */
190 case ATS_DER:
191 if(td->op->der_encoder) {
192 er = der_encode(td, sptr, callback, callback_key);
193 if(er.encoded == -1) {
194 if(er.failed_type && er.failed_type->op->der_encoder) {
195 errno = EBADF; /* Structure has incorrect form. */
196 } else {
197 errno = ENOENT; /* DER is not defined for this type. */
198 }
199 }
200 } else {
201 errno = ENOENT; /* Transfer syntax is not defined for this type. */
202 ASN__ENCODE_FAILED;
203 }
204 break;
205 case ATS_CER:
206 errno = ENOENT; /* Transfer syntax is not defined for any type. */
207 ASN__ENCODE_FAILED;
208
209#ifdef ASN_DISABLE_OER_SUPPORT
210 case ATS_BASIC_OER:
211 case ATS_CANONICAL_OER:
212 errno = ENOENT; /* PER is not defined. */
213 ASN__ENCODE_FAILED;
214 break;
215#else /* ASN_DISABLE_OER_SUPPORT */
216 case ATS_BASIC_OER:
217 /* CANONICAL-OER is a superset of BASIC-OER. */
218 /* Fall through. */
219 case ATS_CANONICAL_OER:
220 if(td->op->oer_encoder) {
221 er = oer_encode(td, sptr, callback, callback_key);
222 if(er.encoded == -1) {
223 if(er.failed_type && er.failed_type->op->oer_encoder) {
224 errno = EBADF; /* Structure has incorrect form. */
225 } else {
226 errno = ENOENT; /* OER is not defined for this type. */
227 }
228 }
229 } else {
230 errno = ENOENT; /* Transfer syntax is not defined for this type. */
231 ASN__ENCODE_FAILED;
232 }
233 break;
234#endif /* ASN_DISABLE_OER_SUPPORT */
235
236#ifdef ASN_DISABLE_PER_SUPPORT
237 case ATS_UNALIGNED_BASIC_PER:
238 case ATS_UNALIGNED_CANONICAL_PER:
239 errno = ENOENT; /* PER is not defined. */
240 ASN__ENCODE_FAILED;
241 break;
242#else /* ASN_DISABLE_PER_SUPPORT */
243 case ATS_UNALIGNED_BASIC_PER:
244 /* CANONICAL-UPER is a superset of BASIC-UPER. */
245 /* Fall through. */
246 case ATS_UNALIGNED_CANONICAL_PER:
247 if(td->op->uper_encoder) {
248 er = uper_encode(td, sptr, callback, callback_key);
249 if(er.encoded == -1) {
250 if(er.failed_type && er.failed_type->op->uper_encoder) {
251 errno = EBADF; /* Structure has incorrect form. */
252 } else {
253 errno = ENOENT; /* UPER is not defined for this type. */
254 }
255 } else {
256 ASN_DEBUG("Complete encoded in %ld bits", (long)er.encoded);
257 if(er.encoded == 0) {
258 /* Enforce "Complete Encoding" of X.691 #11.1 */
259 if(callback("\0", 1, callback_key) < 0) {
260 errno = EBADF;
261 ASN__ENCODE_FAILED;
262 }
263 er.encoded = 8; /* Exactly 8 zero bits is added. */
264 }
265 /* Convert bits into bytes */
266 er.encoded = (er.encoded + 7) >> 3;
267 }
268 } else {
269 errno = ENOENT; /* Transfer syntax is not defined for this type. */
270 ASN__ENCODE_FAILED;
271 }
272 break;
273#endif /* ASN_DISABLE_PER_SUPPORT */
274
275 case ATS_BASIC_XER:
276 /* CANONICAL-XER is a superset of BASIC-XER. */
277 xer_flags &= ~XER_F_CANONICAL;
278 xer_flags |= XER_F_BASIC;
279 /* Fall through. */
280 case ATS_CANONICAL_XER:
281 if(td->op->xer_encoder) {
282 er = xer_encode(td, sptr, xer_flags, callback, callback_key);
283 if(er.encoded == -1) {
284 if(er.failed_type && er.failed_type->op->xer_encoder) {
285 errno = EBADF; /* Structure has incorrect form. */
286 } else {
287 errno = ENOENT; /* XER is not defined for this type. */
288 }
289 }
290 } else {
291 errno = ENOENT; /* Transfer syntax is not defined for this type. */
292 ASN__ENCODE_FAILED;
293 }
294 break;
295
Lev Walkin6d46bc32017-09-12 21:34:00 -0700296 default:
297 errno = ENOENT;
298 ASN__ENCODE_FAILED;
299 }
300
301 return er;
302}
Lev Walkine8bbe932017-09-12 23:06:52 -0700303
304asn_dec_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -0700305asn_decode(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkine8bbe932017-09-12 23:06:52 -0700306 enum asn_transfer_syntax syntax, struct asn_TYPE_descriptor_s *td,
307 void **sptr, const void *buffer, size_t size) {
308
Lev Walkina5972be2017-09-29 23:15:58 -0700309 if(!td || !td->op || !sptr || (size && !buffer)) {
Lev Walkine8bbe932017-09-12 23:06:52 -0700310 ASN__DECODE_FAILED;
311 }
312
313 switch(syntax) {
314 case ATS_CER:
315 case ATS_NONSTANDARD_PLAINTEXT:
316 default:
317 errno = ENOENT;
318 ASN__DECODE_FAILED;
319
Lev Walkina5972be2017-09-29 23:15:58 -0700320 case ATS_RANDOM:
321 if(!td->op->random_fill) {
322 ASN__DECODE_FAILED;
323 } else {
324 if(asn_random_fill(td, sptr, 16000) == 0) {
325 asn_dec_rval_t ret = {RC_OK, 0};
326 return ret;
327 } else {
328 ASN__DECODE_FAILED;
329 }
330 }
331 break;
332
Lev Walkine8bbe932017-09-12 23:06:52 -0700333 case ATS_DER:
334 case ATS_BER:
Lev Walkinafbf2a92017-09-12 23:30:27 -0700335 return ber_decode(opt_codec_ctx, td, sptr, buffer, size);
Lev Walkine8bbe932017-09-12 23:06:52 -0700336
337 case ATS_BASIC_OER:
338 case ATS_CANONICAL_OER:
339#ifdef ASN_DISABLE_OER_SUPPORT
340 errno = ENOENT;
341 ASN__DECODE_FAILED;
342#else
Lev Walkinafbf2a92017-09-12 23:30:27 -0700343 return oer_decode(opt_codec_ctx, td, sptr, buffer, size);
Lev Walkine8bbe932017-09-12 23:06:52 -0700344#endif
345
346 case ATS_UNALIGNED_BASIC_PER:
347 case ATS_UNALIGNED_CANONICAL_PER:
348#ifdef ASN_DISABLE_PER_SUPPORT
349 errno = ENOENT;
350 ASN__DECODE_FAILED;
351#else
Lev Walkinafbf2a92017-09-12 23:30:27 -0700352 return uper_decode_complete(opt_codec_ctx, td, sptr, buffer, size);
Lev Walkine8bbe932017-09-12 23:06:52 -0700353#endif
354
355 case ATS_BASIC_XER:
356 case ATS_CANONICAL_XER:
Lev Walkinafbf2a92017-09-12 23:30:27 -0700357 return xer_decode(opt_codec_ctx, td, sptr, buffer, size);
Lev Walkine8bbe932017-09-12 23:06:52 -0700358 }
359}
360