asn1.c revision 122394
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 of this software and documentation and use in source and 9 * binary forms, with or without modification, are permitted provided that 10 * the following conditions are met: 11 * 12 * 1. Redistributions of source code or documentation must retain the above 13 * copyright notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS 22 * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 23 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 24 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 25 * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 28 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 31 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * $Begemot: bsnmp/lib/asn1.c,v 1.24 2003/01/28 13:44:34 hbb Exp $ 34 * 35 * ASN.1 for SNMP. 36 */ 37#include <sys/types.h> 38#include <stdio.h> 39#include <stdlib.h> 40#include <stdarg.h> 41#include <string.h> 42#include <inttypes.h> 43#include <assert.h> 44#include "asn1.h" 45 46static void asn_error_func(const struct asn_buf *, const char *, ...); 47 48void (*asn_error)(const struct asn_buf *, const char *, ...) = asn_error_func; 49 50/* 51 * Read the next header. This reads the tag (note, that only single 52 * byte tags are supported for now) and the length field. The length field 53 * is restricted to a 32-bit value. 54 * All errors of this function stop the decoding. 55 */ 56enum asn_err 57asn_get_header(struct asn_buf *b, u_char *type, asn_len_t *len) 58{ 59 u_int length; 60 61 if (b->asn_len == 0) { 62 asn_error(b, "no identifier for header"); 63 return (ASN_ERR_EOBUF); 64 } 65 *type = *b->asn_cptr; 66 if ((*type & ASN_TYPE_MASK) > 0x30) { 67 asn_error(b, "types > 0x30 not supported (%u)", 68 *type & ASN_TYPE_MASK); 69 return (ASN_ERR_FAILED); 70 } 71 b->asn_cptr++; 72 b->asn_len--; 73 if (b->asn_len == 0) { 74 asn_error(b, "no length field"); 75 return (ASN_ERR_EOBUF); 76 } 77 if (*b->asn_cptr & 0x80) { 78 length = *b->asn_cptr++ & 0x7f; 79 b->asn_len--; 80 if (length == 0) { 81 asn_error(b, "indefinite length not supported"); 82 return (ASN_ERR_FAILED); 83 } 84 if (length > ASN_MAXLENLEN) { 85 asn_error(b, "long length too long (%u)", length); 86 return (ASN_ERR_FAILED); 87 } 88 if (length > b->asn_len) { 89 asn_error(b, "long length truncated"); 90 return (ASN_ERR_EOBUF); 91 } 92 *len = 0; 93 while (length--) { 94 *len = (*len << 8) | *b->asn_cptr++; 95 b->asn_len--; 96 } 97 } else { 98 *len = *b->asn_cptr++; 99 b->asn_len--; 100 } 101 return (ASN_ERR_OK); 102} 103 104/* 105 * Write a length field (restricted to values < 2^32-1) and return the 106 * number of bytes this field takes. If ptr is NULL, the length is computed 107 * but nothing is written. If the length would be too large return 0. 108 */ 109static u_int 110asn_put_len(u_char *ptr, asn_len_t len) 111{ 112 u_int lenlen, lenlen1; 113 asn_len_t tmp; 114 115 if (len > ASN_MAXLEN) { 116 asn_error(NULL, "encoding length too long: (%u)", len); 117 return (0); 118 } 119 120 if (len <= 127) { 121 if (ptr) 122 *ptr++ = (u_char)len; 123 return (1); 124 } else { 125 lenlen = 0; 126 /* compute number of bytes for value (is at least 1) */ 127 for (tmp = len; tmp != 0; tmp >>= 8) 128 lenlen++; 129 if (ptr != NULL) { 130 *ptr++ = (u_char)lenlen | 0x80; 131 lenlen1 = lenlen; 132 while (lenlen1-- > 0) { 133 ptr[lenlen1] = len & 0xff; 134 len >>= 8; 135 } 136 } 137 return (lenlen + 1); 138 } 139} 140 141/* 142 * Write a header (tag and length fields). 143 * Tags are restricted to one byte tags (value <= 0x30) and the 144 * lenght field to 16-bit. All errors stop the encoding. 145 */ 146enum asn_err 147asn_put_header(struct asn_buf *b, u_char type, asn_len_t len) 148{ 149 u_int lenlen; 150 151 /* tag field */ 152 if ((type & ASN_TYPE_MASK) > 0x30) { 153 asn_error(NULL, "types > 0x30 not supported (%u)", 154 type & ASN_TYPE_MASK); 155 return (ASN_ERR_FAILED); 156 } 157 if (b->asn_len == 0) 158 return (ASN_ERR_EOBUF); 159 160 *b->asn_ptr++ = type; 161 b->asn_len--; 162 163 /* length field */ 164 if ((lenlen = asn_put_len(NULL, len)) == 0) 165 return (ASN_ERR_FAILED); 166 if (b->asn_len < lenlen) 167 return (ASN_ERR_EOBUF); 168 169 (void)asn_put_len(b->asn_ptr, len); 170 b->asn_ptr += lenlen; 171 b->asn_len -= lenlen; 172 return (ASN_ERR_OK); 173} 174 175 176/* 177 * This constructs a temporary sequence header with space for the maximum 178 * length field (three byte). Set the pointer that ptr points to to the 179 * start of the encoded header. This is used for a later call to 180 * asn_commit_header which will fix-up the length field and move the 181 * value if needed. All errors should stop the encoding. 182 */ 183#define TEMP_LEN (1 + ASN_MAXLENLEN + 1) 184enum asn_err 185asn_put_temp_header(struct asn_buf *b, u_char type, u_char **ptr) 186{ 187 int ret; 188 189 if (b->asn_len < TEMP_LEN) 190 return (ASN_ERR_EOBUF); 191 *ptr = b->asn_ptr; 192 if ((ret = asn_put_header(b, type, ASN_MAXLEN)) == ASN_ERR_OK) 193 assert(b->asn_ptr == *ptr + TEMP_LEN); 194 return (ret); 195} 196enum asn_err 197asn_commit_header(struct asn_buf *b, u_char *ptr) 198{ 199 asn_len_t len; 200 u_int lenlen, shift; 201 202 /* compute length of encoded value without header */ 203 len = b->asn_ptr - (ptr + TEMP_LEN); 204 205 /* insert length. may not fail. */ 206 lenlen = asn_put_len(ptr + 1, len); 207 if (lenlen > TEMP_LEN - 1) 208 return (ASN_ERR_FAILED); 209 210 if (lenlen < TEMP_LEN - 1) { 211 /* shift value down */ 212 shift = (TEMP_LEN - 1) - lenlen; 213 memmove(ptr + 1 + lenlen, ptr + TEMP_LEN, len); 214 b->asn_ptr -= shift; 215 b->asn_len += shift; 216 } 217 return (ASN_ERR_OK); 218} 219#undef TEMP_LEN 220 221/* 222 * BER integer. This may be used to get a signed 64 bit integer at maximum. 223 * The maximum length should be checked by the caller. This cannot overflow 224 * if the caller ensures that len is at maximum 8. 225 * 226 * <bytes> 227 */ 228static enum asn_err 229asn_get_real_integer(struct asn_buf *b, asn_len_t len, int64_t *vp) 230{ 231 u_int64_t val; 232 int neg = 0; 233 enum asn_err err; 234 235 if (b->asn_len < len) { 236 asn_error(b, "truncated integer"); 237 return (ASN_ERR_EOBUF); 238 } 239 if (len == 0) { 240 asn_error(b, "zero-length integer"); 241 *vp = 0; 242 return (ASN_ERR_BADLEN); 243 } 244 err = ASN_ERR_OK; 245 if (len > 8) 246 err = ASN_ERR_RANGE; 247 if (*b->asn_cptr & 0x80) 248 neg = 1; 249 val = 0; 250 while (len--) { 251 val <<= 8; 252 val |= neg ? (u_char)~*b->asn_cptr : *b->asn_cptr; 253 b->asn_len--; 254 b->asn_cptr++; 255 } 256 if (neg) { 257 *vp = -(int64_t)val - 1; 258 } else 259 *vp = (int64_t)val; 260 return (err); 261} 262 263/* 264 * Write a signed integer with the given type. The caller has to ensure 265 * that the actual value is ok for this type. 266 */ 267static enum asn_err 268asn_put_real_integer(struct asn_buf *b, u_char type, int64_t ival) 269{ 270 int i, neg = 0; 271# define OCTETS 8 272 u_char buf[OCTETS]; 273 u_int64_t val; 274 enum asn_err ret; 275 276 if (ival < 0) { 277 /* this may fail if |INT64_MIN| > |INT64_MAX| and 278 * the value is between * INT64_MIN <= ival < -(INT64_MAX+1) */ 279 val = (u_int64_t)-(ival + 1); 280 neg = 1; 281 } else 282 val = (u_int64_t)ival; 283 284 /* split the value into octets */ 285 for (i = OCTETS - 1; i >= 0; i--) { 286 buf[i] = val & 0xff; 287 if (neg) 288 buf[i] = ~buf[i]; 289 val >>= 8; 290 } 291 /* no leading 9 zeroes or ones */ 292 for (i = 0; i < OCTETS - 1; i++) 293 if (!((buf[i] == 0xff && (buf[i + 1] & 0x80) != 0) || 294 (buf[i] == 0x00 && (buf[i + 1] & 0x80) == 0))) 295 break; 296 if ((ret = asn_put_header(b, type, OCTETS - i))) 297 return (ret); 298 if (OCTETS - (u_int)i > b->asn_len) 299 return (ASN_ERR_EOBUF); 300 301 while (i < OCTETS) { 302 *b->asn_ptr++ = buf[i++]; 303 b->asn_len--; 304 } 305 return (ASN_ERR_OK); 306# undef OCTETS 307} 308 309 310/* 311 * The same for unsigned 64-bitters. Here we have the problem, that overflow 312 * can happen, because the value maybe 9 bytes long. In this case the 313 * first byte must be 0. 314 */ 315static enum asn_err 316asn_get_real_unsigned(struct asn_buf *b, asn_len_t len, u_int64_t *vp) 317{ 318 enum asn_err err; 319 320 if (b->asn_len < len) { 321 asn_error(b, "truncated integer"); 322 return (ASN_ERR_EOBUF); 323 } 324 if (len == 0) { 325 asn_error(b, "zero-length integer"); 326 *vp = 0; 327 return (ASN_ERR_BADLEN); 328 } 329 err = ASN_ERR_OK; 330 *vp = 0; 331 if ((*b->asn_cptr & 0x80) || (len == 9 && *b->asn_cptr != 0)) { 332 /* negative integer or too larger */ 333 *vp = 0xffffffffffffffffULL; 334 err = ASN_ERR_RANGE; 335 } 336 337 while (len--) { 338 *vp = (*vp << 8) | *b->asn_cptr++; 339 b->asn_len--; 340 } 341 return (err); 342} 343 344 345/* 346 * Values with the msb on need 9 octets. 347 */ 348static int 349asn_put_real_unsigned(struct asn_buf *b, u_char type, u_int64_t val) 350{ 351 int i; 352# define OCTETS 9 353 u_char buf[OCTETS]; 354 enum asn_err ret; 355 356 /* split the value into octets */ 357 for (i = OCTETS - 1; i >= 0; i--) { 358 buf[i] = val & 0xff; 359 val >>= 8; 360 } 361 /* no leading 9 zeroes */ 362 for (i = 0; i < OCTETS - 1; i++) 363 if (!(buf[i] == 0x00 && (buf[i + 1] & 0x80) == 0)) 364 break; 365 if ((ret = asn_put_header(b, type, OCTETS - i))) 366 return (ret); 367 if (OCTETS - (u_int)i > b->asn_len) 368 return (ASN_ERR_EOBUF); 369 370 while (i < OCTETS) { 371 *b->asn_ptr++ = buf[i++]; 372 b->asn_len--; 373 } 374#undef OCTETS 375 return (ASN_ERR_OK); 376} 377 378/* 379 * The ASN.1 INTEGER type is restricted to 32-bit signed by the SMI. 380 */ 381enum asn_err 382asn_get_integer_raw(struct asn_buf *b, asn_len_t len, int32_t *vp) 383{ 384 int64_t val; 385 enum asn_err ret; 386 387 if ((ret = asn_get_real_integer(b, len, &val)) == ASN_ERR_OK) { 388 if (len > 4) 389 ret = ASN_ERR_BADLEN; 390 else if (val > INT32_MAX || val < INT32_MIN) 391 /* may not happen */ 392 ret = ASN_ERR_RANGE; 393 *vp = (int32_t)val; 394 } 395 return (ret); 396} 397 398enum asn_err 399asn_get_integer(struct asn_buf *b, int32_t *vp) 400{ 401 asn_len_t len; 402 u_char type; 403 enum asn_err err; 404 405 if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK) 406 return (err); 407 if (type != ASN_TYPE_INTEGER) { 408 asn_error(b, "bad type for integer (%u)", type); 409 return (ASN_ERR_TAG); 410 } 411 412 return (asn_get_integer_raw(b, len, vp)); 413} 414 415enum asn_err 416asn_put_integer(struct asn_buf *b, int32_t val) 417{ 418 return (asn_put_real_integer(b, ASN_TYPE_INTEGER, val)); 419} 420 421/* 422 * OCTETSTRING 423 * 424 * <0x04> <len> <data ...> 425 * 426 * Get an octetstring. noctets must point to the buffer size and on 427 * return will contain the size of the octetstring, regardless of the 428 * buffer size. 429 */ 430enum asn_err 431asn_get_octetstring_raw(struct asn_buf *b, asn_len_t len, u_char *octets, 432 u_int *noctets) 433{ 434 enum asn_err err = ASN_ERR_OK; 435 436 if (*noctets < len) { 437 asn_error(b, "octetstring truncated"); 438 err = ASN_ERR_RANGE; 439 } 440 if (b->asn_len < len) { 441 asn_error(b, "truncatet octetstring"); 442 return (ASN_ERR_EOBUF); 443 } 444 if (*noctets < len) 445 memcpy(octets, b->asn_cptr, *noctets); 446 else 447 memcpy(octets, b->asn_cptr, len); 448 *noctets = len; 449 b->asn_cptr += len; 450 b->asn_len -= len; 451 return (err); 452} 453 454enum asn_err 455asn_get_octetstring(struct asn_buf *b, u_char *octets, u_int *noctets) 456{ 457 enum asn_err err; 458 u_char type; 459 asn_len_t len; 460 461 if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK) 462 return (err); 463 if (type != ASN_TYPE_OCTETSTRING) { 464 asn_error(b, "bad type for octetstring (%u)", type); 465 return (ASN_ERR_TAG); 466 } 467 return (asn_get_octetstring_raw(b, len, octets, noctets)); 468} 469 470enum asn_err 471asn_put_octetstring(struct asn_buf *b, const u_char *octets, u_int noctets) 472{ 473 enum asn_err ret; 474 475 if ((ret = asn_put_header(b, ASN_TYPE_OCTETSTRING, noctets)) != ASN_ERR_OK) 476 return (ret); 477 if (b->asn_len < noctets) 478 return (ASN_ERR_EOBUF); 479 480 memcpy(b->asn_ptr, octets, noctets); 481 b->asn_ptr += noctets; 482 b->asn_len -= noctets; 483 return (ASN_ERR_OK); 484} 485 486/* 487 * NULL 488 * 489 * <0x05> <0x00> 490 */ 491enum asn_err 492asn_get_null_raw(struct asn_buf *b, asn_len_t len) 493{ 494 if (len != 0) { 495 if (b->asn_len < len) { 496 asn_error(b, "truncated NULL"); 497 return (ASN_ERR_EOBUF); 498 } 499 asn_error(b, "bad length for NULL (%u)", len); 500 b->asn_len -= len; 501 b->asn_ptr += len; 502 return (ASN_ERR_BADLEN); 503 } 504 return (ASN_ERR_OK); 505} 506 507enum asn_err 508asn_get_null(struct asn_buf *b) 509{ 510 u_char type; 511 asn_len_t len; 512 enum asn_err err; 513 514 if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK) 515 return (err); 516 if (type != ASN_TYPE_NULL) { 517 asn_error(b, "bad type for NULL (%u)", type); 518 return (ASN_ERR_TAG); 519 } 520 return (asn_get_null_raw(b, len)); 521} 522 523enum asn_err 524asn_put_null(struct asn_buf *b) 525{ 526 return (asn_put_header(b, ASN_TYPE_NULL, 0)); 527} 528 529enum asn_err 530asn_put_exception(struct asn_buf *b, u_int except) 531{ 532 return (asn_put_header(b, ASN_CLASS_CONTEXT | except, 0)); 533} 534 535/* 536 * OBJID 537 * 538 * <0x06> <len> <subid...> 539 */ 540enum asn_err 541asn_get_objid_raw(struct asn_buf *b, asn_len_t len, struct asn_oid *oid) 542{ 543 asn_subid_t subid; 544 enum asn_err err; 545 546 if (b->asn_len < len) { 547 asn_error(b, "truncated OBJID"); 548 return (ASN_ERR_EOBUF); 549 } 550 oid->len = 0; 551 if (len == 0) { 552 asn_error(b, "short OBJID"); 553 oid->subs[oid->len++] = 0; 554 oid->subs[oid->len++] = 0; 555 return (ASN_ERR_BADLEN); 556 } 557 err = ASN_ERR_OK; 558 while (len != 0) { 559 if (oid->len == ASN_MAXOIDLEN) { 560 asn_error(b, "OID too long (%u)", oid->len); 561 b->asn_cptr += len; 562 b->asn_len -= len; 563 return (ASN_ERR_BADLEN); 564 } 565 subid = 0; 566 do { 567 if (len == 0) { 568 asn_error(b, "unterminated subid"); 569 return (ASN_ERR_EOBUF); 570 } 571 if (subid > (ASN_MAXID >> 7)) { 572 asn_error(b, "OBID subid too larger"); 573 err = ASN_ERR_RANGE; 574 } 575 subid = (subid << 7) | (*b->asn_cptr & 0x7f); 576 len--; 577 b->asn_len--; 578 } while (*b->asn_cptr++ & 0x80); 579 if (oid->len == 0) { 580 if (subid < 80) { 581 oid->subs[oid->len++] = subid / 40; 582 oid->subs[oid->len++] = subid % 40; 583 } else { 584 oid->subs[oid->len++] = 2; 585 oid->subs[oid->len++] = subid - 80; 586 } 587 } else { 588 oid->subs[oid->len++] = subid; 589 } 590 } 591 return (err); 592 593} 594 595enum asn_err 596asn_get_objid(struct asn_buf *b, struct asn_oid *oid) 597{ 598 u_char type; 599 asn_len_t len; 600 enum asn_err err; 601 602 if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK) 603 return (err); 604 if (type != ASN_TYPE_OBJID) { 605 asn_error(b, "bad type for OBJID (%u)", type); 606 return (ASN_ERR_TAG); 607 } 608 return (asn_get_objid_raw(b, len, oid)); 609} 610 611enum asn_err 612asn_put_objid(struct asn_buf *b, const struct asn_oid *oid) 613{ 614 asn_subid_t first, sub; 615 enum asn_err err, err1; 616 u_int i, oidlen; 617 asn_len_t len; 618 619 err = ASN_ERR_OK; 620 if (oid->len == 0) { 621 /* illegal */ 622 asn_error(NULL, "short oid"); 623 err = ASN_ERR_RANGE; 624 first = 0; 625 oidlen = 2; 626 } else if (oid->len == 1) { 627 /* illegal */ 628 asn_error(b, "short oid"); 629 if (oid->subs[0] > 2) 630 asn_error(NULL, "oid[0] too large (%u)", oid->subs[0]); 631 err = ASN_ERR_RANGE; 632 first = oid->subs[0] * 40; 633 oidlen = 2; 634 } else { 635 if (oid->len > ASN_MAXOIDLEN) { 636 asn_error(NULL, "oid too long %u", oid->len); 637 err = ASN_ERR_RANGE; 638 } 639 if (oid->subs[0] > 2 || 640 (oid->subs[0] < 2 && oid->subs[0] >= 40)) { 641 asn_error(NULL, "oid out of range (%u,%u)", 642 oid->subs[0], oid->subs[1]); 643 err = ASN_ERR_RANGE; 644 } 645 first = 40 * oid->subs[0] + oid->subs[1]; 646 oidlen = oid->len; 647 } 648 len = 0; 649 for (i = 1; i < oidlen; i++) { 650 sub = (i == 1) ? first : oid->subs[i]; 651 if (sub > ASN_MAXID) { 652 asn_error(NULL, "oid subid too large"); 653 err = ASN_ERR_RANGE; 654 } 655 len += (sub <= 0x7f) ? 1 656 : (sub <= 0x3fff) ? 2 657 : (sub <= 0x1fffff) ? 3 658 : (sub <= 0xfffffff) ? 4 659 : 5; 660 } 661 if ((err1 = asn_put_header(b, ASN_TYPE_OBJID, len)) != ASN_ERR_OK) 662 return (err1); 663 if (b->asn_len < len) 664 return (ASN_ERR_EOBUF); 665 666 for (i = 1; i < oidlen; i++) { 667 sub = (i == 1) ? first : oid->subs[i]; 668 if (sub <= 0x7f) { 669 *b->asn_ptr++ = sub; 670 b->asn_len--; 671 } else if (sub <= 0x3fff) { 672 *b->asn_ptr++ = (sub >> 7) | 0x80; 673 *b->asn_ptr++ = sub & 0x7f; 674 b->asn_len -= 2; 675 } else if (sub <= 0x1fffff) { 676 *b->asn_ptr++ = (sub >> 14) | 0x80; 677 *b->asn_ptr++ = ((sub >> 7) & 0x7f) | 0x80; 678 *b->asn_ptr++ = sub & 0x7f; 679 b->asn_len -= 3; 680 } else if (sub <= 0xfffffff) { 681 *b->asn_ptr++ = (sub >> 21) | 0x80; 682 *b->asn_ptr++ = ((sub >> 14) & 0x7f) | 0x80; 683 *b->asn_ptr++ = ((sub >> 7) & 0x7f) | 0x80; 684 *b->asn_ptr++ = sub & 0x7f; 685 b->asn_len -= 4; 686 } else { 687 *b->asn_ptr++ = (sub >> 28) | 0x80; 688 *b->asn_ptr++ = ((sub >> 21) & 0x7f) | 0x80; 689 *b->asn_ptr++ = ((sub >> 14) & 0x7f) | 0x80; 690 *b->asn_ptr++ = ((sub >> 7) & 0x7f) | 0x80; 691 *b->asn_ptr++ = sub & 0x7f; 692 b->asn_len -= 5; 693 } 694 } 695 return (err); 696} 697/* 698 * SEQUENCE header 699 * 700 * <0x10|0x20> <len> <data...> 701 */ 702enum asn_err 703asn_get_sequence(struct asn_buf *b, asn_len_t *len) 704{ 705 u_char type; 706 enum asn_err err; 707 708 if ((err = asn_get_header(b, &type, len)) != ASN_ERR_OK) 709 return (err); 710 if (type != (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED)) { 711 asn_error(b, "bad sequence type %u", type); 712 return (ASN_ERR_TAG); 713 } 714 if (*len > b->asn_len) { 715 asn_error(b, "truncated sequence"); 716 return (ASN_ERR_EOBUF); 717 } 718 return (ASN_ERR_OK); 719} 720 721 722/* 723 * Application types 724 * 725 * 0x40 4 MSB 2MSB 2LSB LSB 726 */ 727enum asn_err 728asn_get_ipaddress_raw(struct asn_buf *b, asn_len_t len, u_char *addr) 729{ 730 u_int i; 731 732 if (b->asn_len < len) { 733 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