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