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