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 * 8f06ca4afSHartmut Brandt * Redistribution of this software and documentation and use in source and 9f06ca4afSHartmut Brandt * binary forms, with or without modification, are permitted provided that 10f06ca4afSHartmut Brandt * the following conditions are met: 11f06ca4afSHartmut Brandt * 12f06ca4afSHartmut Brandt * 1. Redistributions of source code or documentation must retain the above 13f06ca4afSHartmut Brandt * copyright notice, this list of conditions and the following disclaimer. 14f06ca4afSHartmut Brandt * 2. Redistributions in binary form must reproduce the above copyright 15f06ca4afSHartmut Brandt * notice, this list of conditions and the following disclaimer in the 16f06ca4afSHartmut Brandt * documentation and/or other materials provided with the distribution. 17f06ca4afSHartmut Brandt * 3. Neither the name of the Institute nor the names of its contributors 18f06ca4afSHartmut Brandt * may be used to endorse or promote products derived from this software 19f06ca4afSHartmut Brandt * without specific prior written permission. 20f06ca4afSHartmut Brandt * 21f06ca4afSHartmut Brandt * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS 22f06ca4afSHartmut Brandt * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 23f06ca4afSHartmut Brandt * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 24f06ca4afSHartmut Brandt * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 25f06ca4afSHartmut Brandt * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26f06ca4afSHartmut Brandt * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27f06ca4afSHartmut Brandt * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 28f06ca4afSHartmut Brandt * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29f06ca4afSHartmut Brandt * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30f06ca4afSHartmut Brandt * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 31f06ca4afSHartmut Brandt * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32f06ca4afSHartmut Brandt * 33f06ca4afSHartmut Brandt * $Begemot: bsnmp/lib/asn1.c,v 1.24 2003/01/28 13:44:34 hbb Exp $ 34f06ca4afSHartmut Brandt * 35f06ca4afSHartmut Brandt * ASN.1 for SNMP. 36f06ca4afSHartmut Brandt */ 37f06ca4afSHartmut Brandt #include <sys/types.h> 38f06ca4afSHartmut Brandt #include <stdio.h> 39f06ca4afSHartmut Brandt #include <stdlib.h> 40f06ca4afSHartmut Brandt #include <stdarg.h> 41f06ca4afSHartmut Brandt #include <string.h> 42f06ca4afSHartmut Brandt #include <inttypes.h> 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 { 231f06ca4afSHartmut Brandt u_int64_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; 247f06ca4afSHartmut Brandt if (*b->asn_cptr & 0x80) 248f06ca4afSHartmut Brandt neg = 1; 249f06ca4afSHartmut Brandt val = 0; 250f06ca4afSHartmut Brandt while (len--) { 251f06ca4afSHartmut Brandt val <<= 8; 252f06ca4afSHartmut Brandt val |= neg ? (u_char)~*b->asn_cptr : *b->asn_cptr; 253f06ca4afSHartmut Brandt b->asn_len--; 254f06ca4afSHartmut Brandt b->asn_cptr++; 255f06ca4afSHartmut Brandt } 256f06ca4afSHartmut Brandt if (neg) { 257f06ca4afSHartmut Brandt *vp = -(int64_t)val - 1; 258f06ca4afSHartmut Brandt } else 259f06ca4afSHartmut Brandt *vp = (int64_t)val; 260f06ca4afSHartmut Brandt return (err); 261f06ca4afSHartmut Brandt } 262f06ca4afSHartmut Brandt 263f06ca4afSHartmut Brandt /* 264f06ca4afSHartmut Brandt * Write a signed integer with the given type. The caller has to ensure 265f06ca4afSHartmut Brandt * that the actual value is ok for this type. 266f06ca4afSHartmut Brandt */ 267f06ca4afSHartmut Brandt static enum asn_err 268f06ca4afSHartmut Brandt asn_put_real_integer(struct asn_buf *b, u_char type, int64_t ival) 269f06ca4afSHartmut Brandt { 270f06ca4afSHartmut Brandt int i, neg = 0; 271f06ca4afSHartmut Brandt # define OCTETS 8 272f06ca4afSHartmut Brandt u_char buf[OCTETS]; 273f06ca4afSHartmut Brandt u_int64_t val; 274f06ca4afSHartmut Brandt enum asn_err ret; 275f06ca4afSHartmut Brandt 276f06ca4afSHartmut Brandt if (ival < 0) { 277f06ca4afSHartmut Brandt /* this may fail if |INT64_MIN| > |INT64_MAX| and 278f06ca4afSHartmut Brandt * the value is between * INT64_MIN <= ival < -(INT64_MAX+1) */ 279f06ca4afSHartmut Brandt val = (u_int64_t)-(ival + 1); 280f06ca4afSHartmut Brandt neg = 1; 281f06ca4afSHartmut Brandt } else 282f06ca4afSHartmut Brandt val = (u_int64_t)ival; 283f06ca4afSHartmut Brandt 284f06ca4afSHartmut Brandt /* split the value into octets */ 285f06ca4afSHartmut Brandt for (i = OCTETS - 1; i >= 0; i--) { 286f06ca4afSHartmut Brandt buf[i] = val & 0xff; 287f06ca4afSHartmut Brandt if (neg) 288f06ca4afSHartmut Brandt buf[i] = ~buf[i]; 289f06ca4afSHartmut Brandt val >>= 8; 290f06ca4afSHartmut Brandt } 291f06ca4afSHartmut Brandt /* no leading 9 zeroes or ones */ 292f06ca4afSHartmut Brandt for (i = 0; i < OCTETS - 1; i++) 293f06ca4afSHartmut Brandt if (!((buf[i] == 0xff && (buf[i + 1] & 0x80) != 0) || 294f06ca4afSHartmut Brandt (buf[i] == 0x00 && (buf[i + 1] & 0x80) == 0))) 295f06ca4afSHartmut Brandt break; 296f06ca4afSHartmut Brandt if ((ret = asn_put_header(b, type, OCTETS - i))) 297f06ca4afSHartmut Brandt return (ret); 298f06ca4afSHartmut Brandt if (OCTETS - (u_int)i > b->asn_len) 299f06ca4afSHartmut Brandt return (ASN_ERR_EOBUF); 300f06ca4afSHartmut Brandt 301f06ca4afSHartmut Brandt while (i < OCTETS) { 302f06ca4afSHartmut Brandt *b->asn_ptr++ = buf[i++]; 303f06ca4afSHartmut Brandt b->asn_len--; 304f06ca4afSHartmut Brandt } 305f06ca4afSHartmut Brandt return (ASN_ERR_OK); 306f06ca4afSHartmut Brandt # undef OCTETS 307f06ca4afSHartmut Brandt } 308f06ca4afSHartmut Brandt 309f06ca4afSHartmut Brandt 310f06ca4afSHartmut Brandt /* 311f06ca4afSHartmut Brandt * The same for unsigned 64-bitters. Here we have the problem, that overflow 312f06ca4afSHartmut Brandt * can happen, because the value maybe 9 bytes long. In this case the 313f06ca4afSHartmut Brandt * first byte must be 0. 314f06ca4afSHartmut Brandt */ 315f06ca4afSHartmut Brandt static enum asn_err 316f06ca4afSHartmut Brandt asn_get_real_unsigned(struct asn_buf *b, asn_len_t len, u_int64_t *vp) 317f06ca4afSHartmut Brandt { 318f06ca4afSHartmut Brandt enum asn_err err; 319f06ca4afSHartmut Brandt 320f06ca4afSHartmut Brandt if (b->asn_len < len) { 321f06ca4afSHartmut Brandt asn_error(b, "truncated integer"); 322f06ca4afSHartmut Brandt return (ASN_ERR_EOBUF); 323f06ca4afSHartmut Brandt } 324f06ca4afSHartmut Brandt if (len == 0) { 325f06ca4afSHartmut Brandt asn_error(b, "zero-length integer"); 326f06ca4afSHartmut Brandt *vp = 0; 327f06ca4afSHartmut Brandt return (ASN_ERR_BADLEN); 328f06ca4afSHartmut Brandt } 329f06ca4afSHartmut Brandt err = ASN_ERR_OK; 330f06ca4afSHartmut Brandt *vp = 0; 331f06ca4afSHartmut Brandt if ((*b->asn_cptr & 0x80) || (len == 9 && *b->asn_cptr != 0)) { 332f06ca4afSHartmut Brandt /* negative integer or too larger */ 333f06ca4afSHartmut Brandt *vp = 0xffffffffffffffffULL; 334f06ca4afSHartmut Brandt err = ASN_ERR_RANGE; 335f06ca4afSHartmut Brandt } 336f06ca4afSHartmut Brandt 337f06ca4afSHartmut Brandt while (len--) { 338f06ca4afSHartmut Brandt *vp = (*vp << 8) | *b->asn_cptr++; 339f06ca4afSHartmut Brandt b->asn_len--; 340f06ca4afSHartmut Brandt } 341f06ca4afSHartmut Brandt return (err); 342f06ca4afSHartmut Brandt } 343f06ca4afSHartmut Brandt 344f06ca4afSHartmut Brandt 345f06ca4afSHartmut Brandt /* 346f06ca4afSHartmut Brandt * Values with the msb on need 9 octets. 347f06ca4afSHartmut Brandt */ 348f06ca4afSHartmut Brandt static int 349f06ca4afSHartmut Brandt asn_put_real_unsigned(struct asn_buf *b, u_char type, u_int64_t val) 350f06ca4afSHartmut Brandt { 351f06ca4afSHartmut Brandt int i; 352f06ca4afSHartmut Brandt # define OCTETS 9 353f06ca4afSHartmut Brandt u_char buf[OCTETS]; 354f06ca4afSHartmut Brandt enum asn_err ret; 355f06ca4afSHartmut Brandt 356f06ca4afSHartmut Brandt /* split the value into octets */ 357f06ca4afSHartmut Brandt for (i = OCTETS - 1; i >= 0; i--) { 358f06ca4afSHartmut Brandt buf[i] = val & 0xff; 359f06ca4afSHartmut Brandt val >>= 8; 360f06ca4afSHartmut Brandt } 361f06ca4afSHartmut Brandt /* no leading 9 zeroes */ 362f06ca4afSHartmut Brandt for (i = 0; i < OCTETS - 1; i++) 363f06ca4afSHartmut Brandt if (!(buf[i] == 0x00 && (buf[i + 1] & 0x80) == 0)) 364f06ca4afSHartmut Brandt break; 365f06ca4afSHartmut Brandt if ((ret = asn_put_header(b, type, OCTETS - i))) 366f06ca4afSHartmut Brandt return (ret); 367f06ca4afSHartmut Brandt if (OCTETS - (u_int)i > b->asn_len) 368f06ca4afSHartmut Brandt return (ASN_ERR_EOBUF); 369f06ca4afSHartmut Brandt 370f06ca4afSHartmut Brandt while (i < OCTETS) { 371f06ca4afSHartmut Brandt *b->asn_ptr++ = buf[i++]; 372f06ca4afSHartmut Brandt b->asn_len--; 373f06ca4afSHartmut Brandt } 374f06ca4afSHartmut Brandt #undef OCTETS 375f06ca4afSHartmut Brandt return (ASN_ERR_OK); 376f06ca4afSHartmut Brandt } 377f06ca4afSHartmut Brandt 378f06ca4afSHartmut Brandt /* 379f06ca4afSHartmut Brandt * The ASN.1 INTEGER type is restricted to 32-bit signed by the SMI. 380f06ca4afSHartmut Brandt */ 381f06ca4afSHartmut Brandt enum asn_err 382f06ca4afSHartmut Brandt asn_get_integer_raw(struct asn_buf *b, asn_len_t len, int32_t *vp) 383f06ca4afSHartmut Brandt { 384f06ca4afSHartmut Brandt int64_t val; 385f06ca4afSHartmut Brandt enum asn_err ret; 386f06ca4afSHartmut Brandt 387f06ca4afSHartmut Brandt if ((ret = asn_get_real_integer(b, len, &val)) == ASN_ERR_OK) { 388f06ca4afSHartmut Brandt if (len > 4) 389f06ca4afSHartmut Brandt ret = ASN_ERR_BADLEN; 390f06ca4afSHartmut Brandt else if (val > INT32_MAX || val < INT32_MIN) 391f06ca4afSHartmut Brandt /* may not happen */ 392f06ca4afSHartmut Brandt ret = ASN_ERR_RANGE; 393f06ca4afSHartmut Brandt *vp = (int32_t)val; 394f06ca4afSHartmut Brandt } 395f06ca4afSHartmut Brandt return (ret); 396f06ca4afSHartmut Brandt } 397f06ca4afSHartmut Brandt 398f06ca4afSHartmut Brandt enum asn_err 399f06ca4afSHartmut Brandt asn_get_integer(struct asn_buf *b, int32_t *vp) 400f06ca4afSHartmut Brandt { 401f06ca4afSHartmut Brandt asn_len_t len; 402f06ca4afSHartmut Brandt u_char type; 403f06ca4afSHartmut Brandt enum asn_err err; 404f06ca4afSHartmut Brandt 405f06ca4afSHartmut Brandt if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK) 406f06ca4afSHartmut Brandt return (err); 407f06ca4afSHartmut Brandt if (type != ASN_TYPE_INTEGER) { 408f06ca4afSHartmut Brandt asn_error(b, "bad type for integer (%u)", type); 409f06ca4afSHartmut Brandt return (ASN_ERR_TAG); 410f06ca4afSHartmut Brandt } 411f06ca4afSHartmut Brandt 412f06ca4afSHartmut Brandt return (asn_get_integer_raw(b, len, vp)); 413f06ca4afSHartmut Brandt } 414f06ca4afSHartmut Brandt 415f06ca4afSHartmut Brandt enum asn_err 416f06ca4afSHartmut Brandt asn_put_integer(struct asn_buf *b, int32_t val) 417f06ca4afSHartmut Brandt { 418f06ca4afSHartmut Brandt return (asn_put_real_integer(b, ASN_TYPE_INTEGER, val)); 419f06ca4afSHartmut Brandt } 420f06ca4afSHartmut Brandt 421f06ca4afSHartmut Brandt /* 422f06ca4afSHartmut Brandt * OCTETSTRING 423f06ca4afSHartmut Brandt * 424f06ca4afSHartmut Brandt * <0x04> <len> <data ...> 425f06ca4afSHartmut Brandt * 426f06ca4afSHartmut Brandt * Get an octetstring. noctets must point to the buffer size and on 427f06ca4afSHartmut Brandt * return will contain the size of the octetstring, regardless of the 428f06ca4afSHartmut Brandt * buffer size. 429f06ca4afSHartmut Brandt */ 430f06ca4afSHartmut Brandt enum asn_err 431f06ca4afSHartmut Brandt asn_get_octetstring_raw(struct asn_buf *b, asn_len_t len, u_char *octets, 432f06ca4afSHartmut Brandt u_int *noctets) 433f06ca4afSHartmut Brandt { 434f06ca4afSHartmut Brandt enum asn_err err = ASN_ERR_OK; 435f06ca4afSHartmut Brandt 436f06ca4afSHartmut Brandt if (*noctets < len) { 437f06ca4afSHartmut Brandt asn_error(b, "octetstring truncated"); 438f06ca4afSHartmut Brandt err = ASN_ERR_RANGE; 439f06ca4afSHartmut Brandt } 440f06ca4afSHartmut Brandt if (b->asn_len < len) { 441f06ca4afSHartmut Brandt asn_error(b, "truncatet octetstring"); 442f06ca4afSHartmut Brandt return (ASN_ERR_EOBUF); 443f06ca4afSHartmut Brandt } 444f06ca4afSHartmut Brandt if (*noctets < len) 445f06ca4afSHartmut Brandt memcpy(octets, b->asn_cptr, *noctets); 446f06ca4afSHartmut Brandt else 447f06ca4afSHartmut Brandt memcpy(octets, b->asn_cptr, len); 448f06ca4afSHartmut Brandt *noctets = len; 449f06ca4afSHartmut Brandt b->asn_cptr += len; 450f06ca4afSHartmut Brandt b->asn_len -= len; 451f06ca4afSHartmut Brandt return (err); 452f06ca4afSHartmut Brandt } 453f06ca4afSHartmut Brandt 454f06ca4afSHartmut Brandt enum asn_err 455f06ca4afSHartmut Brandt asn_get_octetstring(struct asn_buf *b, u_char *octets, u_int *noctets) 456f06ca4afSHartmut Brandt { 457f06ca4afSHartmut Brandt enum asn_err err; 458f06ca4afSHartmut Brandt u_char type; 459f06ca4afSHartmut Brandt asn_len_t len; 460f06ca4afSHartmut Brandt 461f06ca4afSHartmut Brandt if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK) 462f06ca4afSHartmut Brandt return (err); 463f06ca4afSHartmut Brandt if (type != ASN_TYPE_OCTETSTRING) { 464f06ca4afSHartmut Brandt asn_error(b, "bad type for octetstring (%u)", type); 465f06ca4afSHartmut Brandt return (ASN_ERR_TAG); 466f06ca4afSHartmut Brandt } 467f06ca4afSHartmut Brandt return (asn_get_octetstring_raw(b, len, octets, noctets)); 468f06ca4afSHartmut Brandt } 469f06ca4afSHartmut Brandt 470f06ca4afSHartmut Brandt enum asn_err 471f06ca4afSHartmut Brandt asn_put_octetstring(struct asn_buf *b, const u_char *octets, u_int noctets) 472f06ca4afSHartmut Brandt { 473f06ca4afSHartmut Brandt enum asn_err ret; 474f06ca4afSHartmut Brandt 475f06ca4afSHartmut Brandt if ((ret = asn_put_header(b, ASN_TYPE_OCTETSTRING, noctets)) != ASN_ERR_OK) 476f06ca4afSHartmut Brandt return (ret); 477f06ca4afSHartmut Brandt if (b->asn_len < noctets) 478f06ca4afSHartmut Brandt return (ASN_ERR_EOBUF); 479f06ca4afSHartmut Brandt 480f06ca4afSHartmut Brandt memcpy(b->asn_ptr, octets, noctets); 481f06ca4afSHartmut Brandt b->asn_ptr += noctets; 482f06ca4afSHartmut Brandt b->asn_len -= noctets; 483f06ca4afSHartmut Brandt return (ASN_ERR_OK); 484f06ca4afSHartmut Brandt } 485f06ca4afSHartmut Brandt 486f06ca4afSHartmut Brandt /* 487f06ca4afSHartmut Brandt * NULL 488f06ca4afSHartmut Brandt * 489f06ca4afSHartmut Brandt * <0x05> <0x00> 490f06ca4afSHartmut Brandt */ 491f06ca4afSHartmut Brandt enum asn_err 492f06ca4afSHartmut Brandt asn_get_null_raw(struct asn_buf *b, asn_len_t len) 493f06ca4afSHartmut Brandt { 494f06ca4afSHartmut Brandt if (len != 0) { 495f06ca4afSHartmut Brandt if (b->asn_len < len) { 496f06ca4afSHartmut Brandt asn_error(b, "truncated NULL"); 497f06ca4afSHartmut Brandt return (ASN_ERR_EOBUF); 498f06ca4afSHartmut Brandt } 499f06ca4afSHartmut Brandt asn_error(b, "bad length for NULL (%u)", len); 500f06ca4afSHartmut Brandt b->asn_len -= len; 501f06ca4afSHartmut Brandt b->asn_ptr += len; 502f06ca4afSHartmut Brandt return (ASN_ERR_BADLEN); 503f06ca4afSHartmut Brandt } 504f06ca4afSHartmut Brandt return (ASN_ERR_OK); 505f06ca4afSHartmut Brandt } 506f06ca4afSHartmut Brandt 507f06ca4afSHartmut Brandt enum asn_err 508f06ca4afSHartmut Brandt asn_get_null(struct asn_buf *b) 509f06ca4afSHartmut Brandt { 510f06ca4afSHartmut Brandt u_char type; 511f06ca4afSHartmut Brandt asn_len_t len; 512f06ca4afSHartmut Brandt enum asn_err err; 513f06ca4afSHartmut Brandt 514f06ca4afSHartmut Brandt if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK) 515f06ca4afSHartmut Brandt return (err); 516f06ca4afSHartmut Brandt if (type != ASN_TYPE_NULL) { 517f06ca4afSHartmut Brandt asn_error(b, "bad type for NULL (%u)", type); 518f06ca4afSHartmut Brandt return (ASN_ERR_TAG); 519f06ca4afSHartmut Brandt } 520f06ca4afSHartmut Brandt return (asn_get_null_raw(b, len)); 521f06ca4afSHartmut Brandt } 522f06ca4afSHartmut Brandt 523f06ca4afSHartmut Brandt enum asn_err 524f06ca4afSHartmut Brandt asn_put_null(struct asn_buf *b) 525f06ca4afSHartmut Brandt { 526f06ca4afSHartmut Brandt return (asn_put_header(b, ASN_TYPE_NULL, 0)); 527f06ca4afSHartmut Brandt } 528f06ca4afSHartmut Brandt 529f06ca4afSHartmut Brandt enum asn_err 530f06ca4afSHartmut Brandt asn_put_exception(struct asn_buf *b, u_int except) 531f06ca4afSHartmut Brandt { 532f06ca4afSHartmut Brandt return (asn_put_header(b, ASN_CLASS_CONTEXT | except, 0)); 533f06ca4afSHartmut Brandt } 534f06ca4afSHartmut Brandt 535f06ca4afSHartmut Brandt /* 536f06ca4afSHartmut Brandt * OBJID 537f06ca4afSHartmut Brandt * 538f06ca4afSHartmut Brandt * <0x06> <len> <subid...> 539f06ca4afSHartmut Brandt */ 540f06ca4afSHartmut Brandt enum asn_err 541f06ca4afSHartmut Brandt asn_get_objid_raw(struct asn_buf *b, asn_len_t len, struct asn_oid *oid) 542f06ca4afSHartmut Brandt { 543f06ca4afSHartmut Brandt asn_subid_t subid; 544f06ca4afSHartmut Brandt enum asn_err err; 545f06ca4afSHartmut Brandt 546f06ca4afSHartmut Brandt if (b->asn_len < len) { 547f06ca4afSHartmut Brandt asn_error(b, "truncated OBJID"); 548f06ca4afSHartmut Brandt return (ASN_ERR_EOBUF); 549f06ca4afSHartmut Brandt } 550f06ca4afSHartmut Brandt oid->len = 0; 551f06ca4afSHartmut Brandt if (len == 0) { 552f06ca4afSHartmut Brandt asn_error(b, "short OBJID"); 553f06ca4afSHartmut Brandt oid->subs[oid->len++] = 0; 554f06ca4afSHartmut Brandt oid->subs[oid->len++] = 0; 555f06ca4afSHartmut Brandt return (ASN_ERR_BADLEN); 556f06ca4afSHartmut Brandt } 557f06ca4afSHartmut Brandt err = ASN_ERR_OK; 558f06ca4afSHartmut Brandt while (len != 0) { 559f06ca4afSHartmut Brandt if (oid->len == ASN_MAXOIDLEN) { 560f06ca4afSHartmut Brandt asn_error(b, "OID too long (%u)", oid->len); 561f06ca4afSHartmut Brandt b->asn_cptr += len; 562f06ca4afSHartmut Brandt b->asn_len -= len; 563f06ca4afSHartmut Brandt return (ASN_ERR_BADLEN); 564f06ca4afSHartmut Brandt } 565f06ca4afSHartmut Brandt subid = 0; 566f06ca4afSHartmut Brandt do { 567f06ca4afSHartmut Brandt if (len == 0) { 568f06ca4afSHartmut Brandt asn_error(b, "unterminated subid"); 569f06ca4afSHartmut Brandt return (ASN_ERR_EOBUF); 570f06ca4afSHartmut Brandt } 571f06ca4afSHartmut Brandt if (subid > (ASN_MAXID >> 7)) { 572f06ca4afSHartmut Brandt asn_error(b, "OBID subid too larger"); 573f06ca4afSHartmut Brandt err = ASN_ERR_RANGE; 574f06ca4afSHartmut Brandt } 575f06ca4afSHartmut Brandt subid = (subid << 7) | (*b->asn_cptr & 0x7f); 576f06ca4afSHartmut Brandt len--; 577f06ca4afSHartmut Brandt b->asn_len--; 578f06ca4afSHartmut Brandt } while (*b->asn_cptr++ & 0x80); 579f06ca4afSHartmut Brandt if (oid->len == 0) { 580f06ca4afSHartmut Brandt if (subid < 80) { 581f06ca4afSHartmut Brandt oid->subs[oid->len++] = subid / 40; 582f06ca4afSHartmut Brandt oid->subs[oid->len++] = subid % 40; 583f06ca4afSHartmut Brandt } else { 584f06ca4afSHartmut Brandt oid->subs[oid->len++] = 2; 585f06ca4afSHartmut Brandt oid->subs[oid->len++] = subid - 80; 586f06ca4afSHartmut Brandt } 587f06ca4afSHartmut Brandt } else { 588f06ca4afSHartmut Brandt oid->subs[oid->len++] = subid; 589f06ca4afSHartmut Brandt } 590f06ca4afSHartmut Brandt } 591f06ca4afSHartmut Brandt return (err); 592f06ca4afSHartmut Brandt 593f06ca4afSHartmut Brandt } 594f06ca4afSHartmut Brandt 595f06ca4afSHartmut Brandt enum asn_err 596f06ca4afSHartmut Brandt asn_get_objid(struct asn_buf *b, struct asn_oid *oid) 597f06ca4afSHartmut Brandt { 598f06ca4afSHartmut Brandt u_char type; 599f06ca4afSHartmut Brandt asn_len_t len; 600f06ca4afSHartmut Brandt enum asn_err err; 601f06ca4afSHartmut Brandt 602f06ca4afSHartmut Brandt if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK) 603f06ca4afSHartmut Brandt return (err); 604f06ca4afSHartmut Brandt if (type != ASN_TYPE_OBJID) { 605f06ca4afSHartmut Brandt asn_error(b, "bad type for OBJID (%u)", type); 606f06ca4afSHartmut Brandt return (ASN_ERR_TAG); 607f06ca4afSHartmut Brandt } 608f06ca4afSHartmut Brandt return (asn_get_objid_raw(b, len, oid)); 609f06ca4afSHartmut Brandt } 610f06ca4afSHartmut Brandt 611f06ca4afSHartmut Brandt enum asn_err 612f06ca4afSHartmut Brandt asn_put_objid(struct asn_buf *b, const struct asn_oid *oid) 613f06ca4afSHartmut Brandt { 614f06ca4afSHartmut Brandt asn_subid_t first, sub; 615f06ca4afSHartmut Brandt enum asn_err err, err1; 616f06ca4afSHartmut Brandt u_int i, oidlen; 617f06ca4afSHartmut Brandt asn_len_t len; 618f06ca4afSHartmut Brandt 619f06ca4afSHartmut Brandt err = ASN_ERR_OK; 620f06ca4afSHartmut Brandt if (oid->len == 0) { 621f06ca4afSHartmut Brandt /* illegal */ 622f06ca4afSHartmut Brandt asn_error(NULL, "short oid"); 623f06ca4afSHartmut Brandt err = ASN_ERR_RANGE; 624f06ca4afSHartmut Brandt first = 0; 625f06ca4afSHartmut Brandt oidlen = 2; 626f06ca4afSHartmut Brandt } else if (oid->len == 1) { 627f06ca4afSHartmut Brandt /* illegal */ 628f06ca4afSHartmut Brandt asn_error(b, "short oid"); 629f06ca4afSHartmut Brandt if (oid->subs[0] > 2) 630f06ca4afSHartmut Brandt asn_error(NULL, "oid[0] too large (%u)", oid->subs[0]); 631f06ca4afSHartmut Brandt err = ASN_ERR_RANGE; 632f06ca4afSHartmut Brandt first = oid->subs[0] * 40; 633f06ca4afSHartmut Brandt oidlen = 2; 634f06ca4afSHartmut Brandt } else { 635f06ca4afSHartmut Brandt if (oid->len > ASN_MAXOIDLEN) { 636f06ca4afSHartmut Brandt asn_error(NULL, "oid too long %u", oid->len); 637f06ca4afSHartmut Brandt err = ASN_ERR_RANGE; 638f06ca4afSHartmut Brandt } 639f06ca4afSHartmut Brandt if (oid->subs[0] > 2 || 640f06ca4afSHartmut Brandt (oid->subs[0] < 2 && oid->subs[0] >= 40)) { 641f06ca4afSHartmut Brandt asn_error(NULL, "oid out of range (%u,%u)", 642f06ca4afSHartmut Brandt oid->subs[0], oid->subs[1]); 643f06ca4afSHartmut Brandt err = ASN_ERR_RANGE; 644f06ca4afSHartmut Brandt } 645f06ca4afSHartmut Brandt first = 40 * oid->subs[0] + oid->subs[1]; 646f06ca4afSHartmut Brandt oidlen = oid->len; 647f06ca4afSHartmut Brandt } 648f06ca4afSHartmut Brandt len = 0; 649f06ca4afSHartmut Brandt for (i = 1; i < oidlen; i++) { 650f06ca4afSHartmut Brandt sub = (i == 1) ? first : oid->subs[i]; 651f06ca4afSHartmut Brandt if (sub > ASN_MAXID) { 652f06ca4afSHartmut Brandt asn_error(NULL, "oid subid too large"); 653f06ca4afSHartmut Brandt err = ASN_ERR_RANGE; 654f06ca4afSHartmut Brandt } 655f06ca4afSHartmut Brandt len += (sub <= 0x7f) ? 1 656f06ca4afSHartmut Brandt : (sub <= 0x3fff) ? 2 657f06ca4afSHartmut Brandt : (sub <= 0x1fffff) ? 3 658f06ca4afSHartmut Brandt : (sub <= 0xfffffff) ? 4 659f06ca4afSHartmut Brandt : 5; 660f06ca4afSHartmut Brandt } 661f06ca4afSHartmut Brandt if ((err1 = asn_put_header(b, ASN_TYPE_OBJID, len)) != ASN_ERR_OK) 662f06ca4afSHartmut Brandt return (err1); 663f06ca4afSHartmut Brandt if (b->asn_len < len) 664f06ca4afSHartmut Brandt return (ASN_ERR_EOBUF); 665f06ca4afSHartmut Brandt 666f06ca4afSHartmut Brandt for (i = 1; i < oidlen; i++) { 667f06ca4afSHartmut Brandt sub = (i == 1) ? first : oid->subs[i]; 668f06ca4afSHartmut Brandt if (sub <= 0x7f) { 669f06ca4afSHartmut Brandt *b->asn_ptr++ = sub; 670f06ca4afSHartmut Brandt b->asn_len--; 671f06ca4afSHartmut Brandt } else if (sub <= 0x3fff) { 672f06ca4afSHartmut Brandt *b->asn_ptr++ = (sub >> 7) | 0x80; 673f06ca4afSHartmut Brandt *b->asn_ptr++ = sub & 0x7f; 674f06ca4afSHartmut Brandt b->asn_len -= 2; 675f06ca4afSHartmut Brandt } else if (sub <= 0x1fffff) { 676f06ca4afSHartmut Brandt *b->asn_ptr++ = (sub >> 14) | 0x80; 677f06ca4afSHartmut Brandt *b->asn_ptr++ = ((sub >> 7) & 0x7f) | 0x80; 678f06ca4afSHartmut Brandt *b->asn_ptr++ = sub & 0x7f; 679f06ca4afSHartmut Brandt b->asn_len -= 3; 680f06ca4afSHartmut Brandt } else if (sub <= 0xfffffff) { 681f06ca4afSHartmut Brandt *b->asn_ptr++ = (sub >> 21) | 0x80; 682f06ca4afSHartmut Brandt *b->asn_ptr++ = ((sub >> 14) & 0x7f) | 0x80; 683f06ca4afSHartmut Brandt *b->asn_ptr++ = ((sub >> 7) & 0x7f) | 0x80; 684f06ca4afSHartmut Brandt *b->asn_ptr++ = sub & 0x7f; 685f06ca4afSHartmut Brandt b->asn_len -= 4; 686f06ca4afSHartmut Brandt } else { 687f06ca4afSHartmut Brandt *b->asn_ptr++ = (sub >> 28) | 0x80; 688f06ca4afSHartmut Brandt *b->asn_ptr++ = ((sub >> 21) & 0x7f) | 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 -= 5; 693f06ca4afSHartmut Brandt } 694f06ca4afSHartmut Brandt } 695f06ca4afSHartmut Brandt return (err); 696f06ca4afSHartmut Brandt } 697f06ca4afSHartmut Brandt /* 698f06ca4afSHartmut Brandt * SEQUENCE header 699f06ca4afSHartmut Brandt * 700f06ca4afSHartmut Brandt * <0x10|0x20> <len> <data...> 701f06ca4afSHartmut Brandt */ 702f06ca4afSHartmut Brandt enum asn_err 703f06ca4afSHartmut Brandt asn_get_sequence(struct asn_buf *b, asn_len_t *len) 704f06ca4afSHartmut Brandt { 705f06ca4afSHartmut Brandt u_char type; 706f06ca4afSHartmut Brandt enum asn_err err; 707f06ca4afSHartmut Brandt 708f06ca4afSHartmut Brandt if ((err = asn_get_header(b, &type, len)) != ASN_ERR_OK) 709f06ca4afSHartmut Brandt return (err); 710f06ca4afSHartmut Brandt if (type != (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED)) { 711f06ca4afSHartmut Brandt asn_error(b, "bad sequence type %u", type); 712f06ca4afSHartmut Brandt return (ASN_ERR_TAG); 713f06ca4afSHartmut Brandt } 714f06ca4afSHartmut Brandt if (*len > b->asn_len) { 715f06ca4afSHartmut Brandt asn_error(b, "truncated sequence"); 716f06ca4afSHartmut Brandt return (ASN_ERR_EOBUF); 717f06ca4afSHartmut Brandt } 718f06ca4afSHartmut Brandt return (ASN_ERR_OK); 719f06ca4afSHartmut Brandt } 720f06ca4afSHartmut Brandt 721f06ca4afSHartmut Brandt 722f06ca4afSHartmut Brandt /* 723f06ca4afSHartmut Brandt * Application types 724f06ca4afSHartmut Brandt * 725f06ca4afSHartmut Brandt * 0x40 4 MSB 2MSB 2LSB LSB 726f06ca4afSHartmut Brandt */ 727f06ca4afSHartmut Brandt enum asn_err 728f06ca4afSHartmut Brandt asn_get_ipaddress_raw(struct asn_buf *b, asn_len_t len, u_char *addr) 729f06ca4afSHartmut Brandt { 730f06ca4afSHartmut Brandt u_int i; 731f06ca4afSHartmut Brandt 732f06ca4afSHartmut Brandt if (b->asn_len < len) { 733f06ca4afSHartmut Brandt asn_error(b, "truncated ip-address"); 734f06ca4afSHartmut Brandt return (ASN_ERR_EOBUF); 735f06ca4afSHartmut Brandt } 736f06ca4afSHartmut Brandt if (len < 4) { 737f06ca4afSHartmut Brandt asn_error(b, "short length for ip-Address %u", len); 738f06ca4afSHartmut Brandt for (i = 0; i < len; i++) 739f06ca4afSHartmut Brandt *addr++ = *b->asn_cptr++; 740f06ca4afSHartmut Brandt while (i++ < len) 741f06ca4afSHartmut Brandt *addr++ = 0; 742f06ca4afSHartmut Brandt b->asn_len -= len; 743f06ca4afSHartmut Brandt return (ASN_ERR_BADLEN); 744f06ca4afSHartmut Brandt } 745f06ca4afSHartmut Brandt for (i = 0; i < 4; i++) 746f06ca4afSHartmut Brandt *addr++ = *b->asn_cptr++; 747f06ca4afSHartmut Brandt b->asn_cptr += len - 4; 748f06ca4afSHartmut Brandt b->asn_len -= len; 749f06ca4afSHartmut Brandt return (ASN_ERR_OK); 750f06ca4afSHartmut Brandt } 751f06ca4afSHartmut Brandt 752f06ca4afSHartmut Brandt enum asn_err 753f06ca4afSHartmut Brandt asn_get_ipaddress(struct asn_buf *b, u_char *addr) 754f06ca4afSHartmut Brandt { 755f06ca4afSHartmut Brandt u_char type; 756f06ca4afSHartmut Brandt asn_len_t len; 757f06ca4afSHartmut Brandt enum asn_err err; 758f06ca4afSHartmut Brandt 759f06ca4afSHartmut Brandt if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK) 760f06ca4afSHartmut Brandt return (err); 761f06ca4afSHartmut Brandt if (type != (ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS)) { 762f06ca4afSHartmut Brandt asn_error(b, "bad type for ip-address %u", type); 763f06ca4afSHartmut Brandt return (ASN_ERR_TAG); 764f06ca4afSHartmut Brandt } 765f06ca4afSHartmut Brandt return (asn_get_ipaddress_raw(b, len, addr)); 766f06ca4afSHartmut Brandt } 767f06ca4afSHartmut Brandt 768f06ca4afSHartmut Brandt enum asn_err 769f06ca4afSHartmut Brandt asn_put_ipaddress(struct asn_buf *b, const u_char *addr) 770f06ca4afSHartmut Brandt { 771f06ca4afSHartmut Brandt enum asn_err err; 772f06ca4afSHartmut Brandt 773f06ca4afSHartmut Brandt if ((err = asn_put_header(b, ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS, 774f06ca4afSHartmut Brandt 4)) != ASN_ERR_OK) 775f06ca4afSHartmut Brandt return (err); 776f06ca4afSHartmut Brandt if (b->asn_len < 4) 777f06ca4afSHartmut Brandt return (ASN_ERR_EOBUF); 778f06ca4afSHartmut Brandt 779f06ca4afSHartmut Brandt memcpy(b->asn_ptr, addr, 4); 780f06ca4afSHartmut Brandt b->asn_ptr += 4; 781f06ca4afSHartmut Brandt b->asn_len -= 4; 782f06ca4afSHartmut Brandt return (ASN_ERR_OK); 783f06ca4afSHartmut Brandt } 784f06ca4afSHartmut Brandt 785f06ca4afSHartmut Brandt 786f06ca4afSHartmut Brandt /* 787f06ca4afSHartmut Brandt * UNSIGNED32 788f06ca4afSHartmut Brandt * 789f06ca4afSHartmut Brandt * 0x42|0x41 <len> ... 790f06ca4afSHartmut Brandt */ 791f06ca4afSHartmut Brandt enum asn_err 792f06ca4afSHartmut Brandt asn_get_uint32_raw(struct asn_buf *b, asn_len_t len, u_int32_t *vp) 793f06ca4afSHartmut Brandt { 794f06ca4afSHartmut Brandt u_int64_t v; 795f06ca4afSHartmut Brandt enum asn_err err; 796f06ca4afSHartmut Brandt 797f06ca4afSHartmut Brandt if ((err = asn_get_real_unsigned(b, len, &v)) == ASN_ERR_OK) { 798f06ca4afSHartmut Brandt if (len > 5) { 799f06ca4afSHartmut Brandt asn_error(b, "uint32 too long %u", len); 800f06ca4afSHartmut Brandt err = ASN_ERR_BADLEN; 801f06ca4afSHartmut Brandt } else if (v > UINT32_MAX) { 802f06ca4afSHartmut Brandt asn_error(b, "uint32 too large %llu", v); 803f06ca4afSHartmut Brandt err = ASN_ERR_RANGE; 804f06ca4afSHartmut Brandt } 805f06ca4afSHartmut Brandt *vp = (u_int32_t)v; 806f06ca4afSHartmut Brandt } 807f06ca4afSHartmut Brandt return (err); 808f06ca4afSHartmut Brandt } 809f06ca4afSHartmut Brandt 810f06ca4afSHartmut Brandt enum asn_err 811f06ca4afSHartmut Brandt asn_put_uint32(struct asn_buf *b, u_char type, u_int32_t val) 812f06ca4afSHartmut Brandt { 813f06ca4afSHartmut Brandt u_int64_t v = val; 814f06ca4afSHartmut Brandt 815f06ca4afSHartmut Brandt return (asn_put_real_unsigned(b, ASN_CLASS_APPLICATION|type, v)); 816f06ca4afSHartmut Brandt } 817f06ca4afSHartmut Brandt 818f06ca4afSHartmut Brandt /* 819f06ca4afSHartmut Brandt * COUNTER64 820f06ca4afSHartmut Brandt * 0x46 <len> ... 821f06ca4afSHartmut Brandt */ 822f06ca4afSHartmut Brandt enum asn_err 823f06ca4afSHartmut Brandt asn_get_counter64_raw(struct asn_buf *b, asn_len_t len, u_int64_t *vp) 824f06ca4afSHartmut Brandt { 825f06ca4afSHartmut Brandt return (asn_get_real_unsigned(b, len, vp)); 826f06ca4afSHartmut Brandt } 827f06ca4afSHartmut Brandt 828f06ca4afSHartmut Brandt enum asn_err 829f06ca4afSHartmut Brandt asn_put_counter64(struct asn_buf *b, u_int64_t val) 830f06ca4afSHartmut Brandt { 831f06ca4afSHartmut Brandt return (asn_put_real_unsigned(b, 832f06ca4afSHartmut Brandt ASN_CLASS_APPLICATION | ASN_APP_COUNTER64, val)); 833f06ca4afSHartmut Brandt } 834f06ca4afSHartmut Brandt 835f06ca4afSHartmut Brandt /* 836f06ca4afSHartmut Brandt * TimeTicks 837f06ca4afSHartmut Brandt * 0x43 <len> ... 838f06ca4afSHartmut Brandt */ 839f06ca4afSHartmut Brandt enum asn_err 840f06ca4afSHartmut Brandt asn_get_timeticks(struct asn_buf *b, u_int32_t *vp) 841f06ca4afSHartmut Brandt { 842f06ca4afSHartmut Brandt asn_len_t len; 843f06ca4afSHartmut Brandt u_char type; 844f06ca4afSHartmut Brandt enum asn_err err; 845f06ca4afSHartmut Brandt 846f06ca4afSHartmut Brandt if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK) 847f06ca4afSHartmut Brandt return (err); 848f06ca4afSHartmut Brandt if (type != (ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS)) { 849f06ca4afSHartmut Brandt asn_error(b, "bad type for timeticks %u", type); 850f06ca4afSHartmut Brandt return (ASN_ERR_TAG); 851f06ca4afSHartmut Brandt } 852f06ca4afSHartmut Brandt return (asn_get_uint32_raw(b, len, vp)); 853f06ca4afSHartmut Brandt } 854f06ca4afSHartmut Brandt 855f06ca4afSHartmut Brandt enum asn_err 856f06ca4afSHartmut Brandt asn_put_timeticks(struct asn_buf *b, u_int32_t val) 857f06ca4afSHartmut Brandt { 858f06ca4afSHartmut Brandt u_int64_t v = val; 859f06ca4afSHartmut Brandt 860f06ca4afSHartmut Brandt return (asn_put_real_unsigned(b, 861f06ca4afSHartmut Brandt ASN_CLASS_APPLICATION | ASN_APP_TIMETICKS, v)); 862f06ca4afSHartmut Brandt } 863f06ca4afSHartmut Brandt 864f06ca4afSHartmut Brandt /* 865f06ca4afSHartmut Brandt * Construct a new OID by taking a range of sub ids of the original oid. 866f06ca4afSHartmut Brandt */ 867f06ca4afSHartmut Brandt void 868f06ca4afSHartmut Brandt asn_slice_oid(struct asn_oid *dest, const struct asn_oid *src, 869f06ca4afSHartmut Brandt u_int from, u_int to) 870f06ca4afSHartmut Brandt { 871f06ca4afSHartmut Brandt if (from >= to) { 872f06ca4afSHartmut Brandt dest->len = 0; 873f06ca4afSHartmut Brandt return; 874f06ca4afSHartmut Brandt } 875f06ca4afSHartmut Brandt dest->len = to - from; 876f06ca4afSHartmut Brandt memcpy(dest->subs, &src->subs[from], dest->len * sizeof(dest->subs[0])); 877f06ca4afSHartmut Brandt } 878f06ca4afSHartmut Brandt 879f06ca4afSHartmut Brandt /* 880f06ca4afSHartmut Brandt * Append from to to 881f06ca4afSHartmut Brandt */ 882f06ca4afSHartmut Brandt void 883f06ca4afSHartmut Brandt asn_append_oid(struct asn_oid *to, const struct asn_oid *from) 884f06ca4afSHartmut Brandt { 885f06ca4afSHartmut Brandt memcpy(&to->subs[to->len], &from->subs[0], 886f06ca4afSHartmut Brandt from->len * sizeof(from->subs[0])); 887f06ca4afSHartmut Brandt to->len += from->len; 888f06ca4afSHartmut Brandt } 889f06ca4afSHartmut Brandt 890f06ca4afSHartmut Brandt /* 891f06ca4afSHartmut Brandt * Skip a value 892f06ca4afSHartmut Brandt */ 893f06ca4afSHartmut Brandt enum asn_err 894f06ca4afSHartmut Brandt asn_skip(struct asn_buf *b, asn_len_t len) 895f06ca4afSHartmut Brandt { 896f06ca4afSHartmut Brandt if (b->asn_len < len) 897f06ca4afSHartmut Brandt return (ASN_ERR_EOBUF); 898f06ca4afSHartmut Brandt b->asn_cptr += len; 899f06ca4afSHartmut Brandt b->asn_len -= len; 900f06ca4afSHartmut Brandt return (ASN_ERR_OK); 901f06ca4afSHartmut Brandt } 902f06ca4afSHartmut Brandt 903f06ca4afSHartmut Brandt /* 904f06ca4afSHartmut Brandt * Compare two OIDs. 905f06ca4afSHartmut Brandt * 906f06ca4afSHartmut Brandt * o1 < o2 : -1 907f06ca4afSHartmut Brandt * o1 > o2 : +1 908f06ca4afSHartmut Brandt * o1 = o2 : 0 909f06ca4afSHartmut Brandt */ 910f06ca4afSHartmut Brandt int 911f06ca4afSHartmut Brandt asn_compare_oid(const struct asn_oid *o1, const struct asn_oid *o2) 912f06ca4afSHartmut Brandt { 913f06ca4afSHartmut Brandt u_long i; 914f06ca4afSHartmut Brandt 915f06ca4afSHartmut Brandt for (i = 0; i < o1->len && i < o2->len; i++) { 916f06ca4afSHartmut Brandt if (o1->subs[i] < o2->subs[i]) 917f06ca4afSHartmut Brandt return (-1); 918f06ca4afSHartmut Brandt if (o1->subs[i] > o2->subs[i]) 919f06ca4afSHartmut Brandt return (+1); 920f06ca4afSHartmut Brandt } 921f06ca4afSHartmut Brandt if (o1->len < o2->len) 922f06ca4afSHartmut Brandt return (-1); 923f06ca4afSHartmut Brandt if (o1->len > o2->len) 924f06ca4afSHartmut Brandt return (+1); 925f06ca4afSHartmut Brandt return (0); 926f06ca4afSHartmut Brandt } 927f06ca4afSHartmut Brandt 928f06ca4afSHartmut Brandt /* 929f06ca4afSHartmut Brandt * Check whether an OID is a sub-string of another OID. 930f06ca4afSHartmut Brandt */ 931f06ca4afSHartmut Brandt int 932f06ca4afSHartmut Brandt asn_is_suboid(const struct asn_oid *o1, const struct asn_oid *o2) 933f06ca4afSHartmut Brandt { 934f06ca4afSHartmut Brandt u_long i; 935f06ca4afSHartmut Brandt 936f06ca4afSHartmut Brandt for (i = 0; i < o1->len; i++) 937f06ca4afSHartmut Brandt if (i >= o2->len || o1->subs[i] != o2->subs[i]) 938f06ca4afSHartmut Brandt return (0); 939f06ca4afSHartmut Brandt return (1); 940f06ca4afSHartmut Brandt } 941f06ca4afSHartmut Brandt 942f06ca4afSHartmut Brandt /* 943f06ca4afSHartmut Brandt * Put a string representation of an oid into a user buffer. This buffer 944f06ca4afSHartmut Brandt * is assumed to be at least ASN_OIDSTRLEN characters long. 945f06ca4afSHartmut Brandt * 946f06ca4afSHartmut Brandt * sprintf is assumed not to fail here. 947f06ca4afSHartmut Brandt */ 948f06ca4afSHartmut Brandt char * 949f06ca4afSHartmut Brandt asn_oid2str_r(const struct asn_oid *oid, char *buf) 950f06ca4afSHartmut Brandt { 951f06ca4afSHartmut Brandt u_int len, i; 952f06ca4afSHartmut Brandt char *ptr; 953f06ca4afSHartmut Brandt 954f06ca4afSHartmut Brandt if ((len = oid->len) > ASN_MAXOIDLEN) 955f06ca4afSHartmut Brandt len = ASN_MAXOIDLEN; 956f06ca4afSHartmut Brandt buf[0] = '\0'; 957f06ca4afSHartmut Brandt for (i = 0, ptr = buf; i < len; i++) { 958f06ca4afSHartmut Brandt if (i > 0) 959f06ca4afSHartmut Brandt *ptr++ = '.'; 960f06ca4afSHartmut Brandt ptr += sprintf(ptr, "%u", oid->subs[i]); 961f06ca4afSHartmut Brandt } 962f06ca4afSHartmut Brandt return (buf); 963f06ca4afSHartmut Brandt } 964f06ca4afSHartmut Brandt 965f06ca4afSHartmut Brandt /* 966f06ca4afSHartmut Brandt * Make a string from an OID in a private buffer. 967f06ca4afSHartmut Brandt */ 968f06ca4afSHartmut Brandt char * 969f06ca4afSHartmut Brandt asn_oid2str(const struct asn_oid *oid) 970f06ca4afSHartmut Brandt { 971f06ca4afSHartmut Brandt static char str[ASN_OIDSTRLEN]; 972f06ca4afSHartmut Brandt 973f06ca4afSHartmut Brandt return (asn_oid2str_r(oid, str)); 974f06ca4afSHartmut Brandt } 975f06ca4afSHartmut Brandt 976f06ca4afSHartmut Brandt 977f06ca4afSHartmut Brandt static void 978f06ca4afSHartmut Brandt asn_error_func(const struct asn_buf *b, const char *err, ...) 979f06ca4afSHartmut Brandt { 980f06ca4afSHartmut Brandt va_list ap; 981f06ca4afSHartmut Brandt u_long i; 982f06ca4afSHartmut Brandt 983f06ca4afSHartmut Brandt fprintf(stderr, "ASN.1: "); 984f06ca4afSHartmut Brandt va_start(ap, err); 985f06ca4afSHartmut Brandt vfprintf(stderr, err, ap); 986f06ca4afSHartmut Brandt va_end(ap); 987f06ca4afSHartmut Brandt 988f06ca4afSHartmut Brandt if (b != NULL) { 989f06ca4afSHartmut Brandt fprintf(stderr, " at"); 990f06ca4afSHartmut Brandt for (i = 0; b->asn_len > i; i++) 991f06ca4afSHartmut Brandt fprintf(stderr, " %02x", b->asn_cptr[i]); 992f06ca4afSHartmut Brandt } 993f06ca4afSHartmut Brandt fprintf(stderr, "\n"); 994f06ca4afSHartmut Brandt } 995