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