blob: 7daaaef6898d0c53339224cb883352e65076e2b2 [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001/*-
2 * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
3 * Redistribution and modifications are permitted subject to BSD license.
4 */
Lev Walkina9cc46e2004-09-22 16:06:28 +00005#include <asn_internal.h>
Lev Walkinf15320b2004-06-03 03:38:44 +00006#include <constr_TYPE.h>
7#include <ber_tlv_length.h>
8#include <ber_tlv_tag.h>
9
10ssize_t
11ber_fetch_length(int _is_constructed, void *bufptr, size_t size,
12 ber_tlv_len_t *len_r) {
Lev Walkinc2346572004-08-11 09:07:36 +000013 uint8_t *buf = (uint8_t *)bufptr;
Lev Walkinf15320b2004-06-03 03:38:44 +000014 unsigned oct;
15
16 if(size == 0)
17 return 0; /* Want more */
18
19 oct = *(uint8_t *)buf;
20 if((oct & 0x80) == 0) {
21 /*
22 * Short definite length.
23 */
Lev Walkin619b6aa2004-08-19 18:10:27 +000024 *len_r = oct; /* & 0x7F */
Lev Walkinf15320b2004-06-03 03:38:44 +000025 return 1;
26 } else {
27 ber_tlv_len_t len;
Lev Walkind9bd7752004-06-05 08:17:50 +000028 size_t skipped;
Lev Walkinf15320b2004-06-03 03:38:44 +000029
30 if(_is_constructed && oct == 0x80) {
31 *len_r = -1; /* Indefinite length */
32 return 1;
33 }
34
35 if(oct == 0xff) {
36 /* Reserved in standard for future use. */
37 return -1;
38 }
39
40 oct &= 0x7F; /* Leave only the 7 LS bits */
41 for(len = 0, buf++, skipped = 1;
Lev Walkin619b6aa2004-08-19 18:10:27 +000042 oct && (++skipped <= size); buf++, oct--) {
Lev Walkinf15320b2004-06-03 03:38:44 +000043
44 len = (len << 8) | *buf;
45 if(len < 0
46 || (len >> ((8 * sizeof(len)) - 8) && oct > 1)) {
47 /*
48 * Too large length value.
49 */
50 return -1;
51 }
52 }
53
54 if(oct == 0) {
55 *len_r = len;
56 return skipped;
57 }
58
59 return 0; /* Want more */
60 }
61
62}
63
64ssize_t
65ber_skip_length(int _is_constructed, void *ptr, size_t size) {
66 ber_tlv_len_t vlen; /* Length of V in TLV */
67 ssize_t tl; /* Length of L in TLV */
68 ssize_t ll; /* Length of L in TLV */
Lev Walkind9bd7752004-06-05 08:17:50 +000069 size_t skip;
Lev Walkinf15320b2004-06-03 03:38:44 +000070
71 /*
72 * Determine the size of L in TLV.
73 */
74 ll = ber_fetch_length(_is_constructed, ptr, size, &vlen);
75 if(ll <= 0) return ll;
76
77 /*
78 * Definite length.
79 */
80 if(vlen >= 0) {
81 skip = ll + vlen;
82 if(skip > size)
83 return 0; /* Want more */
84 return skip;
85 }
86
87 /*
88 * Indefinite length!
89 */
90 ASN_DEBUG("Skipping indefinite length");
Lev Walkin4ce78ca2004-08-25 01:34:11 +000091 for(skip = ll, ptr = ((char *)ptr) + ll, size -= ll;;) {
Lev Walkinf15320b2004-06-03 03:38:44 +000092 ber_tlv_tag_t tag;
93
94 /* Fetch the tag */
95 tl = ber_fetch_tag(ptr, size, &tag);
96 if(tl <= 0) return tl;
97
98 ll = ber_skip_length(BER_TLV_CONSTRUCTED(ptr),
Lev Walkin4ce78ca2004-08-25 01:34:11 +000099 ((char *)ptr) + tl, size - tl);
Lev Walkinf15320b2004-06-03 03:38:44 +0000100 if(ll <= 0) return ll;
101
102 skip += tl + ll;
103
104 /*
105 * This may be the end of the indefinite length structure,
106 * two consecutive 0 octets.
107 * Check if it is true.
108 */
109 if(((uint8_t *)ptr)[0] == 0
110 && ((uint8_t *)ptr)[1] == 0)
111 return skip;
112
Lev Walkin4ce78ca2004-08-25 01:34:11 +0000113 ptr = ((char *)ptr) + tl + ll;
Lev Walkinf15320b2004-06-03 03:38:44 +0000114 size -= tl + ll;
115 }
116
117 /* UNREACHABLE */
118}
119
120ssize_t
121der_tlv_length_serialize(ber_tlv_len_t len, void *bufp, size_t size) {
Lev Walkin619b6aa2004-08-19 18:10:27 +0000122 size_t required_size; /* Size of len encoding */
Lev Walkinc2346572004-08-11 09:07:36 +0000123 uint8_t *buf = (uint8_t *)bufp;
Lev Walkinf15320b2004-06-03 03:38:44 +0000124 uint8_t *end;
Lev Walkin619b6aa2004-08-19 18:10:27 +0000125 size_t i;
Lev Walkinf15320b2004-06-03 03:38:44 +0000126
127 if(len <= 127) {
128 /* Encoded in 1 octet */
129 if(size) *buf = len;
130 return 1;
131 }
132
133 /*
134 * Compute the size of the subsequent bytes.
135 */
Lev Walkin619b6aa2004-08-19 18:10:27 +0000136 for(required_size = 1, i = 8; i < 8 * sizeof(len); i += 8) {
137 if(len >> i)
138 required_size++;
139 else
140 break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000141 }
142
Lev Walkin619b6aa2004-08-19 18:10:27 +0000143 if(size < required_size)
144 return required_size + 1;
145
146 *buf++ = 0x80 | required_size; /* Length of the encoding */
Lev Walkinf15320b2004-06-03 03:38:44 +0000147
148 /*
149 * Produce the len encoding, space permitting.
150 */
Lev Walkin619b6aa2004-08-19 18:10:27 +0000151 end = buf + required_size;
152 for(i -= 8; buf < end; i -= 8, buf++)
153 *buf = (len >> i);
Lev Walkinf15320b2004-06-03 03:38:44 +0000154
Lev Walkin619b6aa2004-08-19 18:10:27 +0000155 return required_size + 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000156}
157