/src/strongswan/src/libstrongswan/asn1/asn1.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2006 Martin Will |
3 | | * Copyright (C) 2000-2016 Andreas Steffen |
4 | | * |
5 | | * |
6 | | * Copyright (C) secunet Security Networks AG |
7 | | * |
8 | | * This program is free software; you can redistribute it and/or modify it |
9 | | * under the terms of the GNU General Public License as published by the |
10 | | * Free Software Foundation; either version 2 of the License, or (at your |
11 | | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. |
12 | | * |
13 | | * This program is distributed in the hope that it will be useful, but |
14 | | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
15 | | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
16 | | * for more details. |
17 | | */ |
18 | | |
19 | | #include <stdio.h> |
20 | | #include <string.h> |
21 | | #include <time.h> |
22 | | |
23 | | #include <utils/debug.h> |
24 | | |
25 | | #include "oid.h" |
26 | | #include "asn1.h" |
27 | | #include "asn1_parser.h" |
28 | | |
29 | | /** |
30 | | * Commonly used ASN1 values. |
31 | | */ |
32 | | const chunk_t ASN1_INTEGER_0 = chunk_from_chars(0x02, 0x01, 0x00); |
33 | | const chunk_t ASN1_INTEGER_1 = chunk_from_chars(0x02, 0x01, 0x01); |
34 | | const chunk_t ASN1_INTEGER_2 = chunk_from_chars(0x02, 0x01, 0x02); |
35 | | |
36 | | /* |
37 | | * Described in header |
38 | | */ |
39 | | chunk_t asn1_algorithmIdentifier_params(int oid, chunk_t params) |
40 | 0 | { |
41 | 0 | return asn1_wrap(ASN1_SEQUENCE, "mm", asn1_build_known_oid(oid), params); |
42 | 0 | } |
43 | | |
44 | | /* |
45 | | * Described in header |
46 | | */ |
47 | | chunk_t asn1_algorithmIdentifier(int oid) |
48 | 0 | { |
49 | 0 | chunk_t parameters; |
50 | | |
51 | | /* some algorithmIdentifiers have a NULL parameters field and some do not */ |
52 | 0 | switch (oid) |
53 | 0 | { |
54 | 0 | case OID_ECDSA_WITH_SHA1: |
55 | 0 | case OID_ECDSA_WITH_SHA224: |
56 | 0 | case OID_ECDSA_WITH_SHA256: |
57 | 0 | case OID_ECDSA_WITH_SHA384: |
58 | 0 | case OID_ECDSA_WITH_SHA512: |
59 | 0 | case OID_ED25519: |
60 | 0 | case OID_ED448: |
61 | 0 | parameters = chunk_empty; |
62 | 0 | break; |
63 | 0 | default: |
64 | 0 | parameters = asn1_simple_object(ASN1_NULL, chunk_empty); |
65 | 0 | break; |
66 | 0 | } |
67 | 0 | return asn1_algorithmIdentifier_params(oid, parameters); |
68 | 0 | } |
69 | | |
70 | | /* |
71 | | * Defined in header. |
72 | | */ |
73 | | int asn1_known_oid(chunk_t object) |
74 | 27.9k | { |
75 | 27.9k | int oid = 0; |
76 | | |
77 | 415k | while (object.len) |
78 | 415k | { |
79 | 415k | if (oid_names[oid].octet == *object.ptr) |
80 | 96.5k | { |
81 | 96.5k | if (--object.len == 0 || oid_names[oid].down == 0) |
82 | 25.0k | { |
83 | 25.0k | return oid; /* found terminal symbol */ |
84 | 25.0k | } |
85 | 71.4k | else |
86 | 71.4k | { |
87 | 71.4k | object.ptr++; oid++; /* advance to next hex octet */ |
88 | 71.4k | } |
89 | 96.5k | } |
90 | 319k | else |
91 | 319k | { |
92 | 319k | if (oid_names[oid].next) |
93 | 316k | { |
94 | 316k | oid = oid_names[oid].next; |
95 | 316k | } |
96 | 2.80k | else |
97 | 2.80k | { |
98 | 2.80k | return OID_UNKNOWN; |
99 | 2.80k | } |
100 | 319k | } |
101 | 415k | } |
102 | 59 | return OID_UNKNOWN; |
103 | 27.9k | } |
104 | | |
105 | | /* |
106 | | * Defined in header. |
107 | | */ |
108 | | chunk_t asn1_build_known_oid(int n) |
109 | 0 | { |
110 | 0 | chunk_t oid; |
111 | 0 | int i; |
112 | |
|
113 | 0 | if (n < 0 || n >= OID_MAX) |
114 | 0 | { |
115 | 0 | return chunk_empty; |
116 | 0 | } |
117 | | |
118 | 0 | i = oid_names[n].level + 1; |
119 | 0 | oid = chunk_alloc(2 + i); |
120 | 0 | oid.ptr[0] = ASN1_OID; |
121 | 0 | oid.ptr[1] = i; |
122 | |
|
123 | 0 | do |
124 | 0 | { |
125 | 0 | if (oid_names[n].level >= i) |
126 | 0 | { |
127 | 0 | n--; |
128 | 0 | continue; |
129 | 0 | } |
130 | 0 | oid.ptr[--i + 2] = oid_names[n--].octet; |
131 | 0 | } |
132 | 0 | while (i > 0); |
133 | | |
134 | 0 | return oid; |
135 | 0 | } |
136 | | |
137 | | /** |
138 | | * Returns the number of bytes required to encode the given OID node |
139 | | */ |
140 | | static int bytes_required(u_int val) |
141 | 0 | { |
142 | 0 | int shift, required = 1; |
143 | | |
144 | | /* sufficient to handle 32 bit node numbers */ |
145 | 0 | for (shift = 28; shift; shift -= 7) |
146 | 0 | { |
147 | 0 | if (val >> shift) |
148 | 0 | { /* do not encode leading zeroes */ |
149 | 0 | required++; |
150 | 0 | } |
151 | 0 | } |
152 | 0 | return required; |
153 | 0 | } |
154 | | |
155 | | /* |
156 | | * Defined in header. |
157 | | */ |
158 | | chunk_t asn1_oid_from_string(char *str) |
159 | 0 | { |
160 | 0 | enumerator_t *enumerator; |
161 | 0 | size_t buf_len = 64; |
162 | 0 | u_char buf[buf_len]; |
163 | 0 | char *end; |
164 | 0 | int i = 0, pos = 0, req, shift; |
165 | 0 | u_int val, first = 0; |
166 | |
|
167 | 0 | enumerator = enumerator_create_token(str, ".", ""); |
168 | 0 | while (enumerator->enumerate(enumerator, &str)) |
169 | 0 | { |
170 | 0 | val = strtoul(str, &end, 10); |
171 | 0 | req = bytes_required(val); |
172 | 0 | if (end == str || pos + req > buf_len) |
173 | 0 | { |
174 | 0 | pos = 0; |
175 | 0 | break; |
176 | 0 | } |
177 | 0 | switch (i++) |
178 | 0 | { |
179 | 0 | case 0: |
180 | 0 | first = val; |
181 | 0 | break; |
182 | 0 | case 1: |
183 | 0 | buf[pos++] = first * 40 + val; |
184 | 0 | break; |
185 | 0 | default: |
186 | 0 | for (shift = (req - 1) * 7; shift; shift -= 7) |
187 | 0 | { |
188 | 0 | buf[pos++] = 0x80 | ((val >> shift) & 0x7F); |
189 | 0 | } |
190 | 0 | buf[pos++] = val & 0x7F; |
191 | 0 | } |
192 | 0 | } |
193 | 0 | enumerator->destroy(enumerator); |
194 | |
|
195 | 0 | return chunk_clone(chunk_create(buf, pos)); |
196 | 0 | } |
197 | | |
198 | | /* |
199 | | * Defined in header. |
200 | | */ |
201 | | char *asn1_oid_to_string(chunk_t oid) |
202 | 1.44k | { |
203 | 1.44k | size_t len = 64; |
204 | 1.44k | char buf[len], *pos = buf; |
205 | 1.44k | int written; |
206 | 1.44k | u_int val; |
207 | | |
208 | 1.44k | if (!oid.len) |
209 | 30 | { |
210 | 30 | return NULL; |
211 | 30 | } |
212 | 1.41k | val = oid.ptr[0] / 40; |
213 | 1.41k | written = snprintf(buf, len, "%u.%u", val, oid.ptr[0] - val * 40); |
214 | 1.41k | oid = chunk_skip(oid, 1); |
215 | 1.41k | if (written < 0 || written >= len) |
216 | 0 | { |
217 | 0 | return NULL; |
218 | 0 | } |
219 | 1.41k | pos += written; |
220 | 1.41k | len -= written; |
221 | 1.41k | val = 0; |
222 | | |
223 | 7.54k | while (oid.len) |
224 | 6.19k | { |
225 | 6.19k | val = (val << 7) + (u_int)(oid.ptr[0] & 0x7f); |
226 | | |
227 | 6.19k | if (oid.ptr[0] < 128) |
228 | 4.23k | { |
229 | 4.23k | written = snprintf(pos, len, ".%u", val); |
230 | 4.23k | if (written < 0 || written >= len) |
231 | 67 | { |
232 | 67 | return NULL; |
233 | 67 | } |
234 | 4.17k | pos += written; |
235 | 4.17k | len -= written; |
236 | 4.17k | val = 0; |
237 | 4.17k | } |
238 | 6.13k | oid = chunk_skip(oid, 1); |
239 | 6.13k | } |
240 | 1.34k | return (val == 0) ? strdup(buf) : NULL; |
241 | 1.41k | } |
242 | | |
243 | | /* |
244 | | * Defined in header. |
245 | | */ |
246 | | size_t asn1_length(chunk_t *blob) |
247 | 196k | { |
248 | 196k | u_char n; |
249 | 196k | size_t len; |
250 | | |
251 | 196k | if (blob->len < 2) |
252 | 83 | { |
253 | 83 | DBG2(DBG_ASN, "insufficient number of octets to parse ASN.1 length"); |
254 | 83 | return ASN1_INVALID_LENGTH; |
255 | 83 | } |
256 | | |
257 | | /* read length field, skip tag and length */ |
258 | 196k | n = blob->ptr[1]; |
259 | 196k | blob->ptr += 2; |
260 | 196k | blob->len -= 2; |
261 | | |
262 | 196k | if ((n & 0x80) == 0) |
263 | 191k | { /* single length octet */ |
264 | 191k | if (n > blob->len) |
265 | 421 | { |
266 | 421 | DBG2(DBG_ASN, "length is larger than remaining blob size"); |
267 | 421 | return ASN1_INVALID_LENGTH; |
268 | 421 | } |
269 | 191k | return n; |
270 | 191k | } |
271 | | |
272 | | /* composite length, determine number of length octets */ |
273 | 4.27k | n &= 0x7f; |
274 | | |
275 | 4.27k | if (n == 0 || n > blob->len) |
276 | 292 | { |
277 | 292 | DBG2(DBG_ASN, "number of length octets invalid"); |
278 | 292 | return ASN1_INVALID_LENGTH; |
279 | 292 | } |
280 | | |
281 | 3.98k | if (n > sizeof(len)) |
282 | 122 | { |
283 | 122 | DBG2(DBG_ASN, "number of length octets is larger than limit of" |
284 | 122 | " %d octets", (int)sizeof(len)); |
285 | 122 | return ASN1_INVALID_LENGTH; |
286 | 122 | } |
287 | | |
288 | 3.86k | len = 0; |
289 | | |
290 | 11.3k | while (n-- > 0) |
291 | 7.51k | { |
292 | 7.51k | len = 256*len + *blob->ptr++; |
293 | 7.51k | blob->len--; |
294 | 7.51k | } |
295 | 3.86k | if (len > blob->len) |
296 | 307 | { |
297 | 307 | DBG2(DBG_ASN, "length is larger than remaining blob size"); |
298 | 307 | return ASN1_INVALID_LENGTH; |
299 | 307 | } |
300 | 3.55k | return len; |
301 | 3.86k | } |
302 | | |
303 | | /* |
304 | | * See header. |
305 | | */ |
306 | | int asn1_unwrap(chunk_t *blob, chunk_t *inner) |
307 | 4.27k | { |
308 | 4.27k | chunk_t res; |
309 | 4.27k | u_char len; |
310 | 4.27k | int type; |
311 | | |
312 | 4.27k | if (blob->len < 2) |
313 | 7 | { |
314 | 7 | return ASN1_INVALID; |
315 | 7 | } |
316 | 4.26k | type = blob->ptr[0]; |
317 | 4.26k | len = blob->ptr[1]; |
318 | 4.26k | *blob = chunk_skip(*blob, 2); |
319 | | |
320 | 4.26k | if ((len & 0x80) == 0) |
321 | 3.92k | { /* single length octet */ |
322 | 3.92k | res.len = len; |
323 | 3.92k | } |
324 | 345 | else |
325 | 345 | { /* composite length, determine number of length octets */ |
326 | 345 | len &= 0x7f; |
327 | 345 | if (len == 0 || len > blob->len || len > sizeof(res.len)) |
328 | 43 | { |
329 | 43 | return ASN1_INVALID; |
330 | 43 | } |
331 | 302 | res.len = 0; |
332 | 1.84k | while (len-- > 0) |
333 | 1.53k | { |
334 | 1.53k | res.len = 256 * res.len + blob->ptr[0]; |
335 | 1.53k | *blob = chunk_skip(*blob, 1); |
336 | 1.53k | } |
337 | 302 | } |
338 | 4.22k | if (res.len > blob->len) |
339 | 195 | { |
340 | 195 | return ASN1_INVALID; |
341 | 195 | } |
342 | 4.02k | res.ptr = blob->ptr; |
343 | 4.02k | *blob = chunk_skip(*blob, res.len); |
344 | | /* updating inner not before we are finished allows a caller to pass |
345 | | * blob = inner */ |
346 | 4.02k | *inner = res; |
347 | 4.02k | return type; |
348 | 4.22k | } |
349 | | |
350 | | static const int days[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; |
351 | | static const int tm_leap_1970 = 477; |
352 | | |
353 | | /** |
354 | | * Converts ASN.1 UTCTIME or GENERALIZEDTIME into calendar time |
355 | | */ |
356 | | time_t asn1_to_time(const chunk_t *utctime, asn1_t type) |
357 | 61.3k | { |
358 | 61.3k | int tm_year, tm_mon, tm_day, tm_hour, tm_min, tm_sec; |
359 | 61.3k | int tm_leap_4, tm_leap_100, tm_leap_400, tm_leap; |
360 | 61.3k | int tz_hour, tz_min, tz_offset; |
361 | 61.3k | time_t tm_days, tm_secs; |
362 | 61.3k | char buf[BUF_LEN], *eot = NULL; |
363 | | |
364 | 61.3k | snprintf(buf, sizeof(buf), "%.*s", (int)utctime->len, utctime->ptr); |
365 | | |
366 | 61.3k | if ((eot = strchr(buf, 'Z')) != NULL) |
367 | 58.3k | { |
368 | 58.3k | tz_offset = 0; /* Zulu time with a zero time zone offset */ |
369 | 58.3k | } |
370 | 3.00k | else if ((eot = strchr(buf, '+')) != NULL) |
371 | 578 | { |
372 | 578 | if (sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min) != 2) |
373 | 222 | { |
374 | 222 | return 0; /* error in positive timezone offset format */ |
375 | 222 | } |
376 | 356 | tz_offset = 3600*tz_hour + 60*tz_min; /* positive time zone offset */ |
377 | 356 | } |
378 | 2.42k | else if ((eot = strchr(buf, '-')) != NULL) |
379 | 832 | { |
380 | 832 | if (sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min) != 2) |
381 | 290 | { |
382 | 290 | return 0; /* error in negative timezone offset format */ |
383 | 290 | } |
384 | 542 | tz_offset = -3600*tz_hour - 60*tz_min; /* negative time zone offset */ |
385 | 542 | } |
386 | 1.59k | else |
387 | 1.59k | { |
388 | 1.59k | return 0; /* error in time format */ |
389 | 1.59k | } |
390 | | |
391 | | /* parse ASN.1 time string */ |
392 | 59.2k | { |
393 | 59.2k | const char* format = (type == ASN1_UTCTIME)? "%2d%2d%2d%2d%2d": |
394 | 59.2k | "%4d%2d%2d%2d%2d"; |
395 | | |
396 | 59.2k | if (sscanf(buf, format, &tm_year, &tm_mon, &tm_day, |
397 | 59.2k | &tm_hour, &tm_min) != 5) |
398 | 1.84k | { |
399 | 1.84k | return 0; /* error in [yy]yymmddhhmm time format */ |
400 | 1.84k | } |
401 | 59.2k | } |
402 | | |
403 | | /* is there a seconds field? */ |
404 | 57.4k | if ((eot - buf) == ((type == ASN1_UTCTIME)?12:14)) |
405 | 56.3k | { |
406 | 56.3k | if (sscanf(eot-2, "%2d", &tm_sec) != 1) |
407 | 382 | { |
408 | 382 | return 0; /* error in ss seconds field format */ |
409 | 382 | } |
410 | 56.3k | } |
411 | 1.10k | else |
412 | 1.10k | { |
413 | 1.10k | tm_sec = 0; |
414 | 1.10k | } |
415 | | |
416 | | /* representation of two-digit years */ |
417 | 57.0k | if (type == ASN1_UTCTIME) |
418 | 56.2k | { |
419 | 56.2k | tm_year += (tm_year < 50) ? 2000 : 1900; |
420 | 56.2k | } |
421 | | |
422 | | /* prevent obvious 32 bit integer overflows */ |
423 | 57.0k | if (sizeof(time_t) == 4 && (tm_year > 2038 || tm_year < 1901)) |
424 | 0 | { |
425 | 0 | return TIME_32_BIT_SIGNED_MAX; |
426 | 0 | } |
427 | | |
428 | | /* representation of months as 0..11*/ |
429 | 57.0k | if (tm_mon < 1 || tm_mon > 12) |
430 | 790 | { |
431 | 790 | return 0; |
432 | 790 | } |
433 | 56.2k | tm_mon--; |
434 | | |
435 | | /* representation of days as 0..30 */ |
436 | 56.2k | if (tm_day < 1 || tm_day > 31) |
437 | 862 | { /* we don't actually validate the day in relation to tm_year/tm_mon */ |
438 | 862 | return 0; |
439 | 862 | } |
440 | 55.3k | tm_day--; |
441 | | |
442 | 55.3k | if (tm_hour < 0 || tm_hour > 23 || |
443 | 55.3k | tm_min < 0 || tm_min > 59 || |
444 | 55.3k | tm_sec < 0 || tm_sec > 60 /* allow leap seconds */) |
445 | 1.30k | { |
446 | 1.30k | return 0; |
447 | 1.30k | } |
448 | | |
449 | | /* number of leap years between last year and 1970? */ |
450 | 54.0k | tm_leap_4 = (tm_year - 1) / 4; |
451 | 54.0k | tm_leap_100 = tm_leap_4 / 25; |
452 | 54.0k | tm_leap_400 = tm_leap_100 / 4; |
453 | 54.0k | tm_leap = tm_leap_4 - tm_leap_100 + tm_leap_400 - tm_leap_1970; |
454 | | |
455 | | /* if date later then February, is the current year a leap year? */ |
456 | 54.0k | if (tm_mon > 1 && (tm_year % 4 == 0) && |
457 | 54.0k | (tm_year % 100 != 0 || tm_year % 400 == 0)) |
458 | 10.7k | { |
459 | 10.7k | tm_leap++; |
460 | 10.7k | } |
461 | 54.0k | tm_days = 365 * (tm_year - 1970) + days[tm_mon] + tm_day + tm_leap; |
462 | 54.0k | tm_secs = 60 * (60 * (24 * tm_days + tm_hour) + tm_min) + tm_sec - tz_offset; |
463 | | |
464 | 54.0k | if (sizeof(time_t) == 4) |
465 | 0 | { /* has a 32 bit signed integer overflow occurred? */ |
466 | 0 | if (tm_year > 1970 && tm_secs < 0) |
467 | 0 | { /* depending on the time zone, the first days in 1970 may result in |
468 | | * a negative value, but dates after 1970 never will */ |
469 | 0 | return TIME_32_BIT_SIGNED_MAX; |
470 | 0 | } |
471 | 0 | if (tm_year < 1969 && tm_secs > 0) |
472 | 0 | { /* similarly, tm_secs is not positive for dates before 1970, except |
473 | | * for the last days in 1969, depending on the time zone */ |
474 | 0 | return TIME_32_BIT_SIGNED_MAX; |
475 | 0 | } |
476 | 0 | } |
477 | 54.0k | return tm_secs; |
478 | 54.0k | } |
479 | | |
480 | | /** |
481 | | * Convert a date into ASN.1 UTCTIME or GENERALIZEDTIME format |
482 | | */ |
483 | | chunk_t asn1_from_time(const time_t *time, asn1_t type) |
484 | 0 | { |
485 | 0 | int offset; |
486 | 0 | const char *format; |
487 | 0 | char buf[BUF_LEN]; |
488 | 0 | chunk_t formatted_time; |
489 | 0 | struct tm t = {}; |
490 | |
|
491 | 0 | gmtime_r(time, &t); |
492 | | /* RFC 5280 says that dates through the year 2049 MUST be encoded as UTCTIME |
493 | | * and dates in 2050 or later MUST be encoded as GENERALIZEDTIME. We only |
494 | | * enforce the latter to avoid overflows but allow callers to force the |
495 | | * encoding to GENERALIZEDTIME */ |
496 | 0 | type = (t.tm_year >= 150) ? ASN1_GENERALIZEDTIME : type; |
497 | 0 | if (type == ASN1_GENERALIZEDTIME) |
498 | 0 | { |
499 | 0 | format = "%04d%02d%02d%02d%02d%02dZ"; |
500 | 0 | offset = 1900; |
501 | 0 | } |
502 | 0 | else /* ASN1_UTCTIME */ |
503 | 0 | { |
504 | 0 | format = "%02d%02d%02d%02d%02d%02dZ"; |
505 | 0 | offset = (t.tm_year < 100) ? 0 : -100; |
506 | 0 | } |
507 | 0 | snprintf(buf, BUF_LEN, format, t.tm_year + offset, |
508 | 0 | t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec); |
509 | 0 | formatted_time.ptr = buf; |
510 | 0 | formatted_time.len = strlen(buf); |
511 | 0 | return asn1_simple_object(type, formatted_time); |
512 | 0 | } |
513 | | |
514 | | /* |
515 | | * Defined in header. |
516 | | */ |
517 | | void asn1_debug_simple_object(chunk_t object, asn1_t type, bool private) |
518 | 90.5k | { |
519 | 90.5k | int oid; |
520 | | |
521 | 90.5k | switch (type) |
522 | 90.5k | { |
523 | 13.9k | case ASN1_OID: |
524 | 13.9k | oid = asn1_known_oid(object); |
525 | 13.9k | if (oid == OID_UNKNOWN) |
526 | 1.44k | { |
527 | 1.44k | char *oid_str = asn1_oid_to_string(object); |
528 | | |
529 | 1.44k | if (!oid_str) |
530 | 491 | { |
531 | 491 | break; |
532 | 491 | } |
533 | 954 | DBG2(DBG_ASN, " %s", oid_str); |
534 | 954 | free(oid_str); |
535 | 954 | } |
536 | 12.5k | else |
537 | 12.5k | { |
538 | 12.5k | DBG2(DBG_ASN, " '%s'", oid_names[oid].name); |
539 | 12.5k | } |
540 | 13.5k | return; |
541 | 13.5k | case ASN1_UTF8STRING: |
542 | 0 | case ASN1_IA5STRING: |
543 | 0 | case ASN1_PRINTABLESTRING: |
544 | 0 | case ASN1_T61STRING: |
545 | 0 | case ASN1_VISIBLESTRING: |
546 | 0 | DBG2(DBG_ASN, " '%.*s'", (int)object.len, object.ptr); |
547 | 0 | return; |
548 | 30.0k | case ASN1_UTCTIME: |
549 | 30.6k | case ASN1_GENERALIZEDTIME: |
550 | 30.6k | { |
551 | 30.6k | #if DEBUG_LEVEL >= 2 |
552 | 30.6k | time_t time = asn1_to_time(&object, type); |
553 | 30.6k | DBG2(DBG_ASN, " '%T'", &time, TRUE); |
554 | 30.6k | #endif |
555 | 30.6k | } |
556 | 30.6k | return; |
557 | 45.8k | default: |
558 | 45.8k | break; |
559 | 90.5k | } |
560 | 46.3k | if (private) |
561 | 0 | { |
562 | 0 | DBG4(DBG_ASN, "%B", &object); |
563 | 0 | } |
564 | 46.3k | else |
565 | 46.3k | { |
566 | 46.3k | DBG3(DBG_ASN, "%B", &object); |
567 | 46.3k | } |
568 | 46.3k | } |
569 | | |
570 | | /** |
571 | | * parse an ASN.1 simple type |
572 | | */ |
573 | | bool asn1_parse_simple_object(chunk_t *object, asn1_t type, u_int level, const char* name) |
574 | 75 | { |
575 | 75 | size_t len; |
576 | | |
577 | | /* an ASN.1 object must possess at least a tag and length field */ |
578 | 75 | if (object->len < 2) |
579 | 2 | { |
580 | 2 | DBG2(DBG_ASN, "L%d - %s: ASN.1 object smaller than 2 octets", level, |
581 | 2 | name); |
582 | 2 | return FALSE; |
583 | 2 | } |
584 | | |
585 | 73 | if (*object->ptr != type) |
586 | 12 | { |
587 | 12 | DBG2(DBG_ASN, "L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x", |
588 | 12 | level, name, type, *object->ptr); |
589 | 12 | return FALSE; |
590 | 12 | } |
591 | | |
592 | 61 | len = asn1_length(object); |
593 | | |
594 | 61 | if (len == ASN1_INVALID_LENGTH) |
595 | 2 | { |
596 | 2 | DBG2(DBG_ASN, "L%d - %s: length of ASN.1 object invalid or too large", |
597 | 2 | level, name); |
598 | 2 | return FALSE; |
599 | 2 | } |
600 | | |
601 | 59 | DBG2(DBG_ASN, "L%d - %s:", level, name); |
602 | 59 | asn1_debug_simple_object(*object, type, FALSE); |
603 | 59 | return TRUE; |
604 | 61 | } |
605 | | |
606 | | /* |
607 | | * Described in header |
608 | | */ |
609 | | uint64_t asn1_parse_integer_uint64(chunk_t blob) |
610 | 234 | { |
611 | 234 | uint64_t val = 0; |
612 | 234 | int i; |
613 | | |
614 | 5.95k | for (i = 0; i < blob.len; i++) |
615 | 5.71k | { /* if it is longer than 8 bytes, we just use the 8 LSBs */ |
616 | 5.71k | val <<= 8; |
617 | 5.71k | val |= (uint64_t)blob.ptr[i]; |
618 | 5.71k | } |
619 | 234 | return val; |
620 | 234 | } |
621 | | |
622 | | /* |
623 | | * Described in header |
624 | | */ |
625 | | chunk_t asn1_integer_from_uint64(uint64_t val) |
626 | 0 | { |
627 | 0 | u_char buf[sizeof(val)]; |
628 | 0 | chunk_t enc = chunk_empty; |
629 | |
|
630 | 0 | if (val < 0x100) |
631 | 0 | { |
632 | 0 | buf[0] = (u_char)val; |
633 | 0 | return chunk_clone(chunk_create(buf, 1)); |
634 | 0 | } |
635 | 0 | for (enc.ptr = buf + sizeof(val); val; enc.len++, val >>= 8) |
636 | 0 | { /* fill the buffer from the end */ |
637 | 0 | *(--enc.ptr) = val & 0xff; |
638 | 0 | } |
639 | 0 | return chunk_clone(enc); |
640 | 0 | } |
641 | | |
642 | | /* |
643 | | * Described in header |
644 | | */ |
645 | | int asn1_parse_algorithmIdentifier(chunk_t blob, int level0, chunk_t *parameters) |
646 | 2.21k | { |
647 | 2.21k | chunk_t object; |
648 | 2.21k | int alg = OID_UNKNOWN; |
649 | | |
650 | 2.21k | if (asn1_unwrap(&blob, &blob) == ASN1_SEQUENCE) |
651 | 2.05k | { |
652 | 2.05k | if (level0 >= 0) |
653 | 2.05k | { |
654 | 2.05k | DBG2(DBG_ASN, "L%d - algorithmIdentifier:", level0); |
655 | 2.05k | } |
656 | | |
657 | 2.05k | if (asn1_unwrap(&blob, &object) == ASN1_OID) |
658 | 1.85k | { |
659 | 1.85k | if (level0 >= 0) |
660 | 1.85k | { |
661 | 1.85k | DBG2(DBG_ASN, "L%d - algorithm:", level0+1); |
662 | 1.85k | asn1_debug_simple_object(object, ASN1_OID, FALSE); |
663 | 1.85k | } |
664 | 1.85k | alg = asn1_known_oid(object); |
665 | | |
666 | 1.85k | if (blob.len) |
667 | 1.38k | { |
668 | 1.38k | if (level0 >= 0) |
669 | 1.38k | { |
670 | 1.38k | DBG2(DBG_ASN, "L%d - parameters:", level0+1); |
671 | 1.38k | DBG3(DBG_ASN, "%B", &blob); |
672 | 1.38k | } |
673 | 1.38k | if (parameters) |
674 | 1.23k | { |
675 | 1.23k | *parameters = blob; |
676 | 1.23k | } |
677 | 1.38k | } |
678 | 1.85k | } |
679 | 2.05k | } |
680 | 2.21k | return alg; |
681 | 2.21k | } |
682 | | |
683 | | /* |
684 | | * tests if a blob contains a valid ASN.1 set or sequence |
685 | | */ |
686 | | bool is_asn1(chunk_t blob) |
687 | 3.89k | { |
688 | 3.89k | u_int len; |
689 | 3.89k | u_char tag; |
690 | | |
691 | 3.89k | if (!blob.len || !blob.ptr) |
692 | 0 | { |
693 | 0 | return FALSE; |
694 | 0 | } |
695 | | |
696 | 3.89k | tag = *blob.ptr; |
697 | 3.89k | if (tag != ASN1_SEQUENCE && tag != ASN1_SET && tag != ASN1_OCTET_STRING) |
698 | 1.94k | { |
699 | 1.94k | DBG2(DBG_ASN, " file content is not binary ASN.1"); |
700 | 1.94k | return FALSE; |
701 | 1.94k | } |
702 | | |
703 | 1.95k | len = asn1_length(&blob); |
704 | | |
705 | 1.95k | if (len == ASN1_INVALID_LENGTH) |
706 | 177 | { |
707 | 177 | return FALSE; |
708 | 177 | } |
709 | | |
710 | | /* exact match */ |
711 | 1.77k | if (len == blob.len) |
712 | 1.66k | { |
713 | 1.66k | return TRUE; |
714 | 1.66k | } |
715 | | |
716 | | /* some websites append a surplus newline character to the blob */ |
717 | 117 | if (len + 1 == blob.len && *(blob.ptr + len) == '\n') |
718 | 11 | { |
719 | 11 | return TRUE; |
720 | 11 | } |
721 | | |
722 | 106 | DBG2(DBG_ASN, " file size does not match ASN.1 coded length"); |
723 | 106 | return FALSE; |
724 | 117 | } |
725 | | |
726 | | /* |
727 | | * Defined in header. |
728 | | */ |
729 | | bool asn1_is_printablestring(chunk_t str) |
730 | 0 | { |
731 | 0 | const char printablestring_charset[] = |
732 | 0 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 '()+,-./:=?"; |
733 | 0 | u_int i; |
734 | |
|
735 | 0 | for (i = 0; i < str.len; i++) |
736 | 0 | { |
737 | 0 | if (strchr(printablestring_charset, str.ptr[i]) == NULL) |
738 | 0 | { |
739 | 0 | return FALSE; |
740 | 0 | } |
741 | 0 | } |
742 | 0 | return TRUE; |
743 | 0 | } |
744 | | |
745 | | /** |
746 | | * codes ASN.1 lengths up to a size of 16'777'215 bytes |
747 | | */ |
748 | | static void asn1_code_length(size_t length, chunk_t *code) |
749 | 0 | { |
750 | 0 | if (length < 128) |
751 | 0 | { |
752 | 0 | code->ptr[0] = length; |
753 | 0 | code->len = 1; |
754 | 0 | } |
755 | 0 | else if (length < 256) |
756 | 0 | { |
757 | 0 | code->ptr[0] = 0x81; |
758 | 0 | code->ptr[1] = (u_char) length; |
759 | 0 | code->len = 2; |
760 | 0 | } |
761 | 0 | else if (length < 65536) |
762 | 0 | { |
763 | 0 | code->ptr[0] = 0x82; |
764 | 0 | code->ptr[1] = length >> 8; |
765 | 0 | code->ptr[2] = length & 0x00ff; |
766 | 0 | code->len = 3; |
767 | 0 | } |
768 | 0 | else |
769 | 0 | { |
770 | 0 | code->ptr[0] = 0x83; |
771 | 0 | code->ptr[1] = length >> 16; |
772 | 0 | code->ptr[2] = (length >> 8) & 0x00ff; |
773 | 0 | code->ptr[3] = length & 0x0000ff; |
774 | 0 | code->len = 4; |
775 | 0 | } |
776 | 0 | } |
777 | | |
778 | | /** |
779 | | * build an empty asn.1 object with tag and length fields already filled in |
780 | | */ |
781 | | u_char* asn1_build_object(chunk_t *object, asn1_t type, size_t datalen) |
782 | 0 | { |
783 | 0 | u_char length_buf[4]; |
784 | 0 | chunk_t length = { length_buf, 0 }; |
785 | 0 | u_char *pos; |
786 | | |
787 | | /* code the asn.1 length field */ |
788 | 0 | asn1_code_length(datalen, &length); |
789 | | |
790 | | /* allocate memory for the asn.1 TLV object */ |
791 | 0 | object->len = 1 + length.len + datalen; |
792 | 0 | object->ptr = malloc(object->len); |
793 | | |
794 | | /* set position pointer at the start of the object */ |
795 | 0 | pos = object->ptr; |
796 | | |
797 | | /* copy the asn.1 tag field and advance the pointer */ |
798 | 0 | *pos++ = type; |
799 | | |
800 | | /* copy the asn.1 length field and advance the pointer */ |
801 | 0 | memcpy(pos, length.ptr, length.len); |
802 | 0 | pos += length.len; |
803 | |
|
804 | 0 | return pos; |
805 | 0 | } |
806 | | |
807 | | /** |
808 | | * Build a simple ASN.1 object |
809 | | */ |
810 | | chunk_t asn1_simple_object(asn1_t tag, chunk_t content) |
811 | 0 | { |
812 | 0 | chunk_t object; |
813 | |
|
814 | 0 | u_char *pos = asn1_build_object(&object, tag, content.len); |
815 | 0 | memcpy(pos, content.ptr, content.len); |
816 | |
|
817 | 0 | return object; |
818 | 0 | } |
819 | | |
820 | | /** |
821 | | * Build an ASN.1 BIT_STRING object |
822 | | */ |
823 | | chunk_t asn1_bitstring(const char *mode, chunk_t content) |
824 | 0 | { |
825 | 0 | chunk_t object; |
826 | 0 | u_char *pos = asn1_build_object(&object, ASN1_BIT_STRING, 1 + content.len); |
827 | |
|
828 | 0 | *pos++ = 0x00; |
829 | 0 | memcpy(pos, content.ptr, content.len); |
830 | 0 | if (*mode == 'm') |
831 | 0 | { |
832 | 0 | free(content.ptr); |
833 | 0 | } |
834 | 0 | return object; |
835 | 0 | } |
836 | | |
837 | | /** |
838 | | * Build an ASN.1 INTEGER object |
839 | | */ |
840 | | chunk_t asn1_integer(const char *mode, chunk_t content) |
841 | 0 | { |
842 | 0 | chunk_t zero = chunk_from_chars(0x00), object; |
843 | 0 | size_t len; |
844 | 0 | u_char *pos; |
845 | 0 | bool move; |
846 | |
|
847 | 0 | if (content.len == 0) |
848 | 0 | { /* make sure 0 is encoded properly */ |
849 | 0 | content = zero; |
850 | 0 | move = FALSE; |
851 | 0 | } |
852 | 0 | else |
853 | 0 | { |
854 | 0 | move = (*mode == 'm'); |
855 | 0 | } |
856 | | |
857 | | /* ASN.1 integers must be positive numbers in two's complement */ |
858 | 0 | len = content.len + ((*content.ptr & 0x80) ? 1 : 0); |
859 | 0 | pos = asn1_build_object(&object, ASN1_INTEGER, len); |
860 | 0 | if (len > content.len) |
861 | 0 | { |
862 | 0 | *pos++ = 0x00; |
863 | 0 | } |
864 | 0 | memcpy(pos, content.ptr, content.len); |
865 | |
|
866 | 0 | if (move) |
867 | 0 | { |
868 | 0 | free(content.ptr); |
869 | 0 | } |
870 | 0 | return object; |
871 | 0 | } |
872 | | |
873 | | /** |
874 | | * Build an ASN.1 object from a variable number of individual chunks. |
875 | | * Depending on the mode, chunks either are moved ('m') or copied ('c'). |
876 | | */ |
877 | | chunk_t asn1_wrap(asn1_t type, const char *mode, ...) |
878 | 0 | { |
879 | 0 | chunk_t construct; |
880 | 0 | va_list chunks; |
881 | 0 | u_char *pos; |
882 | 0 | int i; |
883 | 0 | int count = strlen(mode); |
884 | | |
885 | | /* sum up lengths of individual chunks */ |
886 | 0 | va_start(chunks, mode); |
887 | 0 | construct.len = 0; |
888 | 0 | for (i = 0; i < count; i++) |
889 | 0 | { |
890 | 0 | chunk_t ch = va_arg(chunks, chunk_t); |
891 | 0 | construct.len += ch.len; |
892 | 0 | } |
893 | 0 | va_end(chunks); |
894 | | |
895 | | /* allocate needed memory for construct */ |
896 | 0 | pos = asn1_build_object(&construct, type, construct.len); |
897 | | |
898 | | /* copy or move the chunks */ |
899 | 0 | va_start(chunks, mode); |
900 | 0 | for (i = 0; i < count; i++) |
901 | 0 | { |
902 | 0 | chunk_t ch = va_arg(chunks, chunk_t); |
903 | |
|
904 | 0 | memcpy(pos, ch.ptr, ch.len); |
905 | 0 | pos += ch.len; |
906 | |
|
907 | 0 | switch (*mode++) |
908 | 0 | { |
909 | 0 | case 's': |
910 | 0 | chunk_clear(&ch); |
911 | 0 | break; |
912 | 0 | case 'm': |
913 | 0 | free(ch.ptr); |
914 | 0 | break; |
915 | 0 | default: |
916 | 0 | break; |
917 | 0 | } |
918 | 0 | } |
919 | 0 | va_end(chunks); |
920 | |
|
921 | 0 | return construct; |
922 | 0 | } |
923 | | |
924 | | /** |
925 | | * ASN.1 definition of time |
926 | | */ |
927 | | static const asn1Object_t timeObjects[] = { |
928 | | { 0, "utcTime", ASN1_UTCTIME, ASN1_OPT|ASN1_BODY }, /* 0 */ |
929 | | { 0, "end opt", ASN1_EOC, ASN1_END }, /* 1 */ |
930 | | { 0, "generalizeTime", ASN1_GENERALIZEDTIME, ASN1_OPT|ASN1_BODY }, /* 2 */ |
931 | | { 0, "end opt", ASN1_EOC, ASN1_END }, /* 3 */ |
932 | | { 0, "exit", ASN1_EOC, ASN1_EXIT } |
933 | | }; |
934 | | #ifdef TIME_UTC |
935 | | /* used by C11 timespec_get(), <time.h> */ |
936 | | # undef TIME_UTC |
937 | | #endif |
938 | 220k | #define TIME_UTC 0 |
939 | 64.8k | #define TIME_GENERALIZED 2 |
940 | | |
941 | | /** |
942 | | * extracts and converts a UTCTIME or GENERALIZEDTIME object |
943 | | */ |
944 | | time_t asn1_parse_time(chunk_t blob, int level0) |
945 | 32.1k | { |
946 | 32.1k | asn1_parser_t *parser; |
947 | 32.1k | chunk_t object; |
948 | 32.1k | int objectID; |
949 | 32.1k | time_t utc_time = 0; |
950 | | |
951 | 32.1k | parser= asn1_parser_create(timeObjects, blob); |
952 | 32.1k | parser->set_top_level(parser, level0); |
953 | | |
954 | 127k | while (parser->iterate(parser, &objectID, &object)) |
955 | 94.9k | { |
956 | 94.9k | if (objectID == TIME_UTC || objectID == TIME_GENERALIZED) |
957 | 30.6k | { |
958 | 30.6k | utc_time = asn1_to_time(&object, (objectID == TIME_UTC) |
959 | 30.6k | ? ASN1_UTCTIME : ASN1_GENERALIZEDTIME); |
960 | 30.6k | } |
961 | 94.9k | } |
962 | 32.1k | parser->destroy(parser); |
963 | 32.1k | return utc_time; |
964 | 32.1k | } |