/src/open5gs/lib/asn1c/common/OCTET_STRING.c
Line | Count | Source |
1 | | /*- |
2 | | * Copyright (c) 2003-2017 Lev Walkin <vlm@lionet.info>. |
3 | | * All rights reserved. |
4 | | * Redistribution and modifications are permitted subject to BSD license. |
5 | | */ |
6 | | #include <asn_internal.h> |
7 | | #include <OCTET_STRING.h> |
8 | | #include <errno.h> |
9 | | |
10 | | /* |
11 | | * OCTET STRING basic type description. |
12 | | */ |
13 | | static const ber_tlv_tag_t asn_DEF_OCTET_STRING_tags[] = { |
14 | | (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) |
15 | | }; |
16 | | asn_OCTET_STRING_specifics_t asn_SPC_OCTET_STRING_specs = { |
17 | | sizeof(OCTET_STRING_t), |
18 | | offsetof(OCTET_STRING_t, _asn_ctx), |
19 | | ASN_OSUBV_STR |
20 | | }; |
21 | | asn_TYPE_operation_t asn_OP_OCTET_STRING = { |
22 | | .kind = ASN_KIND_PRIMITIVE, |
23 | | OCTET_STRING_free, |
24 | | #if !defined(ASN_DISABLE_PRINT_SUPPORT) |
25 | | OCTET_STRING_print, /* OCTET STRING generally means a non-ascii sequence */ |
26 | | #else |
27 | | 0, |
28 | | #endif /* !defined(ASN_DISABLE_PRINT_SUPPORT) */ |
29 | | OCTET_STRING_compare, |
30 | | OCTET_STRING_copy, |
31 | | #if !defined(ASN_DISABLE_BER_SUPPORT) |
32 | | OCTET_STRING_decode_ber, |
33 | | OCTET_STRING_encode_der, |
34 | | #else |
35 | | 0, |
36 | | 0, |
37 | | #endif /* !defined(ASN_DISABLE_BER_SUPPORT) */ |
38 | | #if !defined(ASN_DISABLE_XER_SUPPORT) |
39 | | OCTET_STRING_decode_xer_auto, /* Auto-detect hex or Base64 format for decoding */ |
40 | | OCTET_STRING_encode_xer_base64, /* Per X.693, Base64 is the default encoding for OCTET STRING */ |
41 | | #else |
42 | | 0, |
43 | | 0, |
44 | | #endif /* !defined(ASN_DISABLE_XER_SUPPORT) */ |
45 | | #if !defined(ASN_DISABLE_JER_SUPPORT) |
46 | | OCTET_STRING_decode_jer_hex, |
47 | | OCTET_STRING_encode_jer, |
48 | | #else |
49 | | 0, |
50 | | 0, |
51 | | #endif /* !defined(ASN_DISABLE_JER_SUPPORT) */ |
52 | | #if !defined(ASN_DISABLE_OER_SUPPORT) |
53 | | OCTET_STRING_decode_oer, |
54 | | OCTET_STRING_encode_oer, |
55 | | #else |
56 | | 0, |
57 | | 0, |
58 | | #endif /* !defined(ASN_DISABLE_OER_SUPPORT) */ |
59 | | #if !defined(ASN_DISABLE_UPER_SUPPORT) |
60 | | OCTET_STRING_decode_uper, /* Unaligned PER decoder */ |
61 | | OCTET_STRING_encode_uper, /* Unaligned PER encoder */ |
62 | | #else |
63 | | 0, |
64 | | 0, |
65 | | #endif /* !defined(ASN_DISABLE_UPER_SUPPORT) */ |
66 | | #if !defined(ASN_DISABLE_APER_SUPPORT) |
67 | | OCTET_STRING_decode_aper, /* Aligned PER decoder */ |
68 | | OCTET_STRING_encode_aper, /* Aligned PER encoder */ |
69 | | #else |
70 | | 0, |
71 | | 0, |
72 | | #endif /* !defined(ASN_DISABLE_APER_SUPPORT) */ |
73 | | #if !defined(ASN_DISABLE_RFILL_SUPPORT) |
74 | | OCTET_STRING_random_fill, |
75 | | #else |
76 | | 0, |
77 | | #endif /* !defined(ASN_DISABLE_RFILL_SUPPORT) */ |
78 | | 0 /* Use generic outmost tag fetcher */, |
79 | | #if !defined(ASN_DISABLE_CBOR_SUPPORT) |
80 | | OCTET_STRING_decode_cbor, |
81 | | OCTET_STRING_encode_cbor, |
82 | | #else |
83 | | 0, |
84 | | 0, |
85 | | #endif /* !defined(ASN_DISABLE_CBOR_SUPPORT) */ |
86 | | }; |
87 | | asn_TYPE_descriptor_t asn_DEF_OCTET_STRING = { |
88 | | "OCTET STRING", /* Canonical name */ |
89 | | "OCTET_STRING", /* XML tag name */ |
90 | | &asn_OP_OCTET_STRING, |
91 | | asn_DEF_OCTET_STRING_tags, |
92 | | sizeof(asn_DEF_OCTET_STRING_tags) |
93 | | / sizeof(asn_DEF_OCTET_STRING_tags[0]), |
94 | | asn_DEF_OCTET_STRING_tags, /* Same as above */ |
95 | | sizeof(asn_DEF_OCTET_STRING_tags) |
96 | | / sizeof(asn_DEF_OCTET_STRING_tags[0]), |
97 | | { |
98 | | #if !defined(ASN_DISABLE_OER_SUPPORT) |
99 | | 0, |
100 | | #endif /* !defined(ASN_DISABLE_OER_SUPPORT) */ |
101 | | #if !defined(ASN_DISABLE_UPER_SUPPORT) || !defined(ASN_DISABLE_APER_SUPPORT) |
102 | | 0, |
103 | | #endif /* !defined(ASN_DISABLE_UPER_SUPPORT) || !defined(ASN_DISABLE_APER_SUPPORT) */ |
104 | | #if !defined(ASN_DISABLE_JER_SUPPORT) |
105 | | 0, |
106 | | #endif /* !defined(ASN_DISABLE_JER_SUPPORT) */ |
107 | | asn_generic_no_constraint |
108 | | }, |
109 | | 0, 0, /* No members */ |
110 | | &asn_SPC_OCTET_STRING_specs |
111 | | }; |
112 | | |
113 | | void |
114 | | OCTET_STRING_free(const asn_TYPE_descriptor_t *td, void *sptr, |
115 | 18.2k | enum asn_struct_free_method method) { |
116 | 18.2k | OCTET_STRING_t *st = (OCTET_STRING_t *)sptr; |
117 | | |
118 | 18.2k | if(!td || !st) |
119 | 0 | return; |
120 | | |
121 | 18.2k | ASN_DEBUG("Freeing %s as OCTET STRING", td->name); |
122 | | |
123 | 18.2k | if(st->buf) { |
124 | 17.9k | FREEMEM(st->buf); |
125 | 17.9k | st->buf = 0; |
126 | 17.9k | } |
127 | | |
128 | | #if !defined(ASN_DISABLE_BER_SUPPORT) |
129 | | const asn_OCTET_STRING_specifics_t *specs; |
130 | | asn_struct_ctx_t *ctx; |
131 | | |
132 | | specs = td->specifics |
133 | | ? (const asn_OCTET_STRING_specifics_t *)td->specifics |
134 | | : &asn_SPC_OCTET_STRING_specs; |
135 | | ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); |
136 | | |
137 | | /* |
138 | | * Remove decode-time stack. |
139 | | */ |
140 | | struct _stack *stck; |
141 | | stck = (struct _stack *)ctx->ptr; |
142 | | if(stck) { |
143 | | while(stck->tail) { |
144 | | struct _stack_el *sel = stck->tail; |
145 | | stck->tail = sel->prev; |
146 | | FREEMEM(sel); |
147 | | } |
148 | | FREEMEM(stck); |
149 | | } |
150 | | #endif /* !defined(ASN_DISABLE_BER_SUPPORT) */ |
151 | | |
152 | 18.2k | switch(method) { |
153 | 7.18k | case ASFM_FREE_EVERYTHING: |
154 | 7.18k | FREEMEM(sptr); |
155 | 7.18k | break; |
156 | 11.0k | case ASFM_FREE_UNDERLYING: |
157 | 11.0k | break; |
158 | 61 | case ASFM_FREE_UNDERLYING_AND_RESET: |
159 | 61 | memset(sptr, 0, |
160 | 61 | td->specifics |
161 | 61 | ? ((const asn_OCTET_STRING_specifics_t *)(td->specifics)) |
162 | 61 | ->struct_size |
163 | 61 | : sizeof(OCTET_STRING_t)); |
164 | 61 | break; |
165 | 18.2k | } |
166 | 18.2k | } |
167 | | |
168 | | /* |
169 | | * Conversion routines. |
170 | | */ |
171 | | int |
172 | 0 | OCTET_STRING_fromBuf(OCTET_STRING_t *st, const char *str, int len) { |
173 | 0 | void *buf; |
174 | |
|
175 | 0 | if(st == 0 || (str == 0 && len)) { |
176 | 0 | errno = EINVAL; |
177 | 0 | return -1; |
178 | 0 | } |
179 | | |
180 | | /* |
181 | | * Clear the OCTET STRING. |
182 | | */ |
183 | 0 | if(str == NULL) { |
184 | 0 | FREEMEM(st->buf); |
185 | 0 | st->buf = 0; |
186 | 0 | st->size = 0; |
187 | 0 | return 0; |
188 | 0 | } |
189 | | |
190 | | /* Determine the original string size, if not explicitly given */ |
191 | 0 | if(len < 0) |
192 | 0 | len = strlen(str); |
193 | | |
194 | | /* Allocate and fill the memory */ |
195 | 0 | buf = MALLOC(len + 1); |
196 | 0 | if(buf == NULL) |
197 | 0 | return -1; |
198 | | |
199 | 0 | memcpy(buf, str, len); |
200 | 0 | ((uint8_t *)buf)[len] = '\0'; /* Couldn't use memcpy(len+1)! */ |
201 | 0 | FREEMEM(st->buf); |
202 | 0 | st->buf = (uint8_t *)buf; |
203 | 0 | st->size = len; |
204 | |
|
205 | 0 | return 0; |
206 | 0 | } |
207 | | |
208 | | OCTET_STRING_t * |
209 | | OCTET_STRING_new_fromBuf(const asn_TYPE_descriptor_t *td, const char *str, |
210 | 0 | int len) { |
211 | 0 | const asn_OCTET_STRING_specifics_t *specs = |
212 | 0 | td->specifics ? (const asn_OCTET_STRING_specifics_t *)td->specifics |
213 | 0 | : &asn_SPC_OCTET_STRING_specs; |
214 | 0 | OCTET_STRING_t *st; |
215 | | |
216 | | /* |
217 | | * Sanity check: struct_size should be at least as large as OCTET_STRING_t. |
218 | | * If it's smaller, accessing OCTET_STRING_t fields could cause memory corruption. |
219 | | */ |
220 | 0 | if(specs->struct_size < sizeof(OCTET_STRING_t)) { |
221 | 0 | ASN_DEBUG("Type descriptor %s has struct_size %u which is smaller than OCTET_STRING_t (%zu)", |
222 | 0 | td->name ? td->name : "unknown", specs->struct_size, sizeof(OCTET_STRING_t)); |
223 | 0 | return NULL; |
224 | 0 | } |
225 | | |
226 | 0 | st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size); |
227 | 0 | if(st && str && OCTET_STRING_fromBuf(st, str, len)) { |
228 | 0 | FREEMEM(st); |
229 | 0 | st = NULL; |
230 | 0 | } |
231 | |
|
232 | 0 | return st; |
233 | 0 | } |
234 | | |
235 | | /* |
236 | | * Lexicographically compare the common prefix of both strings, |
237 | | * and if it is the same return -1 for the smallest string. |
238 | | */ |
239 | | int |
240 | | OCTET_STRING_compare(const asn_TYPE_descriptor_t *td, const void *aptr, |
241 | 0 | const void *bptr) { |
242 | 0 | const asn_OCTET_STRING_specifics_t *specs = td->specifics; |
243 | 0 | const OCTET_STRING_t *a = aptr; |
244 | 0 | const OCTET_STRING_t *b = bptr; |
245 | |
|
246 | 0 | (void)specs; |
247 | 0 | assert(!specs || specs->subvariant != ASN_OSUBV_BIT); |
248 | |
|
249 | 0 | if(a && b) { |
250 | 0 | size_t common_prefix_size = a->size <= b->size ? a->size : b->size; |
251 | 0 | int ret = memcmp(a->buf, b->buf, common_prefix_size); |
252 | 0 | if(ret == 0) { |
253 | | /* Figure out which string with equal prefixes is longer. */ |
254 | 0 | if(a->size < b->size) { |
255 | 0 | return -1; |
256 | 0 | } else if(a->size > b->size) { |
257 | 0 | return 1; |
258 | 0 | } else { |
259 | 0 | return 0; |
260 | 0 | } |
261 | 0 | } else { |
262 | 0 | return ret < 0 ? -1 : 1; |
263 | 0 | } |
264 | 0 | } else if(!a && !b) { |
265 | 0 | return 0; |
266 | 0 | } else if(!a) { |
267 | 0 | return -1; |
268 | 0 | } else { |
269 | 0 | return 1; |
270 | 0 | } |
271 | |
|
272 | 0 | } |
273 | | |
274 | | int |
275 | | OCTET_STRING_copy(const asn_TYPE_descriptor_t *td, void **aptr, |
276 | 0 | const void *bptr) { |
277 | 0 | const asn_OCTET_STRING_specifics_t *specs = |
278 | 0 | td->specifics ? (const asn_OCTET_STRING_specifics_t *)td->specifics |
279 | 0 | : &asn_SPC_OCTET_STRING_specs; |
280 | 0 | OCTET_STRING_t *a = *aptr; |
281 | 0 | const OCTET_STRING_t *b = bptr; |
282 | |
|
283 | 0 | if(!b) { |
284 | 0 | if(a) { |
285 | 0 | FREEMEM(a->buf); |
286 | 0 | a->buf = 0; |
287 | 0 | a->size = 0; |
288 | 0 | FREEMEM(a); |
289 | 0 | } |
290 | 0 | *aptr = 0; |
291 | 0 | return 0; |
292 | 0 | } |
293 | | |
294 | 0 | if(!a) { |
295 | 0 | a = *aptr = (OCTET_STRING_t *)CALLOC(1, specs->struct_size); |
296 | 0 | if(!a) return -1; |
297 | 0 | } |
298 | | |
299 | 0 | void *buf = MALLOC(b->size + 1); |
300 | 0 | if(!buf) return -1; |
301 | 0 | memcpy(buf, b->buf, b->size); |
302 | 0 | ((uint8_t *)buf)[b->size] = '\0'; |
303 | |
|
304 | 0 | FREEMEM(a->buf); |
305 | 0 | a->buf = (uint8_t *)buf; |
306 | 0 | a->size = b->size; |
307 | |
|
308 | 0 | return 0; |
309 | 0 | } |
310 | | |
311 | | #if !defined(ASN_DISABLE_UPER_SUPPORT) || !defined(ASN_DISABLE_APER_SUPPORT) |
312 | | int |
313 | | OCTET_STRING_per_get_characters(asn_per_data_t *po, uint8_t *buf, |
314 | | size_t units, unsigned int bpc, unsigned int unit_bits, |
315 | 12.3k | long lb, long ub, const asn_per_constraints_t *pc) { |
316 | 12.3k | uint8_t *end = buf + units * bpc; |
317 | | |
318 | 12.3k | ASN_DEBUG("Expanding %d characters into (%ld..%ld):%d", |
319 | 12.3k | (int)units, lb, ub, unit_bits); |
320 | | |
321 | | /* X.691: 27.5.4 */ |
322 | 12.3k | if((unsigned long)ub <= ((unsigned long)2 << (unit_bits - 1))) { |
323 | | /* Decode without translation */ |
324 | 12.3k | lb = 0; |
325 | 12.3k | } else if(pc && pc->code2value) { |
326 | 0 | if(unit_bits > 16) |
327 | 0 | return 1; /* FATAL: can't have constrained |
328 | | * UniversalString with more than |
329 | | * 16 million code points */ |
330 | 0 | for(; buf < end; buf += bpc) { |
331 | 0 | int value; |
332 | 0 | int code = per_get_few_bits(po, unit_bits); |
333 | 0 | if(code < 0) return -1; /* WMORE */ |
334 | 0 | value = pc->code2value(code); |
335 | 0 | if(value < 0) { |
336 | 0 | ASN_DEBUG("Code %d (0x%02x) is" |
337 | 0 | " not in map (%ld..%ld)", |
338 | 0 | code, code, lb, ub); |
339 | 0 | return 1; /* FATAL */ |
340 | 0 | } |
341 | 0 | switch(bpc) { |
342 | 0 | case 1: *buf = value; break; |
343 | 0 | case 2: buf[0] = value >> 8; buf[1] = value; break; |
344 | 0 | case 4: buf[0] = value >> 24; buf[1] = value >> 16; |
345 | 0 | buf[2] = value >> 8; buf[3] = value; break; |
346 | 0 | } |
347 | 0 | } |
348 | 0 | return 0; |
349 | 0 | } |
350 | | |
351 | | /* Shortcut the no-op copying to the aligned structure */ |
352 | 12.3k | if(lb == 0 && (unit_bits == 8 * bpc)) { |
353 | 12.3k | return per_get_many_bits(po, buf, 0, unit_bits * units); |
354 | 12.3k | } |
355 | | |
356 | 0 | for(; buf < end; buf += bpc) { |
357 | 0 | int32_t code = per_get_few_bits(po, unit_bits); |
358 | 0 | int32_t ch = code + lb; |
359 | 0 | if(code < 0) return -1; /* WMORE */ |
360 | 0 | if(ch > ub) { |
361 | 0 | ASN_DEBUG("Code %d is out of range (%ld..%ld)", |
362 | 0 | ch, lb, ub); |
363 | 0 | return 1; /* FATAL */ |
364 | 0 | } |
365 | 0 | switch(bpc) { |
366 | 0 | case 1: *buf = ch; break; |
367 | 0 | case 2: buf[0] = ch >> 8; buf[1] = ch; break; |
368 | 0 | case 4: buf[0] = ch >> 24; buf[1] = ch >> 16; |
369 | 0 | buf[2] = ch >> 8; buf[3] = ch; break; |
370 | 0 | } |
371 | 0 | } |
372 | | |
373 | 0 | return 0; |
374 | 0 | } |
375 | | |
376 | | int |
377 | | OCTET_STRING_per_put_characters(asn_per_outp_t *po, const uint8_t *buf, |
378 | | size_t units, unsigned int bpc, unsigned int unit_bits, |
379 | 0 | long lb, long ub, const asn_per_constraints_t *pc) { |
380 | 0 | const uint8_t *end = buf + units * bpc; |
381 | |
|
382 | 0 | ASN_DEBUG("Squeezing %d characters into (%ld..%ld):%d (%d bpc)", |
383 | 0 | (int)units, lb, ub, unit_bits, bpc); |
384 | | |
385 | | /* X.691: 27.5.4 */ |
386 | 0 | if((unsigned long)ub <= ((unsigned long)2 << (unit_bits - 1))) { |
387 | | /* Encode as is */ |
388 | 0 | lb = 0; |
389 | 0 | } else if(pc && pc->value2code) { |
390 | 0 | for(; buf < end; buf += bpc) { |
391 | 0 | int code; |
392 | 0 | uint32_t value; |
393 | 0 | switch(bpc) { |
394 | 0 | case 1: value = *(const uint8_t *)buf; break; |
395 | 0 | case 2: value = (buf[0] << 8) | buf[1]; break; |
396 | 0 | case 4: value = (buf[0] << 24) | (buf[1] << 16) |
397 | 0 | | (buf[2] << 8) | buf[3]; break; |
398 | 0 | default: return -1; |
399 | 0 | } |
400 | 0 | code = pc->value2code(value); |
401 | 0 | if(code < 0) { |
402 | 0 | ASN_DEBUG("Character %d (0x%02x) is" |
403 | 0 | " not in map (%ld..%ld)", |
404 | 0 | *buf, *buf, lb, ub); |
405 | 0 | return -1; |
406 | 0 | } |
407 | 0 | if(per_put_few_bits(po, code, unit_bits)) |
408 | 0 | return -1; |
409 | 0 | } |
410 | 0 | } |
411 | | |
412 | | /* Shortcut the no-op copying to the aligned structure */ |
413 | 0 | if(lb == 0 && (unit_bits == 8 * bpc)) { |
414 | 0 | return per_put_many_bits(po, buf, unit_bits * units); |
415 | 0 | } |
416 | | |
417 | 0 | for(ub -= lb; buf < end; buf += bpc) { |
418 | 0 | int ch; |
419 | 0 | uint32_t value; |
420 | 0 | switch(bpc) { |
421 | 0 | case 1: |
422 | 0 | value = *(const uint8_t *)buf; |
423 | 0 | break; |
424 | 0 | case 2: |
425 | 0 | value = (buf[0] << 8) | buf[1]; |
426 | 0 | break; |
427 | 0 | case 4: |
428 | 0 | value = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; |
429 | 0 | break; |
430 | 0 | default: |
431 | 0 | return -1; |
432 | 0 | } |
433 | 0 | ch = value - lb; |
434 | 0 | if(ch < 0 || ch > ub) { |
435 | 0 | ASN_DEBUG("Character %d (0x%02x) is out of range (%ld..%ld)", *buf, |
436 | 0 | value, lb, ub + lb); |
437 | 0 | return -1; |
438 | 0 | } |
439 | 0 | if(per_put_few_bits(po, ch, unit_bits)) return -1; |
440 | 0 | } |
441 | | |
442 | 0 | return 0; |
443 | 0 | } |
444 | | #endif /* !defined(ASN_DISABLE_UPER_SUPPORT) || !defined(ASN_DISABLE_APER_SUPPORT) */ |