blob: b558d464599b87756dbf8fadcd7a463770e31cbe [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);
65 key->computed_size += size;
66 }
67
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
133 assert(er.encoded < 0 || (size_t)er.encoded == buf_key.computed_size);
134
135 return er;
136}
137
138static asn_enc_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -0700139asn_encode_internal(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin6d46bc32017-09-12 21:34:00 -0700140 enum asn_transfer_syntax syntax, asn_TYPE_descriptor_t *td,
141 void *sptr, asn_app_consume_bytes_f *callback,
142 void *callback_key) {
143 asn_enc_rval_t er;
144 enum xer_encoder_flags_e xer_flags = XER_F_CANONICAL;
145
Lev Walkinafbf2a92017-09-12 23:30:27 -0700146 (void)opt_codec_ctx; /* Parameters are not checked on encode yet. */
Lev Walkin6d46bc32017-09-12 21:34:00 -0700147
148 if(!td || !sptr) {
149 errno = EINVAL;
150 ASN__ENCODE_FAILED;
151 }
152
153 switch(syntax) {
Lev Walkina5972be2017-09-29 23:15:58 -0700154 case ATS_NONSTANDARD_PLAINTEXT:
155 if(td->op->print_struct) {
156 struct callback_count_bytes_key cb_key;
157 cb_key.callback = callback;
158 cb_key.callback_key = callback_key;
159 cb_key.computed_size = 0;
160 if(td->op->print_struct(td, sptr, 1, callback_count_bytes_cb,
161 &cb_key)
162 < 0
163 || callback_count_bytes_cb("\n", 1, &cb_key) < 0) {
164 errno = EBADF; /* Structure has incorrect form. */
165 er.encoded = -1;
166 er.failed_type = td;
167 er.structure_ptr = sptr;
168 } else {
169 er.encoded = cb_key.computed_size;
170 er.failed_type = 0;
171 er.structure_ptr = 0;
172 }
173 } else {
174 errno = ENOENT; /* Transfer syntax is not defined for this type. */
175 ASN__ENCODE_FAILED;
176 }
177 break;
178
179 case ATS_RANDOM:
180 errno = ENOENT; /* Randomization doesn't make sense on output. */
181 ASN__ENCODE_FAILED;
182
Lev Walkin6d46bc32017-09-12 21:34:00 -0700183 case ATS_BER:
184 /* BER is a superset of DER. */
185 /* Fall through. */
186 case ATS_DER:
187 if(td->op->der_encoder) {
188 er = der_encode(td, sptr, callback, callback_key);
189 if(er.encoded == -1) {
190 if(er.failed_type && er.failed_type->op->der_encoder) {
191 errno = EBADF; /* Structure has incorrect form. */
192 } else {
193 errno = ENOENT; /* DER is not defined for this type. */
194 }
195 }
196 } else {
197 errno = ENOENT; /* Transfer syntax is not defined for this type. */
198 ASN__ENCODE_FAILED;
199 }
200 break;
201 case ATS_CER:
202 errno = ENOENT; /* Transfer syntax is not defined for any type. */
203 ASN__ENCODE_FAILED;
204
205#ifdef ASN_DISABLE_OER_SUPPORT
206 case ATS_BASIC_OER:
207 case ATS_CANONICAL_OER:
208 errno = ENOENT; /* PER is not defined. */
209 ASN__ENCODE_FAILED;
210 break;
211#else /* ASN_DISABLE_OER_SUPPORT */
212 case ATS_BASIC_OER:
213 /* CANONICAL-OER is a superset of BASIC-OER. */
214 /* Fall through. */
215 case ATS_CANONICAL_OER:
216 if(td->op->oer_encoder) {
217 er = oer_encode(td, sptr, callback, callback_key);
218 if(er.encoded == -1) {
219 if(er.failed_type && er.failed_type->op->oer_encoder) {
220 errno = EBADF; /* Structure has incorrect form. */
221 } else {
222 errno = ENOENT; /* OER is not defined for this type. */
223 }
224 }
225 } else {
226 errno = ENOENT; /* Transfer syntax is not defined for this type. */
227 ASN__ENCODE_FAILED;
228 }
229 break;
230#endif /* ASN_DISABLE_OER_SUPPORT */
231
232#ifdef ASN_DISABLE_PER_SUPPORT
233 case ATS_UNALIGNED_BASIC_PER:
234 case ATS_UNALIGNED_CANONICAL_PER:
235 errno = ENOENT; /* PER is not defined. */
236 ASN__ENCODE_FAILED;
237 break;
238#else /* ASN_DISABLE_PER_SUPPORT */
239 case ATS_UNALIGNED_BASIC_PER:
240 /* CANONICAL-UPER is a superset of BASIC-UPER. */
241 /* Fall through. */
242 case ATS_UNALIGNED_CANONICAL_PER:
243 if(td->op->uper_encoder) {
244 er = uper_encode(td, sptr, callback, callback_key);
245 if(er.encoded == -1) {
246 if(er.failed_type && er.failed_type->op->uper_encoder) {
247 errno = EBADF; /* Structure has incorrect form. */
248 } else {
249 errno = ENOENT; /* UPER is not defined for this type. */
250 }
251 } else {
252 ASN_DEBUG("Complete encoded in %ld bits", (long)er.encoded);
253 if(er.encoded == 0) {
254 /* Enforce "Complete Encoding" of X.691 #11.1 */
255 if(callback("\0", 1, callback_key) < 0) {
256 errno = EBADF;
257 ASN__ENCODE_FAILED;
258 }
259 er.encoded = 8; /* Exactly 8 zero bits is added. */
260 }
261 /* Convert bits into bytes */
262 er.encoded = (er.encoded + 7) >> 3;
263 }
264 } else {
265 errno = ENOENT; /* Transfer syntax is not defined for this type. */
266 ASN__ENCODE_FAILED;
267 }
268 break;
269#endif /* ASN_DISABLE_PER_SUPPORT */
270
271 case ATS_BASIC_XER:
272 /* CANONICAL-XER is a superset of BASIC-XER. */
273 xer_flags &= ~XER_F_CANONICAL;
274 xer_flags |= XER_F_BASIC;
275 /* Fall through. */
276 case ATS_CANONICAL_XER:
277 if(td->op->xer_encoder) {
278 er = xer_encode(td, sptr, xer_flags, callback, callback_key);
279 if(er.encoded == -1) {
280 if(er.failed_type && er.failed_type->op->xer_encoder) {
281 errno = EBADF; /* Structure has incorrect form. */
282 } else {
283 errno = ENOENT; /* XER is not defined for this type. */
284 }
285 }
286 } else {
287 errno = ENOENT; /* Transfer syntax is not defined for this type. */
288 ASN__ENCODE_FAILED;
289 }
290 break;
291
Lev Walkin6d46bc32017-09-12 21:34:00 -0700292 default:
293 errno = ENOENT;
294 ASN__ENCODE_FAILED;
295 }
296
297 return er;
298}
Lev Walkine8bbe932017-09-12 23:06:52 -0700299
300asn_dec_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -0700301asn_decode(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkine8bbe932017-09-12 23:06:52 -0700302 enum asn_transfer_syntax syntax, struct asn_TYPE_descriptor_s *td,
303 void **sptr, const void *buffer, size_t size) {
304
Lev Walkina5972be2017-09-29 23:15:58 -0700305 if(!td || !td->op || !sptr || (size && !buffer)) {
Lev Walkine8bbe932017-09-12 23:06:52 -0700306 ASN__DECODE_FAILED;
307 }
308
309 switch(syntax) {
310 case ATS_CER:
311 case ATS_NONSTANDARD_PLAINTEXT:
312 default:
313 errno = ENOENT;
314 ASN__DECODE_FAILED;
315
Lev Walkina5972be2017-09-29 23:15:58 -0700316 case ATS_RANDOM:
317 if(!td->op->random_fill) {
318 ASN__DECODE_FAILED;
319 } else {
320 if(asn_random_fill(td, sptr, 16000) == 0) {
321 asn_dec_rval_t ret = {RC_OK, 0};
322 return ret;
323 } else {
324 ASN__DECODE_FAILED;
325 }
326 }
327 break;
328
Lev Walkine8bbe932017-09-12 23:06:52 -0700329 case ATS_DER:
330 case ATS_BER:
Lev Walkinafbf2a92017-09-12 23:30:27 -0700331 return ber_decode(opt_codec_ctx, td, sptr, buffer, size);
Lev Walkine8bbe932017-09-12 23:06:52 -0700332
333 case ATS_BASIC_OER:
334 case ATS_CANONICAL_OER:
335#ifdef ASN_DISABLE_OER_SUPPORT
336 errno = ENOENT;
337 ASN__DECODE_FAILED;
338#else
Lev Walkinafbf2a92017-09-12 23:30:27 -0700339 return oer_decode(opt_codec_ctx, td, sptr, buffer, size);
Lev Walkine8bbe932017-09-12 23:06:52 -0700340#endif
341
342 case ATS_UNALIGNED_BASIC_PER:
343 case ATS_UNALIGNED_CANONICAL_PER:
344#ifdef ASN_DISABLE_PER_SUPPORT
345 errno = ENOENT;
346 ASN__DECODE_FAILED;
347#else
Lev Walkinafbf2a92017-09-12 23:30:27 -0700348 return uper_decode_complete(opt_codec_ctx, td, sptr, buffer, size);
Lev Walkine8bbe932017-09-12 23:06:52 -0700349#endif
350
351 case ATS_BASIC_XER:
352 case ATS_CANONICAL_XER:
Lev Walkinafbf2a92017-09-12 23:30:27 -0700353 return xer_decode(opt_codec_ctx, td, sptr, buffer, size);
Lev Walkine8bbe932017-09-12 23:06:52 -0700354 }
355}
356