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