Moving in e2sim originally from it/test/simulators
[sim/e2-interface.git] / e2sim / ASN1c / ber_tlv_length.c
1 /*****************************************************************************
2 #                                                                            *
3 # Copyright 2019 AT&T Intellectual Property                                  *
4 #                                                                            *
5 # Licensed under the Apache License, Version 2.0 (the "License");            *
6 # you may not use this file except in compliance with the License.           *
7 # You may obtain a copy of the License at                                    *
8 #                                                                            *
9 #      http://www.apache.org/licenses/LICENSE-2.0                            *
10 #                                                                            *
11 # Unless required by applicable law or agreed to in writing, software        *
12 # distributed under the License is distributed on an "AS IS" BASIS,          *
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
14 # See the License for the specific language governing permissions and        *
15 # limitations under the License.                                             *
16 #                                                                            *
17 ******************************************************************************/
18
19 /*-
20  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
21  * Redistribution and modifications are permitted subject to BSD license.
22  */
23 #include <asn_internal.h>
24 #include <ber_tlv_length.h>
25 #include <ber_tlv_tag.h>
26
27 ssize_t
28 ber_fetch_length(int _is_constructed, const void *bufptr, size_t size,
29                 ber_tlv_len_t *len_r) {
30         const uint8_t *buf = (const uint8_t *)bufptr;
31         unsigned oct;
32
33         if(size == 0)
34                 return 0;       /* Want more */
35
36         oct = *(const uint8_t *)buf;
37         if((oct & 0x80) == 0) {
38                 /*
39                  * Short definite length.
40                  */
41                 *len_r = oct;   /* & 0x7F */
42                 return 1;
43         } else {
44                 ber_tlv_len_t len;
45                 size_t skipped;
46
47                 if(_is_constructed && oct == 0x80) {
48                         *len_r = -1;    /* Indefinite length */
49                         return 1;
50                 }
51
52                 if(oct == 0xff) {
53                         /* Reserved in standard for future use. */
54                         return -1;
55                 }
56
57                 oct &= 0x7F;    /* Leave only the 7 LS bits */
58                 for(len = 0, buf++, skipped = 1;
59                         oct && (++skipped <= size); buf++, oct--) {
60
61                         /* Verify that we won't overflow. */
62                         if(!(len >> ((8 * sizeof(len)) - (8+1)))) {
63                                 len = (len << 8) | *buf;
64                         } else {
65                                 /* Too large length value. */
66                                 return -1;
67                         }
68                 }
69
70                 if(oct == 0) {
71                         if(len < 0 || len > RSSIZE_MAX) {
72                                 /* Length value out of sane range. */
73                                 return -1;
74                         }
75
76                         *len_r = len;
77                         return skipped;
78                 }
79
80                 return 0;       /* Want more */
81         }
82
83 }
84
85 ssize_t
86 ber_skip_length(const asn_codec_ctx_t *opt_codec_ctx,
87                 int _is_constructed, const void *ptr, size_t size) {
88         ber_tlv_len_t vlen;     /* Length of V in TLV */
89         ssize_t tl;             /* Length of L in TLV */
90         ssize_t ll;             /* Length of L in TLV */
91         size_t skip;
92
93         /*
94          * Make sure we didn't exceed the maximum stack size.
95          */
96         if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx))
97                 return -1;
98
99         /*
100          * Determine the size of L in TLV.
101          */
102         ll = ber_fetch_length(_is_constructed, ptr, size, &vlen);
103         if(ll <= 0) return ll;
104
105         /*
106          * Definite length.
107          */
108         if(vlen >= 0) {
109                 skip = ll + vlen;
110                 if(skip > size)
111                         return 0;       /* Want more */
112                 return skip;
113         }
114
115         /*
116          * Indefinite length!
117          */
118         ASN_DEBUG("Skipping indefinite length");
119         for(skip = ll, ptr = ((const char *)ptr) + ll, size -= ll;;) {
120                 ber_tlv_tag_t tag;
121
122                 /* Fetch the tag */
123                 tl = ber_fetch_tag(ptr, size, &tag);
124                 if(tl <= 0) return tl;
125
126                 ll = ber_skip_length(opt_codec_ctx,
127                         BER_TLV_CONSTRUCTED(ptr),
128                         ((const char *)ptr) + tl, size - tl);
129                 if(ll <= 0) return ll;
130
131                 skip += tl + ll;
132
133                 /*
134                  * This may be the end of the indefinite length structure,
135                  * two consecutive 0 octets.
136                  * Check if it is true.
137                  */
138                 if(((const uint8_t *)ptr)[0] == 0
139                 && ((const uint8_t *)ptr)[1] == 0)
140                         return skip;
141
142                 ptr = ((const char *)ptr) + tl + ll;
143                 size -= tl + ll;
144         }
145
146         /* UNREACHABLE */
147 }
148
149 size_t
150 der_tlv_length_serialize(ber_tlv_len_t len, void *bufp, size_t size) {
151         size_t required_size;   /* Size of len encoding */
152         uint8_t *buf = (uint8_t *)bufp;
153         uint8_t *end;
154         int i;
155
156         if(len <= 127) {
157                 /* Encoded in 1 octet */
158                 if(size) *buf = (uint8_t)len;
159                 return 1;
160         }
161
162         /*
163          * Compute the size of the subsequent bytes.
164          */
165         for(required_size = 1, i = 8; i < 8 * (int)sizeof(len); i += 8) {
166                 if(len >> i)
167                         required_size++;
168                 else
169                         break;
170         }
171
172         if(size <= required_size)
173                 return required_size + 1;
174
175         *buf++ = (uint8_t)(0x80 | required_size);  /* Length of the encoding */
176
177         /*
178          * Produce the len encoding, space permitting.
179          */
180         end = buf + required_size;
181         for(i -= 8; buf < end; i -= 8, buf++)
182                 *buf = (uint8_t)(len >> i);
183
184         return required_size + 1;
185 }
186