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