/src/libressl/crypto/bytestring/bs_cbs.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* $OpenBSD: bs_cbs.c,v 1.2 2021/12/15 18:02:39 jsing Exp $ */ |
2 | | /* |
3 | | * Copyright (c) 2014, Google Inc. |
4 | | * |
5 | | * Permission to use, copy, modify, and/or distribute this software for any |
6 | | * purpose with or without fee is hereby granted, provided that the above |
7 | | * copyright notice and this permission notice appear in all copies. |
8 | | * |
9 | | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
10 | | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
11 | | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
12 | | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
13 | | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
14 | | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
15 | | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 | | */ |
17 | | |
18 | | #include <stdlib.h> |
19 | | #include <string.h> |
20 | | |
21 | | #include "bytestring.h" |
22 | | |
23 | | void |
24 | | CBS_init(CBS *cbs, const uint8_t *data, size_t len) |
25 | 17.0M | { |
26 | 17.0M | cbs->data = data; |
27 | 17.0M | cbs->initial_len = len; |
28 | 17.0M | cbs->len = len; |
29 | 17.0M | } |
30 | | |
31 | | void |
32 | | CBS_dup(const CBS *cbs, CBS *out) |
33 | 2.01M | { |
34 | 2.01M | CBS_init(out, CBS_data(cbs), CBS_len(cbs)); |
35 | 2.01M | out->initial_len = cbs->initial_len; |
36 | 2.01M | } |
37 | | |
38 | | static int |
39 | | cbs_get(CBS *cbs, const uint8_t **p, size_t n) |
40 | 31.1M | { |
41 | 31.1M | if (cbs->len < n) |
42 | 12.4k | return 0; |
43 | | |
44 | 31.1M | *p = cbs->data; |
45 | 31.1M | cbs->data += n; |
46 | 31.1M | cbs->len -= n; |
47 | 31.1M | return 1; |
48 | 31.1M | } |
49 | | |
50 | | static int |
51 | | cbs_peek(CBS *cbs, const uint8_t **p, size_t n) |
52 | 7.95M | { |
53 | 7.95M | if (cbs->len < n) |
54 | 31.6k | return 0; |
55 | | |
56 | 7.92M | *p = cbs->data; |
57 | 7.92M | return 1; |
58 | 7.95M | } |
59 | | |
60 | | size_t |
61 | | CBS_offset(const CBS *cbs) |
62 | 6.25M | { |
63 | 6.25M | return cbs->initial_len - cbs->len; |
64 | 6.25M | } |
65 | | |
66 | | int |
67 | | CBS_skip(CBS *cbs, size_t len) |
68 | 7.06M | { |
69 | 7.06M | const uint8_t *dummy; |
70 | 7.06M | return cbs_get(cbs, &dummy, len); |
71 | 7.06M | } |
72 | | |
73 | | const uint8_t * |
74 | | CBS_data(const CBS *cbs) |
75 | 9.88M | { |
76 | 9.88M | return cbs->data; |
77 | 9.88M | } |
78 | | |
79 | | size_t |
80 | | CBS_len(const CBS *cbs) |
81 | 35.0M | { |
82 | 35.0M | return cbs->len; |
83 | 35.0M | } |
84 | | |
85 | | int |
86 | | CBS_stow(const CBS *cbs, uint8_t **out_ptr, size_t *out_len) |
87 | 721k | { |
88 | 721k | free(*out_ptr); |
89 | 721k | *out_ptr = NULL; |
90 | 721k | *out_len = 0; |
91 | | |
92 | 721k | if (cbs->len == 0) |
93 | 4.37k | return 1; |
94 | | |
95 | 717k | if ((*out_ptr = malloc(cbs->len)) == NULL) |
96 | 0 | return 0; |
97 | | |
98 | 717k | memcpy(*out_ptr, cbs->data, cbs->len); |
99 | | |
100 | 717k | *out_len = cbs->len; |
101 | 717k | return 1; |
102 | 717k | } |
103 | | |
104 | | int |
105 | | CBS_strdup(const CBS *cbs, char **out_ptr) |
106 | 0 | { |
107 | 0 | free(*out_ptr); |
108 | 0 | *out_ptr = NULL; |
109 | |
|
110 | 0 | if (CBS_contains_zero_byte(cbs)) |
111 | 0 | return 0; |
112 | | |
113 | 0 | *out_ptr = strndup((const char *)cbs->data, cbs->len); |
114 | 0 | return (*out_ptr != NULL); |
115 | 0 | } |
116 | | |
117 | | int |
118 | | CBS_write_bytes(const CBS *cbs, uint8_t *dst, size_t dst_len, size_t *copied) |
119 | 0 | { |
120 | 0 | if (dst_len < cbs->len) |
121 | 0 | return 0; |
122 | | |
123 | 0 | memmove(dst, cbs->data, cbs->len); |
124 | |
|
125 | 0 | if (copied != NULL) |
126 | 0 | *copied = cbs->len; |
127 | |
|
128 | 0 | return 1; |
129 | 0 | } |
130 | | |
131 | | int |
132 | | CBS_contains_zero_byte(const CBS *cbs) |
133 | 0 | { |
134 | 0 | return memchr(cbs->data, 0, cbs->len) != NULL; |
135 | 0 | } |
136 | | |
137 | | int |
138 | | CBS_mem_equal(const CBS *cbs, const uint8_t *data, size_t len) |
139 | 0 | { |
140 | 0 | if (len != cbs->len) |
141 | 0 | return 0; |
142 | | |
143 | 0 | return timingsafe_memcmp(cbs->data, data, len) == 0; |
144 | 0 | } |
145 | | |
146 | | static int |
147 | | cbs_get_u(CBS *cbs, uint32_t *out, size_t len) |
148 | 3.32k | { |
149 | 3.32k | uint32_t result = 0; |
150 | 3.32k | size_t i; |
151 | 3.32k | const uint8_t *data; |
152 | | |
153 | 3.32k | if (len < 1 || len > 4) |
154 | 0 | return 0; |
155 | | |
156 | 3.32k | if (!cbs_get(cbs, &data, len)) |
157 | 810 | return 0; |
158 | | |
159 | 7.58k | for (i = 0; i < len; i++) { |
160 | 5.06k | result <<= 8; |
161 | 5.06k | result |= data[i]; |
162 | 5.06k | } |
163 | 2.51k | *out = result; |
164 | 2.51k | return 1; |
165 | 3.32k | } |
166 | | |
167 | | int |
168 | | CBS_get_u8(CBS *cbs, uint8_t *out) |
169 | 17.7M | { |
170 | 17.7M | const uint8_t *v; |
171 | | |
172 | 17.7M | if (!cbs_get(cbs, &v, 1)) |
173 | 11.2k | return 0; |
174 | | |
175 | 17.7M | *out = *v; |
176 | 17.7M | return 1; |
177 | 17.7M | } |
178 | | |
179 | | int |
180 | | CBS_get_u16(CBS *cbs, uint16_t *out) |
181 | 0 | { |
182 | 0 | uint32_t v; |
183 | |
|
184 | 0 | if (!cbs_get_u(cbs, &v, 2)) |
185 | 0 | return 0; |
186 | | |
187 | 0 | *out = v; |
188 | 0 | return 1; |
189 | 0 | } |
190 | | |
191 | | int |
192 | | CBS_get_u24(CBS *cbs, uint32_t *out) |
193 | 0 | { |
194 | 0 | return cbs_get_u(cbs, out, 3); |
195 | 0 | } |
196 | | |
197 | | int |
198 | | CBS_get_u32(CBS *cbs, uint32_t *out) |
199 | 16 | { |
200 | 16 | return cbs_get_u(cbs, out, 4); |
201 | 16 | } |
202 | | |
203 | | int |
204 | | CBS_get_u64(CBS *cbs, uint64_t *out) |
205 | 10 | { |
206 | 10 | uint32_t a, b; |
207 | | |
208 | 10 | if (cbs->len < 8) |
209 | 2 | return 0; |
210 | | |
211 | 8 | if (!CBS_get_u32(cbs, &a)) |
212 | 0 | return 0; |
213 | 8 | if (!CBS_get_u32(cbs, &b)) |
214 | 0 | return 0; |
215 | | |
216 | 8 | *out = (uint64_t)a << 32 | b; |
217 | 8 | return 1; |
218 | 8 | } |
219 | | |
220 | | int |
221 | | CBS_get_last_u8(CBS *cbs, uint8_t *out) |
222 | 0 | { |
223 | 0 | if (cbs->len == 0) |
224 | 0 | return 0; |
225 | | |
226 | 0 | *out = cbs->data[cbs->len - 1]; |
227 | 0 | cbs->len--; |
228 | 0 | return 1; |
229 | 0 | } |
230 | | |
231 | | int |
232 | | CBS_get_bytes(CBS *cbs, CBS *out, size_t len) |
233 | 6.33M | { |
234 | 6.33M | const uint8_t *v; |
235 | | |
236 | 6.33M | if (!cbs_get(cbs, &v, len)) |
237 | 404 | return 0; |
238 | | |
239 | 6.33M | CBS_init(out, v, len); |
240 | 6.33M | return 1; |
241 | 6.33M | } |
242 | | |
243 | | static int |
244 | | cbs_get_length_prefixed(CBS *cbs, CBS *out, size_t len_len) |
245 | 3.31k | { |
246 | 3.31k | uint32_t len; |
247 | | |
248 | 3.31k | if (!cbs_get_u(cbs, &len, len_len)) |
249 | 810 | return 0; |
250 | | |
251 | 2.50k | return CBS_get_bytes(cbs, out, len); |
252 | 3.31k | } |
253 | | |
254 | | int |
255 | | CBS_get_u8_length_prefixed(CBS *cbs, CBS *out) |
256 | 0 | { |
257 | 0 | return cbs_get_length_prefixed(cbs, out, 1); |
258 | 0 | } |
259 | | |
260 | | int |
261 | | CBS_get_u16_length_prefixed(CBS *cbs, CBS *out) |
262 | 3.31k | { |
263 | 3.31k | return cbs_get_length_prefixed(cbs, out, 2); |
264 | 3.31k | } |
265 | | |
266 | | int |
267 | | CBS_get_u24_length_prefixed(CBS *cbs, CBS *out) |
268 | 0 | { |
269 | 0 | return cbs_get_length_prefixed(cbs, out, 3); |
270 | 0 | } |
271 | | |
272 | | static int |
273 | | cbs_peek_u(CBS *cbs, uint32_t *out, size_t len) |
274 | 7.88M | { |
275 | 7.88M | uint32_t result = 0; |
276 | 7.88M | size_t i; |
277 | 7.88M | const uint8_t *data; |
278 | | |
279 | 7.88M | if (len < 1 || len > 4) |
280 | 0 | return 0; |
281 | | |
282 | 7.88M | if (!cbs_peek(cbs, &data, len)) |
283 | 31.2k | return 0; |
284 | | |
285 | 23.5M | for (i = 0; i < len; i++) { |
286 | 15.7M | result <<= 8; |
287 | 15.7M | result |= data[i]; |
288 | 15.7M | } |
289 | 7.85M | *out = result; |
290 | 7.85M | return 1; |
291 | 7.88M | } |
292 | | |
293 | | int |
294 | | CBS_peek_u8(CBS *cbs, uint8_t *out) |
295 | 68.3k | { |
296 | 68.3k | const uint8_t *v; |
297 | | |
298 | 68.3k | if (!cbs_peek(cbs, &v, 1)) |
299 | 350 | return 0; |
300 | | |
301 | 67.9k | *out = *v; |
302 | 67.9k | return 1; |
303 | 68.3k | } |
304 | | |
305 | | int |
306 | | CBS_peek_u16(CBS *cbs, uint16_t *out) |
307 | 7.88M | { |
308 | 7.88M | uint32_t v; |
309 | | |
310 | 7.88M | if (!cbs_peek_u(cbs, &v, 2)) |
311 | 31.2k | return 0; |
312 | | |
313 | 7.85M | *out = v; |
314 | 7.85M | return 1; |
315 | 7.88M | } |
316 | | |
317 | | int |
318 | | CBS_peek_u24(CBS *cbs, uint32_t *out) |
319 | 0 | { |
320 | 0 | return cbs_peek_u(cbs, out, 3); |
321 | 0 | } |
322 | | |
323 | | int |
324 | | CBS_peek_u32(CBS *cbs, uint32_t *out) |
325 | 0 | { |
326 | 0 | return cbs_peek_u(cbs, out, 4); |
327 | 0 | } |
328 | | |
329 | | int |
330 | | CBS_peek_last_u8(CBS *cbs, uint8_t *out) |
331 | 0 | { |
332 | 0 | if (cbs->len == 0) |
333 | 0 | return 0; |
334 | | |
335 | 0 | *out = cbs->data[cbs->len - 1]; |
336 | 0 | return 1; |
337 | 0 | } |
338 | | |
339 | | int |
340 | | CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned int *out_tag, |
341 | | size_t *out_header_len) |
342 | 0 | { |
343 | 0 | return cbs_get_any_asn1_element_internal(cbs, out, out_tag, |
344 | 0 | out_header_len, 1); |
345 | 0 | } |
346 | | |
347 | | /* |
348 | | * Review X.690 for details on ASN.1 DER encoding. |
349 | | * |
350 | | * If non-strict mode is enabled, then DER rules are relaxed |
351 | | * for indefinite constructs (violates DER but a little closer to BER). |
352 | | * Non-strict mode should only be used by bs_ber.c |
353 | | * |
354 | | * Sections 8, 10 and 11 for DER encoding |
355 | | */ |
356 | | int |
357 | | cbs_get_any_asn1_element_internal(CBS *cbs, CBS *out, unsigned int *out_tag, |
358 | | size_t *out_header_len, int strict) |
359 | 0 | { |
360 | 0 | uint8_t tag, length_byte; |
361 | 0 | CBS header = *cbs; |
362 | 0 | CBS throwaway; |
363 | 0 | size_t len; |
364 | |
|
365 | 0 | if (out == NULL) |
366 | 0 | out = &throwaway; |
367 | | |
368 | | /* |
369 | | * Get identifier octet and length octet. Only 1 octet for each |
370 | | * is a CBS limitation. |
371 | | */ |
372 | 0 | if (!CBS_get_u8(&header, &tag) || !CBS_get_u8(&header, &length_byte)) |
373 | 0 | return 0; |
374 | | |
375 | | /* CBS limitation: long form tags are not supported. */ |
376 | 0 | if ((tag & 0x1f) == 0x1f) |
377 | 0 | return 0; |
378 | | |
379 | 0 | if (out_tag != NULL) |
380 | 0 | *out_tag = tag; |
381 | |
|
382 | 0 | if ((length_byte & 0x80) == 0) { |
383 | | /* Short form length. */ |
384 | 0 | len = ((size_t) length_byte) + 2; |
385 | 0 | if (out_header_len != NULL) |
386 | 0 | *out_header_len = 2; |
387 | |
|
388 | 0 | } else { |
389 | | /* Long form length. */ |
390 | 0 | const size_t num_bytes = length_byte & 0x7f; |
391 | 0 | uint32_t len32; |
392 | | |
393 | | /* ASN.1 reserved value for future extensions */ |
394 | 0 | if (num_bytes == 0x7f) |
395 | 0 | return 0; |
396 | | |
397 | | /* Handle indefinite form length */ |
398 | 0 | if (num_bytes == 0) { |
399 | | /* DER encoding doesn't allow for indefinite form. */ |
400 | 0 | if (strict) |
401 | 0 | return 0; |
402 | | |
403 | | /* Primitive cannot use indefinite in BER or DER. */ |
404 | 0 | if ((tag & CBS_ASN1_CONSTRUCTED) == 0) |
405 | 0 | return 0; |
406 | | |
407 | | /* Constructed, indefinite length allowed in BER. */ |
408 | 0 | if (out_header_len != NULL) |
409 | 0 | *out_header_len = 2; |
410 | 0 | return CBS_get_bytes(cbs, out, 2); |
411 | 0 | } |
412 | | |
413 | | /* CBS limitation. */ |
414 | 0 | if (num_bytes > 4) |
415 | 0 | return 0; |
416 | | |
417 | 0 | if (!cbs_get_u(&header, &len32, num_bytes)) |
418 | 0 | return 0; |
419 | | |
420 | | /* DER has a minimum length octet requirement. */ |
421 | 0 | if (len32 < 128) |
422 | | /* Should have used short form instead */ |
423 | 0 | return 0; |
424 | | |
425 | 0 | if ((len32 >> ((num_bytes - 1) * 8)) == 0) |
426 | | /* Length should have been at least one byte shorter. */ |
427 | 0 | return 0; |
428 | | |
429 | 0 | len = len32; |
430 | 0 | if (len + 2 + num_bytes < len) |
431 | | /* Overflow. */ |
432 | 0 | return 0; |
433 | | |
434 | 0 | len += 2 + num_bytes; |
435 | 0 | if (out_header_len != NULL) |
436 | 0 | *out_header_len = 2 + num_bytes; |
437 | 0 | } |
438 | | |
439 | 0 | return CBS_get_bytes(cbs, out, len); |
440 | 0 | } |
441 | | |
442 | | static int |
443 | | cbs_get_asn1(CBS *cbs, CBS *out, unsigned int tag_value, int skip_header) |
444 | 0 | { |
445 | 0 | size_t header_len; |
446 | 0 | unsigned int tag; |
447 | 0 | CBS throwaway; |
448 | |
|
449 | 0 | if (out == NULL) |
450 | 0 | out = &throwaway; |
451 | |
|
452 | 0 | if (!CBS_get_any_asn1_element(cbs, out, &tag, &header_len) || |
453 | 0 | tag != tag_value) |
454 | 0 | return 0; |
455 | | |
456 | 0 | if (skip_header && !CBS_skip(out, header_len)) |
457 | 0 | return 0; |
458 | | |
459 | 0 | return 1; |
460 | 0 | } |
461 | | |
462 | | int |
463 | | CBS_get_asn1(CBS *cbs, CBS *out, unsigned int tag_value) |
464 | 0 | { |
465 | 0 | return cbs_get_asn1(cbs, out, tag_value, 1 /* skip header */); |
466 | 0 | } |
467 | | |
468 | | int |
469 | | CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned int tag_value) |
470 | 0 | { |
471 | 0 | return cbs_get_asn1(cbs, out, tag_value, 0 /* include header */); |
472 | 0 | } |
473 | | |
474 | | int |
475 | | CBS_peek_asn1_tag(const CBS *cbs, unsigned int tag_value) |
476 | 0 | { |
477 | 0 | if (CBS_len(cbs) < 1) |
478 | 0 | return 0; |
479 | | |
480 | | /* |
481 | | * Tag number 31 indicates the start of a long form number. |
482 | | * This is valid in ASN.1, but CBS only supports short form. |
483 | | */ |
484 | 0 | if ((tag_value & 0x1f) == 0x1f) |
485 | 0 | return 0; |
486 | | |
487 | 0 | return CBS_data(cbs)[0] == tag_value; |
488 | 0 | } |
489 | | |
490 | | /* Encoding details are in ASN.1: X.690 section 8.3 */ |
491 | | int |
492 | | CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) |
493 | 0 | { |
494 | 0 | CBS bytes; |
495 | 0 | const uint8_t *data; |
496 | 0 | size_t i, len; |
497 | |
|
498 | 0 | if (!CBS_get_asn1(cbs, &bytes, CBS_ASN1_INTEGER)) |
499 | 0 | return 0; |
500 | | |
501 | 0 | *out = 0; |
502 | 0 | data = CBS_data(&bytes); |
503 | 0 | len = CBS_len(&bytes); |
504 | |
|
505 | 0 | if (len == 0) |
506 | | /* An INTEGER is encoded with at least one content octet. */ |
507 | 0 | return 0; |
508 | | |
509 | 0 | if ((data[0] & 0x80) != 0) |
510 | | /* Negative number. */ |
511 | 0 | return 0; |
512 | | |
513 | 0 | if (data[0] == 0 && len > 1 && (data[1] & 0x80) == 0) |
514 | | /* Violates smallest encoding rule: excessive leading zeros. */ |
515 | 0 | return 0; |
516 | | |
517 | 0 | for (i = 0; i < len; i++) { |
518 | 0 | if ((*out >> 56) != 0) |
519 | | /* Too large to represent as a uint64_t. */ |
520 | 0 | return 0; |
521 | | |
522 | 0 | *out <<= 8; |
523 | 0 | *out |= data[i]; |
524 | 0 | } |
525 | | |
526 | 0 | return 1; |
527 | 0 | } |
528 | | |
529 | | int |
530 | | CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, unsigned int tag) |
531 | 0 | { |
532 | 0 | if (CBS_peek_asn1_tag(cbs, tag)) { |
533 | 0 | if (!CBS_get_asn1(cbs, out, tag)) |
534 | 0 | return 0; |
535 | | |
536 | 0 | *out_present = 1; |
537 | 0 | } else { |
538 | 0 | *out_present = 0; |
539 | 0 | } |
540 | 0 | return 1; |
541 | 0 | } |
542 | | |
543 | | int |
544 | | CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, int *out_present, |
545 | | unsigned int tag) |
546 | 0 | { |
547 | 0 | CBS child; |
548 | 0 | int present; |
549 | |
|
550 | 0 | if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) |
551 | 0 | return 0; |
552 | | |
553 | 0 | if (present) { |
554 | 0 | if (!CBS_get_asn1(&child, out, CBS_ASN1_OCTETSTRING) || |
555 | 0 | CBS_len(&child) != 0) |
556 | 0 | return 0; |
557 | 0 | } else { |
558 | 0 | CBS_init(out, NULL, 0); |
559 | 0 | } |
560 | 0 | if (out_present) |
561 | 0 | *out_present = present; |
562 | |
|
563 | 0 | return 1; |
564 | 0 | } |
565 | | |
566 | | int |
567 | | CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, unsigned int tag, |
568 | | uint64_t default_value) |
569 | 0 | { |
570 | 0 | CBS child; |
571 | 0 | int present; |
572 | |
|
573 | 0 | if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) |
574 | 0 | return 0; |
575 | | |
576 | 0 | if (present) { |
577 | 0 | if (!CBS_get_asn1_uint64(&child, out) || |
578 | 0 | CBS_len(&child) != 0) |
579 | 0 | return 0; |
580 | 0 | } else { |
581 | 0 | *out = default_value; |
582 | 0 | } |
583 | 0 | return 1; |
584 | 0 | } |
585 | | |
586 | | int |
587 | | CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned int tag, |
588 | | int default_value) |
589 | 0 | { |
590 | 0 | CBS child, child2; |
591 | 0 | int present; |
592 | |
|
593 | 0 | if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) |
594 | 0 | return 0; |
595 | | |
596 | 0 | if (present) { |
597 | 0 | uint8_t boolean; |
598 | |
|
599 | 0 | if (!CBS_get_asn1(&child, &child2, CBS_ASN1_BOOLEAN) || |
600 | 0 | CBS_len(&child2) != 1 || CBS_len(&child) != 0) |
601 | 0 | return 0; |
602 | | |
603 | 0 | boolean = CBS_data(&child2)[0]; |
604 | 0 | if (boolean == 0) |
605 | 0 | *out = 0; |
606 | 0 | else if (boolean == 0xff) |
607 | 0 | *out = 1; |
608 | 0 | else |
609 | 0 | return 0; |
610 | |
|
611 | 0 | } else { |
612 | 0 | *out = default_value; |
613 | 0 | } |
614 | 0 | return 1; |
615 | 0 | } |