/src/wireshark/epan/asn1.c
Line | Count | Source |
1 | | /* asn1.c |
2 | | * Common routines for ASN.1 |
3 | | * 2007 Anders Broman |
4 | | * |
5 | | * Wireshark - Network traffic analyzer |
6 | | * By Gerald Combs <gerald@wireshark.org> |
7 | | * Copyright 1998 Gerald Combs |
8 | | * |
9 | | * SPDX-License-Identifier: GPL-2.0-or-later |
10 | | */ |
11 | | |
12 | | #include "config.h" |
13 | | |
14 | | #include <glib.h> |
15 | | |
16 | | #include <string.h> |
17 | | #include <stdlib.h> |
18 | | #include <math.h> |
19 | | #include <errno.h> |
20 | | #include <fenv.h> |
21 | | |
22 | | #include <epan/packet.h> |
23 | | #include <wsutil/pint.h> |
24 | | #include <wsutil/sign_ext.h> |
25 | | |
26 | | #include "asn1.h" |
27 | | |
28 | 174k | void asn1_ctx_init(asn1_ctx_t *actx, asn1_enc_e encoding, bool aligned, packet_info *pinfo) { |
29 | 174k | memset(actx, '\0', sizeof(*actx)); |
30 | 174k | actx->signature = ASN1_CTX_SIGNATURE; |
31 | 174k | actx->encoding = encoding; |
32 | 174k | actx->aligned = aligned; |
33 | 174k | actx->pinfo = pinfo; |
34 | 174k | } |
35 | | |
36 | 1.31k | bool asn1_ctx_check_signature(asn1_ctx_t *actx) { |
37 | 1.31k | return actx && (actx->signature == ASN1_CTX_SIGNATURE); |
38 | 1.31k | } |
39 | | |
40 | 4 | void asn1_ctx_clean_external(asn1_ctx_t *actx) { |
41 | 4 | memset(&actx->external, '\0', sizeof(actx->external)); |
42 | 4 | actx->external.hf_index = -1; |
43 | 4 | actx->external.encoding = -1; |
44 | 4 | } |
45 | | |
46 | 0 | void asn1_ctx_clean_epdv(asn1_ctx_t *actx) { |
47 | 0 | memset(&actx->embedded_pdv, '\0', sizeof(actx->embedded_pdv)); |
48 | 0 | actx->embedded_pdv.hf_index = -1; |
49 | 0 | actx->embedded_pdv.identification = -1; |
50 | 0 | } |
51 | | |
52 | | |
53 | | /*--- stack/parameters ---*/ |
54 | | |
55 | 7.86k | void asn1_stack_frame_push(asn1_ctx_t *actx, const char *name) { |
56 | 7.86k | asn1_stack_frame_t *frame; |
57 | | |
58 | 7.86k | frame = wmem_new0(actx->pinfo->pool, asn1_stack_frame_t); |
59 | 7.86k | frame->name = name; |
60 | 7.86k | frame->next = actx->stack; |
61 | 7.86k | actx->stack = frame; |
62 | 7.86k | } |
63 | | |
64 | 61 | void asn1_stack_frame_pop(asn1_ctx_t *actx, const char *name) { |
65 | 61 | DISSECTOR_ASSERT(actx->stack); |
66 | 61 | DISSECTOR_ASSERT(!strcmp(actx->stack->name, name)); |
67 | 61 | actx->stack = actx->stack->next; |
68 | 61 | } |
69 | | |
70 | 7.81k | void asn1_stack_frame_check(asn1_ctx_t *actx, const char *name, const asn1_par_def_t *par_def) { |
71 | 7.81k | const asn1_par_def_t *pd = par_def; |
72 | 7.81k | asn1_par_t *par; |
73 | | |
74 | 7.81k | DISSECTOR_ASSERT(actx->stack); |
75 | 7.81k | DISSECTOR_ASSERT(!strcmp(actx->stack->name, name)); |
76 | | |
77 | 7.81k | par = actx->stack->par; |
78 | 23.4k | while (pd->name) { |
79 | 15.6k | DISSECTOR_ASSERT(par); |
80 | 15.6k | DISSECTOR_ASSERT((pd->ptype == ASN1_PAR_IRR) || (par->ptype == pd->ptype)); |
81 | 15.6k | par->name = pd->name; |
82 | 15.6k | pd++; |
83 | 15.6k | par = par->next; |
84 | 15.6k | } |
85 | 7.81k | DISSECTOR_ASSERT(!par); |
86 | 7.81k | } |
87 | | |
88 | 15.6k | static asn1_par_t *get_par_by_name(asn1_ctx_t *actx, const char *name) { |
89 | 15.6k | asn1_par_t *par = NULL; |
90 | | |
91 | 15.6k | DISSECTOR_ASSERT(actx->stack); |
92 | 15.6k | par = actx->stack->par; |
93 | 23.4k | while (par) { |
94 | 23.4k | if (!strcmp(par->name, name)) |
95 | 15.6k | return par; |
96 | 7.81k | par = par->next; |
97 | 7.81k | } |
98 | 0 | return par; |
99 | 15.6k | } |
100 | | |
101 | 15.7k | static asn1_par_t *push_new_par(asn1_ctx_t *actx) { |
102 | 15.7k | asn1_par_t *par, **pp; |
103 | | |
104 | 15.7k | DISSECTOR_ASSERT(actx->stack); |
105 | | |
106 | 15.7k | par = wmem_new0(actx->pinfo->pool, asn1_par_t); |
107 | | |
108 | 15.7k | pp = &(actx->stack->par); |
109 | 23.7k | while (*pp) |
110 | 7.94k | pp = &((*pp)->next); |
111 | 15.7k | *pp = par; |
112 | | |
113 | 15.7k | return par; |
114 | 15.7k | } |
115 | | |
116 | 42 | void asn1_param_push_boolean(asn1_ctx_t *actx, bool value) { |
117 | 42 | asn1_par_t *par; |
118 | | |
119 | 42 | par = push_new_par(actx); |
120 | 42 | par->ptype = ASN1_PAR_BOOLEAN; |
121 | 42 | par->value.v_boolean = value; |
122 | 42 | } |
123 | | |
124 | 15.7k | void asn1_param_push_integer(asn1_ctx_t *actx, int32_t value) { |
125 | 15.7k | asn1_par_t *par; |
126 | | |
127 | 15.7k | par = push_new_par(actx); |
128 | 15.7k | par->ptype = ASN1_PAR_INTEGER; |
129 | 15.7k | par->value.v_integer = value; |
130 | 15.7k | } |
131 | | |
132 | 0 | bool asn1_param_get_boolean(asn1_ctx_t *actx, const char *name) { |
133 | 0 | asn1_par_t *par = NULL; |
134 | |
|
135 | 0 | par = get_par_by_name(actx, name); |
136 | 0 | DISSECTOR_ASSERT(par); |
137 | 0 | return par->value.v_boolean; |
138 | 0 | } |
139 | | |
140 | 15.6k | int32_t asn1_param_get_integer(asn1_ctx_t *actx, const char *name) { |
141 | 15.6k | asn1_par_t *par = NULL; |
142 | | |
143 | 15.6k | par = get_par_by_name(actx, name); |
144 | 15.6k | DISSECTOR_ASSERT(par); |
145 | 15.6k | return par->value.v_integer; |
146 | 15.6k | } |
147 | | |
148 | | |
149 | | /*--- ROSE ---*/ |
150 | | |
151 | 48 | void rose_ctx_init(rose_ctx_t *rctx) { |
152 | 48 | memset(rctx, '\0', sizeof(*rctx)); |
153 | 48 | rctx->signature = ROSE_CTX_SIGNATURE; |
154 | 48 | } |
155 | | |
156 | 16 | bool rose_ctx_check_signature(rose_ctx_t *rctx) { |
157 | 16 | return rctx && (rctx->signature == ROSE_CTX_SIGNATURE); |
158 | 16 | } |
159 | | |
160 | 16 | void rose_ctx_clean_data(rose_ctx_t *rctx) { |
161 | 16 | memset(&rctx->d, '\0', sizeof(rctx->d)); |
162 | 16 | rctx->d.code = -1; |
163 | 16 | } |
164 | | |
165 | 4 | asn1_ctx_t *get_asn1_ctx(void *ptr) { |
166 | 4 | asn1_ctx_t *actx = (asn1_ctx_t*)ptr; |
167 | | |
168 | 4 | if (!asn1_ctx_check_signature(actx)) |
169 | 0 | actx = NULL; |
170 | | |
171 | 4 | return actx; |
172 | 4 | } |
173 | | |
174 | 16 | rose_ctx_t *get_rose_ctx(void *ptr) { |
175 | 16 | rose_ctx_t *rctx = (rose_ctx_t*)ptr; |
176 | 16 | asn1_ctx_t *actx = (asn1_ctx_t*)ptr; |
177 | | |
178 | 16 | if (!asn1_ctx_check_signature(actx)) |
179 | 16 | actx = NULL; |
180 | | |
181 | 16 | if (actx) |
182 | 0 | rctx = actx->rose_ctx; |
183 | | |
184 | 16 | if (!rose_ctx_check_signature(rctx)) |
185 | 0 | rctx = NULL; |
186 | | |
187 | 16 | return rctx; |
188 | 16 | } |
189 | | |
190 | | static double |
191 | 20 | asn1_get_overflow(uint8_t first_octet, int S) { |
192 | 20 | if (first_octet & 0x80) { |
193 | | // Negative exponent |
194 | 10 | return S * 0.0; |
195 | 10 | } else { |
196 | | // Positive exponent |
197 | 10 | return S * HUGE_VAL; |
198 | 10 | } |
199 | 20 | } |
200 | | |
201 | | #ifdef _MSC_VER |
202 | | /* MSVC way of turning on floating point exceptions. */ |
203 | | #pragma float_control(precise, on, push) |
204 | | #pragma float_control(except, on) |
205 | | #pragma fenv_access(on) |
206 | | #endif |
207 | | |
208 | 643 | double asn1_get_real(const uint8_t *real_ptr, int len, int *err) { |
209 | 643 | uint8_t octet; |
210 | 643 | const uint8_t *p; |
211 | 643 | double val = 0; |
212 | 643 | *err = 0; |
213 | | |
214 | | /* XXX - We don't check the asn1 context, and so allow any encoding which |
215 | | * is acceptable in BER, instead of setting EINVAL for overlong encodings |
216 | | * which are not allowed in CER and DER (11.3) nor PER, which uses the |
217 | | * same encoding as CER & DER for the real type after octet alignment |
218 | | * (X.691 15.2). Many of those will set ERANGE instead of EINVAL. |
219 | | */ |
220 | | |
221 | | /* 8.5.2 If the real value is the value zero, |
222 | | * there shall be no contents octets in the encoding. |
223 | | */ |
224 | 643 | if (len < 1) return val; |
225 | | |
226 | 517 | octet = real_ptr[0]; |
227 | 517 | p = real_ptr + 1; |
228 | 517 | len -= 1; |
229 | 517 | if (octet & 0x80) { /* binary encoding */ |
230 | 296 | int i; |
231 | 296 | int8_t S; /* Sign */ |
232 | 296 | uint8_t B; /* log base 2 of the Base */ |
233 | 296 | uint8_t F; /* scaling Factor */ |
234 | 296 | int32_t E = 0; /* Exponent (supported max 3 octets/24 bit) */ |
235 | 296 | uint64_t N = 0; /* N (supported max 8 octets/64 bit) */ |
236 | 296 | int exp = 0; |
237 | | |
238 | 296 | uint8_t lenE; |
239 | 296 | int lenN; |
240 | | |
241 | 296 | if(octet & 0x40) S = -1; else S = 1; |
242 | 296 | switch(octet & 0x30) { |
243 | 149 | case 0x00: B = 1; break; |
244 | 61 | case 0x10: B = 3; break; |
245 | 55 | case 0x20: B = 4; break; |
246 | 31 | case 0x30: /* Reserved */ |
247 | 31 | default: |
248 | 31 | *err = EINVAL; |
249 | 31 | return val; |
250 | 296 | } |
251 | 265 | F = (octet & 0x0c) >> 2; |
252 | | |
253 | | /* 8.5.7.4 Exponent length */ |
254 | 265 | lenE = (octet & 0x3) + 1; |
255 | | |
256 | | /* 8.5.7.4 d) Next octet defines length of exponent */ |
257 | 265 | if (lenE == 4) { |
258 | 103 | if (len < 1) { |
259 | 7 | *err = EINVAL; |
260 | 7 | return val; |
261 | 7 | } |
262 | 96 | lenE = *p; |
263 | 96 | p++; |
264 | 96 | len--; |
265 | 96 | if (lenE == 0 || lenE >= 3) { |
266 | | /* "the third up to the (X plus 3)th (inclusive) contents octets encode |
267 | | * the value of the exponent as a two's complement binary number; the |
268 | | * value of X shall be at least one; the first nine bits of the |
269 | | * transmitted exponent shall not be all zeros or all ones." |
270 | | * The last part means that the exponent could not be representable |
271 | | * as a two's complement number using fewer octets. If there are |
272 | | * three octets, that means that the exponent must be sufficiently |
273 | | * large as not to fit in a IEEE 754 double precision floating point |
274 | | * (exponent offset binary width 11) or even a quadruple precision |
275 | | * binary128 (exponent offset binary width 15), or for that matter, |
276 | | * in an IBM double-precision/long hexadecimal floating point. |
277 | | * |
278 | | * Note that if lenE is 1 or 2 here this is not the smallest encoding |
279 | | * as 8.5.7.4 a) or b) could have been used, so it is still invalid |
280 | | * in CER, DER, or PER. |
281 | | */ |
282 | 57 | if (lenE == 0) { |
283 | 21 | *err = EINVAL; |
284 | 36 | } else if (lenE >= 3) { |
285 | 36 | if (lenE > len) { |
286 | 16 | *err = ERANGE; |
287 | 20 | } else { |
288 | 20 | val = asn1_get_overflow(*p, S); |
289 | 20 | } |
290 | 36 | *err = ERANGE; |
291 | 36 | } |
292 | 57 | return val; |
293 | 57 | } |
294 | 96 | } |
295 | | |
296 | | /* Ensure the buffer len and its content are coherent */ |
297 | 201 | if (lenE > len) { |
298 | 21 | *err = EINVAL; |
299 | 21 | return val; |
300 | 21 | } |
301 | | |
302 | 180 | switch (lenE) { |
303 | 68 | case 1: |
304 | 68 | E = ws_sign_ext32(pntohu8(p), 8); |
305 | 68 | break; |
306 | 77 | case 2: |
307 | 77 | E = ws_sign_ext32(pntohu16(p), 16); |
308 | 77 | break; |
309 | 35 | case 3: |
310 | 35 | E = ws_sign_ext32(pntohu24(p), 24); |
311 | 35 | break; |
312 | 0 | default: |
313 | 0 | ws_assert_not_reached(); |
314 | 180 | } |
315 | | |
316 | 180 | p += lenE; |
317 | | |
318 | | /* 8.5.7.5 "The remaining contents octets encode the value of the integer |
319 | | * N as an unsigned binary number." */ |
320 | 180 | lenN = len - lenE; |
321 | | |
322 | | /* we can't handle integers > 64 bits, but that's ok, as no double precision |
323 | | * floating format can handle that much precision by definition. */ |
324 | | /* Take the fraction from the first 8 octets and then use the length of the |
325 | | * remaining octets to adjust the exponent, losing the excess precision. |
326 | | * If the first octet is all zeros, which is allowed in BER, sigh, NOTE 1, |
327 | | * we should skip past it and any other all zero octets, but we don't. |
328 | | * We also ideally should set floating point exception FE_EXACT or an |
329 | | * errno substitute. */ |
330 | 180 | if (lenN > 8) { |
331 | | // Store the excess precision in bits |
332 | 8 | if (ckd_mul(&exp, 8, lenN - 8)) { |
333 | | // Wow. Really? |
334 | 0 | val = S * HUGE_VAL; |
335 | 0 | *err = ERANGE; |
336 | 0 | return val; |
337 | 0 | } |
338 | 8 | lenN = 8; |
339 | 8 | } |
340 | | |
341 | 929 | for (i=0; i<lenN; i++) { |
342 | 749 | N = (N<<8) | *p; |
343 | 749 | p++; |
344 | 749 | } |
345 | | /* Since E is never larger than 24 bits, B no larger than 4, B*E + F |
346 | | * doesn't overflow an int. */ |
347 | 180 | if (ckd_add(&exp, exp, B*E + F)) { |
348 | 0 | val = S * HUGE_VAL; |
349 | 0 | *err = ERANGE; |
350 | 180 | } else { |
351 | 180 | #ifndef _MSC_VER |
352 | | /* According to the C standard (7.6.1), #pragma STDC FENV_ACCESS ON can |
353 | | * appear at the start of a compound statement (i.e., here), and then |
354 | | * it is restored to its previous state. GCC doesn't support the pragma |
355 | | * and will warn about an unknown pragma. Luckily it doesn't need it |
356 | | * either, but some compilers might. */ |
357 | 180 | DIAG_OFF(unknown-pragmas) |
358 | 180 | #pragma STDC FENV_ACCESS ON |
359 | 180 | #endif |
360 | 180 | errno = 0; |
361 | 180 | feclearexcept(FE_ALL_EXCEPT); |
362 | 180 | val = ldexp((double) S * N, exp); |
363 | 180 | if (errno || fetestexcept(FE_OVERFLOW | FE_UNDERFLOW)) { |
364 | 67 | *err = ERANGE; |
365 | 67 | } |
366 | 180 | #ifndef _MSC_VER |
367 | 180 | DIAG_ON(unknown-pragmas) |
368 | 180 | #endif |
369 | 180 | } |
370 | 221 | } else if (octet & 0x40) { /* SpecialRealValue */ |
371 | 72 | switch (octet & 0x3F) { |
372 | 11 | case 0x00: val = HUGE_VAL; break; |
373 | 13 | case 0x01: val = -HUGE_VAL; break; |
374 | 18 | case 0x02: val = NAN; break; |
375 | 12 | case 0x03: val = -0.0; break; /* Yes, negative 0 is different. */ |
376 | 18 | default: |
377 | 18 | *err = EINVAL; |
378 | 18 | break; |
379 | 72 | } |
380 | 149 | } else { /* decimal encoding */ |
381 | 149 | char *buf; |
382 | | |
383 | 149 | buf = g_strndup((const char*)p, len); |
384 | | /* g_ascii_strtod resets errno and returns ERANGE as appropriate */ |
385 | 149 | val = g_ascii_strtod(buf, NULL); |
386 | 149 | if (errno == ERANGE) { |
387 | 3 | *err = ERANGE; |
388 | 146 | } else if (val == 0.0) { |
389 | | /* Since 0.0 "shall" be encoded with no contents octets (8.5.2), (and |
390 | | * minus 0 per 8.5.9) a return value of 0.0 must be a failed conversion |
391 | | * or where a zero was encoded with decimal encoding in violation of |
392 | | * the specification, and thus EINVAL is appropriate. */ |
393 | 134 | *err = EINVAL; |
394 | 134 | } |
395 | 149 | g_free(buf); |
396 | 149 | } |
397 | | |
398 | 401 | return val; |
399 | 517 | } |
400 | | |
401 | | #ifdef _MSC_VER |
402 | | #pragma float_control(pop) |
403 | | #endif |
404 | | |
405 | | /* |
406 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
407 | | * |
408 | | * Local Variables: |
409 | | * c-basic-offset: 2 |
410 | | * tab-width: 8 |
411 | | * indent-tabs-mode: nil |
412 | | * End: |
413 | | * |
414 | | * ex: set shiftwidth=2 tabstop=8 expandtab: |
415 | | * :indentSize=2:tabSize=8:noTabs=true: |
416 | | */ |