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