]> git.stg.codes - stg.git/blob - libs/smux/asn_application.c
Merge remote-tracking branch 'github/master'
[stg.git] / libs / smux / asn_application.c
1 /*
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
9 static 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);
15
16
17 struct 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  */
26 static int
27 callback_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
39 struct overrun_encoder_key {
40     void *buffer;
41     size_t buffer_size;
42     size_t computed_size;
43 };
44
45 struct dynamic_encoder_key {
46     void *buffer;
47     size_t buffer_size;
48     size_t computed_size;
49 };
50
51 struct 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  */
61 static int
62 overrun_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);
73     }
74     key->computed_size += size;
75
76     return 0;
77 }
78
79 /*
80  * Encoder which dynamically allocates output, and continues
81  * to count even if allocation failed.
82  */
83 static int
84 dynamic_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 /*
117  * Encoder which help convert the application level encoder failure into EIO.
118  */
119 static int
120 callback_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
132 asn_enc_rval_t
133 asn_encode(const asn_codec_ctx_t *opt_codec_ctx,
134            enum asn_transfer_syntax syntax, const asn_TYPE_descriptor_t *td,
135            const void *sptr, asn_app_consume_bytes_f *callback, void *callback_key) {
136     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
148     er = asn_encode_internal(opt_codec_ctx, syntax, td, sptr,
149                              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
159 asn_enc_rval_t
160 asn_encode_to_buffer(const asn_codec_ctx_t *opt_codec_ctx,
161                      enum asn_transfer_syntax syntax,
162                      const asn_TYPE_descriptor_t *td, const void *sptr,
163                      void *buffer, size_t buffer_size) {
164     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
176     er = asn_encode_internal(opt_codec_ctx, syntax, td, sptr,
177                              overrun_encoder_cb, &buf_key);
178
179     if(er.encoded >= 0 && (size_t)er.encoded != buf_key.computed_size) {
180         ASN_DEBUG("asn_encode() returned %" ASN_PRI_SSIZE
181                   " yet produced %" ASN_PRI_SIZE " bytes",
182                   er.encoded, buf_key.computed_size);
183         assert(er.encoded < 0 || (size_t)er.encoded == buf_key.computed_size);
184     }
185
186     return er;
187 }
188
189 asn_encode_to_new_buffer_result_t
190 asn_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",
207                   res.result.encoded, buf_key.computed_size);
208         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
223 static asn_enc_rval_t
224 asn_encode_internal(const asn_codec_ctx_t *opt_codec_ctx,
225                     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) {
228     asn_enc_rval_t er;
229     enum xer_encoder_flags_e xer_flags = XER_F_CANONICAL;
230
231     (void)opt_codec_ctx; /* Parameters are not checked on encode yet. */
232
233     if(!td || !sptr) {
234         errno = EINVAL;
235         ASN__ENCODE_FAILED;
236     }
237
238     switch(syntax) {
239     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
268     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) {
329             er = uper_encode(td, 0, sptr, callback, callback_key);
330             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
377     default:
378         errno = ENOENT;
379         ASN__ENCODE_FAILED;
380     }
381
382     return er;
383 }
384
385 asn_dec_rval_t
386 asn_decode(const asn_codec_ctx_t *opt_codec_ctx,
387            enum asn_transfer_syntax syntax, const asn_TYPE_descriptor_t *td,
388            void **sptr, const void *buffer, size_t size) {
389     if(!td || !td->op || !sptr || (size && !buffer)) {
390         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
400     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
413     case ATS_DER:
414     case ATS_BER:
415         return ber_decode(opt_codec_ctx, td, sptr, buffer, size);
416
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
423         return oer_decode(opt_codec_ctx, td, sptr, buffer, size);
424 #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
432         return uper_decode_complete(opt_codec_ctx, td, sptr, buffer, size);
433 #endif
434
435     case ATS_BASIC_XER:
436     case ATS_CANONICAL_XER:
437         return xer_decode(opt_codec_ctx, td, sptr, buffer, size);
438     }
439 }
440