blob: b18e27f4a93ea2db87f61ac0169183720d4abb6e [file] [log] [blame]
Lev Walkincfc16d32017-08-30 19:15:08 -07001/*
2 * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
3 * All rights reserved.
4 * Redistribution and modifications are permitted subject to BSD license.
5 */
6#ifndef ASN_DISABLE_OER_SUPPORT
7
8#include <asn_internal.h>
9#include <BIT_STRING.h>
10#include <errno.h>
11
12asn_dec_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -070013BIT_STRING_decode_oer(const asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
Lev Walkincfc16d32017-08-30 19:15:08 -070014 const asn_oer_constraints_t *constraints, void **sptr,
15 const void *ptr, size_t size) {
16 BIT_STRING_t *st = (BIT_STRING_t *)*sptr;
17 const asn_oer_constraints_t *cts =
Lev Walkina5972be2017-09-29 23:15:58 -070018 constraints ? constraints : td->encoding_constraints.oer_constraints;
Lev Walkincfc16d32017-08-30 19:15:08 -070019 ssize_t ct_size = cts ? cts->size : -1;
20 asn_dec_rval_t rval = {RC_OK, 0};
21 size_t expected_length = 0;
22
23 (void)opt_codec_ctx;
24
25 if(!st) {
26 st = (BIT_STRING_t *)(*sptr = CALLOC(1, sizeof(*st)));
27 if(!st) ASN__DECODE_FAILED;
28 }
29
30 if(ct_size >= 0) {
31 expected_length = (ct_size + 7) >> 3;
32 st->bits_unused = (8 - (ct_size & 7)) & 7;
33 } else {
34 /*
35 * X.696 (08/2015) #13.3.1
36 * Encode length determinant as _number of octets_, but only
37 * if upper bound is not equal to lower bound.
38 */
39 ssize_t len_len = oer_fetch_length(ptr, size, &expected_length);
40 if(len_len > 0) {
41 ptr = (const char *)ptr + len_len;
42 size -= len_len;
43 } else if(len_len == 0) {
44 ASN__DECODE_STARVED;
45 } else if(len_len < 0) {
46 ASN__DECODE_FAILED;
47 }
48
49 if(expected_length < 1) {
Lev Walkina5b02882017-10-01 22:48:44 -070050 ASN__DECODE_FAILED;
51 } else if(expected_length > size) {
Lev Walkincfc16d32017-08-30 19:15:08 -070052 ASN__DECODE_STARVED;
53 }
54
55 st->bits_unused = ((const uint8_t *)ptr)[0];
56 if(st->bits_unused & ~7) {
57 ASN_DEBUG("%s: unused bits outside of 0..7 range", td->name);
58 ASN__DECODE_FAILED;
59 }
60 ptr = (const char *)ptr + 1;
61 size--;
62 expected_length--;
63 rval.consumed = len_len + 1;
64 }
65
66 if(size < expected_length) {
67 ASN__DECODE_STARVED;
68 } else {
69 uint8_t *buf = MALLOC(expected_length + 1);
70 if(buf == NULL) {
71 ASN__DECODE_FAILED;
72 } else {
73 memcpy(buf, ptr, expected_length);
74 buf[expected_length] = '\0';
75 }
76 FREEMEM(st->buf);
77 st->buf = buf;
78 st->size = expected_length;
79 if(expected_length > 0) {
80 buf[expected_length - 1] &= (0xff << st->bits_unused);
81 }
82
83 rval.consumed += expected_length;
84 return rval;
85 }
86}
87
88/*
89 * Encode as Canonical OER.
90 */
91asn_enc_rval_t
92BIT_STRING_encode_oer(asn_TYPE_descriptor_t *td,
93 const asn_oer_constraints_t *constraints, void *sptr,
94 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkinfc89b9d2017-08-31 00:54:38 -070095 BIT_STRING_t *st = (BIT_STRING_t *)sptr;
96 asn_enc_rval_t erval = {0, 0, 0};
97 const asn_oer_constraints_t *cts =
Lev Walkina5972be2017-09-29 23:15:58 -070098 constraints ? constraints : td->encoding_constraints.oer_constraints;
Lev Walkinfc89b9d2017-08-31 00:54:38 -070099 ssize_t ct_size = cts ? cts->size : -1;
Lev Walkinfc89b9d2017-08-31 00:54:38 -0700100 size_t trailing_zeros = 0;
101 int fix_last_byte = 0;
102
103 if(!st) ASN__ENCODE_FAILED;
104
105 if(st->bits_unused & ~7) {
106 ASN_DEBUG("BIT STRING unused bits %d out of 0..7 range",
107 st->bits_unused);
108 ASN__ENCODE_FAILED;
109 }
110 if(st->bits_unused && !(st->size && st->buf)) {
111 ASN_DEBUG("BIT STRING %s size 0 can't support unused bits %d", td->name,
112 st->bits_unused);
113 ASN__ENCODE_FAILED;
114 }
115
116 if(ct_size >= 0) {
117 size_t ct_bytes = (ct_size + 7) >> 3;
118 if(st->size > ct_bytes) {
119 ASN_DEBUG("More bits in BIT STRING %s (%zd) than constrained %zd",
120 td->name, 8 * st->size - st->bits_unused, ct_size);
121 ASN__ENCODE_FAILED;
122 }
123 trailing_zeros = ct_bytes - st->size; /* Allow larger constraint */
124 } else {
125 uint8_t ub = st->bits_unused & 7;
Lev Walkin71191ba2017-08-31 01:00:00 -0700126 ssize_t len_len = oer_serialize_length(1 + st->size, cb, app_key);
Lev Walkinfc89b9d2017-08-31 00:54:38 -0700127 if(len_len < 0) ASN__ENCODE_FAILED;
128 if(cb(&ub, 1, app_key) < 0) {
129 ASN__ENCODE_FAILED;
130 }
131 erval.encoded += len_len + 1;
132 }
133
134 if(st->bits_unused) {
135 if(st->buf[st->size - 1] & (0xff << st->bits_unused)) {
136 fix_last_byte = 1;
137 }
138 }
139
140 if(cb(st->buf, st->size - fix_last_byte, app_key) < 0) {
141 ASN__ENCODE_FAILED;
142 }
143
144 if(fix_last_byte) {
145 uint8_t b = st->buf[st->size - 1] & (0xff << st->bits_unused);
146 if(cb(&b, 1, app_key) < 0) {
147 ASN__ENCODE_FAILED;
148 }
149 }
150
151 erval.encoded += st->size;
152
153 if(trailing_zeros) {
154 static uint8_t zeros[16];
155 while(trailing_zeros > 0) {
156 int ret;
157 if(trailing_zeros < sizeof(zeros)) {
158 ret = cb(zeros, trailing_zeros, app_key);
159 erval.encoded += trailing_zeros;
160 } else {
161 ret = cb(zeros, sizeof(zeros), app_key);
162 erval.encoded += sizeof(zeros);
163 }
164 if(ret < 0) ASN__ENCODE_FAILED;
165 }
166 }
167
168 return erval;
Lev Walkincfc16d32017-08-30 19:15:08 -0700169}
170
171
172#endif /* ASN_DISABLE_OER_SUPPORT */