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