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