blob: 5b2520761d9052e620aaf31a5949d6d33c338933 [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
45struct callback_failure_catch_key {
46 asn_app_consume_bytes_f *callback;
47 void *callback_key;
48 int callback_failed;
49};
50
51/*
52 * Encoder which doesn't stop counting bytes
53 * even if it reaches the end of the buffer.
54 */
55static int
56overrun_encoder_cb(const void *data, size_t size, void *keyp) {
57 struct overrun_encoder_key *key = keyp;
58
59 if(key->computed_size + size > key->buffer_size) {
60 /*
61 * Avoid accident on the next call:
62 * stop adding bytes to the buffer.
63 */
64 key->buffer_size = 0;
65 } else {
66 memcpy((char *)key->buffer + key->computed_size, data, size);
Lev Walkin6d46bc32017-09-12 21:34:00 -070067 }
Lev Walkina5b02882017-10-01 22:48:44 -070068 key->computed_size += size;
Lev Walkin6d46bc32017-09-12 21:34:00 -070069
70 return 0;
71}
72
73/*
74 * Encoder which help convert the application level encoder failure into EIO.
75 */
76static int
77callback_failure_catch_cb(const void *data, size_t size, void *keyp) {
78 struct callback_failure_catch_key *key = keyp;
79 int ret;
80
81 ret = key->callback(data, size, key->callback_key);
82 if(ret < 0) {
83 key->callback_failed = 1;
84 }
85
86 return ret;
87}
88
89asn_enc_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -070090asn_encode(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin6d46bc32017-09-12 21:34:00 -070091 enum asn_transfer_syntax syntax, asn_TYPE_descriptor_t *td,
92 void *sptr, asn_app_consume_bytes_f *callback, void *callback_key) {
93 struct callback_failure_catch_key cb_key;
94 asn_enc_rval_t er;
95
96 if(!callback) {
97 errno = EINVAL;
98 ASN__ENCODE_FAILED;
99 }
100
101 cb_key.callback = callback;
102 cb_key.callback_key = callback_key;
103 cb_key.callback_failed = 0;
104
Lev Walkinafbf2a92017-09-12 23:30:27 -0700105 er = asn_encode_internal(opt_codec_ctx, syntax, td, sptr,
Lev Walkin6d46bc32017-09-12 21:34:00 -0700106 callback_failure_catch_cb, &cb_key);
107 if(cb_key.callback_failed) {
108 assert(er.encoded == -1);
109 assert(errno == EBADF);
110 errno = EIO;
111 }
112
113 return er;
114}
115
116asn_enc_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -0700117asn_encode_to_buffer(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin20696a42017-10-17 21:27:33 -0700118 enum asn_transfer_syntax syntax,
119 const asn_TYPE_descriptor_t *td, const void *sptr,
120 void *buffer, size_t buffer_size) {
Lev Walkin6d46bc32017-09-12 21:34:00 -0700121 struct overrun_encoder_key buf_key;
122 asn_enc_rval_t er;
123
124 if(buffer_size > 0 && !buffer) {
125 errno = EINVAL;
126 ASN__ENCODE_FAILED;
127 }
128
129 buf_key.buffer = buffer;
130 buf_key.buffer_size = buffer_size;
131 buf_key.computed_size = 0;
132
Lev Walkinafbf2a92017-09-12 23:30:27 -0700133 er = asn_encode_internal(opt_codec_ctx, syntax, td, sptr,
Lev Walkin6d46bc32017-09-12 21:34:00 -0700134 overrun_encoder_cb, &buf_key);
135
Lev Walkina5b02882017-10-01 22:48:44 -0700136 if(er.encoded >= 0 && (size_t)er.encoded != buf_key.computed_size) {
Lev Walkinaa5838c2017-10-03 17:13:33 -0700137 ASN_DEBUG("asn_encode() returned %zd yet produced %zu bytes",
Lev Walkina5b02882017-10-01 22:48:44 -0700138 er.encoded, buf_key.computed_size);
Lev Walkinaa5838c2017-10-03 17:13:33 -0700139 assert(er.encoded < 0 || (size_t)er.encoded == buf_key.computed_size);
Lev Walkina5b02882017-10-01 22:48:44 -0700140 }
Lev Walkin6d46bc32017-09-12 21:34:00 -0700141
142 return er;
143}
144
145static asn_enc_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -0700146asn_encode_internal(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin20696a42017-10-17 21:27:33 -0700147 enum asn_transfer_syntax syntax,
148 const asn_TYPE_descriptor_t *td, const void *sptr,
149 asn_app_consume_bytes_f *callback, void *callback_key) {
Lev Walkin6d46bc32017-09-12 21:34:00 -0700150 asn_enc_rval_t er;
151 enum xer_encoder_flags_e xer_flags = XER_F_CANONICAL;
152
Lev Walkinafbf2a92017-09-12 23:30:27 -0700153 (void)opt_codec_ctx; /* Parameters are not checked on encode yet. */
Lev Walkin6d46bc32017-09-12 21:34:00 -0700154
155 if(!td || !sptr) {
156 errno = EINVAL;
157 ASN__ENCODE_FAILED;
158 }
159
160 switch(syntax) {
Lev Walkina5972be2017-09-29 23:15:58 -0700161 case ATS_NONSTANDARD_PLAINTEXT:
162 if(td->op->print_struct) {
163 struct callback_count_bytes_key cb_key;
164 cb_key.callback = callback;
165 cb_key.callback_key = callback_key;
166 cb_key.computed_size = 0;
167 if(td->op->print_struct(td, sptr, 1, callback_count_bytes_cb,
168 &cb_key)
169 < 0
170 || callback_count_bytes_cb("\n", 1, &cb_key) < 0) {
171 errno = EBADF; /* Structure has incorrect form. */
172 er.encoded = -1;
173 er.failed_type = td;
174 er.structure_ptr = sptr;
175 } else {
176 er.encoded = cb_key.computed_size;
177 er.failed_type = 0;
178 er.structure_ptr = 0;
179 }
180 } else {
181 errno = ENOENT; /* Transfer syntax is not defined for this type. */
182 ASN__ENCODE_FAILED;
183 }
184 break;
185
186 case ATS_RANDOM:
187 errno = ENOENT; /* Randomization doesn't make sense on output. */
188 ASN__ENCODE_FAILED;
189
Lev Walkin6d46bc32017-09-12 21:34:00 -0700190 case ATS_BER:
191 /* BER is a superset of DER. */
192 /* Fall through. */
193 case ATS_DER:
194 if(td->op->der_encoder) {
195 er = der_encode(td, sptr, callback, callback_key);
196 if(er.encoded == -1) {
197 if(er.failed_type && er.failed_type->op->der_encoder) {
198 errno = EBADF; /* Structure has incorrect form. */
199 } else {
200 errno = ENOENT; /* DER is not defined for this type. */
201 }
202 }
203 } else {
204 errno = ENOENT; /* Transfer syntax is not defined for this type. */
205 ASN__ENCODE_FAILED;
206 }
207 break;
208 case ATS_CER:
209 errno = ENOENT; /* Transfer syntax is not defined for any type. */
210 ASN__ENCODE_FAILED;
211
212#ifdef ASN_DISABLE_OER_SUPPORT
213 case ATS_BASIC_OER:
214 case ATS_CANONICAL_OER:
215 errno = ENOENT; /* PER is not defined. */
216 ASN__ENCODE_FAILED;
217 break;
218#else /* ASN_DISABLE_OER_SUPPORT */
219 case ATS_BASIC_OER:
220 /* CANONICAL-OER is a superset of BASIC-OER. */
221 /* Fall through. */
222 case ATS_CANONICAL_OER:
223 if(td->op->oer_encoder) {
224 er = oer_encode(td, sptr, callback, callback_key);
225 if(er.encoded == -1) {
226 if(er.failed_type && er.failed_type->op->oer_encoder) {
227 errno = EBADF; /* Structure has incorrect form. */
228 } else {
229 errno = ENOENT; /* OER is not defined for this type. */
230 }
231 }
232 } else {
233 errno = ENOENT; /* Transfer syntax is not defined for this type. */
234 ASN__ENCODE_FAILED;
235 }
236 break;
237#endif /* ASN_DISABLE_OER_SUPPORT */
238
239#ifdef ASN_DISABLE_PER_SUPPORT
240 case ATS_UNALIGNED_BASIC_PER:
241 case ATS_UNALIGNED_CANONICAL_PER:
242 errno = ENOENT; /* PER is not defined. */
243 ASN__ENCODE_FAILED;
244 break;
245#else /* ASN_DISABLE_PER_SUPPORT */
246 case ATS_UNALIGNED_BASIC_PER:
247 /* CANONICAL-UPER is a superset of BASIC-UPER. */
248 /* Fall through. */
249 case ATS_UNALIGNED_CANONICAL_PER:
250 if(td->op->uper_encoder) {
251 er = uper_encode(td, sptr, callback, callback_key);
252 if(er.encoded == -1) {
253 if(er.failed_type && er.failed_type->op->uper_encoder) {
254 errno = EBADF; /* Structure has incorrect form. */
255 } else {
256 errno = ENOENT; /* UPER is not defined for this type. */
257 }
258 } else {
259 ASN_DEBUG("Complete encoded in %ld bits", (long)er.encoded);
260 if(er.encoded == 0) {
261 /* Enforce "Complete Encoding" of X.691 #11.1 */
262 if(callback("\0", 1, callback_key) < 0) {
263 errno = EBADF;
264 ASN__ENCODE_FAILED;
265 }
266 er.encoded = 8; /* Exactly 8 zero bits is added. */
267 }
268 /* Convert bits into bytes */
269 er.encoded = (er.encoded + 7) >> 3;
270 }
271 } else {
272 errno = ENOENT; /* Transfer syntax is not defined for this type. */
273 ASN__ENCODE_FAILED;
274 }
275 break;
276#endif /* ASN_DISABLE_PER_SUPPORT */
277
278 case ATS_BASIC_XER:
279 /* CANONICAL-XER is a superset of BASIC-XER. */
280 xer_flags &= ~XER_F_CANONICAL;
281 xer_flags |= XER_F_BASIC;
282 /* Fall through. */
283 case ATS_CANONICAL_XER:
284 if(td->op->xer_encoder) {
285 er = xer_encode(td, sptr, xer_flags, callback, callback_key);
286 if(er.encoded == -1) {
287 if(er.failed_type && er.failed_type->op->xer_encoder) {
288 errno = EBADF; /* Structure has incorrect form. */
289 } else {
290 errno = ENOENT; /* XER is not defined for this type. */
291 }
292 }
293 } else {
294 errno = ENOENT; /* Transfer syntax is not defined for this type. */
295 ASN__ENCODE_FAILED;
296 }
297 break;
298
Lev Walkin6d46bc32017-09-12 21:34:00 -0700299 default:
300 errno = ENOENT;
301 ASN__ENCODE_FAILED;
302 }
303
304 return er;
305}
Lev Walkine8bbe932017-09-12 23:06:52 -0700306
307asn_dec_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -0700308asn_decode(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin20696a42017-10-17 21:27:33 -0700309 enum asn_transfer_syntax syntax, const asn_TYPE_descriptor_t *td,
Lev Walkine8bbe932017-09-12 23:06:52 -0700310 void **sptr, const void *buffer, size_t size) {
Lev Walkina5972be2017-09-29 23:15:58 -0700311 if(!td || !td->op || !sptr || (size && !buffer)) {
Lev Walkine8bbe932017-09-12 23:06:52 -0700312 ASN__DECODE_FAILED;
313 }
314
315 switch(syntax) {
316 case ATS_CER:
317 case ATS_NONSTANDARD_PLAINTEXT:
318 default:
319 errno = ENOENT;
320 ASN__DECODE_FAILED;
321
Lev Walkina5972be2017-09-29 23:15:58 -0700322 case ATS_RANDOM:
323 if(!td->op->random_fill) {
324 ASN__DECODE_FAILED;
325 } else {
326 if(asn_random_fill(td, sptr, 16000) == 0) {
327 asn_dec_rval_t ret = {RC_OK, 0};
328 return ret;
329 } else {
330 ASN__DECODE_FAILED;
331 }
332 }
333 break;
334
Lev Walkine8bbe932017-09-12 23:06:52 -0700335 case ATS_DER:
336 case ATS_BER:
Lev Walkinafbf2a92017-09-12 23:30:27 -0700337 return ber_decode(opt_codec_ctx, td, sptr, buffer, size);
Lev Walkine8bbe932017-09-12 23:06:52 -0700338
339 case ATS_BASIC_OER:
340 case ATS_CANONICAL_OER:
341#ifdef ASN_DISABLE_OER_SUPPORT
342 errno = ENOENT;
343 ASN__DECODE_FAILED;
344#else
Lev Walkinafbf2a92017-09-12 23:30:27 -0700345 return oer_decode(opt_codec_ctx, td, sptr, buffer, size);
Lev Walkine8bbe932017-09-12 23:06:52 -0700346#endif
347
348 case ATS_UNALIGNED_BASIC_PER:
349 case ATS_UNALIGNED_CANONICAL_PER:
350#ifdef ASN_DISABLE_PER_SUPPORT
351 errno = ENOENT;
352 ASN__DECODE_FAILED;
353#else
Lev Walkinafbf2a92017-09-12 23:30:27 -0700354 return uper_decode_complete(opt_codec_ctx, td, sptr, buffer, size);
Lev Walkine8bbe932017-09-12 23:06:52 -0700355#endif
356
357 case ATS_BASIC_XER:
358 case ATS_CANONICAL_XER:
Lev Walkinafbf2a92017-09-12 23:30:27 -0700359 return xer_decode(opt_codec_ctx, td, sptr, buffer, size);
Lev Walkine8bbe932017-09-12 23:06:52 -0700360 }
361}
362