/src/open5gs/lib/asn1c/common/UTF8String_rfill.c
Line | Count | Source |
1 | | /* |
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 | | #include <asn_internal.h> |
7 | | #include <UTF8String.h> |
8 | | |
9 | | /* |
10 | | * Biased function for randomizing UTF-8 sequences. |
11 | | */ |
12 | | static size_t |
13 | 0 | UTF8String__random_char(uint8_t *b, size_t size) { |
14 | 0 | static const struct rnd_value { |
15 | 0 | const char *value; |
16 | 0 | size_t size; |
17 | 0 | } values[] = {{"\0", 1}, |
18 | 0 | {"\x01", 1}, |
19 | 0 | {"\x7f", 1}, |
20 | 0 | {"\xc2\xa2", 2}, |
21 | 0 | {"\xe2\x82\xac", 3}, |
22 | 0 | {"\xf0\x90\x8d\x88", 4}, |
23 | 0 | {"\xf4\x8f\xbf\xbf", 4}}; |
24 | |
|
25 | 0 | const struct rnd_value *v; |
26 | 0 | size_t max_idx = 0; |
27 | |
|
28 | 0 | switch(size) { |
29 | 0 | case 0: |
30 | 0 | assert(size != 0); |
31 | 0 | return 0; |
32 | 0 | case 1: |
33 | 0 | max_idx = 2; |
34 | 0 | break; |
35 | 0 | case 2: |
36 | 0 | max_idx = 3; |
37 | 0 | break; |
38 | 0 | default: |
39 | 0 | case 4: |
40 | 0 | max_idx = sizeof(values) / sizeof(values[0]) - 1; |
41 | 0 | break; |
42 | 0 | } |
43 | | |
44 | 0 | v = &values[asn_random_between(0, max_idx)]; |
45 | 0 | memcpy(b, v->value, v->size); |
46 | 0 | return v->size; |
47 | 0 | } |
48 | | |
49 | | static size_t |
50 | 0 | UTF8String__encode_codepoint(uint8_t *b, uint32_t code) { |
51 | 0 | if(code <= 0x7f) { |
52 | 0 | b[0] = code; |
53 | 0 | return 1; |
54 | 0 | } else if(code <= 0x7ff) { |
55 | 0 | b[0] = 0xc0 | (code >> 6); |
56 | 0 | b[1] = 0x80 | (code & 0x3f); |
57 | 0 | return 2; |
58 | 0 | } else if(code >= 0xd800 && code <= 0xdfff) { |
59 | | /* Surrogate code points are not valid Unicode scalar values. */ |
60 | 0 | return UTF8String__encode_codepoint(b, 0xfffd); |
61 | 0 | } else if(code <= 0xffff) { |
62 | 0 | b[0] = 0xe0 | (code >> 12); |
63 | 0 | b[1] = 0x80 | ((code >> 6) & 0x3f); |
64 | 0 | b[2] = 0x80 | (code & 0x3f); |
65 | 0 | return 3; |
66 | 0 | } else if(code <= 0x10ffff) { |
67 | 0 | b[0] = 0xf0 | (code >> 18); |
68 | 0 | b[1] = 0x80 | ((code >> 12) & 0x3f); |
69 | 0 | b[2] = 0x80 | ((code >> 6) & 0x3f); |
70 | 0 | b[3] = 0x80 | (code & 0x3f); |
71 | 0 | return 4; |
72 | 0 | } else { |
73 | 0 | return UTF8String__encode_codepoint(b, 0x10ffff); |
74 | 0 | } |
75 | 0 | } |
76 | | |
77 | | static const asn_per_constraints_t * |
78 | | UTF8String__per_constraints(const asn_TYPE_descriptor_t *td, |
79 | 0 | const asn_encoding_constraints_t *constraints) { |
80 | 0 | #if !defined(ASN_DISABLE_UPER_SUPPORT) || !defined(ASN_DISABLE_APER_SUPPORT) |
81 | 0 | if(constraints && constraints->per_constraints) |
82 | 0 | return constraints->per_constraints; |
83 | 0 | if(td->encoding_constraints.per_constraints) |
84 | 0 | return td->encoding_constraints.per_constraints; |
85 | 0 | #endif /* !defined(ASN_DISABLE_UPER_SUPPORT) || !defined(ASN_DISABLE_APER_SUPPORT) */ |
86 | 0 | return 0; |
87 | 0 | } |
88 | | |
89 | | asn_random_fill_result_t |
90 | | UTF8String_random_fill(const asn_TYPE_descriptor_t *td, void **sptr, |
91 | | const asn_encoding_constraints_t *constraints, |
92 | 0 | size_t max_length) { |
93 | 0 | asn_random_fill_result_t result_ok = {ARFILL_OK, 1}; |
94 | 0 | asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0}; |
95 | 0 | asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0}; |
96 | 0 | uint8_t *buf; |
97 | 0 | uint8_t *bend; |
98 | 0 | uint8_t *b; |
99 | 0 | size_t rnd_len; |
100 | 0 | size_t idx; |
101 | 0 | UTF8String_t *st; |
102 | 0 | const asn_per_constraints_t *pc; |
103 | 0 | uint32_t value_lb = 0; |
104 | 0 | uint32_t value_ub = 0x7f; |
105 | 0 | int has_value_constraint = 0; |
106 | 0 | int force_single_octets = 0; |
107 | |
|
108 | 0 | if(max_length == 0 && !*sptr) return result_skipped; |
109 | | |
110 | 0 | pc = UTF8String__per_constraints(td, constraints); |
111 | 0 | if(pc) { |
112 | 0 | if((pc->value.flags & APC_CONSTRAINED) |
113 | 0 | && pc->value.lower_bound >= 0 |
114 | 0 | && pc->value.lower_bound <= pc->value.upper_bound |
115 | 0 | && pc->value.lower_bound <= 0x10ffff) { |
116 | 0 | value_lb = (uint32_t)pc->value.lower_bound; |
117 | 0 | value_ub = pc->value.upper_bound > 0x10ffff |
118 | 0 | ? 0x10ffff : (uint32_t)pc->value.upper_bound; |
119 | 0 | has_value_constraint = 1; |
120 | 0 | } |
121 | | |
122 | | /* |
123 | | * UTF8String is encoded through OCTET STRING helpers. When a PER |
124 | | * SIZE constraint is present, the encoder checks the number of |
125 | | * octets. Keep randomized values single-octet unless a permitted |
126 | | * alphabet constraint explicitly asks for another range. |
127 | | */ |
128 | 0 | if(pc->size.flags & APC_CONSTRAINED) |
129 | 0 | force_single_octets = 1; |
130 | 0 | } |
131 | | |
132 | | /* |
133 | | * When both a value constraint and a SIZE constraint are present, |
134 | | * restrict generation to code points in the value range that also |
135 | | * fit in a single octet (0..0x7f). If the value range does not |
136 | | * intersect 0..0x7f at all, lift the single-octet restriction and |
137 | | * generate from the full value range. |
138 | | */ |
139 | 0 | if(has_value_constraint && force_single_octets) { |
140 | 0 | if(value_lb > 0x7f) { |
141 | | /* Value range is entirely outside ASCII; allow multi-byte. */ |
142 | 0 | force_single_octets = 0; |
143 | 0 | } else { |
144 | | /* Clamp value range to single-octet region. */ |
145 | 0 | if(value_ub > 0x7f) |
146 | 0 | value_ub = 0x7f; |
147 | 0 | } |
148 | 0 | } |
149 | | |
150 | | /* Figure out how far we should go */ |
151 | 0 | rnd_len = OCTET_STRING_random_length_constrained(td, constraints, |
152 | 0 | max_length / 4); |
153 | |
|
154 | 0 | buf = CALLOC(4, rnd_len + 1); |
155 | 0 | if(!buf) return result_failed; |
156 | | |
157 | 0 | bend = &buf[4 * rnd_len]; |
158 | |
|
159 | 0 | for(b = buf, idx = 0; idx < rnd_len; idx++) { |
160 | 0 | if(has_value_constraint) { |
161 | 0 | uint32_t code = (uint32_t)asn_random_between(value_lb, value_ub); |
162 | 0 | b += UTF8String__encode_codepoint(b, code); |
163 | 0 | } else if(force_single_octets) { |
164 | 0 | b += UTF8String__random_char(b, 1); |
165 | 0 | } else { |
166 | 0 | b += UTF8String__random_char(b, (bend - b)); |
167 | 0 | } |
168 | 0 | } |
169 | 0 | *(uint8_t *)b = 0; |
170 | |
|
171 | 0 | if(*sptr) { |
172 | 0 | st = *sptr; |
173 | 0 | FREEMEM(st->buf); |
174 | 0 | } else { |
175 | 0 | st = (OCTET_STRING_t *)(*sptr = CALLOC(1, sizeof(UTF8String_t))); |
176 | 0 | if(!st) { |
177 | 0 | FREEMEM(buf); |
178 | 0 | return result_failed; |
179 | 0 | } |
180 | 0 | } |
181 | | |
182 | 0 | st->buf = buf; |
183 | 0 | st->size = b - buf; |
184 | |
|
185 | 0 | assert(UTF8String_length(st) == (ssize_t)rnd_len); |
186 | |
|
187 | 0 | return result_ok; |
188 | 0 | } |