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