1122394Sharti/*
2122394Sharti * Copyright (c) 2001-2003
3122394Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4122394Sharti *	All rights reserved.
5122394Sharti *
6122394Sharti * Author: Harti Brandt <harti@freebsd.org>
7133211Sharti *
8133211Sharti * Redistribution and use in source and binary forms, with or without
9133211Sharti * modification, are permitted provided that the following conditions
10133211Sharti * are met:
11133211Sharti * 1. Redistributions of source code must retain the above copyright
12133211Sharti *    notice, this list of conditions and the following disclaimer.
13122394Sharti * 2. Redistributions in binary form must reproduce the above copyright
14122394Sharti *    notice, this list of conditions and the following disclaimer in the
15122394Sharti *    documentation and/or other materials provided with the distribution.
16133211Sharti *
17133211Sharti * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18133211Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19133211Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20133211Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21133211Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22133211Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23133211Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24133211Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25133211Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26133211Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27133211Sharti * SUCH DAMAGE.
28122394Sharti *
29156066Sharti * $Begemot: bsnmp/lib/asn1.c,v 1.31 2005/10/06 07:14:58 brandt_h Exp $
30122394Sharti *
31122394Sharti * ASN.1 for SNMP.
32122394Sharti */
33122394Sharti#include <sys/types.h>
34122394Sharti#include <stdio.h>
35122394Sharti#include <stdlib.h>
36122394Sharti#include <stdarg.h>
37122394Sharti#include <string.h>
38150920Sharti#ifdef HAVE_STDINT_H
39133211Sharti#include <stdint.h>
40150920Sharti#elif defined(HAVE_INTTYPES_H)
41150920Sharti#include <inttypes.h>
42150920Sharti#endif
43122394Sharti#include <assert.h>
44156066Sharti
45156066Sharti#include "support.h"
46122394Sharti#include "asn1.h"
47122394Sharti
48122394Shartistatic void asn_error_func(const struct asn_buf *, const char *, ...);
49122394Sharti
50122394Shartivoid (*asn_error)(const struct asn_buf *, const char *, ...) = asn_error_func;
51122394Sharti
52122394Sharti/*
53122394Sharti * Read the next header. This reads the tag (note, that only single
54122394Sharti * byte tags are supported for now) and the length field. The length field
55122394Sharti * is restricted to a 32-bit value.
56122394Sharti * All errors of this function stop the decoding.
57122394Sharti */
58122394Shartienum asn_err
59122394Shartiasn_get_header(struct asn_buf *b, u_char *type, asn_len_t *len)
60122394Sharti{
61122394Sharti	u_int length;
62122394Sharti
63122394Sharti	if (b->asn_len == 0) {
64122394Sharti		asn_error(b, "no identifier for header");
65122394Sharti		return (ASN_ERR_EOBUF);
66122394Sharti	}
67122394Sharti	*type = *b->asn_cptr;
68122394Sharti	if ((*type & ASN_TYPE_MASK) > 0x30) {
69122394Sharti		asn_error(b, "types > 0x30 not supported (%u)",
70122394Sharti		    *type & ASN_TYPE_MASK);
71122394Sharti		return (ASN_ERR_FAILED);
72122394Sharti	}
73122394Sharti	b->asn_cptr++;
74122394Sharti	b->asn_len--;
75122394Sharti	if (b->asn_len == 0) {
76122394Sharti		asn_error(b, "no length field");
77122394Sharti		return (ASN_ERR_EOBUF);
78122394Sharti	}
79122394Sharti	if (*b->asn_cptr & 0x80) {
80122394Sharti		length = *b->asn_cptr++ & 0x7f;
81122394Sharti		b->asn_len--;
82122394Sharti		if (length == 0) {
83122394Sharti			asn_error(b, "indefinite length not supported");
84122394Sharti			return (ASN_ERR_FAILED);
85122394Sharti		}
86122394Sharti		if (length > ASN_MAXLENLEN) {
87122394Sharti			asn_error(b, "long length too long (%u)", length);
88122394Sharti			return (ASN_ERR_FAILED);
89122394Sharti		}
90122394Sharti		if (length > b->asn_len) {
91122394Sharti			asn_error(b, "long length truncated");
92122394Sharti			return (ASN_ERR_EOBUF);
93122394Sharti		}
94122394Sharti		*len = 0;
95122394Sharti		while (length--) {
96122394Sharti			*len = (*len << 8) | *b->asn_cptr++;
97122394Sharti			b->asn_len--;
98122394Sharti		}
99122394Sharti	} else {
100122394Sharti		*len = *b->asn_cptr++;
101122394Sharti		b->asn_len--;
102122394Sharti	}
103122394Sharti	return (ASN_ERR_OK);
104122394Sharti}
105122394Sharti
106122394Sharti/*
107122394Sharti * Write a length field (restricted to values < 2^32-1) and return the
108122394Sharti * number of bytes this field takes. If ptr is NULL, the length is computed
109122394Sharti * but nothing is written. If the length would be too large return 0.
110122394Sharti */
111122394Shartistatic u_int
112122394Shartiasn_put_len(u_char *ptr, asn_len_t len)
113122394Sharti{
114122394Sharti	u_int lenlen, lenlen1;
115122394Sharti	asn_len_t tmp;
116122394Sharti
117122394Sharti	if (len > ASN_MAXLEN) {
118122394Sharti		asn_error(NULL, "encoding length too long: (%u)", len);
119122394Sharti		return (0);
120122394Sharti	}
121122394Sharti
122122394Sharti	if (len <= 127) {
123122394Sharti		if (ptr)
124122394Sharti			*ptr++ = (u_char)len;
125122394Sharti		return (1);
126122394Sharti	} else {
127122394Sharti		lenlen = 0;
128122394Sharti		/* compute number of bytes for value (is at least 1) */
129122394Sharti		for (tmp = len; tmp != 0; tmp >>= 8)
130122394Sharti			lenlen++;
131122394Sharti		if (ptr != NULL) {
132122394Sharti			*ptr++ = (u_char)lenlen | 0x80;
133122394Sharti			lenlen1 = lenlen;
134122394Sharti			while (lenlen1-- > 0) {
135122394Sharti				ptr[lenlen1] = len & 0xff;
136122394Sharti				len >>= 8;
137122394Sharti			}
138122394Sharti		}
139122394Sharti		return (lenlen + 1);
140122394Sharti	}
141122394Sharti}
142122394Sharti
143122394Sharti/*
144122394Sharti * Write a header (tag and length fields).
145122394Sharti * Tags are restricted to one byte tags (value <= 0x30) and the
146122394Sharti * lenght field to 16-bit. All errors stop the encoding.
147122394Sharti */
148122394Shartienum asn_err
149122394Shartiasn_put_header(struct asn_buf *b, u_char type, asn_len_t len)
150122394Sharti{
151122394Sharti	u_int lenlen;
152122394Sharti
153122394Sharti	/* tag field */
154122394Sharti	if ((type & ASN_TYPE_MASK) > 0x30) {
155122394Sharti		asn_error(NULL, "types > 0x30 not supported (%u)",
156122394Sharti		    type & ASN_TYPE_MASK);
157122394Sharti		return (ASN_ERR_FAILED);
158122394Sharti	}
159122394Sharti	if (b->asn_len == 0)
160122394Sharti		return (ASN_ERR_EOBUF);
161122394Sharti
162122394Sharti	*b->asn_ptr++ = type;
163122394Sharti	b->asn_len--;
164122394Sharti
165122394Sharti	/* length field */
166122394Sharti	if ((lenlen = asn_put_len(NULL, len)) == 0)
167122394Sharti		return (ASN_ERR_FAILED);
168122394Sharti	if (b->asn_len < lenlen)
169122394Sharti		return (ASN_ERR_EOBUF);
170122394Sharti
171122394Sharti	(void)asn_put_len(b->asn_ptr, len);
172122394Sharti	b->asn_ptr += lenlen;
173122394Sharti	b->asn_len -= lenlen;
174122394Sharti	return (ASN_ERR_OK);
175122394Sharti}
176122394Sharti
177122394Sharti
178122394Sharti/*
179122394Sharti * This constructs a temporary sequence header with space for the maximum
180122394Sharti * length field (three byte). Set the pointer that ptr points to to the
181122394Sharti * start of the encoded header. This is used for a later call to
182122394Sharti * asn_commit_header which will fix-up the length field and move the
183122394Sharti * value if needed. All errors should stop the encoding.
184122394Sharti */
185122394Sharti#define	TEMP_LEN (1 + ASN_MAXLENLEN + 1)
186122394Shartienum asn_err
187122394Shartiasn_put_temp_header(struct asn_buf *b, u_char type, u_char **ptr)
188122394Sharti{
189122394Sharti	int ret;
190122394Sharti
191122394Sharti	if (b->asn_len < TEMP_LEN)
192122394Sharti		return (ASN_ERR_EOBUF);
193122394Sharti	*ptr = b->asn_ptr;
194122394Sharti	if ((ret = asn_put_header(b, type, ASN_MAXLEN)) == ASN_ERR_OK)
195122394Sharti		assert(b->asn_ptr == *ptr + TEMP_LEN);
196122394Sharti	return (ret);
197122394Sharti}
198122394Shartienum asn_err
199216294Ssyrinxasn_commit_header(struct asn_buf *b, u_char *ptr, size_t *moved)
200122394Sharti{
201122394Sharti	asn_len_t len;
202122394Sharti	u_int lenlen, shift;
203122394Sharti
204122394Sharti	/* compute length of encoded value without header */
205122394Sharti	len = b->asn_ptr - (ptr + TEMP_LEN);
206122394Sharti
207122394Sharti	/* insert length. may not fail. */
208122394Sharti	lenlen = asn_put_len(ptr + 1, len);
209122394Sharti	if (lenlen > TEMP_LEN - 1)
210122394Sharti		return (ASN_ERR_FAILED);
211122394Sharti
212122394Sharti	if (lenlen < TEMP_LEN - 1) {
213122394Sharti		/* shift value down */
214122394Sharti		shift = (TEMP_LEN - 1) - lenlen;
215122394Sharti		memmove(ptr + 1 + lenlen, ptr + TEMP_LEN, len);
216122394Sharti		b->asn_ptr -= shift;
217122394Sharti		b->asn_len += shift;
218216294Ssyrinx		if (moved != NULL)
219216294Ssyrinx			*moved = shift;
220122394Sharti	}
221122394Sharti	return (ASN_ERR_OK);
222122394Sharti}
223122394Sharti#undef TEMP_LEN
224122394Sharti
225122394Sharti/*
226122394Sharti * BER integer. This may be used to get a signed 64 bit integer at maximum.
227122394Sharti * The maximum length should be checked by the caller. This cannot overflow
228122394Sharti * if the caller ensures that len is at maximum 8.
229122394Sharti *
230122394Sharti * <bytes>
231122394Sharti */
232122394Shartistatic enum asn_err
233122394Shartiasn_get_real_integer(struct asn_buf *b, asn_len_t len, int64_t *vp)
234122394Sharti{
235133211Sharti	uint64_t val;
236122394Sharti	int neg = 0;
237122394Sharti	enum asn_err err;
238122394Sharti
239122394Sharti	if (b->asn_len < len) {
240122394Sharti		asn_error(b, "truncated integer");
241122394Sharti		return (ASN_ERR_EOBUF);
242122394Sharti	}
243122394Sharti	if (len == 0) {
244122394Sharti		asn_error(b, "zero-length integer");
245122394Sharti		*vp = 0;
246122394Sharti		return (ASN_ERR_BADLEN);
247122394Sharti	}
248122394Sharti	err = ASN_ERR_OK;
249122394Sharti	if (len > 8)
250122394Sharti		err = ASN_ERR_RANGE;
251124861Sharti	else if (len > 1 &&
252124861Sharti	    ((*b->asn_cptr == 0x00 && (b->asn_cptr[1] & 0x80) == 0) ||
253124861Sharti	    (*b->asn_cptr == 0xff && (b->asn_cptr[1] & 0x80) == 0x80))) {
254124861Sharti		asn_error(b, "non-minimal integer");
255124861Sharti		err = ASN_ERR_BADLEN;
256124861Sharti	}
257124861Sharti
258122394Sharti	if (*b->asn_cptr & 0x80)
259122394Sharti		neg = 1;
260122394Sharti	val = 0;
261122394Sharti	while (len--) {
262122394Sharti		val <<= 8;
263122394Sharti		val |= neg ? (u_char)~*b->asn_cptr : *b->asn_cptr;
264122394Sharti		b->asn_len--;
265122394Sharti		b->asn_cptr++;
266122394Sharti	}
267122394Sharti	if (neg) {
268122394Sharti		*vp = -(int64_t)val - 1;
269122394Sharti	} else
270122394Sharti		*vp = (int64_t)val;
271122394Sharti	return (err);
272122394Sharti}
273122394Sharti
274122394Sharti/*
275122394Sharti * Write a signed integer with the given type. The caller has to ensure
276122394Sharti * that the actual value is ok for this type.
277122394Sharti */
278122394Shartistatic enum asn_err
279122394Shartiasn_put_real_integer(struct asn_buf *b, u_char type, int64_t ival)
280122394Sharti{
281122394Sharti	int i, neg = 0;
282122394Sharti# define OCTETS 8
283122394Sharti	u_char buf[OCTETS];
284133211Sharti	uint64_t val;
285122394Sharti	enum asn_err ret;
286122394Sharti
287122394Sharti	if (ival < 0) {
288122394Sharti		/* this may fail if |INT64_MIN| > |INT64_MAX| and
289122394Sharti		 * the value is between * INT64_MIN <= ival < -(INT64_MAX+1) */
290133211Sharti		val = (uint64_t)-(ival + 1);
291122394Sharti		neg = 1;
292122394Sharti	} else
293133211Sharti		val = (uint64_t)ival;
294122394Sharti
295122394Sharti	/* split the value into octets */
296122394Sharti	for (i = OCTETS - 1; i >= 0; i--) {
297122394Sharti		buf[i] = val & 0xff;
298122394Sharti		if (neg)
299122394Sharti			buf[i] = ~buf[i];
300122394Sharti		val >>= 8;
301122394Sharti	}
302122394Sharti	/* no leading 9 zeroes or ones */
303122394Sharti	for (i = 0; i < OCTETS - 1; i++)
304122394Sharti		if (!((buf[i] == 0xff && (buf[i + 1] & 0x80) != 0) ||
305122394Sharti		    (buf[i] == 0x00 && (buf[i + 1] & 0x80) == 0)))
306122394Sharti			break;
307122394Sharti	if ((ret = asn_put_header(b, type, OCTETS - i)))
308122394Sharti		return (ret);
309122394Sharti	if (OCTETS - (u_int)i > b->asn_len)
310122394Sharti		return (ASN_ERR_EOBUF);
311122394Sharti
312122394Sharti	while (i < OCTETS) {
313122394Sharti		*b->asn_ptr++ = buf[i++];
314122394Sharti		b->asn_len--;
315122394Sharti	}
316122394Sharti	return (ASN_ERR_OK);
317122394Sharti# undef OCTETS
318122394Sharti}
319122394Sharti
320122394Sharti
321122394Sharti/*
322122394Sharti * The same for unsigned 64-bitters. Here we have the problem, that overflow
323122394Sharti * can happen, because the value maybe 9 bytes long. In this case the
324122394Sharti * first byte must be 0.
325122394Sharti */
326122394Shartistatic enum asn_err
327133211Shartiasn_get_real_unsigned(struct asn_buf *b, asn_len_t len, uint64_t *vp)
328122394Sharti{
329122394Sharti	enum asn_err err;
330122394Sharti
331122394Sharti	if (b->asn_len < len) {
332122394Sharti		asn_error(b, "truncated integer");
333122394Sharti		return (ASN_ERR_EOBUF);
334122394Sharti	}
335122394Sharti	if (len == 0) {
336122394Sharti		asn_error(b, "zero-length integer");
337122394Sharti		*vp = 0;
338122394Sharti		return (ASN_ERR_BADLEN);
339122394Sharti	}
340122394Sharti	err = ASN_ERR_OK;
341122394Sharti	*vp = 0;
342122394Sharti	if ((*b->asn_cptr & 0x80) || (len == 9 && *b->asn_cptr != 0)) {
343122394Sharti		/* negative integer or too larger */
344122394Sharti		*vp = 0xffffffffffffffffULL;
345122394Sharti		err = ASN_ERR_RANGE;
346124861Sharti	} else if (len > 1 &&
347124861Sharti	    *b->asn_cptr == 0x00 && (b->asn_cptr[1] & 0x80) == 0) {
348124861Sharti		asn_error(b, "non-minimal unsigned");
349124861Sharti		err = ASN_ERR_BADLEN;
350122394Sharti	}
351122394Sharti
352122394Sharti	while (len--) {
353122394Sharti		*vp = (*vp << 8) | *b->asn_cptr++;
354122394Sharti		b->asn_len--;
355122394Sharti	}
356122394Sharti	return (err);
357122394Sharti}
358122394Sharti
359122394Sharti
360122394Sharti/*
361122394Sharti * Values with the msb on need 9 octets.
362122394Sharti */
363122394Shartistatic int
364133211Shartiasn_put_real_unsigned(struct asn_buf *b, u_char type, uint64_t val)
365122394Sharti{
366122394Sharti	int i;
367122394Sharti# define OCTETS 9
368122394Sharti	u_char buf[OCTETS];
369122394Sharti	enum asn_err ret;
370122394Sharti
371122394Sharti	/* split the value into octets */
372122394Sharti	for (i = OCTETS - 1; i >= 0; i--) {
373122394Sharti		buf[i] = val & 0xff;
374122394Sharti		val >>= 8;
375122394Sharti	}
376122394Sharti	/* no leading 9 zeroes */
377122394Sharti	for (i = 0; i < OCTETS - 1; i++)
378122394Sharti		if (!(buf[i] == 0x00 && (buf[i + 1] & 0x80) == 0))
379122394Sharti			break;
380122394Sharti	if ((ret = asn_put_header(b, type, OCTETS - i)))
381122394Sharti		return (ret);
382122394Sharti	if (OCTETS - (u_int)i > b->asn_len)
383122394Sharti		return (ASN_ERR_EOBUF);
384122394Sharti
385122394Sharti	while (i < OCTETS) {
386122394Sharti		*b->asn_ptr++ = buf[i++];
387122394Sharti		b->asn_len--;
388122394Sharti	}
389122394Sharti#undef OCTETS
390122394Sharti	return (ASN_ERR_OK);
391122394Sharti}
392122394Sharti
393122394Sharti/*
394122394Sharti * The ASN.1 INTEGER type is restricted to 32-bit signed by the SMI.
395122394Sharti */
396122394Shartienum asn_err
397122394Shartiasn_get_integer_raw(struct asn_buf *b, asn_len_t len, int32_t *vp)
398122394Sharti{
399122394Sharti	int64_t val;
400122394Sharti	enum asn_err ret;
401122394Sharti
402122394Sharti	if ((ret = asn_get_real_integer(b, len, &val)) == ASN_ERR_OK) {
403122394Sharti		if (len > 4)
404122394Sharti			ret = ASN_ERR_BADLEN;
405122394Sharti		else if (val > INT32_MAX || val < INT32_MIN)
406122394Sharti			/* may not happen */
407122394Sharti			ret = ASN_ERR_RANGE;
408122394Sharti		*vp = (int32_t)val;
409122394Sharti	}
410122394Sharti	return (ret);
411122394Sharti}
412122394Sharti
413122394Shartienum asn_err
414122394Shartiasn_get_integer(struct asn_buf *b, int32_t *vp)
415122394Sharti{
416122394Sharti	asn_len_t len;
417122394Sharti	u_char type;
418122394Sharti	enum asn_err err;
419122394Sharti
420122394Sharti	if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK)
421122394Sharti		return (err);
422122394Sharti	if (type != ASN_TYPE_INTEGER) {
423122394Sharti		asn_error(b, "bad type for integer (%u)", type);
424122394Sharti		return (ASN_ERR_TAG);
425122394Sharti	}
426122394Sharti
427122394Sharti	return (asn_get_integer_raw(b, len, vp));
428122394Sharti}
429122394Sharti
430122394Shartienum asn_err
431122394Shartiasn_put_integer(struct asn_buf *b, int32_t val)
432122394Sharti{
433122394Sharti	return (asn_put_real_integer(b, ASN_TYPE_INTEGER, val));
434122394Sharti}
435122394Sharti
436122394Sharti/*
437122394Sharti * OCTETSTRING
438122394Sharti *
439122394Sharti * <0x04> <len> <data ...>
440122394Sharti *
441122394Sharti * Get an octetstring. noctets must point to the buffer size and on
442122394Sharti * return will contain the size of the octetstring, regardless of the
443122394Sharti * buffer size.
444122394Sharti */
445122394Shartienum asn_err
446122394Shartiasn_get_octetstring_raw(struct asn_buf *b, asn_len_t len, u_char *octets,
447122394Sharti    u_int *noctets)
448122394Sharti{
449122394Sharti	enum asn_err err = ASN_ERR_OK;
450122394Sharti
451122394Sharti	if (*noctets < len) {
452122394Sharti		asn_error(b, "octetstring truncated");
453122394Sharti		err = ASN_ERR_RANGE;
454122394Sharti	}
455122394Sharti	if (b->asn_len < len) {
456122394Sharti		asn_error(b, "truncatet octetstring");
457122394Sharti		return (ASN_ERR_EOBUF);
458122394Sharti	}
459122394Sharti	if (*noctets < len)
460122394Sharti		memcpy(octets, b->asn_cptr, *noctets);
461122394Sharti	else
462122394Sharti		memcpy(octets, b->asn_cptr, len);
463122394Sharti	*noctets = len;
464122394Sharti	b->asn_cptr += len;
465122394Sharti	b->asn_len -= len;
466122394Sharti	return (err);
467122394Sharti}
468122394Sharti
469122394Shartienum asn_err
470122394Shartiasn_get_octetstring(struct asn_buf *b, u_char *octets, u_int *noctets)
471122394Sharti{
472122394Sharti	enum asn_err err;
473122394Sharti	u_char type;
474122394Sharti	asn_len_t len;
475122394Sharti
476122394Sharti	if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK)
477122394Sharti		return (err);
478122394Sharti	if (type != ASN_TYPE_OCTETSTRING) {
479122394Sharti		asn_error(b, "bad type for octetstring (%u)", type);
480122394Sharti		return (ASN_ERR_TAG);
481122394Sharti	}
482122394Sharti	return (asn_get_octetstring_raw(b, len, octets, noctets));
483122394Sharti}
484122394Sharti
485122394Shartienum asn_err
486122394Shartiasn_put_octetstring(struct asn_buf *b, const u_char *octets, u_int noctets)
487122394Sharti{
488122394Sharti	enum asn_err ret;
489122394Sharti
490122394Sharti	if ((ret = asn_put_header(b, ASN_TYPE_OCTETSTRING, noctets)) != ASN_ERR_OK)
491122394Sharti		return (ret);
492122394Sharti	if (b->asn_len < noctets)
493122394Sharti		return (ASN_ERR_EOBUF);
494122394Sharti
495122394Sharti	memcpy(b->asn_ptr, octets, noctets);
496122394Sharti	b->asn_ptr += noctets;
497122394Sharti	b->asn_len -= noctets;
498122394Sharti	return (ASN_ERR_OK);
499122394Sharti}
500122394Sharti
501122394Sharti/*
502122394Sharti * NULL
503122394Sharti *
504122394Sharti * <0x05> <0x00>
505122394Sharti */
506122394Shartienum asn_err
507122394Shartiasn_get_null_raw(struct asn_buf *b, asn_len_t len)
508122394Sharti{
509122394Sharti	if (len != 0) {
510122394Sharti		if (b->asn_len < len) {
511122394Sharti			asn_error(b, "truncated NULL");
512122394Sharti			return (ASN_ERR_EOBUF);
513122394Sharti		}
514122394Sharti		asn_error(b, "bad length for NULL (%u)", len);
515122394Sharti		b->asn_len -= len;
516122394Sharti		b->asn_ptr += len;
517122394Sharti		return (ASN_ERR_BADLEN);
518122394Sharti	}
519122394Sharti	return (ASN_ERR_OK);
520122394Sharti}
521122394Sharti
522122394Shartienum asn_err
523122394Shartiasn_get_null(struct asn_buf *b)
524122394Sharti{
525122394Sharti	u_char type;
526122394Sharti	asn_len_t len;
527122394Sharti	enum asn_err err;
528122394Sharti
529122394Sharti	if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK)
530122394Sharti		return (err);
531122394Sharti	if (type != ASN_TYPE_NULL) {
532122394Sharti		asn_error(b, "bad type for NULL (%u)", type);
533122394Sharti		return (ASN_ERR_TAG);
534122394Sharti	}
535122394Sharti	return (asn_get_null_raw(b, len));
536122394Sharti}
537122394Sharti
538122394Shartienum asn_err
539122394Shartiasn_put_null(struct asn_buf *b)
540122394Sharti{
541122394Sharti	return (asn_put_header(b, ASN_TYPE_NULL, 0));
542122394Sharti}
543122394Sharti
544122394Shartienum asn_err
545122394Shartiasn_put_exception(struct asn_buf *b, u_int except)
546122394Sharti{
547122394Sharti	return (asn_put_header(b, ASN_CLASS_CONTEXT | except, 0));
548122394Sharti}
549122394Sharti
550122394Sharti/*
551122394Sharti * OBJID
552122394Sharti *
553122394Sharti * <0x06> <len> <subid...>
554122394Sharti */
555122394Shartienum asn_err
556122394Shartiasn_get_objid_raw(struct asn_buf *b, asn_len_t len, struct asn_oid *oid)
557122394Sharti{
558122394Sharti	asn_subid_t subid;
559122394Sharti	enum asn_err err;
560122394Sharti
561122394Sharti	if (b->asn_len < len) {
562122394Sharti		asn_error(b, "truncated OBJID");
563122394Sharti		return (ASN_ERR_EOBUF);
564122394Sharti	}
565122394Sharti	oid->len = 0;
566122394Sharti	if (len == 0) {
567122394Sharti		asn_error(b, "short OBJID");
568122394Sharti		oid->subs[oid->len++] = 0;
569122394Sharti		oid->subs[oid->len++] = 0;
570122394Sharti		return (ASN_ERR_BADLEN);
571122394Sharti	}
572122394Sharti	err = ASN_ERR_OK;
573122394Sharti	while (len != 0) {
574122394Sharti		if (oid->len == ASN_MAXOIDLEN) {
575122394Sharti			asn_error(b, "OID too long (%u)", oid->len);
576122394Sharti			b->asn_cptr += len;
577122394Sharti			b->asn_len -= len;
578122394Sharti			return (ASN_ERR_BADLEN);
579122394Sharti		}
580122394Sharti		subid = 0;
581122394Sharti		do {
582122394Sharti			if (len == 0) {
583122394Sharti				asn_error(b, "unterminated subid");
584122394Sharti				return (ASN_ERR_EOBUF);
585122394Sharti			}
586122394Sharti			if (subid > (ASN_MAXID >> 7)) {
587122394Sharti				asn_error(b, "OBID subid too larger");
588122394Sharti				err = ASN_ERR_RANGE;
589122394Sharti			}
590122394Sharti			subid = (subid << 7) | (*b->asn_cptr & 0x7f);
591122394Sharti			len--;
592122394Sharti			b->asn_len--;
593122394Sharti		} while (*b->asn_cptr++ & 0x80);
594122394Sharti		if (oid->len == 0) {
595122394Sharti			if (subid < 80) {
596122394Sharti				oid->subs[oid->len++] = subid / 40;
597122394Sharti				oid->subs[oid->len++] = subid % 40;
598122394Sharti			} else {
599122394Sharti				oid->subs[oid->len++] = 2;
600122394Sharti				oid->subs[oid->len++] = subid - 80;
601122394Sharti			}
602122394Sharti		} else {
603122394Sharti			oid->subs[oid->len++] = subid;
604122394Sharti		}
605122394Sharti	}
606122394Sharti	return (err);
607122394Sharti
608122394Sharti}
609122394Sharti
610122394Shartienum asn_err
611122394Shartiasn_get_objid(struct asn_buf *b, struct asn_oid *oid)
612122394Sharti{
613122394Sharti	u_char type;
614122394Sharti	asn_len_t len;
615122394Sharti	enum asn_err err;
616122394Sharti
617122394Sharti	if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK)
618122394Sharti		return (err);
619122394Sharti	if (type != ASN_TYPE_OBJID) {
620122394Sharti		asn_error(b, "bad type for OBJID (%u)", type);
621122394Sharti		return (ASN_ERR_TAG);
622122394Sharti	}
623122394Sharti	return (asn_get_objid_raw(b, len, oid));
624122394Sharti}
625122394Sharti
626122394Shartienum asn_err
627122394Shartiasn_put_objid(struct asn_buf *b, const struct asn_oid *oid)
628122394Sharti{
629122394Sharti	asn_subid_t first, sub;
630122394Sharti	enum asn_err err, err1;
631122394Sharti	u_int i, oidlen;
632122394Sharti	asn_len_t len;
633122394Sharti
634122394Sharti	err = ASN_ERR_OK;
635122394Sharti	if (oid->len == 0) {
636122394Sharti		/* illegal */
637122394Sharti		asn_error(NULL, "short oid");
638122394Sharti		err = ASN_ERR_RANGE;
639122394Sharti		first = 0;
640122394Sharti		oidlen = 2;
641122394Sharti	} else if (oid->len == 1) {
642122394Sharti		/* illegal */
643122394Sharti		asn_error(b, "short oid");
644122394Sharti		if (oid->subs[0] > 2)
645122394Sharti			asn_error(NULL, "oid[0] too large (%u)", oid->subs[0]);
646122394Sharti		err = ASN_ERR_RANGE;
647122394Sharti		first = oid->subs[0] * 40;
648122394Sharti		oidlen = 2;
649122394Sharti	} else {
650122394Sharti		if (oid->len > ASN_MAXOIDLEN) {
651122394Sharti			asn_error(NULL, "oid too long %u", oid->len);
652122394Sharti			err = ASN_ERR_RANGE;
653122394Sharti		}
654122394Sharti		if (oid->subs[0] > 2 ||
655122394Sharti		    (oid->subs[0] < 2 && oid->subs[0] >= 40)) {
656122394Sharti			asn_error(NULL, "oid out of range (%u,%u)",
657122394Sharti			    oid->subs[0], oid->subs[1]);
658122394Sharti			err = ASN_ERR_RANGE;
659122394Sharti		}
660122394Sharti		first = 40 * oid->subs[0] + oid->subs[1];
661122394Sharti		oidlen = oid->len;
662122394Sharti	}
663122394Sharti	len = 0;
664122394Sharti	for (i = 1; i < oidlen; i++) {
665122394Sharti		sub = (i == 1) ? first : oid->subs[i];
666122394Sharti		if (sub > ASN_MAXID) {
667122394Sharti			asn_error(NULL, "oid subid too large");
668122394Sharti			err = ASN_ERR_RANGE;
669122394Sharti		}
670122394Sharti		len += (sub <= 0x7f) ? 1
671122394Sharti		    : (sub <= 0x3fff) ? 2
672122394Sharti		    : (sub <= 0x1fffff) ? 3
673122394Sharti		    : (sub <= 0xfffffff) ? 4
674122394Sharti		    : 5;
675122394Sharti	}
676122394Sharti	if ((err1 = asn_put_header(b, ASN_TYPE_OBJID, len)) != ASN_ERR_OK)
677122394Sharti		return (err1);
678122394Sharti	if (b->asn_len < len)
679122394Sharti		return (ASN_ERR_EOBUF);
680122394Sharti
681122394Sharti	for (i = 1; i < oidlen; i++) {
682122394Sharti		sub = (i == 1) ? first : oid->subs[i];
683122394Sharti		if (sub <= 0x7f) {
684122394Sharti			*b->asn_ptr++ = sub;
685122394Sharti			b->asn_len--;
686122394Sharti		} else if (sub <= 0x3fff) {
687122394Sharti			*b->asn_ptr++ = (sub >> 7) | 0x80;
688122394Sharti			*b->asn_ptr++ = sub & 0x7f;
689122394Sharti			b->asn_len -= 2;
690122394Sharti		} else if (sub <= 0x1fffff) {
691122394Sharti			*b->asn_ptr++ = (sub >> 14) | 0x80;
692122394Sharti			*b->asn_ptr++ = ((sub >> 7) & 0x7f) | 0x80;
693122394Sharti			*b->asn_ptr++ = sub & 0x7f;
694122394Sharti			b->asn_len -= 3;
695122394Sharti		} else if (sub <= 0xfffffff) {
696122394Sharti			*b->asn_ptr++ = (sub >> 21) | 0x80;
697122394Sharti			*b->asn_ptr++ = ((sub >> 14) & 0x7f) | 0x80;
698122394Sharti			*b->asn_ptr++ = ((sub >> 7) & 0x7f) | 0x80;
699122394Sharti			*b->asn_ptr++ = sub & 0x7f;
700122394Sharti			b->asn_len -= 4;
701122394Sharti		} else {
702122394Sharti			*b->asn_ptr++ = (sub >> 28) | 0x80;
703122394Sharti			*b->asn_ptr++ = ((sub >> 21) & 0x7f) | 0x80;
704122394Sharti			*b->asn_ptr++ = ((sub >> 14) & 0x7f) | 0x80;
705122394Sharti			*b->asn_ptr++ = ((sub >> 7) & 0x7f) | 0x80;
706122394Sharti			*b->asn_ptr++ = sub & 0x7f;
707122394Sharti			b->asn_len -= 5;
708122394Sharti		}
709122394Sharti	}
710122394Sharti	return (err);
711122394Sharti}
712122394Sharti/*
713122394Sharti * SEQUENCE header
714122394Sharti *
715122394Sharti * <0x10|0x20> <len> <data...>
716122394Sharti */
717122394Shartienum asn_err
718122394Shartiasn_get_sequence(struct asn_buf *b, asn_len_t *len)
719122394Sharti{
720122394Sharti	u_char type;
721122394Sharti	enum asn_err err;
722122394Sharti
723122394Sharti	if ((err = asn_get_header(b, &type, len)) != ASN_ERR_OK)
724122394Sharti		return (err);
725122394Sharti	if (type != (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED)) {
726122394Sharti		asn_error(b, "bad sequence type %u", type);
727122394Sharti		return (ASN_ERR_TAG);
728122394Sharti	}
729122394Sharti	if (*len > b->asn_len) {
730122394Sharti		asn_error(b, "truncated sequence");
731122394Sharti		return (ASN_ERR_EOBUF);
732122394Sharti	}
733122394Sharti	return (ASN_ERR_OK);
734122394Sharti}
735122394Sharti
736122394Sharti/*
737122394Sharti * Application types
738122394Sharti *
739122394Sharti * 0x40 4 MSB 2MSB 2LSB LSB
740122394Sharti */
741122394Shartienum asn_err
742122394Shartiasn_get_ipaddress_raw(struct asn_buf *b, asn_len_t len, u_char *addr)
743122394Sharti{
744122394Sharti	u_int i;
745122394Sharti
746122394Sharti	if (b->asn_len < len) {
747122394Sharti		asn_error(b, "truncated ip-address");
748122394Sharti		return (ASN_ERR_EOBUF);
749122394Sharti	}
750122394Sharti	if (len < 4) {
751122394Sharti		asn_error(b, "short length for ip-Address %u", len);
752122394Sharti		for (i = 0; i < len; i++)
753122394Sharti			*addr++ = *b->asn_cptr++;
754122394Sharti		while (i++ < len)
755122394Sharti			*addr++ = 0;
756122394Sharti		b->asn_len -= len;
757122394Sharti		return (ASN_ERR_BADLEN);
758122394Sharti	}
759122394Sharti	for (i = 0; i < 4; i++)
760122394Sharti		*addr++ = *b->asn_cptr++;
761122394Sharti	b->asn_cptr += len - 4;
762122394Sharti	b->asn_len -= len;
763122394Sharti	return (ASN_ERR_OK);
764122394Sharti}
765122394Sharti
766122394Shartienum asn_err
767122394Shartiasn_get_ipaddress(struct asn_buf *b, u_char *addr)
768122394Sharti{
769122394Sharti	u_char type;
770122394Sharti	asn_len_t len;
771122394Sharti	enum asn_err err;
772122394Sharti
773122394Sharti	if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK)
774122394Sharti		return (err);
775122394Sharti	if (type != (ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS)) {
776122394Sharti		asn_error(b, "bad type for ip-address %u", type);
777122394Sharti		return (ASN_ERR_TAG);
778122394Sharti	}
779122394Sharti	return (asn_get_ipaddress_raw(b, len, addr));
780122394Sharti}
781122394Sharti
782122394Shartienum asn_err
783122394Shartiasn_put_ipaddress(struct asn_buf *b, const u_char *addr)
784122394Sharti{
785122394Sharti	enum asn_err err;
786122394Sharti
787122394Sharti	if ((err = asn_put_header(b, ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS,
788122394Sharti	    4)) != ASN_ERR_OK)
789122394Sharti		return (err);
790122394Sharti	if (b->asn_len < 4)
791122394Sharti		return (ASN_ERR_EOBUF);
792122394Sharti
793122394Sharti	memcpy(b->asn_ptr, addr, 4);
794122394Sharti	b->asn_ptr += 4;
795122394Sharti	b->asn_len -= 4;
796122394Sharti	return (ASN_ERR_OK);
797122394Sharti}
798122394Sharti
799122394Sharti
800122394Sharti/*
801122394Sharti * UNSIGNED32
802122394Sharti *
803122394Sharti * 0x42|0x41 <len> ...
804122394Sharti */
805122394Shartienum asn_err
806133211Shartiasn_get_uint32_raw(struct asn_buf *b, asn_len_t len, uint32_t *vp)
807122394Sharti{
808133211Sharti	uint64_t v;
809122394Sharti	enum asn_err err;
810122394Sharti
811122394Sharti	if ((err = asn_get_real_unsigned(b, len, &v)) == ASN_ERR_OK) {
812122394Sharti		if (len > 5) {
813122394Sharti			asn_error(b, "uint32 too long %u", len);
814122394Sharti			err = ASN_ERR_BADLEN;
815122394Sharti		} else if (v > UINT32_MAX) {
816122394Sharti			asn_error(b, "uint32 too large %llu", v);
817122394Sharti			err = ASN_ERR_RANGE;
818122394Sharti		}
819133211Sharti		*vp = (uint32_t)v;
820122394Sharti	}
821122394Sharti	return (err);
822122394Sharti}
823122394Sharti
824122394Shartienum asn_err
825133211Shartiasn_put_uint32(struct asn_buf *b, u_char type, uint32_t val)
826122394Sharti{
827133211Sharti	uint64_t v = val;
828122394Sharti
829122394Sharti	return (asn_put_real_unsigned(b, ASN_CLASS_APPLICATION|type, v));
830122394Sharti}
831122394Sharti
832122394Sharti/*
833122394Sharti * COUNTER64
834122394Sharti * 0x46 <len> ...
835122394Sharti */
836122394Shartienum asn_err
837133211Shartiasn_get_counter64_raw(struct asn_buf *b, asn_len_t len, uint64_t *vp)
838122394Sharti{
839122394Sharti	return (asn_get_real_unsigned(b, len, vp));
840122394Sharti}
841122394Sharti
842122394Shartienum asn_err
843133211Shartiasn_put_counter64(struct asn_buf *b, uint64_t val)
844122394Sharti{
845122394Sharti	return (asn_put_real_unsigned(b,
846122394Sharti	    ASN_CLASS_APPLICATION | ASN_APP_COUNTER64, val));
847122394Sharti}
848122394Sharti
849122394Sharti/*
850122394Sharti * TimeTicks
851122394Sharti * 0x43 <len> ...
852122394Sharti */
853122394Shartienum asn_err
854133211Shartiasn_get_timeticks(struct asn_buf *b, uint32_t *vp)
855122394Sharti{
856122394Sharti	asn_len_t len;
857122394Sharti	u_char type;
858122394Sharti	enum asn_err err;
859122394Sharti
860122394Sharti	if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK)
861122394Sharti		return (err);
862122394Sharti	if (type != (ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS)) {
863122394Sharti		asn_error(b, "bad type for timeticks %u", type);
864122394Sharti		return (ASN_ERR_TAG);
865122394Sharti	}
866122394Sharti	return (asn_get_uint32_raw(b, len, vp));
867122394Sharti}
868122394Sharti
869122394Shartienum asn_err
870133211Shartiasn_put_timeticks(struct asn_buf *b, uint32_t val)
871122394Sharti{
872133211Sharti	uint64_t v = val;
873122394Sharti
874122394Sharti	return (asn_put_real_unsigned(b,
875122394Sharti	    ASN_CLASS_APPLICATION | ASN_APP_TIMETICKS, v));
876122394Sharti}
877122394Sharti
878122394Sharti/*
879122394Sharti * Construct a new OID by taking a range of sub ids of the original oid.
880122394Sharti */
881122394Shartivoid
882122394Shartiasn_slice_oid(struct asn_oid *dest, const struct asn_oid *src,
883122394Sharti    u_int from, u_int to)
884122394Sharti{
885122394Sharti	if (from >= to) {
886122394Sharti		dest->len = 0;
887122394Sharti		return;
888122394Sharti	}
889122394Sharti	dest->len = to - from;
890122394Sharti	memcpy(dest->subs, &src->subs[from], dest->len * sizeof(dest->subs[0]));
891122394Sharti}
892122394Sharti
893122394Sharti/*
894122394Sharti * Append from to to
895122394Sharti */
896122394Shartivoid
897122394Shartiasn_append_oid(struct asn_oid *to, const struct asn_oid *from)
898122394Sharti{
899122394Sharti	memcpy(&to->subs[to->len], &from->subs[0],
900122394Sharti	    from->len * sizeof(from->subs[0]));
901122394Sharti	to->len += from->len;
902122394Sharti}
903122394Sharti
904122394Sharti/*
905122394Sharti * Skip a value
906122394Sharti */
907122394Shartienum asn_err
908122394Shartiasn_skip(struct asn_buf *b, asn_len_t len)
909122394Sharti{
910122394Sharti	if (b->asn_len < len)
911122394Sharti		return (ASN_ERR_EOBUF);
912122394Sharti	b->asn_cptr += len;
913122394Sharti	b->asn_len -= len;
914122394Sharti	return (ASN_ERR_OK);
915122394Sharti}
916122394Sharti
917122394Sharti/*
918216294Ssyrinx * Add a padding
919216294Ssyrinx */
920216294Ssyrinxenum asn_err
921216294Ssyrinxasn_pad(struct asn_buf *b, asn_len_t len)
922216294Ssyrinx{
923216294Ssyrinx	if (b->asn_len < len)
924216294Ssyrinx		return (ASN_ERR_EOBUF);
925216294Ssyrinx	b->asn_ptr += len;
926216294Ssyrinx	b->asn_len -= len;
927216294Ssyrinx
928216294Ssyrinx	return (ASN_ERR_OK);
929216294Ssyrinx}
930216294Ssyrinx
931216294Ssyrinx/*
932122394Sharti * Compare two OIDs.
933122394Sharti *
934122394Sharti * o1 < o2 : -1
935122394Sharti * o1 > o2 : +1
936122394Sharti * o1 = o2 :  0
937122394Sharti */
938122394Shartiint
939122394Shartiasn_compare_oid(const struct asn_oid *o1, const struct asn_oid *o2)
940122394Sharti{
941122394Sharti	u_long i;
942122394Sharti
943122394Sharti	for (i = 0; i < o1->len && i < o2->len; i++) {
944122394Sharti		if (o1->subs[i] < o2->subs[i])
945122394Sharti			return (-1);
946122394Sharti		if (o1->subs[i] > o2->subs[i])
947122394Sharti			return (+1);
948122394Sharti	}
949122394Sharti	if (o1->len < o2->len)
950122394Sharti		return (-1);
951122394Sharti	if (o1->len > o2->len)
952122394Sharti		return (+1);
953122394Sharti	return (0);
954122394Sharti}
955122394Sharti
956122394Sharti/*
957122394Sharti * Check whether an OID is a sub-string of another OID.
958122394Sharti */
959122394Shartiint
960122394Shartiasn_is_suboid(const struct asn_oid *o1, const struct asn_oid *o2)
961122394Sharti{
962122394Sharti	u_long i;
963122394Sharti
964122394Sharti	for (i = 0; i < o1->len; i++)
965122394Sharti		if (i >= o2->len || o1->subs[i] != o2->subs[i])
966122394Sharti			return (0);
967122394Sharti	return (1);
968122394Sharti}
969122394Sharti
970122394Sharti/*
971122394Sharti * Put a string representation of an oid into a user buffer. This buffer
972122394Sharti * is assumed to be at least ASN_OIDSTRLEN characters long.
973122394Sharti *
974122394Sharti * sprintf is assumed not to fail here.
975122394Sharti */
976122394Shartichar *
977122394Shartiasn_oid2str_r(const struct asn_oid *oid, char *buf)
978122394Sharti{
979122394Sharti	u_int len, i;
980122394Sharti	char *ptr;
981122394Sharti
982122394Sharti	if ((len = oid->len) > ASN_MAXOIDLEN)
983122394Sharti		len = ASN_MAXOIDLEN;
984122394Sharti	buf[0] = '\0';
985122394Sharti	for (i = 0, ptr = buf; i < len; i++) {
986122394Sharti		if (i > 0)
987122394Sharti			*ptr++ = '.';
988122394Sharti		ptr += sprintf(ptr, "%u", oid->subs[i]);
989122394Sharti	}
990122394Sharti	return (buf);
991122394Sharti}
992122394Sharti
993122394Sharti/*
994122394Sharti * Make a string from an OID in a private buffer.
995122394Sharti */
996122394Shartichar *
997122394Shartiasn_oid2str(const struct asn_oid *oid)
998122394Sharti{
999122394Sharti	static char str[ASN_OIDSTRLEN];
1000122394Sharti
1001122394Sharti	return (asn_oid2str_r(oid, str));
1002122394Sharti}
1003122394Sharti
1004122394Sharti
1005122394Shartistatic void
1006122394Shartiasn_error_func(const struct asn_buf *b, const char *err, ...)
1007122394Sharti{
1008122394Sharti	va_list ap;
1009122394Sharti	u_long i;
1010122394Sharti
1011122394Sharti	fprintf(stderr, "ASN.1: ");
1012122394Sharti	va_start(ap, err);
1013122394Sharti	vfprintf(stderr, err, ap);
1014122394Sharti	va_end(ap);
1015122394Sharti
1016122394Sharti	if (b != NULL) {
1017122394Sharti		fprintf(stderr, " at");
1018122394Sharti		for (i = 0; b->asn_len > i; i++)
1019122394Sharti			fprintf(stderr, " %02x", b->asn_cptr[i]);
1020122394Sharti	}
1021122394Sharti	fprintf(stderr, "\n");
1022122394Sharti}
1023