PageRenderTime 70ms CodeModel.GetById 18ms app.highlight 44ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/bsnmp/lib/asn1.c

https://bitbucket.org/freebsd/freebsd-head/
C | 1022 lines | 760 code | 96 blank | 166 comment | 205 complexity | ecdbec4225147616aaa2fbc0324824f6 MD5 | raw file
   1/*
   2 * Copyright (c) 2001-2003
   3 *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
   4 *	All rights reserved.
   5 *
   6 * Author: Harti Brandt <harti@freebsd.org>
   7 * 
   8 * Redistribution and use in source and binary forms, with or without
   9 * modification, are permitted provided that the following conditions
  10 * are met:
  11 * 1. Redistributions of source code must retain the above copyright
  12 *    notice, this list of conditions and the following disclaimer.
  13 * 2. Redistributions in binary form must reproduce the above copyright
  14 *    notice, this list of conditions and the following disclaimer in the
  15 *    documentation and/or other materials provided with the distribution.
  16 * 
  17 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
  21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27 * SUCH DAMAGE.
  28 *
  29 * $Begemot: bsnmp/lib/asn1.c,v 1.31 2005/10/06 07:14:58 brandt_h Exp $
  30 *
  31 * ASN.1 for SNMP.
  32 */
  33#include <sys/types.h>
  34#include <stdio.h>
  35#include <stdlib.h>
  36#include <stdarg.h>
  37#include <string.h>
  38#ifdef HAVE_STDINT_H
  39#include <stdint.h>
  40#elif defined(HAVE_INTTYPES_H)
  41#include <inttypes.h>
  42#endif
  43#include <assert.h>
  44
  45#include "support.h"
  46#include "asn1.h"
  47
  48static void asn_error_func(const struct asn_buf *, const char *, ...);
  49
  50void (*asn_error)(const struct asn_buf *, const char *, ...) = asn_error_func;
  51
  52/*
  53 * Read the next header. This reads the tag (note, that only single
  54 * byte tags are supported for now) and the length field. The length field
  55 * is restricted to a 32-bit value.
  56 * All errors of this function stop the decoding.
  57 */
  58enum asn_err
  59asn_get_header(struct asn_buf *b, u_char *type, asn_len_t *len)
  60{
  61	u_int length;
  62
  63	if (b->asn_len == 0) {
  64		asn_error(b, "no identifier for header");
  65		return (ASN_ERR_EOBUF);
  66	}
  67	*type = *b->asn_cptr;
  68	if ((*type & ASN_TYPE_MASK) > 0x30) {
  69		asn_error(b, "types > 0x30 not supported (%u)",
  70		    *type & ASN_TYPE_MASK);
  71		return (ASN_ERR_FAILED);
  72	}
  73	b->asn_cptr++;
  74	b->asn_len--;
  75	if (b->asn_len == 0) {
  76		asn_error(b, "no length field");
  77		return (ASN_ERR_EOBUF);
  78	}
  79	if (*b->asn_cptr & 0x80) {
  80		length = *b->asn_cptr++ & 0x7f;
  81		b->asn_len--;
  82		if (length == 0) {
  83			asn_error(b, "indefinite length not supported");
  84			return (ASN_ERR_FAILED);
  85		}
  86		if (length > ASN_MAXLENLEN) {
  87			asn_error(b, "long length too long (%u)", length);
  88			return (ASN_ERR_FAILED);
  89		}
  90		if (length > b->asn_len) {
  91			asn_error(b, "long length truncated");
  92			return (ASN_ERR_EOBUF);
  93		}
  94		*len = 0;
  95		while (length--) {
  96			*len = (*len << 8) | *b->asn_cptr++;
  97			b->asn_len--;
  98		}
  99	} else {
 100		*len = *b->asn_cptr++;
 101		b->asn_len--;
 102	}
 103	return (ASN_ERR_OK);
 104}
 105
 106/*
 107 * Write a length field (restricted to values < 2^32-1) and return the
 108 * number of bytes this field takes. If ptr is NULL, the length is computed
 109 * but nothing is written. If the length would be too large return 0.
 110 */
 111static u_int
 112asn_put_len(u_char *ptr, asn_len_t len)
 113{
 114	u_int lenlen, lenlen1;
 115	asn_len_t tmp;
 116
 117	if (len > ASN_MAXLEN) {
 118		asn_error(NULL, "encoding length too long: (%u)", len);
 119		return (0);
 120	}
 121
 122	if (len <= 127) {
 123		if (ptr)
 124			*ptr++ = (u_char)len;
 125		return (1);
 126	} else {
 127		lenlen = 0;
 128		/* compute number of bytes for value (is at least 1) */
 129		for (tmp = len; tmp != 0; tmp >>= 8)
 130			lenlen++;
 131		if (ptr != NULL) {
 132			*ptr++ = (u_char)lenlen | 0x80;
 133			lenlen1 = lenlen;
 134			while (lenlen1-- > 0) {
 135				ptr[lenlen1] = len & 0xff;
 136				len >>= 8;
 137			}
 138		}
 139		return (lenlen + 1);
 140	}
 141}
 142
 143/*
 144 * Write a header (tag and length fields).
 145 * Tags are restricted to one byte tags (value <= 0x30) and the
 146 * lenght field to 16-bit. All errors stop the encoding.
 147 */
 148enum asn_err
 149asn_put_header(struct asn_buf *b, u_char type, asn_len_t len)
 150{
 151	u_int lenlen;
 152
 153	/* tag field */
 154	if ((type & ASN_TYPE_MASK) > 0x30) {
 155		asn_error(NULL, "types > 0x30 not supported (%u)",
 156		    type & ASN_TYPE_MASK);
 157		return (ASN_ERR_FAILED);
 158	}
 159	if (b->asn_len == 0)
 160		return (ASN_ERR_EOBUF);
 161
 162	*b->asn_ptr++ = type;
 163	b->asn_len--;
 164
 165	/* length field */
 166	if ((lenlen = asn_put_len(NULL, len)) == 0)
 167		return (ASN_ERR_FAILED);
 168	if (b->asn_len < lenlen)
 169		return (ASN_ERR_EOBUF);
 170
 171	(void)asn_put_len(b->asn_ptr, len);
 172	b->asn_ptr += lenlen;
 173	b->asn_len -= lenlen;
 174	return (ASN_ERR_OK);
 175}
 176
 177
 178/*
 179 * This constructs a temporary sequence header with space for the maximum
 180 * length field (three byte). Set the pointer that ptr points to to the
 181 * start of the encoded header. This is used for a later call to
 182 * asn_commit_header which will fix-up the length field and move the
 183 * value if needed. All errors should stop the encoding.
 184 */
 185#define	TEMP_LEN (1 + ASN_MAXLENLEN + 1)
 186enum asn_err
 187asn_put_temp_header(struct asn_buf *b, u_char type, u_char **ptr)
 188{
 189	int ret;
 190
 191	if (b->asn_len < TEMP_LEN)
 192		return (ASN_ERR_EOBUF);
 193	*ptr = b->asn_ptr;
 194	if ((ret = asn_put_header(b, type, ASN_MAXLEN)) == ASN_ERR_OK)
 195		assert(b->asn_ptr == *ptr + TEMP_LEN);
 196	return (ret);
 197}
 198enum asn_err
 199asn_commit_header(struct asn_buf *b, u_char *ptr, size_t *moved)
 200{
 201	asn_len_t len;
 202	u_int lenlen, shift;
 203
 204	/* compute length of encoded value without header */
 205	len = b->asn_ptr - (ptr + TEMP_LEN);
 206
 207	/* insert length. may not fail. */
 208	lenlen = asn_put_len(ptr + 1, len);
 209	if (lenlen > TEMP_LEN - 1)
 210		return (ASN_ERR_FAILED);
 211
 212	if (lenlen < TEMP_LEN - 1) {
 213		/* shift value down */
 214		shift = (TEMP_LEN - 1) - lenlen;
 215		memmove(ptr + 1 + lenlen, ptr + TEMP_LEN, len);
 216		b->asn_ptr -= shift;
 217		b->asn_len += shift;
 218		if (moved != NULL)
 219			*moved = shift;
 220	}
 221	return (ASN_ERR_OK);
 222}
 223#undef TEMP_LEN
 224
 225/*
 226 * BER integer. This may be used to get a signed 64 bit integer at maximum.
 227 * The maximum length should be checked by the caller. This cannot overflow
 228 * if the caller ensures that len is at maximum 8.
 229 *
 230 * <bytes>
 231 */
 232static enum asn_err
 233asn_get_real_integer(struct asn_buf *b, asn_len_t len, int64_t *vp)
 234{
 235	uint64_t val;
 236	int neg = 0;
 237	enum asn_err err;
 238
 239	if (b->asn_len < len) {
 240		asn_error(b, "truncated integer");
 241		return (ASN_ERR_EOBUF);
 242	}
 243	if (len == 0) {
 244		asn_error(b, "zero-length integer");
 245		*vp = 0;
 246		return (ASN_ERR_BADLEN);
 247	}
 248	err = ASN_ERR_OK;
 249	if (len > 8)
 250		err = ASN_ERR_RANGE;
 251	else if (len > 1 &&
 252	    ((*b->asn_cptr == 0x00 && (b->asn_cptr[1] & 0x80) == 0) ||
 253	    (*b->asn_cptr == 0xff && (b->asn_cptr[1] & 0x80) == 0x80))) {
 254		asn_error(b, "non-minimal integer");
 255		err = ASN_ERR_BADLEN;
 256	}
 257
 258	if (*b->asn_cptr & 0x80)
 259		neg = 1;
 260	val = 0;
 261	while (len--) {
 262		val <<= 8;
 263		val |= neg ? (u_char)~*b->asn_cptr : *b->asn_cptr;
 264		b->asn_len--;
 265		b->asn_cptr++;
 266	}
 267	if (neg) {
 268		*vp = -(int64_t)val - 1;
 269	} else
 270		*vp = (int64_t)val;
 271	return (err);
 272}
 273
 274/*
 275 * Write a signed integer with the given type. The caller has to ensure
 276 * that the actual value is ok for this type.
 277 */
 278static enum asn_err
 279asn_put_real_integer(struct asn_buf *b, u_char type, int64_t ival)
 280{
 281	int i, neg = 0;
 282# define OCTETS 8
 283	u_char buf[OCTETS];
 284	uint64_t val;
 285	enum asn_err ret;
 286
 287	if (ival < 0) {
 288		/* this may fail if |INT64_MIN| > |INT64_MAX| and 
 289		 * the value is between * INT64_MIN <= ival < -(INT64_MAX+1) */
 290		val = (uint64_t)-(ival + 1);
 291		neg = 1;
 292	} else
 293		val = (uint64_t)ival;
 294
 295	/* split the value into octets */
 296	for (i = OCTETS - 1; i >= 0; i--) {
 297		buf[i] = val & 0xff;
 298		if (neg)
 299			buf[i] = ~buf[i];
 300		val >>= 8;
 301	}
 302	/* no leading 9 zeroes or ones */
 303	for (i = 0; i < OCTETS - 1; i++)
 304		if (!((buf[i] == 0xff && (buf[i + 1] & 0x80) != 0) ||
 305		    (buf[i] == 0x00 && (buf[i + 1] & 0x80) == 0)))
 306			break;
 307	if ((ret = asn_put_header(b, type, OCTETS - i)))
 308		return (ret);
 309	if (OCTETS - (u_int)i > b->asn_len)
 310		return (ASN_ERR_EOBUF);
 311
 312	while (i < OCTETS) {
 313		*b->asn_ptr++ = buf[i++];
 314		b->asn_len--;
 315	}
 316	return (ASN_ERR_OK);
 317# undef OCTETS
 318}
 319
 320
 321/*
 322 * The same for unsigned 64-bitters. Here we have the problem, that overflow
 323 * can happen, because the value maybe 9 bytes long. In this case the
 324 * first byte must be 0.
 325 */
 326static enum asn_err
 327asn_get_real_unsigned(struct asn_buf *b, asn_len_t len, uint64_t *vp)
 328{
 329	enum asn_err err;
 330
 331	if (b->asn_len < len) {
 332		asn_error(b, "truncated integer");
 333		return (ASN_ERR_EOBUF);
 334	}
 335	if (len == 0) {
 336		asn_error(b, "zero-length integer");
 337		*vp = 0;
 338		return (ASN_ERR_BADLEN);
 339	}
 340	err = ASN_ERR_OK;
 341	*vp = 0;
 342	if ((*b->asn_cptr & 0x80) || (len == 9 && *b->asn_cptr != 0)) {
 343		/* negative integer or too larger */
 344		*vp = 0xffffffffffffffffULL;
 345		err = ASN_ERR_RANGE;
 346	} else if (len > 1 &&
 347	    *b->asn_cptr == 0x00 && (b->asn_cptr[1] & 0x80) == 0) {
 348		asn_error(b, "non-minimal unsigned");
 349		err = ASN_ERR_BADLEN;
 350	}
 351
 352	while (len--) {
 353		*vp = (*vp << 8) | *b->asn_cptr++;
 354		b->asn_len--;
 355	}
 356	return (err);
 357}
 358
 359
 360/*
 361 * Values with the msb on need 9 octets.
 362 */
 363static int
 364asn_put_real_unsigned(struct asn_buf *b, u_char type, uint64_t val)
 365{
 366	int i;
 367# define OCTETS 9
 368	u_char buf[OCTETS];
 369	enum asn_err ret;
 370
 371	/* split the value into octets */
 372	for (i = OCTETS - 1; i >= 0; i--) {
 373		buf[i] = val & 0xff;
 374		val >>= 8;
 375	}
 376	/* no leading 9 zeroes */
 377	for (i = 0; i < OCTETS - 1; i++)
 378		if (!(buf[i] == 0x00 && (buf[i + 1] & 0x80) == 0))
 379			break;
 380	if ((ret = asn_put_header(b, type, OCTETS - i)))
 381		return (ret);
 382	if (OCTETS - (u_int)i > b->asn_len)
 383		return (ASN_ERR_EOBUF);
 384
 385	while (i < OCTETS) {
 386		*b->asn_ptr++ = buf[i++];
 387		b->asn_len--;
 388	}
 389#undef OCTETS
 390	return (ASN_ERR_OK);
 391}
 392
 393/*
 394 * The ASN.1 INTEGER type is restricted to 32-bit signed by the SMI.
 395 */
 396enum asn_err
 397asn_get_integer_raw(struct asn_buf *b, asn_len_t len, int32_t *vp)
 398{
 399	int64_t val;
 400	enum asn_err ret;
 401
 402	if ((ret = asn_get_real_integer(b, len, &val)) == ASN_ERR_OK) {
 403		if (len > 4)
 404			ret = ASN_ERR_BADLEN;
 405		else if (val > INT32_MAX || val < INT32_MIN)
 406			/* may not happen */
 407			ret = ASN_ERR_RANGE;
 408		*vp = (int32_t)val;
 409	}
 410	return (ret);
 411}
 412
 413enum asn_err
 414asn_get_integer(struct asn_buf *b, int32_t *vp)
 415{
 416	asn_len_t len;
 417	u_char type;
 418	enum asn_err err;
 419
 420	if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK)
 421		return (err);
 422	if (type != ASN_TYPE_INTEGER) {
 423		asn_error(b, "bad type for integer (%u)", type);
 424		return (ASN_ERR_TAG);
 425	}
 426
 427	return (asn_get_integer_raw(b, len, vp));
 428}
 429
 430enum asn_err
 431asn_put_integer(struct asn_buf *b, int32_t val)
 432{
 433	return (asn_put_real_integer(b, ASN_TYPE_INTEGER, val));
 434}
 435
 436/*
 437 * OCTETSTRING
 438 *
 439 * <0x04> <len> <data ...>
 440 *
 441 * Get an octetstring. noctets must point to the buffer size and on
 442 * return will contain the size of the octetstring, regardless of the
 443 * buffer size.
 444 */
 445enum asn_err
 446asn_get_octetstring_raw(struct asn_buf *b, asn_len_t len, u_char *octets,
 447    u_int *noctets)
 448{
 449	enum asn_err err = ASN_ERR_OK;
 450
 451	if (*noctets < len) {
 452		asn_error(b, "octetstring truncated");
 453		err = ASN_ERR_RANGE;
 454	}
 455	if (b->asn_len < len) {
 456		asn_error(b, "truncatet octetstring");
 457		return (ASN_ERR_EOBUF);
 458	}
 459	if (*noctets < len)
 460		memcpy(octets, b->asn_cptr, *noctets);
 461	else
 462		memcpy(octets, b->asn_cptr, len);
 463	*noctets = len;
 464	b->asn_cptr += len;
 465	b->asn_len -= len;
 466	return (err);
 467}
 468
 469enum asn_err
 470asn_get_octetstring(struct asn_buf *b, u_char *octets, u_int *noctets)
 471{
 472	enum asn_err err;
 473	u_char type;
 474	asn_len_t len;
 475
 476	if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK)
 477		return (err);
 478	if (type != ASN_TYPE_OCTETSTRING) {
 479		asn_error(b, "bad type for octetstring (%u)", type);
 480		return (ASN_ERR_TAG);
 481	}
 482	return (asn_get_octetstring_raw(b, len, octets, noctets));
 483}
 484
 485enum asn_err
 486asn_put_octetstring(struct asn_buf *b, const u_char *octets, u_int noctets)
 487{
 488	enum asn_err ret;
 489
 490	if ((ret = asn_put_header(b, ASN_TYPE_OCTETSTRING, noctets)) != ASN_ERR_OK)
 491		return (ret);
 492	if (b->asn_len < noctets)
 493		return (ASN_ERR_EOBUF);
 494
 495	memcpy(b->asn_ptr, octets, noctets);
 496	b->asn_ptr += noctets;
 497	b->asn_len -= noctets;
 498	return (ASN_ERR_OK);
 499}
 500
 501/*
 502 * NULL
 503 *
 504 * <0x05> <0x00>
 505 */
 506enum asn_err
 507asn_get_null_raw(struct asn_buf *b, asn_len_t len)
 508{
 509	if (len != 0) {
 510		if (b->asn_len < len) {
 511			asn_error(b, "truncated NULL");
 512			return (ASN_ERR_EOBUF);
 513		}
 514		asn_error(b, "bad length for NULL (%u)", len);
 515		b->asn_len -= len;
 516		b->asn_ptr += len;
 517		return (ASN_ERR_BADLEN);
 518	}
 519	return (ASN_ERR_OK);
 520}
 521
 522enum asn_err
 523asn_get_null(struct asn_buf *b)
 524{
 525	u_char type;
 526	asn_len_t len;
 527	enum asn_err err;
 528
 529	if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK)
 530		return (err);
 531	if (type != ASN_TYPE_NULL) {
 532		asn_error(b, "bad type for NULL (%u)", type);
 533		return (ASN_ERR_TAG);
 534	}
 535	return (asn_get_null_raw(b, len));
 536}
 537
 538enum asn_err
 539asn_put_null(struct asn_buf *b)
 540{
 541	return (asn_put_header(b, ASN_TYPE_NULL, 0));
 542}
 543
 544enum asn_err
 545asn_put_exception(struct asn_buf *b, u_int except)
 546{
 547	return (asn_put_header(b, ASN_CLASS_CONTEXT | except, 0));
 548}
 549
 550/*
 551 * OBJID
 552 *
 553 * <0x06> <len> <subid...>
 554 */
 555enum asn_err
 556asn_get_objid_raw(struct asn_buf *b, asn_len_t len, struct asn_oid *oid)
 557{
 558	asn_subid_t subid;
 559	enum asn_err err;
 560
 561	if (b->asn_len < len) {
 562		asn_error(b, "truncated OBJID");
 563		return (ASN_ERR_EOBUF);
 564	}
 565	oid->len = 0;
 566	if (len == 0) {
 567		asn_error(b, "short OBJID");
 568		oid->subs[oid->len++] = 0;
 569		oid->subs[oid->len++] = 0;
 570		return (ASN_ERR_BADLEN);
 571	}
 572	err = ASN_ERR_OK;
 573	while (len != 0) {
 574		if (oid->len == ASN_MAXOIDLEN) {
 575			asn_error(b, "OID too long (%u)", oid->len);
 576			b->asn_cptr += len;
 577			b->asn_len -= len;
 578			return (ASN_ERR_BADLEN);
 579		}
 580		subid = 0;
 581		do {
 582			if (len == 0) {
 583				asn_error(b, "unterminated subid");
 584				return (ASN_ERR_EOBUF);
 585			}
 586			if (subid > (ASN_MAXID >> 7)) {
 587				asn_error(b, "OBID subid too larger");
 588				err = ASN_ERR_RANGE;
 589			}
 590			subid = (subid << 7) | (*b->asn_cptr & 0x7f);
 591			len--;
 592			b->asn_len--;
 593		} while (*b->asn_cptr++ & 0x80);
 594		if (oid->len == 0) {
 595			if (subid < 80) {
 596				oid->subs[oid->len++] = subid / 40;
 597				oid->subs[oid->len++] = subid % 40;
 598			} else {
 599				oid->subs[oid->len++] = 2;
 600				oid->subs[oid->len++] = subid - 80;
 601			}
 602		} else {
 603			oid->subs[oid->len++] = subid;
 604		}
 605	}
 606	return (err);
 607
 608}
 609
 610enum asn_err
 611asn_get_objid(struct asn_buf *b, struct asn_oid *oid)
 612{
 613	u_char type;
 614	asn_len_t len;
 615	enum asn_err err;
 616
 617	if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK)
 618		return (err);
 619	if (type != ASN_TYPE_OBJID) {
 620		asn_error(b, "bad type for OBJID (%u)", type);
 621		return (ASN_ERR_TAG);
 622	}
 623	return (asn_get_objid_raw(b, len, oid));
 624}
 625
 626enum asn_err
 627asn_put_objid(struct asn_buf *b, const struct asn_oid *oid)
 628{
 629	asn_subid_t first, sub;
 630	enum asn_err err, err1;
 631	u_int i, oidlen;
 632	asn_len_t len;
 633
 634	err = ASN_ERR_OK;
 635	if (oid->len == 0) {
 636		/* illegal */
 637		asn_error(NULL, "short oid");
 638		err = ASN_ERR_RANGE;
 639		first = 0;
 640		oidlen = 2;
 641	} else if (oid->len == 1) {
 642		/* illegal */
 643		asn_error(b, "short oid");
 644		if (oid->subs[0] > 2)
 645			asn_error(NULL, "oid[0] too large (%u)", oid->subs[0]);
 646		err = ASN_ERR_RANGE;
 647		first = oid->subs[0] * 40;
 648		oidlen = 2;
 649	} else {
 650		if (oid->len > ASN_MAXOIDLEN) {
 651			asn_error(NULL, "oid too long %u", oid->len);
 652			err = ASN_ERR_RANGE;
 653		}
 654		if (oid->subs[0] > 2 ||
 655		    (oid->subs[0] < 2 && oid->subs[0] >= 40)) {
 656			asn_error(NULL, "oid out of range (%u,%u)",
 657			    oid->subs[0], oid->subs[1]);
 658			err = ASN_ERR_RANGE;
 659		}
 660		first = 40 * oid->subs[0] + oid->subs[1];
 661		oidlen = oid->len;
 662	}
 663	len = 0;
 664	for (i = 1; i < oidlen; i++) {
 665		sub = (i == 1) ? first : oid->subs[i];
 666		if (sub > ASN_MAXID) {
 667			asn_error(NULL, "oid subid too large");
 668			err = ASN_ERR_RANGE;
 669		}
 670		len += (sub <= 0x7f) ? 1
 671		    : (sub <= 0x3fff) ? 2
 672		    : (sub <= 0x1fffff) ? 3
 673		    : (sub <= 0xfffffff) ? 4
 674		    : 5;
 675	}
 676	if ((err1 = asn_put_header(b, ASN_TYPE_OBJID, len)) != ASN_ERR_OK)
 677		return (err1);
 678	if (b->asn_len < len)
 679		return (ASN_ERR_EOBUF);
 680
 681	for (i = 1; i < oidlen; i++) {
 682		sub = (i == 1) ? first : oid->subs[i];
 683		if (sub <= 0x7f) {
 684			*b->asn_ptr++ = sub;
 685			b->asn_len--;
 686		} else if (sub <= 0x3fff) {
 687			*b->asn_ptr++ = (sub >> 7) | 0x80;
 688			*b->asn_ptr++ = sub & 0x7f;
 689			b->asn_len -= 2;
 690		} else if (sub <= 0x1fffff) {
 691			*b->asn_ptr++ = (sub >> 14) | 0x80;
 692			*b->asn_ptr++ = ((sub >> 7) & 0x7f) | 0x80;
 693			*b->asn_ptr++ = sub & 0x7f;
 694			b->asn_len -= 3;
 695		} else if (sub <= 0xfffffff) {
 696			*b->asn_ptr++ = (sub >> 21) | 0x80;
 697			*b->asn_ptr++ = ((sub >> 14) & 0x7f) | 0x80;
 698			*b->asn_ptr++ = ((sub >> 7) & 0x7f) | 0x80;
 699			*b->asn_ptr++ = sub & 0x7f;
 700			b->asn_len -= 4;
 701		} else {
 702			*b->asn_ptr++ = (sub >> 28) | 0x80;
 703			*b->asn_ptr++ = ((sub >> 21) & 0x7f) | 0x80;
 704			*b->asn_ptr++ = ((sub >> 14) & 0x7f) | 0x80;
 705			*b->asn_ptr++ = ((sub >> 7) & 0x7f) | 0x80;
 706			*b->asn_ptr++ = sub & 0x7f;
 707			b->asn_len -= 5;
 708		}
 709	}
 710	return (err);
 711}
 712/*
 713 * SEQUENCE header
 714 *
 715 * <0x10|0x20> <len> <data...>
 716 */
 717enum asn_err
 718asn_get_sequence(struct asn_buf *b, asn_len_t *len)
 719{
 720	u_char type;
 721	enum asn_err err;
 722
 723	if ((err = asn_get_header(b, &type, len)) != ASN_ERR_OK)
 724		return (err);
 725	if (type != (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED)) {
 726		asn_error(b, "bad sequence type %u", type);
 727		return (ASN_ERR_TAG);
 728	}
 729	if (*len > b->asn_len) {
 730		asn_error(b, "truncated sequence");
 731		return (ASN_ERR_EOBUF);
 732	}
 733	return (ASN_ERR_OK);
 734}
 735
 736/*
 737 * Application types
 738 *
 739 * 0x40 4 MSB 2MSB 2LSB LSB
 740 */
 741enum asn_err
 742asn_get_ipaddress_raw(struct asn_buf *b, asn_len_t len, u_char *addr)
 743{
 744	u_int i;
 745
 746	if (b->asn_len < len) {
 747		asn_error(b, "truncated ip-address");
 748		return (ASN_ERR_EOBUF);
 749	}
 750	if (len < 4) {
 751		asn_error(b, "short length for ip-Address %u", len);
 752		for (i = 0; i < len; i++)
 753			*addr++ = *b->asn_cptr++;
 754		while (i++ < len)
 755			*addr++ = 0;
 756		b->asn_len -= len;
 757		return (ASN_ERR_BADLEN);
 758	}
 759	for (i = 0; i < 4; i++)
 760		*addr++ = *b->asn_cptr++;
 761	b->asn_cptr += len - 4;
 762	b->asn_len -= len;
 763	return (ASN_ERR_OK);
 764}
 765
 766enum asn_err
 767asn_get_ipaddress(struct asn_buf *b, u_char *addr)
 768{
 769	u_char type;
 770	asn_len_t len;
 771	enum asn_err err;
 772
 773	if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK)
 774		return (err);
 775	if (type != (ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS)) {
 776		asn_error(b, "bad type for ip-address %u", type);
 777		return (ASN_ERR_TAG);
 778	}
 779	return (asn_get_ipaddress_raw(b, len, addr));
 780}
 781
 782enum asn_err
 783asn_put_ipaddress(struct asn_buf *b, const u_char *addr)
 784{
 785	enum asn_err err;
 786
 787	if ((err = asn_put_header(b, ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS,
 788	    4)) != ASN_ERR_OK)
 789		return (err);
 790	if (b->asn_len < 4)
 791		return (ASN_ERR_EOBUF);
 792
 793	memcpy(b->asn_ptr, addr, 4);
 794	b->asn_ptr += 4;
 795	b->asn_len -= 4;
 796	return (ASN_ERR_OK);
 797}
 798
 799
 800/*
 801 * UNSIGNED32
 802 *
 803 * 0x42|0x41 <len> ...
 804 */
 805enum asn_err
 806asn_get_uint32_raw(struct asn_buf *b, asn_len_t len, uint32_t *vp)
 807{
 808	uint64_t v;
 809	enum asn_err err;
 810
 811	if ((err = asn_get_real_unsigned(b, len, &v)) == ASN_ERR_OK) {
 812		if (len > 5) {
 813			asn_error(b, "uint32 too long %u", len);
 814			err = ASN_ERR_BADLEN;
 815		} else if (v > UINT32_MAX) {
 816			asn_error(b, "uint32 too large %llu", v);
 817			err = ASN_ERR_RANGE;
 818		}
 819		*vp = (uint32_t)v;
 820	}
 821	return (err);
 822}
 823
 824enum asn_err
 825asn_put_uint32(struct asn_buf *b, u_char type, uint32_t val)
 826{
 827	uint64_t v = val;
 828
 829	return (asn_put_real_unsigned(b, ASN_CLASS_APPLICATION|type, v));
 830}
 831
 832/*
 833 * COUNTER64
 834 * 0x46 <len> ...
 835 */
 836enum asn_err
 837asn_get_counter64_raw(struct asn_buf *b, asn_len_t len, uint64_t *vp)
 838{
 839	return (asn_get_real_unsigned(b, len, vp));
 840}
 841
 842enum asn_err
 843asn_put_counter64(struct asn_buf *b, uint64_t val)
 844{
 845	return (asn_put_real_unsigned(b,
 846	    ASN_CLASS_APPLICATION | ASN_APP_COUNTER64, val));
 847}
 848
 849/*
 850 * TimeTicks
 851 * 0x43 <len> ...
 852 */
 853enum asn_err
 854asn_get_timeticks(struct asn_buf *b, uint32_t *vp)
 855{
 856	asn_len_t len;
 857	u_char type;
 858	enum asn_err err;
 859
 860	if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK)
 861		return (err);
 862	if (type != (ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS)) {
 863		asn_error(b, "bad type for timeticks %u", type);
 864		return (ASN_ERR_TAG);
 865	}
 866	return (asn_get_uint32_raw(b, len, vp));
 867}
 868
 869enum asn_err
 870asn_put_timeticks(struct asn_buf *b, uint32_t val)
 871{
 872	uint64_t v = val;
 873
 874	return (asn_put_real_unsigned(b,
 875	    ASN_CLASS_APPLICATION | ASN_APP_TIMETICKS, v));
 876}
 877
 878/*
 879 * Construct a new OID by taking a range of sub ids of the original oid.
 880 */
 881void
 882asn_slice_oid(struct asn_oid *dest, const struct asn_oid *src,
 883    u_int from, u_int to)
 884{
 885	if (from >= to) {
 886		dest->len = 0;
 887		return;
 888	}
 889	dest->len = to - from;
 890	memcpy(dest->subs, &src->subs[from], dest->len * sizeof(dest->subs[0]));
 891}
 892
 893/* 
 894 * Append from to to
 895 */
 896void
 897asn_append_oid(struct asn_oid *to, const struct asn_oid *from)
 898{
 899	memcpy(&to->subs[to->len], &from->subs[0],
 900	    from->len * sizeof(from->subs[0]));
 901	to->len += from->len;
 902}
 903
 904/*
 905 * Skip a value
 906 */
 907enum asn_err
 908asn_skip(struct asn_buf *b, asn_len_t len)
 909{
 910	if (b->asn_len < len)
 911		return (ASN_ERR_EOBUF);
 912	b->asn_cptr += len;
 913	b->asn_len -= len;
 914	return (ASN_ERR_OK);
 915}
 916
 917/*
 918 * Add a padding
 919 */
 920enum asn_err
 921asn_pad(struct asn_buf *b, asn_len_t len)
 922{
 923	if (b->asn_len < len)
 924		return (ASN_ERR_EOBUF);
 925	b->asn_ptr += len;
 926	b->asn_len -= len;
 927
 928	return (ASN_ERR_OK);
 929}
 930
 931/*
 932 * Compare two OIDs.
 933 *
 934 * o1 < o2 : -1
 935 * o1 > o2 : +1
 936 * o1 = o2 :  0
 937 */
 938int
 939asn_compare_oid(const struct asn_oid *o1, const struct asn_oid *o2)
 940{
 941	u_long i;
 942
 943	for (i = 0; i < o1->len && i < o2->len; i++) {
 944		if (o1->subs[i] < o2->subs[i])
 945			return (-1);
 946		if (o1->subs[i] > o2->subs[i])
 947			return (+1);
 948	}
 949	if (o1->len < o2->len)
 950		return (-1);
 951	if (o1->len > o2->len)
 952		return (+1);
 953	return (0);
 954}
 955
 956/*
 957 * Check whether an OID is a sub-string of another OID.
 958 */
 959int
 960asn_is_suboid(const struct asn_oid *o1, const struct asn_oid *o2)
 961{
 962	u_long i;
 963
 964	for (i = 0; i < o1->len; i++)
 965		if (i >= o2->len || o1->subs[i] != o2->subs[i])
 966			return (0);
 967	return (1);
 968}
 969
 970/*
 971 * Put a string representation of an oid into a user buffer. This buffer
 972 * is assumed to be at least ASN_OIDSTRLEN characters long.
 973 *
 974 * sprintf is assumed not to fail here.
 975 */
 976char *
 977asn_oid2str_r(const struct asn_oid *oid, char *buf)
 978{
 979	u_int len, i;
 980	char *ptr;
 981
 982	if ((len = oid->len) > ASN_MAXOIDLEN)
 983		len = ASN_MAXOIDLEN;
 984	buf[0] = '\0';
 985	for (i = 0, ptr = buf; i < len; i++) {
 986		if (i > 0)
 987			*ptr++ = '.';
 988		ptr += sprintf(ptr, "%u", oid->subs[i]);
 989	}
 990	return (buf);
 991}
 992
 993/*
 994 * Make a string from an OID in a private buffer.
 995 */
 996char *
 997asn_oid2str(const struct asn_oid *oid)
 998{
 999	static char str[ASN_OIDSTRLEN];
1000
1001	return (asn_oid2str_r(oid, str));
1002}
1003
1004
1005static void
1006asn_error_func(const struct asn_buf *b, const char *err, ...)
1007{
1008	va_list ap;
1009	u_long i;
1010
1011	fprintf(stderr, "ASN.1: ");
1012	va_start(ap, err);
1013	vfprintf(stderr, err, ap);
1014	va_end(ap);
1015
1016	if (b != NULL) {
1017		fprintf(stderr, " at");
1018		for (i = 0; b->asn_len > i; i++)
1019			fprintf(stderr, " %02x", b->asn_cptr[i]);
1020	}
1021	fprintf(stderr, "\n");
1022}