2 * Copyright (c) 2009 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 #define ABORT_ON_ERROR() abort()
42 #define ABORT_ON_ERROR() do { } while(0)
45 #define DPOC(data,offset) ((const void *)(((const unsigned char *)data) + offset))
46 #define DPO(data,offset) ((void *)(((unsigned char *)data) + offset))
49 static struct asn1_type_func prim
[] = {
50 #define el(name, type) { \
51 (asn1_type_encode)der_put_##name, \
52 (asn1_type_decode)der_get_##name, \
53 (asn1_type_length)der_length_##name, \
54 (asn1_type_copy)der_copy_##name, \
55 (asn1_type_release)der_free_##name, \
58 #define elber(name, type) { \
59 (asn1_type_encode)der_put_##name, \
60 (asn1_type_decode)der_get_##name##_ber, \
61 (asn1_type_length)der_length_##name, \
62 (asn1_type_copy)der_copy_##name, \
63 (asn1_type_release)der_free_##name, \
67 el(heim_integer
, heim_integer
),
69 el(integer64
, int64_t),
70 el(unsigned, unsigned),
71 el(unsigned64
, uint64_t),
72 el(general_string
, heim_general_string
),
73 el(octet_string
, heim_octet_string
),
74 elber(octet_string
, heim_octet_string
),
75 el(ia5_string
, heim_ia5_string
),
76 el(bmp_string
, heim_bmp_string
),
77 el(universal_string
, heim_universal_string
),
78 el(printable_string
, heim_printable_string
),
79 el(visible_string
, heim_visible_string
),
80 el(utf8string
, heim_utf8_string
),
81 el(generalized_time
, time_t),
83 el(bit_string
, heim_bit_string
),
84 { (asn1_type_encode
)der_put_boolean
, (asn1_type_decode
)der_get_boolean
,
85 (asn1_type_length
)der_length_boolean
, (asn1_type_copy
)der_copy_integer
,
86 (asn1_type_release
)der_free_integer
, sizeof(int)
89 el(general_string
, heim_general_string
),
95 sizeofType(const struct asn1_template
*t
)
101 * Here is abstraction to not so well evil fact of bit fields in C,
102 * they are endian dependent, so when getting and setting bits in the
103 * host local structure we need to know the endianness of the host.
105 * Its not the first time in Heimdal this have bitten us, and some day
106 * we'll grow up and use #defined constant, but bit fields are still
107 * so pretty and shiny.
111 bmember_get_bit(const unsigned char *p
, void *data
,
112 unsigned int bit
, size_t size
)
114 unsigned int localbit
= bit
% 8;
115 if ((*p
>> (7 - localbit
)) & 1) {
116 #ifdef WORDS_BIGENDIAN
117 *(unsigned int *)data
|= (1 << ((size
* 8) - bit
- 1));
119 *(unsigned int *)data
|= (1 << bit
);
125 bmember_isset_bit(const void *data
, unsigned int bit
, size_t size
)
127 #ifdef WORDS_BIGENDIAN
128 if ((*(unsigned int *)data
) & (1 << ((size
* 8) - bit
- 1)))
132 if ((*(unsigned int *)data
) & (1 << bit
))
139 bmember_put_bit(unsigned char *p
, const void *data
, unsigned int bit
,
140 size_t size
, unsigned int *bitset
)
142 unsigned int localbit
= bit
% 8;
144 if (bmember_isset_bit(data
, bit
, size
)) {
145 *p
|= (1 << (7 - localbit
));
147 *bitset
= (7 - localbit
) + 1;
152 _asn1_decode(const struct asn1_template
*t
, unsigned flags
,
153 const unsigned char *p
, size_t len
, void *data
, size_t *retsize
)
155 size_t elements
= A1_HEADER_LEN(t
);
158 const unsigned char *startp
= NULL
;
159 unsigned int template_flags
= t
->tt
;
161 /* skip over header */
164 if (template_flags
& A1_HF_PRESERVE
)
168 switch (t
->tt
& A1_OP_MASK
) {
170 case A1_OP_TYPE_EXTERN
: {
171 size_t newsize
, size
;
172 void *el
= DPO(data
, t
->offset
);
173 void **pel
= (void **)el
;
175 if ((t
->tt
& A1_OP_MASK
) == A1_OP_TYPE
) {
176 size
= sizeofType(t
->ptr
);
178 const struct asn1_type_func
*f
= t
->ptr
;
182 if (t
->tt
& A1_FLAG_OPTIONAL
) {
183 *pel
= calloc(1, size
);
188 if ((t
->tt
& A1_OP_MASK
) == A1_OP_TYPE
) {
189 ret
= _asn1_decode(t
->ptr
, flags
, p
, len
, el
, &newsize
);
191 const struct asn1_type_func
*f
= t
->ptr
;
192 ret
= (f
->decode
)(p
, len
, el
, &newsize
);
195 if (t
->tt
& A1_FLAG_OPTIONAL
) {
202 p
+= newsize
; len
-= newsize
;
210 void *olddata
= data
;
211 int is_indefinite
= 0;
212 int subflags
= flags
;
214 ret
= der_match_tag_and_length(p
, len
, A1_TAG_CLASS(t
->tt
),
215 &dertype
, A1_TAG_TAG(t
->tt
),
218 if (t
->tt
& A1_FLAG_OPTIONAL
)
226 * Only allow indefinite encoding for OCTET STRING and BER
227 * for now. Should handle BIT STRING too.
230 if (dertype
!= A1_TAG_TYPE(t
->tt
) && (flags
& A1_PF_ALLOW_BER
)) {
231 const struct asn1_template
*subtype
= t
->ptr
;
232 subtype
++; /* skip header */
234 if (((subtype
->tt
& A1_OP_MASK
) == A1_OP_PARSE
) &&
235 A1_PARSE_TYPE(subtype
->tt
) == A1T_OCTET_STRING
)
236 subflags
|= A1_PF_INDEFINTE
;
239 if (datalen
== ASN1_INDEFINITE
) {
240 if ((flags
& A1_PF_ALLOW_BER
) == 0)
246 /* hide EndOfContent for sub-decoder, catching it below */
248 } else if (datalen
> len
)
251 data
= DPO(data
, t
->offset
);
253 if (t
->tt
& A1_FLAG_OPTIONAL
) {
254 void **el
= (void **)data
;
255 size_t ellen
= sizeofType(t
->ptr
);
257 *el
= calloc(1, ellen
);
263 ret
= _asn1_decode(t
->ptr
, subflags
, p
, datalen
, data
, &newsize
);
267 if (newsize
!= datalen
)
268 return ASN1_EXTRA_DATA
;
274 * Indefinite encoding needs a trailing EndOfContent,
278 ret
= der_match_tag_and_length(p
, len
, ASN1_C_UNIV
,
279 &dertype
, UT_EndOfContent
,
286 return ASN1_INDEF_EXTRA_DATA
;
294 unsigned int type
= A1_PARSE_TYPE(t
->tt
);
296 void *el
= DPO(data
, t
->offset
);
299 * INDEFINITE primitive types are one element after the
300 * same type but non-INDEFINITE version.
302 if (flags
& A1_PF_INDEFINTE
)
305 if (type
>= sizeof(prim
)/sizeof(prim
[0])) {
307 return ASN1_PARSE_ERROR
;
310 ret
= (prim
[type
].decode
)(p
, len
, el
, &newsize
);
313 p
+= newsize
; len
-= newsize
;
319 struct template_of
*el
= DPO(data
, t
->offset
);
321 size_t ellen
= sizeofType(t
->ptr
);
322 size_t vallength
= 0;
326 size_t newlen
= vallength
+ ellen
;
327 if (vallength
> newlen
)
328 return ASN1_OVERFLOW
;
330 tmp
= realloc(el
->val
, newlen
);
334 memset(DPO(tmp
, vallength
), 0, ellen
);
337 ret
= _asn1_decode(t
->ptr
, flags
& (~A1_PF_INDEFINTE
), p
, len
,
338 DPO(el
->val
, vallength
), &newsize
);
343 p
+= newsize
; len
-= newsize
;
348 case A1_OP_BMEMBER
: {
349 const struct asn1_template
*bmember
= t
->ptr
;
350 size_t size
= bmember
->offset
;
351 size_t els
= A1_HEADER_LEN(bmember
);
356 memset(data
, 0, size
);
363 while (bmember
->offset
/ 8 > pos
/ 8) {
370 bmember_get_bit(p
, data
, bmember
->offset
, size
);
378 const struct asn1_template
*choice
= t
->ptr
;
379 unsigned int *element
= DPO(data
, choice
->offset
);
383 for (i
= 1; i
< A1_HEADER_LEN(choice
) + 1; i
++) {
384 /* should match first tag instead, store it in choice.tt */
385 ret
= _asn1_decode(choice
[i
].ptr
, 0, p
, len
,
386 DPO(data
, choice
[i
].offset
), &datalen
);
389 p
+= datalen
; len
-= datalen
;
391 } else if (ret
!= ASN1_BAD_ID
&& ret
!= ASN1_MISPLACED_FIELD
&& ret
!= ASN1_MISSING_FIELD
) {
395 if (i
>= A1_HEADER_LEN(choice
) + 1) {
400 ret
= der_get_octet_string(p
, len
,
401 DPO(data
, choice
->tt
), &datalen
);
404 p
+= datalen
; len
-= datalen
;
411 return ASN1_PARSE_ERROR
;
416 /* if we are using padding, eat up read of context */
417 if (template_flags
& A1_HF_ELLIPSIS
)
426 * saved the raw bits if asked for it, useful for signature
430 heim_octet_string
*save
= data
;
432 save
->data
= malloc(oldlen
);
433 if (save
->data
== NULL
)
436 save
->length
= oldlen
;
437 memcpy(save
->data
, startp
, oldlen
);
444 _asn1_encode(const struct asn1_template
*t
, unsigned char *p
, size_t len
,
445 const void *data
, size_t *retsize
)
447 size_t elements
= A1_HEADER_LEN(t
);
451 t
+= A1_HEADER_LEN(t
);
454 switch (t
->tt
& A1_OP_MASK
) {
456 case A1_OP_TYPE_EXTERN
: {
458 const void *el
= DPOC(data
, t
->offset
);
460 if (t
->tt
& A1_FLAG_OPTIONAL
) {
461 void **pel
= (void **)el
;
467 if ((t
->tt
& A1_OP_MASK
) == A1_OP_TYPE
) {
468 ret
= _asn1_encode(t
->ptr
, p
, len
, el
, &newsize
);
470 const struct asn1_type_func
*f
= t
->ptr
;
471 ret
= (f
->encode
)(p
, len
, el
, &newsize
);
476 p
-= newsize
; len
-= newsize
;
481 const void *olddata
= data
;
484 data
= DPOC(data
, t
->offset
);
486 if (t
->tt
& A1_FLAG_OPTIONAL
) {
487 void **el
= (void **)data
;
495 ret
= _asn1_encode(t
->ptr
, p
, len
, data
, &datalen
);
499 len
-= datalen
; p
-= datalen
;
501 ret
= der_put_length_and_tag(p
, len
, datalen
,
504 A1_TAG_TAG(t
->tt
), &l
);
515 unsigned int type
= A1_PARSE_TYPE(t
->tt
);
517 const void *el
= DPOC(data
, t
->offset
);
519 if (type
> sizeof(prim
)/sizeof(prim
[0])) {
521 return ASN1_PARSE_ERROR
;
524 ret
= (prim
[type
].encode
)(p
, len
, el
, &newsize
);
527 p
-= newsize
; len
-= newsize
;
532 const struct template_of
*el
= DPOC(data
, t
->offset
);
533 size_t ellen
= sizeofType(t
->ptr
);
534 struct heim_octet_string
*val
;
535 unsigned char *elptr
= el
->val
;
541 if (el
->len
> UINT_MAX
/sizeof(val
[0]))
544 val
= malloc(sizeof(val
[0]) * el
->len
);
548 for(totallen
= 0, i
= 0; i
< el
->len
; i
++) {
552 val
[i
].length
= _asn1_length(t
->ptr
, elptr
);
553 val
[i
].data
= malloc(val
[i
].length
);
555 ret
= _asn1_encode(t
->ptr
, DPO(val
[i
].data
, val
[i
].length
- 1),
556 val
[i
].length
, elptr
, &l
);
560 next
= elptr
+ ellen
;
566 totallen
+= val
[i
].length
;
568 if (ret
== 0 && totallen
> len
)
580 qsort(val
, el
->len
, sizeof(val
[0]), _heim_der_set_sort
);
585 memcpy(p
+ 1, val
[i
].data
, val
[i
].length
);
594 struct template_of
*el
= DPO(data
, t
->offset
);
595 size_t ellen
= sizeofType(t
->ptr
);
598 unsigned char *elptr
= el
->val
;
603 elptr
+= ellen
* (el
->len
- 1);
605 for (i
= 0; i
< el
->len
; i
++) {
606 ret
= _asn1_encode(t
->ptr
, p
, len
,
611 p
-= newsize
; len
-= newsize
;
617 case A1_OP_BMEMBER
: {
618 const struct asn1_template
*bmember
= t
->ptr
;
619 size_t size
= bmember
->offset
;
620 size_t els
= A1_HEADER_LEN(bmember
);
623 unsigned int bitset
= 0;
624 int rfc1510
= (bmember
->tt
& A1_HBF_RFC1510
);
631 pos
= bmember
->offset
;
634 while (bmember
->offset
/ 8 < pos
/ 8) {
635 if (rfc1510
|| bitset
|| c
) {
637 return ASN1_OVERFLOW
;
643 bmember_put_bit(&c
, data
, bmember
->offset
, size
, &bitset
);
646 if (rfc1510
|| bitset
) {
648 return ASN1_OVERFLOW
;
653 return ASN1_OVERFLOW
;
654 if (rfc1510
|| bitset
== 0)
664 const struct asn1_template
*choice
= t
->ptr
;
665 const unsigned int *element
= DPOC(data
, choice
->offset
);
669 if (*element
> A1_HEADER_LEN(choice
)) {
670 printf("element: %d\n", *element
);
671 return ASN1_PARSE_ERROR
;
675 ret
+= der_put_octet_string(p
, len
,
676 DPOC(data
, choice
->tt
), &datalen
);
679 el
= DPOC(data
, choice
->offset
);
680 ret
= _asn1_encode(choice
->ptr
, p
, len
, el
, &datalen
);
684 len
-= datalen
; p
-= datalen
;
695 *retsize
= oldlen
- len
;
701 _asn1_length(const struct asn1_template
*t
, const void *data
)
703 size_t elements
= A1_HEADER_LEN(t
);
706 t
+= A1_HEADER_LEN(t
);
709 switch (t
->tt
& A1_OP_MASK
) {
711 case A1_OP_TYPE_EXTERN
: {
712 const void *el
= DPOC(data
, t
->offset
);
714 if (t
->tt
& A1_FLAG_OPTIONAL
) {
715 void **pel
= (void **)el
;
721 if ((t
->tt
& A1_OP_MASK
) == A1_OP_TYPE
) {
722 ret
+= _asn1_length(t
->ptr
, el
);
724 const struct asn1_type_func
*f
= t
->ptr
;
725 ret
+= (f
->length
)(el
);
731 const void *olddata
= data
;
733 data
= DPO(data
, t
->offset
);
735 if (t
->tt
& A1_FLAG_OPTIONAL
) {
736 void **el
= (void **)data
;
743 datalen
= _asn1_length(t
->ptr
, data
);
744 ret
+= der_length_tag(A1_TAG_TAG(t
->tt
)) + der_length_len(datalen
);
750 unsigned int type
= A1_PARSE_TYPE(t
->tt
);
751 const void *el
= DPOC(data
, t
->offset
);
753 if (type
> sizeof(prim
)/sizeof(prim
[0])) {
757 ret
+= (prim
[type
].length
)(el
);
762 const struct template_of
*el
= DPOC(data
, t
->offset
);
763 size_t ellen
= sizeofType(t
->ptr
);
764 const unsigned char *element
= el
->val
;
767 for (i
= 0; i
< el
->len
; i
++) {
768 ret
+= _asn1_length(t
->ptr
, element
);
774 case A1_OP_BMEMBER
: {
775 const struct asn1_template
*bmember
= t
->ptr
;
776 size_t size
= bmember
->offset
;
777 size_t els
= A1_HEADER_LEN(bmember
);
778 int rfc1510
= (bmember
->tt
& A1_HBF_RFC1510
);
789 if (bmember_isset_bit(data
, bmember
->offset
, size
)) {
790 ret
+= (bmember
->offset
/ 8) + 1;
799 const struct asn1_template
*choice
= t
->ptr
;
800 const unsigned int *element
= DPOC(data
, choice
->offset
);
802 if (*element
> A1_HEADER_LEN(choice
))
806 ret
+= der_length_octet_string(DPOC(data
, choice
->tt
));
809 ret
+= _asn1_length(choice
->ptr
, DPOC(data
, choice
->offset
));
824 _asn1_free(const struct asn1_template
*t
, void *data
)
826 size_t elements
= A1_HEADER_LEN(t
);
828 if (t
->tt
& A1_HF_PRESERVE
)
829 der_free_octet_string(data
);
834 switch (t
->tt
& A1_OP_MASK
) {
836 case A1_OP_TYPE_EXTERN
: {
837 void *el
= DPO(data
, t
->offset
);
839 if (t
->tt
& A1_FLAG_OPTIONAL
) {
840 void **pel
= (void **)el
;
846 if ((t
->tt
& A1_OP_MASK
) == A1_OP_TYPE
) {
847 _asn1_free(t
->ptr
, el
);
849 const struct asn1_type_func
*f
= t
->ptr
;
852 if (t
->tt
& A1_FLAG_OPTIONAL
)
858 unsigned int type
= A1_PARSE_TYPE(t
->tt
);
859 void *el
= DPO(data
, t
->offset
);
861 if (type
> sizeof(prim
)/sizeof(prim
[0])) {
865 (prim
[type
].release
)(el
);
869 void *el
= DPO(data
, t
->offset
);
871 if (t
->tt
& A1_FLAG_OPTIONAL
) {
872 void **pel
= (void **)el
;
878 _asn1_free(t
->ptr
, el
);
880 if (t
->tt
& A1_FLAG_OPTIONAL
)
887 struct template_of
*el
= DPO(data
, t
->offset
);
888 size_t ellen
= sizeofType(t
->ptr
);
889 unsigned char *element
= el
->val
;
892 for (i
= 0; i
< el
->len
; i
++) {
893 _asn1_free(t
->ptr
, element
);
905 const struct asn1_template
*choice
= t
->ptr
;
906 const unsigned int *element
= DPOC(data
, choice
->offset
);
908 if (*element
> A1_HEADER_LEN(choice
))
912 der_free_octet_string(DPO(data
, choice
->tt
));
915 _asn1_free(choice
->ptr
, DPO(data
, choice
->offset
));
929 _asn1_copy(const struct asn1_template
*t
, const void *from
, void *to
)
931 size_t elements
= A1_HEADER_LEN(t
);
933 int preserve
= (t
->tt
& A1_HF_PRESERVE
);
938 ret
= der_copy_octet_string(from
, to
);
944 switch (t
->tt
& A1_OP_MASK
) {
946 case A1_OP_TYPE_EXTERN
: {
947 const void *fel
= DPOC(from
, t
->offset
);
948 void *tel
= DPO(to
, t
->offset
);
949 void **ptel
= (void **)tel
;
952 if ((t
->tt
& A1_OP_MASK
) == A1_OP_TYPE
) {
953 size
= sizeofType(t
->ptr
);
955 const struct asn1_type_func
*f
= t
->ptr
;
959 if (t
->tt
& A1_FLAG_OPTIONAL
) {
960 void **pfel
= (void **)fel
;
965 tel
= *ptel
= calloc(1, size
);
970 if ((t
->tt
& A1_OP_MASK
) == A1_OP_TYPE
) {
971 ret
= _asn1_copy(t
->ptr
, fel
, tel
);
973 const struct asn1_type_func
*f
= t
->ptr
;
974 ret
= (f
->copy
)(fel
, tel
);
978 if (t
->tt
& A1_FLAG_OPTIONAL
) {
987 unsigned int type
= A1_PARSE_TYPE(t
->tt
);
988 const void *fel
= DPOC(from
, t
->offset
);
989 void *tel
= DPO(to
, t
->offset
);
991 if (type
> sizeof(prim
)/sizeof(prim
[0])) {
993 return ASN1_PARSE_ERROR
;
995 ret
= (prim
[type
].copy
)(fel
, tel
);
1001 const void *oldfrom
= from
;
1005 from
= DPOC(from
, t
->offset
);
1006 to
= DPO(to
, t
->offset
);
1008 if (t
->tt
& A1_FLAG_OPTIONAL
) {
1009 void **fel
= (void **)from
;
1018 to
= *tel
= calloc(1, sizeofType(t
->ptr
));
1023 ret
= _asn1_copy(t
->ptr
, from
, to
);
1025 if (t
->tt
& A1_FLAG_OPTIONAL
) {
1039 const struct template_of
*fel
= DPOC(from
, t
->offset
);
1040 struct template_of
*tel
= DPO(to
, t
->offset
);
1041 size_t ellen
= sizeofType(t
->ptr
);
1044 tel
->val
= calloc(fel
->len
, ellen
);
1045 if (tel
->val
== NULL
)
1048 tel
->len
= fel
->len
;
1050 for (i
= 0; i
< fel
->len
; i
++) {
1051 ret
= _asn1_copy(t
->ptr
,
1052 DPOC(fel
->val
, (i
* ellen
)),
1053 DPO(tel
->val
, (i
*ellen
)));
1059 case A1_OP_BMEMBER
: {
1060 const struct asn1_template
*bmember
= t
->ptr
;
1061 size_t size
= bmember
->offset
;
1062 memcpy(to
, from
, size
);
1065 case A1_OP_CHOICE
: {
1066 const struct asn1_template
*choice
= t
->ptr
;
1067 const unsigned int *felement
= DPOC(from
, choice
->offset
);
1068 unsigned int *telement
= DPO(to
, choice
->offset
);
1070 if (*felement
> A1_HEADER_LEN(choice
))
1071 return ASN1_PARSE_ERROR
;
1073 *telement
= *felement
;
1075 if (*felement
== 0) {
1076 ret
= der_copy_octet_string(DPOC(from
, choice
->tt
), DPO(to
, choice
->tt
));
1078 choice
+= *felement
;
1079 ret
= _asn1_copy(choice
->ptr
,
1080 DPOC(from
, choice
->offset
),
1081 DPO(to
, choice
->offset
));
1098 _asn1_decode_top(const struct asn1_template
*t
, unsigned flags
, const unsigned char *p
, size_t len
, void *data
, size_t *size
)
1101 memset(data
, 0, t
->offset
);
1102 ret
= _asn1_decode(t
, flags
, p
, len
, data
, size
);
1104 _asn1_free(t
, data
);
1105 memset(data
, 0, t
->offset
);
1112 _asn1_copy_top(const struct asn1_template
*t
, const void *from
, void *to
)
1115 memset(to
, 0, t
->offset
);
1116 ret
= _asn1_copy(t
, from
, to
);
1119 memset(to
, 0, t
->offset
);