]> git.stg.codes - stg.git/blob - libs/smux/ber_tlv_length.c
Merge remote-tracking branch 'github/master'
[stg.git] / libs / smux / ber_tlv_length.c
1 /*-
2  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
3  * Redistribution and modifications are permitted subject to BSD license.
4  */
5 #include <asn_internal.h>
6 #include <ber_tlv_length.h>
7 #include <ber_tlv_tag.h>
8
9 ssize_t
10 ber_fetch_length(int _is_constructed, const void *bufptr, size_t size,
11                 ber_tlv_len_t *len_r) {
12         const uint8_t *buf = (const uint8_t *)bufptr;
13         unsigned oct;
14
15         if(size == 0)
16                 return 0;       /* Want more */
17
18         oct = *(const uint8_t *)buf;
19         if((oct & 0x80) == 0) {
20                 /*
21                  * Short definite length.
22                  */
23                 *len_r = oct;   /* & 0x7F */
24                 return 1;
25         } else {
26                 ber_tlv_len_t len;
27                 size_t skipped;
28
29                 if(_is_constructed && oct == 0x80) {
30                         *len_r = -1;    /* Indefinite length */
31                         return 1;
32                 }
33
34                 if(oct == 0xff) {
35                         /* Reserved in standard for future use. */
36                         return -1;
37                 }
38
39                 oct &= 0x7F;    /* Leave only the 7 LS bits */
40                 for(len = 0, buf++, skipped = 1;
41                         oct && (++skipped <= size); buf++, oct--) {
42
43                         /* Verify that we won't overflow. */
44                         if(!(len >> ((8 * sizeof(len)) - (8+1)))) {
45                                 len = (len << 8) | *buf;
46                         } else {
47                                 /* Too large length value. */
48                                 return -1;
49                         }
50                 }
51
52                 if(oct == 0) {
53                         if(len < 0 || len > RSSIZE_MAX) {
54                                 /* Length value out of sane range. */
55                                 return -1;
56                         }
57
58                         *len_r = len;
59                         return skipped;
60                 }
61
62                 return 0;       /* Want more */
63         }
64
65 }
66
67 ssize_t
68 ber_skip_length(const asn_codec_ctx_t *opt_codec_ctx,
69                 int _is_constructed, const void *ptr, size_t size) {
70         ber_tlv_len_t vlen;     /* Length of V in TLV */
71         ssize_t tl;             /* Length of L in TLV */
72         ssize_t ll;             /* Length of L in TLV */
73         size_t skip;
74
75         /*
76          * Make sure we didn't exceed the maximum stack size.
77          */
78         if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx))
79                 return -1;
80
81         /*
82          * Determine the size of L in TLV.
83          */
84         ll = ber_fetch_length(_is_constructed, ptr, size, &vlen);
85         if(ll <= 0) return ll;
86
87         /*
88          * Definite length.
89          */
90         if(vlen >= 0) {
91                 skip = ll + vlen;
92                 if(skip > size)
93                         return 0;       /* Want more */
94                 return skip;
95         }
96
97         /*
98          * Indefinite length!
99          */
100         ASN_DEBUG("Skipping indefinite length");
101         for(skip = ll, ptr = ((const char *)ptr) + ll, size -= ll;;) {
102                 ber_tlv_tag_t tag;
103
104                 /* Fetch the tag */
105                 tl = ber_fetch_tag(ptr, size, &tag);
106                 if(tl <= 0) return tl;
107
108                 ll = ber_skip_length(opt_codec_ctx,
109                         BER_TLV_CONSTRUCTED(ptr),
110                         ((const char *)ptr) + tl, size - tl);
111                 if(ll <= 0) return ll;
112
113                 skip += tl + ll;
114
115                 /*
116                  * This may be the end of the indefinite length structure,
117                  * two consecutive 0 octets.
118                  * Check if it is true.
119                  */
120                 if(((const uint8_t *)ptr)[0] == 0
121                 && ((const uint8_t *)ptr)[1] == 0)
122                         return skip;
123
124                 ptr = ((const char *)ptr) + tl + ll;
125                 size -= tl + ll;
126         }
127
128         /* UNREACHABLE */
129 }
130
131 size_t
132 der_tlv_length_serialize(ber_tlv_len_t len, void *bufp, size_t size) {
133         size_t required_size;   /* Size of len encoding */
134         uint8_t *buf = (uint8_t *)bufp;
135         uint8_t *end;
136         int i;
137
138         if(len <= 127) {
139                 /* Encoded in 1 octet */
140                 if(size) *buf = (uint8_t)len;
141                 return 1;
142         }
143
144         /*
145          * Compute the size of the subsequent bytes.
146          */
147         for(required_size = 1, i = 8; i < 8 * (int)sizeof(len); i += 8) {
148                 if(len >> i)
149                         required_size++;
150                 else
151                         break;
152         }
153
154         if(size <= required_size)
155                 return required_size + 1;
156
157         *buf++ = (uint8_t)(0x80 | required_size);  /* Length of the encoding */
158
159         /*
160          * Produce the len encoding, space permitting.
161          */
162         end = buf + required_size;
163         for(i -= 8; buf < end; i -= 8, buf++)
164                 *buf = (uint8_t)(len >> i);
165
166         return required_size + 1;
167 }
168