5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2003 - 2005 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
19 /* Basic Encoding Rules (BER) encoder and decoder. */
21 #include "silcincludes.h"
24 /* Encodes a BER data block into the `ber', which must already have
25 sufficient space allocated. Caller can use silc_ber_encoded_len
26 function to determine how much to allocate space before calling this
27 function. If the `indefinite' is TRUE then the BER block will not
28 include the length of the data in the BER block. */
30 bool silc_ber_encode(SilcBuffer ber, SilcBerClass ber_class,
31 SilcBerEncoding encoding, SilcUInt32 tag,
32 const unsigned char *data, SilcUInt32 data_len,
41 /* Check that buffer is of correct size */
42 if (silc_buffer_len(ber) < silc_ber_encoded_len(tag, data_len, indefinite))
45 /* Put the class and encoding */
46 ber->data[i] = (ber_class << 6) | (encoding << 5);
51 ber->data[i++] |= tag;
54 ber->data[i++] |= 0x1f;
56 /* Save the tag in multiple octets where 7-bits in the octet is the tag
57 value and bit 8 is set, except for the last octet. */
65 ber->data[i++] = 0x80 | ((tag >> (--c * 7)) & 0x7f);
66 ber->data[i++] = tag & 0x7f;
69 /* Put the length of data */
71 if (data_len < 0x80) {
72 /* Use short form for less than 128 bytes */
73 ber->data[i++] = data_len;
77 /* Calculate the number of octets for the length field */
84 ber->data[i++] = 0x80 | c;
86 /* Put the actual length field octets, 8-bits per octet. */
88 ber->data[i++] = (data_len >> (--c * 8)) & 0xff;
89 ber->data[i++] = data_len & 0xff;
92 /* In indefinite form the length of data is not present in the BER */
93 ber->data[i++] = 0x80;
98 memcpy(&ber->data[i], data, data_len);
100 /* Put end-of-content octets if length is indefinite */
102 ber->data[i + data_len] = ber->data[i + data_len + 1] = 0x00;
107 /* Decodesa a BER data from the buffer `ber'. Returns the class,
108 encoding and the tag number for the BER data into `ber_class',
109 `encoding' and `tag'. A pointer to the start of the data area is
110 returned into `data'. If the length of the data is available from
111 the BER data the length is returned into `data_len'. If the
112 `indefinite' is TRUE then the length found in `data_len' was found
113 by finding end-of-contents octets from the data. The
114 `identifier_len' is the length of the BER header, and the length
115 of the entire BER object is `identifier_len' + `data_len'. */
117 bool silc_ber_decode(SilcBuffer ber, SilcBerClass *ber_class,
118 SilcBerEncoding *encoding, SilcUInt32 *tag,
119 const unsigned char **data, SilcUInt32 *data_len,
120 bool *indefinite, SilcUInt32 *identifier_len)
125 if (!ber || silc_buffer_len(ber) == 0) {
126 SILC_LOG_DEBUG(("Invalid data buffer"));
132 *ber_class = (ber->data[0] >> 6) & 0x03;
136 *encoding = (ber->data[0] >> 5) & 0x01;
138 /* Get the tag. Assume short tag, the most common case */
139 t = ber->data[i++] & 0x1f;
141 /* If the tag is over 31 then take it from next octets */
143 if (i >= silc_buffer_len(ber)) {
144 SILC_LOG_DEBUG(("Malformed BER: Not enough bytes"));
148 /* The tag is in next octets in 7-bits parts, parse them out. All
149 octets except the last one has bit 8 set. */
151 while (ber->data[i] & 0x80) {
153 t |= ber->data[i++] & 0x7f;
155 if (i >= silc_buffer_len(ber)) {
156 SILC_LOG_DEBUG(("Malformed BER: Not enough bytes"));
161 /* Last 7-bits part */
163 t |= ber->data[i++] & 0x7f;
168 if (i >= silc_buffer_len(ber)) {
169 SILC_LOG_DEBUG(("Malformed BER: Not enough bytes"));
173 /* Get the data length and the actual data */
174 if (data && data_len) {
175 /* Assume short format for length */
176 *data_len = ber->data[i++];
180 /* The bit 8 is set if the length is in long format */
181 if (*data_len & 0x80) {
182 /* If the format is definite then this octet includes the number
183 of length octets. If indefinite it is zero and data is ended
184 with end-of-contents octets (two zero bytes). */
185 c = *data_len & 0x7f;
187 if (i >= silc_buffer_len(ber)) {
188 SILC_LOG_DEBUG(("Malformed BER: Not enough bytes"));
192 /* Get the length from c many octects (8-bits per octet) */
196 *data_len |= ber->data[i++] & 0xff;
198 if (i >= silc_buffer_len(ber)) {
199 SILC_LOG_DEBUG(("Malformed BER: Length is too long"));
205 /* It is indefinite and we attempt to find out the length by
206 finding the end-of-contents octets. */
210 while (c + 1 < silc_buffer_len(ber)) {
211 if (ber->data[c] == 0x00 && ber->data[c + 1] == 0x00)
215 if (c >= silc_buffer_len(ber)) {
216 SILC_LOG_DEBUG(("Malformed BER: could not find end-of-content"));
223 if (*data_len > silc_buffer_len(ber) - i) {
224 SILC_LOG_DEBUG(("Malformed BER: Length is too long"));
228 /* Pointer to data area */
229 *data = (const unsigned char *)ber->data + i;
238 /* Calculates the length of the encoded BER data object. This utility
239 function can be used to calculate how much to allocate space before
240 encoding with silc_ber_encode. */
242 SilcUInt32 silc_ber_encoded_len(SilcUInt32 tag, SilcUInt32 data_len,
257 if (data_len >= 0x80) {
268 return len + data_len;