blob: af872366fb1e2f4b89efb58b9f8662e89916cd41 [file] [log] [blame]
vlmfa67ddc2004-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 */
5#include <constr_TYPE.h>
6#include <ber_tlv_length.h>
7#include <ber_tlv_tag.h>
8
9ssize_t
10ber_fetch_length(int _is_constructed, void *bufptr, size_t size,
11 ber_tlv_len_t *len_r) {
12 uint8_t *buf = bufptr;
13 unsigned oct;
14
15 if(size == 0)
16 return 0; /* Want more */
17
18 oct = *(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;
vlmb42843a2004-06-05 08:17:50 +000027 size_t skipped;
vlmfa67ddc2004-06-03 03:38:44 +000028
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 len = (len << 8) | *buf;
44 if(len < 0
45 || (len >> ((8 * sizeof(len)) - 8) && oct > 1)) {
46 /*
47 * Too large length value.
48 */
49 return -1;
50 }
51 }
52
53 if(oct == 0) {
54 *len_r = len;
55 return skipped;
56 }
57
58 return 0; /* Want more */
59 }
60
61}
62
63ssize_t
64ber_skip_length(int _is_constructed, void *ptr, size_t size) {
65 ber_tlv_len_t vlen; /* Length of V in TLV */
66 ssize_t tl; /* Length of L in TLV */
67 ssize_t ll; /* Length of L in TLV */
vlmb42843a2004-06-05 08:17:50 +000068 size_t skip;
vlmfa67ddc2004-06-03 03:38:44 +000069
70 /*
71 * Determine the size of L in TLV.
72 */
73 ll = ber_fetch_length(_is_constructed, ptr, size, &vlen);
74 if(ll <= 0) return ll;
75
76 /*
77 * Definite length.
78 */
79 if(vlen >= 0) {
80 skip = ll + vlen;
81 if(skip > size)
82 return 0; /* Want more */
83 return skip;
84 }
85
86 /*
87 * Indefinite length!
88 */
89 ASN_DEBUG("Skipping indefinite length");
vlm1ff928d2004-08-11 08:10:13 +000090 for(skip = ll, (char *)ptr += ll, size -= ll;;) {
vlmfa67ddc2004-06-03 03:38:44 +000091 ber_tlv_tag_t tag;
92
93 /* Fetch the tag */
94 tl = ber_fetch_tag(ptr, size, &tag);
95 if(tl <= 0) return tl;
96
97 ll = ber_skip_length(BER_TLV_CONSTRUCTED(ptr),
vlm1ff928d2004-08-11 08:10:13 +000098 (char *)ptr + tl, size - tl);
vlmfa67ddc2004-06-03 03:38:44 +000099 if(ll <= 0) return ll;
100
101 skip += tl + ll;
102
103 /*
104 * This may be the end of the indefinite length structure,
105 * two consecutive 0 octets.
106 * Check if it is true.
107 */
108 if(((uint8_t *)ptr)[0] == 0
109 && ((uint8_t *)ptr)[1] == 0)
110 return skip;
111
vlm1ff928d2004-08-11 08:10:13 +0000112 (char *)ptr += tl + ll;
vlmfa67ddc2004-06-03 03:38:44 +0000113 size -= tl + ll;
114 }
115
116 /* UNREACHABLE */
117}
118
119ssize_t
120der_tlv_length_serialize(ber_tlv_len_t len, void *bufp, size_t size) {
vlmb42843a2004-06-05 08:17:50 +0000121 size_t computed_size; /* Size of len encoding */
vlmfa67ddc2004-06-03 03:38:44 +0000122 uint8_t *buf = bufp;
123 uint8_t *end;
124 int i;
125
126 if(len <= 127) {
127 /* Encoded in 1 octet */
128 if(size) *buf = len;
129 return 1;
130 }
131
132 /*
133 * Compute the size of the subsequent bytes.
134 */
135 computed_size = sizeof(len); /* assert(sizeof(len)<128), n.p. */
136 for(i = (8*(sizeof(len)-1)); i > 0; i -= 8) {
137 if((len >> i) & 0xFF) break;
138 computed_size--;
139 }
140
141 if(size) {
142 *buf++ = 0x80 | computed_size; /* Length of the encoding */
143 size--;
144 }
145
146 /*
147 * Produce the len encoding, space permitting.
148 */
149 if(size > computed_size)
150 end = buf + computed_size;
151 else
152 end = buf + size;
153 for((void)i /* Reuse bits count */; buf < end; i -= 8, buf++) {
154 *buf = (len >> i) & 0xFF;
155 }
156
157 return computed_size + 1;
158}
159