asn1.c revision 122394
1100894Srwatson/*
2189797Srwatson * Copyright (c) 2001-2003
3100894Srwatson *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4145160Srwatson *	All rights reserved.
5163606Srwatson *
6182063Srwatson * Author: Harti Brandt <harti@freebsd.org>
7100894Srwatson *
8100894Srwatson * Redistribution of this software and documentation and use in source and
9100894Srwatson * binary forms, with or without modification, are permitted provided that
10100894Srwatson * the following conditions are met:
11100894Srwatson *
12106392Srwatson * 1. Redistributions of source code or documentation must retain the above
13106392Srwatson *    copyright notice, this list of conditions and the following disclaimer.
14106392Srwatson * 2. Redistributions in binary form must reproduce the above copyright
15106392Srwatson *    notice, this list of conditions and the following disclaimer in the
16100894Srwatson *    documentation and/or other materials provided with the distribution.
17147983Srwatson * 3. Neither the name of the Institute nor the names of its contributors
18147983Srwatson *    may be used to endorse or promote products derived from this software
19147983Srwatson *    without specific prior written permission.
20189797Srwatson *
21189797Srwatson * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS
22189797Srwatson * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23100894Srwatson * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24100894Srwatson * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
25100894Srwatson * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS  BE LIABLE FOR ANY DIRECT, INDIRECT,
26100894Srwatson * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27100894Srwatson * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
28100894Srwatson * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29100894Srwatson * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30100894Srwatson * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
31100894Srwatson * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32100894Srwatson *
33100894Srwatson * $Begemot: bsnmp/lib/asn1.c,v 1.24 2003/01/28 13:44:34 hbb Exp $
34100894Srwatson *
35100894Srwatson * ASN.1 for SNMP.
36100894Srwatson */
37100894Srwatson#include <sys/types.h>
38100894Srwatson#include <stdio.h>
39100894Srwatson#include <stdlib.h>
40100894Srwatson#include <stdarg.h>
41100894Srwatson#include <string.h>
42100894Srwatson#include <inttypes.h>
43100894Srwatson#include <assert.h>
44116182Sobrien#include "asn1.h"
45116182Sobrien
46116182Sobrienstatic void asn_error_func(const struct asn_buf *, const char *, ...);
47116182Sobrien
48100894Srwatsonvoid (*asn_error)(const struct asn_buf *, const char *, ...) = asn_error_func;
49101173Srwatson
50100894Srwatson/*
51263233Srwatson * Read the next header. This reads the tag (note, that only single
52177785Skib * byte tags are supported for now) and the length field. The length field
53100979Srwatson * is restricted to a 32-bit value.
54100979Srwatson * All errors of this function stop the decoding.
55102949Sbde */
56100979Srwatsonenum asn_err
57100979Srwatsonasn_get_header(struct asn_buf *b, u_char *type, asn_len_t *len)
58100979Srwatson{
59100979Srwatson	u_int length;
60219028Snetchild
61100894Srwatson	if (b->asn_len == 0) {
62100894Srwatson		asn_error(b, "no identifier for header");
63100979Srwatson		return (ASN_ERR_EOBUF);
64100979Srwatson	}
65100979Srwatson	*type = *b->asn_cptr;
66100979Srwatson	if ((*type & ASN_TYPE_MASK) > 0x30) {
67100979Srwatson		asn_error(b, "types > 0x30 not supported (%u)",
68100979Srwatson		    *type & ASN_TYPE_MASK);
69100979Srwatson		return (ASN_ERR_FAILED);
70100894Srwatson	}
71163606Srwatson	b->asn_cptr++;
72121374Srwatson	b->asn_len--;
73165469Srwatson	if (b->asn_len == 0) {
74121374Srwatson		asn_error(b, "no length field");
75100979Srwatson		return (ASN_ERR_EOBUF);
76100979Srwatson	}
77219258Snetchild	if (*b->asn_cptr & 0x80) {
78219028Snetchild		length = *b->asn_cptr++ & 0x7f;
79105988Srwatson		b->asn_len--;
80225617Skmacy		if (length == 0) {
81105694Srwatson			asn_error(b, "indefinite length not supported");
82105694Srwatson			return (ASN_ERR_FAILED);
83105694Srwatson		}
84105694Srwatson		if (length > ASN_MAXLENLEN) {
85105694Srwatson			asn_error(b, "long length too long (%u)", length);
86105694Srwatson			return (ASN_ERR_FAILED);
87105694Srwatson		}
88107849Salfred		if (length > b->asn_len) {
89105694Srwatson			asn_error(b, "long length truncated");
90105694Srwatson			return (ASN_ERR_EOBUF);
91105694Srwatson		}
92105694Srwatson		*len = 0;
93105694Srwatson		while (length--) {
94105694Srwatson			*len = (*len << 8) | *b->asn_cptr++;
95105694Srwatson			b->asn_len--;
96105694Srwatson		}
97105694Srwatson	} else {
98105694Srwatson		*len = *b->asn_cptr++;
99105694Srwatson		b->asn_len--;
100105694Srwatson	}
101105694Srwatson	return (ASN_ERR_OK);
102105694Srwatson}
103105694Srwatson
104105694Srwatson/*
105105694Srwatson * Write a length field (restricted to values < 2^32-1) and return the
106105694Srwatson * number of bytes this field takes. If ptr is NULL, the length is computed
107105694Srwatson * but nothing is written. If the length would be too large return 0.
108111119Simp */
109105694Srwatsonstatic u_int
110105694Srwatsonasn_put_len(u_char *ptr, asn_len_t len)
111105694Srwatson{
112105694Srwatson	u_int lenlen, lenlen1;
113105694Srwatson	asn_len_t tmp;
114105694Srwatson
115105694Srwatson	if (len > ASN_MAXLEN) {
116111119Simp		asn_error(NULL, "encoding length too long: (%u)", len);
117172930Srwatson		return (0);
118122159Srwatson	}
119105694Srwatson
120105694Srwatson	if (len <= 127) {
121105694Srwatson		if (ptr)
122105694Srwatson			*ptr++ = (u_char)len;
123105694Srwatson		return (1);
124105694Srwatson	} else {
125105694Srwatson		lenlen = 0;
126105694Srwatson		/* compute number of bytes for value (is at least 1) */
127105694Srwatson		for (tmp = len; tmp != 0; tmp >>= 8)
128100979Srwatson			lenlen++;
129225617Skmacy		if (ptr != NULL) {
130100894Srwatson			*ptr++ = (u_char)lenlen | 0x80;
131105694Srwatson			lenlen1 = lenlen;
132105694Srwatson			while (lenlen1-- > 0) {
133100979Srwatson				ptr[lenlen1] = len & 0xff;
134100894Srwatson				len >>= 8;
135105694Srwatson			}
136105694Srwatson		}
137105694Srwatson		return (lenlen + 1);
138105694Srwatson	}
139105694Srwatson}
140105694Srwatson
141105694Srwatson/*
142105694Srwatson * Write a header (tag and length fields).
143111119Simp * Tags are restricted to one byte tags (value <= 0x30) and the
144105694Srwatson * lenght field to 16-bit. All errors stop the encoding.
145105694Srwatson */
146105694Srwatsonenum asn_err
147105694Srwatsonasn_put_header(struct asn_buf *b, u_char type, asn_len_t len)
148105694Srwatson{
149105694Srwatson	u_int lenlen;
150111119Simp
151172930Srwatson	/* tag field */
152122159Srwatson	if ((type & ASN_TYPE_MASK) > 0x30) {
153100979Srwatson		asn_error(NULL, "types > 0x30 not supported (%u)",
154105694Srwatson		    type & ASN_TYPE_MASK);
155100979Srwatson		return (ASN_ERR_FAILED);
156105694Srwatson	}
157105694Srwatson	if (b->asn_len == 0)
158100979Srwatson		return (ASN_ERR_EOBUF);
159100979Srwatson
160100979Srwatson	*b->asn_ptr++ = type;
161100979Srwatson	b->asn_len--;
162225617Skmacy
163100979Srwatson	/* length field */
164100979Srwatson	if ((lenlen = asn_put_len(NULL, len)) == 0)
165122524Srwatson		return (ASN_ERR_FAILED);
166100979Srwatson	if (b->asn_len < lenlen)
167105694Srwatson		return (ASN_ERR_EOBUF);
168105694Srwatson
169100979Srwatson	(void)asn_put_len(b->asn_ptr, len);
170100979Srwatson	b->asn_ptr += lenlen;
171182063Srwatson	b->asn_len -= lenlen;
172182063Srwatson	return (ASN_ERR_OK);
173182063Srwatson}
174105694Srwatson
175100979Srwatson
176100979Srwatson/*
177100979Srwatson * This constructs a temporary sequence header with space for the maximum
178105694Srwatson * length field (three byte). Set the pointer that ptr points to to the
179100979Srwatson * start of the encoded header. This is used for a later call to
180100979Srwatson * asn_commit_header which will fix-up the length field and move the
181100979Srwatson * value if needed. All errors should stop the encoding.
182111119Simp */
183105694Srwatson#define	TEMP_LEN (1 + ASN_MAXLENLEN + 1)
184105694Srwatsonenum asn_err
185105694Srwatsonasn_put_temp_header(struct asn_buf *b, u_char type, u_char **ptr)
186105694Srwatson{
187105694Srwatson	int ret;
188105694Srwatson
189122524Srwatson	if (b->asn_len < TEMP_LEN)
190172930Srwatson		return (ASN_ERR_EOBUF);
191105694Srwatson	*ptr = b->asn_ptr;
192122524Srwatson	if ((ret = asn_put_header(b, type, ASN_MAXLEN)) == ASN_ERR_OK)
193122524Srwatson		assert(b->asn_ptr == *ptr + TEMP_LEN);
194105694Srwatson	return (ret);
195100979Srwatson}
196100979Srwatsonenum asn_err
197100979Srwatsonasn_commit_header(struct asn_buf *b, u_char *ptr)
198100979Srwatson{
199100979Srwatson	asn_len_t len;
200100979Srwatson	u_int lenlen, shift;
201172930Srwatson
202100979Srwatson	/* compute length of encoded value without header */
203100979Srwatson	len = b->asn_ptr - (ptr + TEMP_LEN);
204100979Srwatson
205105694Srwatson	/* insert length. may not fail. */
206100979Srwatson	lenlen = asn_put_len(ptr + 1, len);
207100979Srwatson	if (lenlen > TEMP_LEN - 1)
208100979Srwatson		return (ASN_ERR_FAILED);
209100979Srwatson
210172930Srwatson	if (lenlen < TEMP_LEN - 1) {
211280130Smjg		/* shift value down */
212100979Srwatson		shift = (TEMP_LEN - 1) - lenlen;
213100979Srwatson		memmove(ptr + 1 + lenlen, ptr + TEMP_LEN, len);
214100979Srwatson		b->asn_ptr -= shift;
215184412Srwatson		b->asn_len += shift;
216105694Srwatson	}
217105694Srwatson	return (ASN_ERR_OK);
218122524Srwatson}
219105694Srwatson#undef TEMP_LEN
220100979Srwatson
221100979Srwatson/*
222100979Srwatson * BER integer. This may be used to get a signed 64 bit integer at maximum.
223225617Skmacy * The maximum length should be checked by the caller. This cannot overflow
224100979Srwatson * if the caller ensures that len is at maximum 8.
225105694Srwatson *
226122524Srwatson * <bytes>
227100979Srwatson */
228105694Srwatsonstatic enum asn_err
229100979Srwatsonasn_get_real_integer(struct asn_buf *b, asn_len_t len, int64_t *vp)
230100979Srwatson{
231122820Srwatson	u_int64_t val;
232255219Spjd	int neg = 0;
233105694Srwatson	enum asn_err err;
234241896Skib
235100979Srwatson	if (b->asn_len < len) {
236105694Srwatson		asn_error(b, "truncated integer");
237105694Srwatson		return (ASN_ERR_EOBUF);
238105694Srwatson	}
239100979Srwatson	if (len == 0) {
240105694Srwatson		asn_error(b, "zero-length integer");
241105694Srwatson		*vp = 0;
242105694Srwatson		return (ASN_ERR_BADLEN);
243105694Srwatson	}
244111119Simp	err = ASN_ERR_OK;
245105694Srwatson	if (len > 8)
246105694Srwatson		err = ASN_ERR_RANGE;
247105694Srwatson	if (*b->asn_cptr & 0x80)
248105694Srwatson		neg = 1;
249105694Srwatson	val = 0;
250105694Srwatson	while (len--) {
251111119Simp		val <<= 8;
252255219Spjd		val |= neg ? (u_char)~*b->asn_cptr : *b->asn_cptr;
253100979Srwatson		b->asn_len--;
254100979Srwatson		b->asn_cptr++;
255100979Srwatson	}
256105694Srwatson	if (neg) {
257100979Srwatson		*vp = -(int64_t)val - 1;
258100979Srwatson	} else
259100979Srwatson		*vp = (int64_t)val;
260234032Srwatson	return (err);
261234032Srwatson}
262234032Srwatson
263234032Srwatson/*
264116678Sphk * Write a signed integer with the given type. The caller has to ensure
265122524Srwatson * that the actual value is ok for this type.
266175202Sattilio */
267172930Srwatsonstatic enum asn_err
268175294Sattilioasn_put_real_integer(struct asn_buf *b, u_char type, int64_t ival)
269172930Srwatson{
270122584Srwatson	int i, neg = 0;
271122584Srwatson# define OCTETS 8
272122584Srwatson	u_char buf[OCTETS];
273105694Srwatson	u_int64_t val;
274100979Srwatson	enum asn_err ret;
275234032Srwatson
276234032Srwatson	if (ival < 0) {
277234032Srwatson		/* this may fail if |INT64_MIN| > |INT64_MAX| and
278234032Srwatson		 * the value is between * INT64_MIN <= ival < -(INT64_MAX+1) */
279109153Sdillon		val = (u_int64_t)-(ival + 1);
280122524Srwatson		neg = 1;
281105694Srwatson	} else
282172930Srwatson		val = (u_int64_t)ival;
283105694Srwatson
284172930Srwatson	/* split the value into octets */
285122159Srwatson	for (i = OCTETS - 1; i >= 0; i--) {
286122524Srwatson		buf[i] = val & 0xff;
287105694Srwatson		if (neg)
288122584Srwatson			buf[i] = ~buf[i];
289122820Srwatson		val >>= 8;
290234032Srwatson	}
291234032Srwatson	/* no leading 9 zeroes or ones */
292234032Srwatson	for (i = 0; i < OCTETS - 1; i++)
293234032Srwatson		if (!((buf[i] == 0xff && (buf[i + 1] & 0x80) != 0) ||
294122820Srwatson		    (buf[i] == 0x00 && (buf[i + 1] & 0x80) == 0)))
295122820Srwatson			break;
296145160Srwatson	if ((ret = asn_put_header(b, type, OCTETS - i)))
297172930Srwatson		return (ret);
298145160Srwatson	if (OCTETS - (u_int)i > b->asn_len)
299172930Srwatson		return (ASN_ERR_EOBUF);
300122820Srwatson
301122820Srwatson	while (i < OCTETS) {
302122820Srwatson		*b->asn_ptr++ = buf[i++];
303122820Srwatson		b->asn_len--;
304105694Srwatson	}
305122584Srwatson	return (ASN_ERR_OK);
306105694Srwatson# undef OCTETS
307100979Srwatson}
308105694Srwatson
309234032Srwatson
310234032Srwatson/*
311105694Srwatson * The same for unsigned 64-bitters. Here we have the problem, that overflow
312105694Srwatson * can happen, because the value maybe 9 bytes long. In this case the
313105694Srwatson * first byte must be 0.
314100979Srwatson */
315100979Srwatsonstatic enum asn_err
316100979Srwatsonasn_get_real_unsigned(struct asn_buf *b, asn_len_t len, u_int64_t *vp)
317100979Srwatson{
318225617Skmacy	enum asn_err err;
319100979Srwatson
320105694Srwatson	if (b->asn_len < len) {
321100979Srwatson		asn_error(b, "truncated integer");
322122524Srwatson		return (ASN_ERR_EOBUF);
323105694Srwatson	}
324241896Skib	if (len == 0) {
325100979Srwatson		asn_error(b, "zero-length integer");
326182063Srwatson		*vp = 0;
327182063Srwatson		return (ASN_ERR_BADLEN);
328182063Srwatson	}
329105694Srwatson	err = ASN_ERR_OK;
330105694Srwatson	*vp = 0;
331105694Srwatson	if ((*b->asn_cptr & 0x80) || (len == 9 && *b->asn_cptr != 0)) {
332105694Srwatson		/* negative integer or too larger */
333105694Srwatson		*vp = 0xffffffffffffffffULL;
334105694Srwatson		err = ASN_ERR_RANGE;
335105694Srwatson	}
336105694Srwatson
337111119Simp	while (len--) {
338105694Srwatson		*vp = (*vp << 8) | *b->asn_cptr++;
339105694Srwatson		b->asn_len--;
340105694Srwatson	}
341105694Srwatson	return (err);
342105694Srwatson}
343105694Srwatson
344111119Simp
345241896Skib/*
346150914Scsjp * Values with the msb on need 9 octets.
347100979Srwatson */
348100979Srwatsonstatic int
349100979Srwatsonasn_put_real_unsigned(struct asn_buf *b, u_char type, u_int64_t val)
350100979Srwatson{
351122524Srwatson	int i;
352172930Srwatson# define OCTETS 9
353172930Srwatson	u_char buf[OCTETS];
354122159Srwatson	enum asn_err ret;
355105694Srwatson
356100979Srwatson	/* split the value into octets */
357122524Srwatson	for (i = OCTETS - 1; i >= 0; i--) {
358105694Srwatson		buf[i] = val & 0xff;
359105694Srwatson		val >>= 8;
360105694Srwatson	}
361105694Srwatson	/* no leading 9 zeroes */
362105694Srwatson	for (i = 0; i < OCTETS - 1; i++)
363105694Srwatson		if (!(buf[i] == 0x00 && (buf[i + 1] & 0x80) == 0))
364105694Srwatson			break;
365105694Srwatson	if ((ret = asn_put_header(b, type, OCTETS - i)))
366105694Srwatson		return (ret);
367105694Srwatson	if (OCTETS - (u_int)i > b->asn_len)
368105694Srwatson		return (ASN_ERR_EOBUF);
369225617Skmacy
370105694Srwatson	while (i < OCTETS) {
371105694Srwatson		*b->asn_ptr++ = buf[i++];
372105694Srwatson		b->asn_len--;
373122524Srwatson	}
374105694Srwatson#undef OCTETS
375241896Skib	return (ASN_ERR_OK);
376105694Srwatson}
377182063Srwatson
378182063Srwatson/*
379182063Srwatson * The ASN.1 INTEGER type is restricted to 32-bit signed by the SMI.
380105694Srwatson */
381100979Srwatsonenum asn_err
382105694Srwatsonasn_get_integer_raw(struct asn_buf *b, asn_len_t len, int32_t *vp)
383105694Srwatson{
384105694Srwatson	int64_t val;
385105694Srwatson	enum asn_err ret;
386105694Srwatson
387105694Srwatson	if ((ret = asn_get_real_integer(b, len, &val)) == ASN_ERR_OK) {
388111119Simp		if (len > 4)
389105694Srwatson			ret = ASN_ERR_BADLEN;
390105694Srwatson		else if (val > INT32_MAX || val < INT32_MIN)
391105694Srwatson			/* may not happen */
392105694Srwatson			ret = ASN_ERR_RANGE;
393105694Srwatson		*vp = (int32_t)val;
394105694Srwatson	}
395111119Simp	return (ret);
396241896Skib}
397150914Scsjp
398105694Srwatsonenum asn_err
399105694Srwatsonasn_get_integer(struct asn_buf *b, int32_t *vp)
400100979Srwatson{
401100979Srwatson	asn_len_t len;
402122524Srwatson	u_char type;
403172930Srwatson	enum asn_err err;
404172930Srwatson
405122159Srwatson	if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK)
406105694Srwatson		return (err);
407122524Srwatson	if (type != ASN_TYPE_INTEGER) {
408100979Srwatson		asn_error(b, "bad type for integer (%u)", type);
409105694Srwatson		return (ASN_ERR_TAG);
410105694Srwatson	}
411105694Srwatson
412100979Srwatson	return (asn_get_integer_raw(b, len, vp));
413105694Srwatson}
414105694Srwatson
415105694Srwatsonenum asn_err
416100979Srwatsonasn_put_integer(struct asn_buf *b, int32_t val)
417100979Srwatson{
418100979Srwatson	return (asn_put_real_integer(b, ASN_TYPE_INTEGER, val));
419100979Srwatson}
420225617Skmacy
421100979Srwatson/*
422122524Srwatson * OCTETSTRING
423105694Srwatson *
424122820Srwatson * <0x04> <len> <data ...>
425100979Srwatson *
426100979Srwatson * Get an octetstring. noctets must point to the buffer size and on
427100979Srwatson * return will contain the size of the octetstring, regardless of the
428105694Srwatson * buffer size.
429255219Spjd */
430105694Srwatsonenum asn_err
431241896Skibasn_get_octetstring_raw(struct asn_buf *b, asn_len_t len, u_char *octets,
432100979Srwatson    u_int *noctets)
433105694Srwatson{
434100979Srwatson	enum asn_err err = ASN_ERR_OK;
435105694Srwatson
436100979Srwatson	if (*noctets < len) {
437105694Srwatson		asn_error(b, "octetstring truncated");
438100979Srwatson		err = ASN_ERR_RANGE;
439105694Srwatson	}
440100979Srwatson	if (b->asn_len < len) {
441111119Simp		asn_error(b, "truncatet octetstring");
442105694Srwatson		return (ASN_ERR_EOBUF);
443105694Srwatson	}
444105694Srwatson	if (*noctets < len)
445105694Srwatson		memcpy(octets, b->asn_cptr, *noctets);
446105694Srwatson	else
447105694Srwatson		memcpy(octets, b->asn_cptr, len);
448255219Spjd	*noctets = len;
449100979Srwatson	b->asn_cptr += len;
450105694Srwatson	b->asn_len -= len;
451100979Srwatson	return (err);
452100979Srwatson}
453100979Srwatson
454100979Srwatsonenum asn_err
455234032Srwatsonasn_get_octetstring(struct asn_buf *b, u_char *octets, u_int *noctets)
456234032Srwatson{
457234032Srwatson	enum asn_err err;
458234032Srwatson	u_char type;
459122524Srwatson	asn_len_t len;
460172930Srwatson
461105694Srwatson	if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK)
462122524Srwatson		return (err);
463105694Srwatson	if (type != ASN_TYPE_OCTETSTRING) {
464105694Srwatson		asn_error(b, "bad type for octetstring (%u)", type);
465116678Sphk		return (ASN_ERR_TAG);
466100979Srwatson	}
467105694Srwatson	return (asn_get_octetstring_raw(b, len, octets, noctets));
468122524Srwatson}
469100979Srwatson
470105694Srwatsonenum asn_err
471175202Sattilioasn_put_octetstring(struct asn_buf *b, const u_char *octets, u_int noctets)
472122524Srwatson{
473175294Sattilio	enum asn_err ret;
474100979Srwatson
475122524Srwatson	if ((ret = asn_put_header(b, ASN_TYPE_OCTETSTRING, noctets)) != ASN_ERR_OK)
476100979Srwatson		return (ret);
477105694Srwatson	if (b->asn_len < noctets)
478100979Srwatson		return (ASN_ERR_EOBUF);
479234032Srwatson
480234032Srwatson	memcpy(b->asn_ptr, octets, noctets);
481234032Srwatson	b->asn_ptr += noctets;
482234032Srwatson	b->asn_len -= noctets;
483122524Srwatson	return (ASN_ERR_OK);
484172930Srwatson}
485105694Srwatson
486109153Sdillon/*
487105694Srwatson * NULL
488125293Srwatson *
489125293Srwatson * <0x05> <0x00>
490105694Srwatson */
491105694Srwatsonenum asn_err
492122524Srwatsonasn_get_null_raw(struct asn_buf *b, asn_len_t len)
493100979Srwatson{
494105694Srwatson	if (len != 0) {
495122820Srwatson		if (b->asn_len < len) {
496234032Srwatson			asn_error(b, "truncated NULL");
497234032Srwatson			return (ASN_ERR_EOBUF);
498234032Srwatson		}
499234032Srwatson		asn_error(b, "bad length for NULL (%u)", len);
500122820Srwatson		b->asn_len -= len;
501172930Srwatson		b->asn_ptr += len;
502122820Srwatson		return (ASN_ERR_BADLEN);
503122820Srwatson	}
504122820Srwatson	return (ASN_ERR_OK);
505122820Srwatson}
506122820Srwatson
507122820Srwatsonenum asn_err
508122820Srwatsonasn_get_null(struct asn_buf *b)
509122820Srwatson{
510100979Srwatson	u_char type;
511100979Srwatson	asn_len_t len;
512100979Srwatson	enum asn_err err;
513234032Srwatson
514100979Srwatson	if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK)
515105694Srwatson		return (err);
516105694Srwatson	if (type != ASN_TYPE_NULL) {
517100979Srwatson		asn_error(b, "bad type for NULL (%u)", type);
518100979Srwatson		return (ASN_ERR_TAG);
519100979Srwatson	}
520100979Srwatson	return (asn_get_null_raw(b, len));
521225617Skmacy}
522100979Srwatson
523122524Srwatsonenum asn_err
524100979Srwatsonasn_put_null(struct asn_buf *b)
525100979Srwatson{
526105694Srwatson	return (asn_put_header(b, ASN_TYPE_NULL, 0));
527105694Srwatson}
528241896Skib
529100979Srwatsonenum asn_err
530182063Srwatsonasn_put_exception(struct asn_buf *b, u_int except)
531182063Srwatson{
532182063Srwatson	return (asn_put_header(b, ASN_CLASS_CONTEXT | except, 0));
533105694Srwatson}
534100979Srwatson
535105694Srwatson/*
536100979Srwatson * OBJID
537105694Srwatson *
538100979Srwatson * <0x06> <len> <subid...>
539105694Srwatson */
540100979Srwatsonenum asn_err
541111119Simpasn_get_objid_raw(struct asn_buf *b, asn_len_t len, struct asn_oid *oid)
542105694Srwatson{
543105694Srwatson	asn_subid_t subid;
544105694Srwatson	enum asn_err err;
545105694Srwatson
546105694Srwatson	if (b->asn_len < len) {
547105694Srwatson		asn_error(b, "truncated OBJID");
548122524Srwatson		return (ASN_ERR_EOBUF);
549172930Srwatson	}
550105694Srwatson	oid->len = 0;
551122524Srwatson	if (len == 0) {
552122524Srwatson		asn_error(b, "short OBJID");
553105694Srwatson		oid->subs[oid->len++] = 0;
554241896Skib		oid->subs[oid->len++] = 0;
555150914Scsjp		return (ASN_ERR_BADLEN);
556100979Srwatson	}
557105694Srwatson	err = ASN_ERR_OK;
558105694Srwatson	while (len != 0) {
559156893Stegge		if (oid->len == ASN_MAXOIDLEN) {
560122524Srwatson			asn_error(b, "OID too long (%u)", oid->len);
561105694Srwatson			b->asn_cptr += len;
562156893Stegge			b->asn_len -= len;
563156893Stegge			return (ASN_ERR_BADLEN);
564105694Srwatson		}
565105694Srwatson		subid = 0;
566105694Srwatson		do {
567122524Srwatson			if (len == 0) {
568122524Srwatson				asn_error(b, "unterminated subid");
569105694Srwatson				return (ASN_ERR_EOBUF);
570105694Srwatson			}
571105694Srwatson			if (subid > (ASN_MAXID >> 7)) {
572105694Srwatson				asn_error(b, "OBID subid too larger");
573225617Skmacy				err = ASN_ERR_RANGE;
574105694Srwatson			}
575122524Srwatson			subid = (subid << 7) | (*b->asn_cptr & 0x7f);
576105694Srwatson			len--;
577105694Srwatson			b->asn_len--;
578105694Srwatson		} while (*b->asn_cptr++ & 0x80);
579105694Srwatson		if (oid->len == 0) {
580241896Skib			if (subid < 80) {
581105694Srwatson				oid->subs[oid->len++] = subid / 40;
582182063Srwatson				oid->subs[oid->len++] = subid % 40;
583182063Srwatson			} else {
584182063Srwatson				oid->subs[oid->len++] = 2;
585105694Srwatson				oid->subs[oid->len++] = subid - 80;
586100979Srwatson			}
587105694Srwatson		} else {
588105694Srwatson			oid->subs[oid->len++] = subid;
589105694Srwatson		}
590100979Srwatson	}
591105694Srwatson	return (err);
592100979Srwatson
593111119Simp}
594105694Srwatson
595105694Srwatsonenum asn_err
596105694Srwatsonasn_get_objid(struct asn_buf *b, struct asn_oid *oid)
597105694Srwatson{
598105694Srwatson	u_char type;
599105694Srwatson	asn_len_t len;
600122524Srwatson	enum asn_err err;
601172930Srwatson
602105694Srwatson	if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK)
603122524Srwatson		return (err);
604122524Srwatson	if (type != ASN_TYPE_OBJID) {
605105694Srwatson		asn_error(b, "bad type for OBJID (%u)", type);
606241896Skib		return (ASN_ERR_TAG);
607150914Scsjp	}
608105694Srwatson	return (asn_get_objid_raw(b, len, oid));
609105694Srwatson}
610105694Srwatson
611156893Steggeenum asn_err
612122524Srwatsonasn_put_objid(struct asn_buf *b, const struct asn_oid *oid)
613105694Srwatson{
614156893Stegge	asn_subid_t first, sub;
615156893Stegge	enum asn_err err, err1;
616105694Srwatson	u_int i, oidlen;
617105694Srwatson	asn_len_t len;
618100979Srwatson
619122524Srwatson	err = ASN_ERR_OK;
620122524Srwatson	if (oid->len == 0) {
621100979Srwatson		/* illegal */
622100979Srwatson		asn_error(NULL, "short oid");
623100979Srwatson		err = ASN_ERR_RANGE;
624102123Srwatson		first = 0;
625225617Skmacy		oidlen = 2;
626102123Srwatson	} else if (oid->len == 1) {
627102123Srwatson		/* illegal */
628102123Srwatson		asn_error(b, "short oid");
629189797Srwatson		if (oid->subs[0] > 2)
630102123Srwatson			asn_error(NULL, "oid[0] too large (%u)", oid->subs[0]);
631107849Salfred		err = ASN_ERR_RANGE;
632102123Srwatson		first = oid->subs[0] * 40;
633102123Srwatson		oidlen = 2;
634102123Srwatson	} else {
635102123Srwatson		if (oid->len > ASN_MAXOIDLEN) {
636119494Srwatson			asn_error(NULL, "oid too long %u", oid->len);
637102123Srwatson			err = ASN_ERR_RANGE;
638102123Srwatson		}
639102123Srwatson		if (oid->subs[0] > 2 ||
640107849Salfred		    (oid->subs[0] < 2 && oid->subs[0] >= 40)) {
641102123Srwatson			asn_error(NULL, "oid out of range (%u,%u)",
642102123Srwatson			    oid->subs[0], oid->subs[1]);
643102123Srwatson			err = ASN_ERR_RANGE;
644102123Srwatson		}
645189797Srwatson		first = 40 * oid->subs[0] + oid->subs[1];
646189797Srwatson		oidlen = oid->len;
647114806Srwatson	}
648114806Srwatson	len = 0;
649114806Srwatson	for (i = 1; i < oidlen; i++) {
650114806Srwatson		sub = (i == 1) ? first : oid->subs[i];
651114806Srwatson		if (sub > ASN_MAXID) {
652114806Srwatson			asn_error(NULL, "oid subid too large");
653114806Srwatson			err = ASN_ERR_RANGE;
654114806Srwatson		}
655189797Srwatson		len += (sub <= 0x7f) ? 1
656114806Srwatson		    : (sub <= 0x3fff) ? 2
657102123Srwatson		    : (sub <= 0x1fffff) ? 3
658102123Srwatson		    : (sub <= 0xfffffff) ? 4
659102123Srwatson		    : 5;
660102123Srwatson	}
661100979Srwatson	if ((err1 = asn_put_header(b, ASN_TYPE_OBJID, len)) != ASN_ERR_OK)
662100979Srwatson		return (err1);
663100979Srwatson	if (b->asn_len < len)
664225617Skmacy		return (ASN_ERR_EOBUF);
665105694Srwatson
666105694Srwatson	for (i = 1; i < oidlen; i++) {
667105694Srwatson		sub = (i == 1) ? first : oid->subs[i];
668105694Srwatson		if (sub <= 0x7f) {
669105694Srwatson			*b->asn_ptr++ = sub;
670105694Srwatson			b->asn_len--;
671225617Skmacy		} else if (sub <= 0x3fff) {
672100979Srwatson			*b->asn_ptr++ = (sub >> 7) | 0x80;
673100979Srwatson			*b->asn_ptr++ = sub & 0x7f;
674100894Srwatson			b->asn_len -= 2;
675100894Srwatson		} else if (sub <= 0x1fffff) {
676100894Srwatson			*b->asn_ptr++ = (sub >> 14) | 0x80;
677100894Srwatson			*b->asn_ptr++ = ((sub >> 7) & 0x7f) | 0x80;
678225617Skmacy			*b->asn_ptr++ = sub & 0x7f;
679100894Srwatson			b->asn_len -= 3;
680100894Srwatson		} else if (sub <= 0xfffffff) {
681100894Srwatson			*b->asn_ptr++ = (sub >> 21) | 0x80;
682100894Srwatson			*b->asn_ptr++ = ((sub >> 14) & 0x7f) | 0x80;
683100894Srwatson			*b->asn_ptr++ = ((sub >> 7) & 0x7f) | 0x80;
684100894Srwatson			*b->asn_ptr++ = sub & 0x7f;
685225617Skmacy			b->asn_len -= 4;
686100894Srwatson		} else {
687100894Srwatson			*b->asn_ptr++ = (sub >> 28) | 0x80;
688100894Srwatson			*b->asn_ptr++ = ((sub >> 21) & 0x7f) | 0x80;
689100894Srwatson			*b->asn_ptr++ = ((sub >> 14) & 0x7f) | 0x80;
690100894Srwatson			*b->asn_ptr++ = ((sub >> 7) & 0x7f) | 0x80;
691100894Srwatson			*b->asn_ptr++ = sub & 0x7f;
692225617Skmacy			b->asn_len -= 5;
693100894Srwatson		}
694100894Srwatson	}
695100894Srwatson	return (err);
696100894Srwatson}
697100894Srwatson/*
698100894Srwatson * SEQUENCE header
699225617Skmacy *
700105694Srwatson * <0x10|0x20> <len> <data...>
701105694Srwatson */
702105694Srwatsonenum asn_err
703105694Srwatsonasn_get_sequence(struct asn_buf *b, asn_len_t *len)
704105694Srwatson{
705105694Srwatson	u_char type;
706225617Skmacy	enum asn_err err;
707100894Srwatson
708100894Srwatson	if ((err = asn_get_header(b, &type, len)) != ASN_ERR_OK)
709100894Srwatson		return (err);
710100894Srwatson	if (type != (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED)) {
711100894Srwatson		asn_error(b, "bad sequence type %u", type);
712100894Srwatson		return (ASN_ERR_TAG);
713225617Skmacy	}
714100894Srwatson	if (*len > b->asn_len) {
715100894Srwatson		asn_error(b, "truncated sequence");
716100894Srwatson		return (ASN_ERR_EOBUF);
717100894Srwatson	}
718100979Srwatson	return (ASN_ERR_OK);
719102123Srwatson}
720225617Skmacy
721105694Srwatson
722105694Srwatson/*
723105694Srwatson * Application types
724105694Srwatson *
725105694Srwatson * 0x40 4 MSB 2MSB 2LSB LSB
726105694Srwatson */
727225617Skmacyenum asn_err
728102123Srwatsonasn_get_ipaddress_raw(struct asn_buf *b, asn_len_t len, u_char *addr)
729102123Srwatson{
730102123Srwatson	u_int i;
731102123Srwatson
732102123Srwatson	if (b->asn_len < len) {
733128901Srwatson		asn_error(b, "truncated ip-address");
734		return (ASN_ERR_EOBUF);
735	}
736	if (len < 4) {
737		asn_error(b, "short length for ip-Address %u", len);
738		for (i = 0; i < len; i++)
739			*addr++ = *b->asn_cptr++;
740		while (i++ < len)
741			*addr++ = 0;
742		b->asn_len -= len;
743		return (ASN_ERR_BADLEN);
744	}
745	for (i = 0; i < 4; i++)
746		*addr++ = *b->asn_cptr++;
747	b->asn_cptr += len - 4;
748	b->asn_len -= len;
749	return (ASN_ERR_OK);
750}
751
752enum asn_err
753asn_get_ipaddress(struct asn_buf *b, u_char *addr)
754{
755	u_char type;
756	asn_len_t len;
757	enum asn_err err;
758
759	if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK)
760		return (err);
761	if (type != (ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS)) {
762		asn_error(b, "bad type for ip-address %u", type);
763		return (ASN_ERR_TAG);
764	}
765	return (asn_get_ipaddress_raw(b, len, addr));
766}
767
768enum asn_err
769asn_put_ipaddress(struct asn_buf *b, const u_char *addr)
770{
771	enum asn_err err;
772
773	if ((err = asn_put_header(b, ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS,
774	    4)) != ASN_ERR_OK)
775		return (err);
776	if (b->asn_len < 4)
777		return (ASN_ERR_EOBUF);
778
779	memcpy(b->asn_ptr, addr, 4);
780	b->asn_ptr += 4;
781	b->asn_len -= 4;
782	return (ASN_ERR_OK);
783}
784
785
786/*
787 * UNSIGNED32
788 *
789 * 0x42|0x41 <len> ...
790 */
791enum asn_err
792asn_get_uint32_raw(struct asn_buf *b, asn_len_t len, u_int32_t *vp)
793{
794	u_int64_t v;
795	enum asn_err err;
796
797	if ((err = asn_get_real_unsigned(b, len, &v)) == ASN_ERR_OK) {
798		if (len > 5) {
799			asn_error(b, "uint32 too long %u", len);
800			err = ASN_ERR_BADLEN;
801		} else if (v > UINT32_MAX) {
802			asn_error(b, "uint32 too large %llu", v);
803			err = ASN_ERR_RANGE;
804		}
805		*vp = (u_int32_t)v;
806	}
807	return (err);
808}
809
810enum asn_err
811asn_put_uint32(struct asn_buf *b, u_char type, u_int32_t val)
812{
813	u_int64_t v = val;
814
815	return (asn_put_real_unsigned(b, ASN_CLASS_APPLICATION|type, v));
816}
817
818/*
819 * COUNTER64
820 * 0x46 <len> ...
821 */
822enum asn_err
823asn_get_counter64_raw(struct asn_buf *b, asn_len_t len, u_int64_t *vp)
824{
825	return (asn_get_real_unsigned(b, len, vp));
826}
827
828enum asn_err
829asn_put_counter64(struct asn_buf *b, u_int64_t val)
830{
831	return (asn_put_real_unsigned(b,
832	    ASN_CLASS_APPLICATION | ASN_APP_COUNTER64, val));
833}
834
835/*
836 * TimeTicks
837 * 0x43 <len> ...
838 */
839enum asn_err
840asn_get_timeticks(struct asn_buf *b, u_int32_t *vp)
841{
842	asn_len_t len;
843	u_char type;
844	enum asn_err err;
845
846	if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK)
847		return (err);
848	if (type != (ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS)) {
849		asn_error(b, "bad type for timeticks %u", type);
850		return (ASN_ERR_TAG);
851	}
852	return (asn_get_uint32_raw(b, len, vp));
853}
854
855enum asn_err
856asn_put_timeticks(struct asn_buf *b, u_int32_t val)
857{
858	u_int64_t v = val;
859
860	return (asn_put_real_unsigned(b,
861	    ASN_CLASS_APPLICATION | ASN_APP_TIMETICKS, v));
862}
863
864/*
865 * Construct a new OID by taking a range of sub ids of the original oid.
866 */
867void
868asn_slice_oid(struct asn_oid *dest, const struct asn_oid *src,
869    u_int from, u_int to)
870{
871	if (from >= to) {
872		dest->len = 0;
873		return;
874	}
875	dest->len = to - from;
876	memcpy(dest->subs, &src->subs[from], dest->len * sizeof(dest->subs[0]));
877}
878
879/*
880 * Append from to to
881 */
882void
883asn_append_oid(struct asn_oid *to, const struct asn_oid *from)
884{
885	memcpy(&to->subs[to->len], &from->subs[0],
886	    from->len * sizeof(from->subs[0]));
887	to->len += from->len;
888}
889
890/*
891 * Skip a value
892 */
893enum asn_err
894asn_skip(struct asn_buf *b, asn_len_t len)
895{
896	if (b->asn_len < len)
897		return (ASN_ERR_EOBUF);
898	b->asn_cptr += len;
899	b->asn_len -= len;
900	return (ASN_ERR_OK);
901}
902
903/*
904 * Compare two OIDs.
905 *
906 * o1 < o2 : -1
907 * o1 > o2 : +1
908 * o1 = o2 :  0
909 */
910int
911asn_compare_oid(const struct asn_oid *o1, const struct asn_oid *o2)
912{
913	u_long i;
914
915	for (i = 0; i < o1->len && i < o2->len; i++) {
916		if (o1->subs[i] < o2->subs[i])
917			return (-1);
918		if (o1->subs[i] > o2->subs[i])
919			return (+1);
920	}
921	if (o1->len < o2->len)
922		return (-1);
923	if (o1->len > o2->len)
924		return (+1);
925	return (0);
926}
927
928/*
929 * Check whether an OID is a sub-string of another OID.
930 */
931int
932asn_is_suboid(const struct asn_oid *o1, const struct asn_oid *o2)
933{
934	u_long i;
935
936	for (i = 0; i < o1->len; i++)
937		if (i >= o2->len || o1->subs[i] != o2->subs[i])
938			return (0);
939	return (1);
940}
941
942/*
943 * Put a string representation of an oid into a user buffer. This buffer
944 * is assumed to be at least ASN_OIDSTRLEN characters long.
945 *
946 * sprintf is assumed not to fail here.
947 */
948char *
949asn_oid2str_r(const struct asn_oid *oid, char *buf)
950{
951	u_int len, i;
952	char *ptr;
953
954	if ((len = oid->len) > ASN_MAXOIDLEN)
955		len = ASN_MAXOIDLEN;
956	buf[0] = '\0';
957	for (i = 0, ptr = buf; i < len; i++) {
958		if (i > 0)
959			*ptr++ = '.';
960		ptr += sprintf(ptr, "%u", oid->subs[i]);
961	}
962	return (buf);
963}
964
965/*
966 * Make a string from an OID in a private buffer.
967 */
968char *
969asn_oid2str(const struct asn_oid *oid)
970{
971	static char str[ASN_OIDSTRLEN];
972
973	return (asn_oid2str_r(oid, str));
974}
975
976
977static void
978asn_error_func(const struct asn_buf *b, const char *err, ...)
979{
980	va_list ap;
981	u_long i;
982
983	fprintf(stderr, "ASN.1: ");
984	va_start(ap, err);
985	vfprintf(stderr, err, ap);
986	va_end(ap);
987
988	if (b != NULL) {
989		fprintf(stderr, " at");
990		for (i = 0; b->asn_len > i; i++)
991			fprintf(stderr, " %02x", b->asn_cptr[i]);
992	}
993	fprintf(stderr, "\n");
994}
995