Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / env / common / vera / niu_ippktgen / C / libnet / src / libnet_asn1.c
CommitLineData
86530b38
AT
1/*
2 * $Id: libnet_asn1.c,v 1.19 2005/11/29 22:53:41 carlosc Exp $
3 *
4 * libnet 1.1
5 * libnet_asn1.c - Abstract Syntax Notation One routines
6 *
7 * Abstract Syntax Notation One, ASN.1
8 * As defined in ISO/IS 8824 and ISO/IS 8825
9 * This implements a subset of the above International Standards that
10 * is sufficient to implement SNMP.
11 *
12 * Encodes abstract data types into a machine independent stream of bytes.
13 *
14 * Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University
15 * All rights reserved.
16 *
17 * Permission to use, copy, modify, and distribute this software and its
18 * documentation for any purpose and without fee is hereby granted,
19 * provided that the above copyright notice appear in all copies and that
20 * both that copyright notice and this permission notice appear in
21 * supporting documentation, and that the name of CMU not be
22 * used in advertising or publicity pertaining to distribution of the
23 * software without specific, written prior permission.
24 *
25 * CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
26 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
27 * CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
28 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
29 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
30 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
31 * SOFTWARE.
32 *
33 * Copyright (c) 1998 - 2004 Mike D. Schiffman <mike@infonexus.com>
34 * All rights reserved.
35 *
36 * Copyright (c) 1993, 1994, 1995, 1996, 1998
37 * The Regents of the University of California. All rights reserved.
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that: (1) source code distributions
41 * retain the above copyright notice and this paragraph in its entirety, (2)
42 * distributions including binary code include the above copyright notice and
43 * this paragraph in its entirety in the documentation or other materials
44 * provided with the distribution, and (3) all advertising materials mentioning
45 * features or use of this software display the following acknowledgement:
46 * ``This product includes software developed by the University of California,
47 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
48 * the University nor the names of its contributors may be used to endorse
49 * or promote products derived from this software without specific prior
50 * written permission.
51 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
52 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
53 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
54 */
55
56#if (HAVE_CONFIG_H)
57#include "../include/config.h"
58#endif
59#if (!(_WIN32) || (__CYGWIN__))
60#include "../include/libnet.h"
61#else
62#include "../include/win32/libnet.h"
63#endif
64
65u_int8_t *
66libnet_build_asn1_int(u_int8_t *data, int *datalen, u_int8_t type, int32_t *int_p,
67 int int_s)
68{
69 /*
70 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
71 */
72 register int32_t integer;
73 register u_int32_t mask;
74
75 if (int_s != sizeof (int32_t))
76 {
77 return (NULL);
78 }
79 integer = *int_p;
80
81 /*
82 * Truncate "unnecessary" bytes off of the most significant end of this
83 * 2's complement integer. There should be no sequence of 9 consecutive
84 * 1's or 0's at the most significant end of the integer.
85 */
86 mask = ((u_int32_t) 0x1FF) << ((8 * (sizeof (int32_t) - 1)) - 1);
87 /* mask is 0xFF800000 on a big-endian machine */
88
89 while ((((integer & mask) == 0) || ((integer & mask) == mask)) && int_s > 1)
90 {
91 int_s--;
92 integer <<= 8;
93 }
94
95 data = libnet_build_asn1_header(data, datalen, type, int_s);
96
97 if (data == NULL || *datalen < int_s)
98 {
99 return (NULL);
100 }
101
102 *datalen -= int_s;
103
104 mask = ((u_int32_t) 0xFF) << (8 * (sizeof(int32_t) - 1));
105 /* mask is 0xFF000000 on a big-endian machine */
106
107 while (int_s--)
108 {
109 *data++ = (u_int8_t)((integer & mask) >> (8 * (sizeof (int32_t) - 1)));
110 integer <<= 8;
111 }
112 return (data);
113}
114
115
116u_int8_t *
117libnet_build_asn1_uint(u_int8_t *data, int *datalen, u_int8_t type, u_int32_t *int_p,
118 int int_s)
119{
120 /*
121 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
122 */
123 register u_int32_t integer;
124 register u_int32_t mask;
125 int add_null_byte = 0;
126
127 if (int_s != sizeof (int32_t))
128 {
129 return (NULL);
130 }
131 integer = *int_p;
132
133 mask = ((u_int32_t) 0xFF) << (8 * (sizeof (int32_t) - 1));
134 /* mask is 0xFF000000 on a big-endian machine */
135
136 if ((u_int8_t)((integer & mask) >> (8 * (sizeof (int32_t) - 1))) & 0x80)
137 {
138 /* if MSB is set */
139 add_null_byte = 1;
140 int_s++;
141 }
142 else
143 {
144 /*
145 * Truncate "unnecessary" bytes off of the most significant end of this
146 * 2's complement integer. There should be no sequence of 9
147 * consecutive 1's or 0's at the most significant end of the
148 * integer.
149 */
150 mask = ((u_int32_t) 0x1FF) << ((8 * (sizeof(int32_t) - 1)) - 1);
151 /* mask is 0xFF800000 on a big-endian machine */
152
153 while (((integer & mask) == 0) && int_s > 1)
154 {
155 int_s--;
156 integer <<= 8;
157 }
158 }
159
160 data = libnet_build_asn1_header(data, datalen, type, int_s);
161
162 if (data == NULL || *datalen < int_s)
163 {
164 return (NULL);
165 }
166
167 *datalen -= int_s;
168
169 if (add_null_byte == 1)
170 {
171 *data++ = '\0';
172 int_s--;
173 }
174
175 mask = ((u_int32_t) 0xFF) << (8 * (sizeof(int32_t) - 1));
176 /* mask is 0xFF000000 on a big-endian machine */
177
178 while (int_s--)
179 {
180 *data++ = (u_int8_t)((integer & mask) >> (8 * (sizeof (int32_t) - 1)));
181 integer <<= 8;
182 }
183 return (data);
184}
185
186
187u_int8_t *
188libnet_build_asn1_string(u_int8_t *data, int *datalen, u_int8_t type,
189 u_int8_t *string, int str_s)
190{
191
192 /*
193 * ASN.1 octet string ::= primstring | cmpdstring
194 * primstring ::= 0x04 asnlength byte {byte}*
195 * cmpdstring ::= 0x24 asnlength string {string}*
196 * This code will never send a compound string.
197 */
198 data = libnet_build_asn1_header(data, datalen, type, str_s);
199
200 if (data == NULL || *datalen < str_s)
201 {
202 return (NULL);
203 }
204 memmove(data, string, str_s);
205 *datalen -= str_s;
206
207 return (data + str_s);
208}
209
210
211u_int8_t *
212libnet_build_asn1_header(u_int8_t *data, int *datalen, u_int8_t type, int len)
213{
214 if (*datalen < 1)
215 {
216 return (NULL);
217 }
218 *data++ = type;
219 (*datalen)--;
220
221 return (libnet_build_asn1_length(data, datalen, len));
222}
223
224
225u_int8_t *
226libnet_build_asn1_sequence(u_int8_t *data, int *datalen, u_int8_t type, int len)
227{
228 *datalen -= 4;
229 if (*datalen < 0)
230 {
231 *datalen += 4; /* fix up before punting */
232 return (NULL);
233 }
234 *data++ = type;
235 *data++ = (u_int8_t)(0x02 | ASN_LONG_LEN);
236 *data++ = (u_int8_t)((len >> 8) & 0xFF);
237 *data++ = (u_int8_t)(len & 0xFF);
238 return (data);
239}
240
241
242u_int8_t *
243libnet_build_asn1_length(u_int8_t *data, int *datalen, int len)
244{
245 u_int8_t *start_data = data;
246
247 /* no indefinite lengths sent */
248 if (len < 0x80)
249 {
250 if (*datalen < 1)
251 {
252 return (NULL);
253 }
254 *data++ = (u_int8_t)len;
255 }
256 else if (len <= 0xFF)
257 {
258 if (*datalen < 2)
259 {
260 return (NULL);
261 }
262 *data++ = (u_int8_t)(0x01 | ASN_LONG_LEN);
263 *data++ = (u_int8_t)len;
264 }
265 else /* 0xFF < len <= 0xFFFF */
266 {
267 if (*datalen < 3)
268 {
269 return (NULL);
270 }
271 *data++ = (u_int8_t)(0x02 | ASN_LONG_LEN);
272 *data++ = (u_int8_t)((len >> 8) & 0xFF);
273 *data++ = (u_int8_t)(len & 0xFF);
274 }
275 *datalen -= (data - start_data);
276 return (data);
277}
278
279
280u_int8_t *
281libnet_build_asn1_objid(u_int8_t *data, int *datalen, u_int8_t type, oid *objid,
282 int objidlen)
283{
284 /*
285 * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
286 * subidentifier ::= {leadingbyte}* lastbyte
287 * leadingbyte ::= 1 7bitvalue
288 * lastbyte ::= 0 7bitvalue
289 */
290 int asnlen;
291 register oid *op = objid;
292 u_int8_t objid_size[MAX_OID_LEN];
293 register u_int32_t objid_val;
294 u_int32_t first_objid_val;
295 register int i;
296
297 /* check if there are at least 2 sub-identifiers */
298 if (objidlen < 2)
299 {
300 /* there are not, so make OID have two with value of zero */
301 objid_val = 0;
302 objidlen = 2;
303 }
304 else
305 {
306 /* combine the first two values */
307 objid_val = (op[0] * 40) + op[1];
308 op += 2;
309 }
310 first_objid_val = objid_val;
311
312 /* calculate the number of bytes needed to store the encoded value */
313 for (i = 1, asnlen = 0;;)
314 {
315 if (objid_val < (unsigned)0x80)
316 {
317 objid_size[i] = 1;
318 asnlen += 1;
319 }
320 else if (objid_val < (unsigned)0x4000)
321 {
322 objid_size[i] = 2;
323 asnlen += 2;
324 }
325 else if (objid_val < (unsigned)0x200000)
326 {
327 objid_size[i] = 3;
328 asnlen += 3;
329 }
330 else if (objid_val < (unsigned)0x10000000)
331 {
332 objid_size[i] = 4;
333 asnlen += 4;
334 }
335 else
336 {
337 objid_size[i] = 5;
338 asnlen += 5;
339 }
340 i++;
341 if (i >= objidlen)
342 {
343 break;
344 }
345 objid_val = *op++;
346 }
347
348 /* store the ASN.1 tag and length */
349 data = libnet_build_asn1_header(data, datalen, type, asnlen);
350 if (data == NULL || *datalen < asnlen)
351 {
352 return (NULL);
353 }
354
355 /* store the encoded OID value */
356 for (i = 1, objid_val = first_objid_val, op = objid + 2; i < objidlen; i++)
357 {
358 if (i != 1)
359 {
360 objid_val = *op++;
361 }
362 switch (objid_size[i])
363 {
364 case 1:
365 *data++ = (u_int8_t)objid_val;
366 break;
367
368 case 2:
369 *data++ = (u_int8_t)((objid_val >> 7) | 0x80);
370 *data++ = (u_int8_t)(objid_val & 0x07f);
371 break;
372 case 3:
373 *data++ = (u_int8_t)((objid_val >> 14) | 0x80);
374 *data++ = (u_int8_t)((objid_val >> 7 & 0x7f) | 0x80);
375 *data++ = (u_int8_t)(objid_val & 0x07f);
376 break;
377
378 case 4:
379 *data++ = (u_int8_t)((objid_val >> 21) | 0x80);
380 *data++ = (u_int8_t)((objid_val >> 14 & 0x7f) | 0x80);
381 *data++ = (u_int8_t)((objid_val >> 7 & 0x7f) | 0x80);
382 *data++ = (u_int8_t)(objid_val & 0x07f);
383 break;
384
385 case 5:
386 *data++ = (u_int8_t)((objid_val >> 28) | 0x80);
387 *data++ = (u_int8_t)((objid_val >> 21 & 0x7f) | 0x80);
388 *data++ = (u_int8_t)((objid_val >> 14 & 0x7f) | 0x80);
389 *data++ = (u_int8_t)((objid_val >> 7 & 0x7f) | 0x80);
390 *data++ = (u_int8_t)(objid_val & 0x07f);
391 break;
392 }
393 }
394
395 /* return the length and data ptagr */
396 *datalen -= asnlen;
397 return (data);
398}
399
400
401u_int8_t *
402libnet_build_asn1_null(u_int8_t *data, int *datalen, u_int8_t type)
403{
404 /*
405 * ASN.1 null ::= 0x05 0x00
406 */
407 return (libnet_build_asn1_header(data, datalen, type, 0));
408}
409
410
411u_int8_t *
412libnet_build_asn1_bitstring(u_int8_t *data, int *datalen, u_int8_t type,
413 u_int8_t *string, int str_s)
414{
415
416 /*
417 * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
418 */
419 if (str_s < 1 || *string > 7)
420 {
421 return (NULL);
422 }
423 data = libnet_build_asn1_header(data, datalen, type, str_s);
424
425 if (data == NULL || *datalen < str_s)
426 {
427 return (NULL);
428 }
429
430 memmove(data, string, str_s);
431 *datalen -= str_s;
432
433 return (data + str_s);
434}
435
436/* EOF */