19e7c127fSCraig Rodrigues /* $OpenBSD: ber.c,v 1.9 2015/02/12 00:30:38 pelikan Exp $ */
29e7c127fSCraig Rodrigues
39e7c127fSCraig Rodrigues /*
49e7c127fSCraig Rodrigues * Copyright (c) 2007 Reyk Floeter <reyk@vantronix.net>
59e7c127fSCraig Rodrigues * Copyright (c) 2006, 2007 Claudio Jeker <claudio@openbsd.org>
69e7c127fSCraig Rodrigues * Copyright (c) 2006, 2007 Marc Balmer <mbalmer@openbsd.org>
79e7c127fSCraig Rodrigues *
89e7c127fSCraig Rodrigues * Permission to use, copy, modify, and distribute this software for any
99e7c127fSCraig Rodrigues * purpose with or without fee is hereby granted, provided that the above
109e7c127fSCraig Rodrigues * copyright notice and this permission notice appear in all copies.
119e7c127fSCraig Rodrigues *
129e7c127fSCraig Rodrigues * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
139e7c127fSCraig Rodrigues * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
149e7c127fSCraig Rodrigues * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
159e7c127fSCraig Rodrigues * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
169e7c127fSCraig Rodrigues * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
179e7c127fSCraig Rodrigues * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
189e7c127fSCraig Rodrigues * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
199e7c127fSCraig Rodrigues */
209e7c127fSCraig Rodrigues
219e7c127fSCraig Rodrigues #include <sys/types.h>
229e7c127fSCraig Rodrigues
239e7c127fSCraig Rodrigues #include <errno.h>
249e7c127fSCraig Rodrigues #include <limits.h>
259e7c127fSCraig Rodrigues #include <stdlib.h>
269e7c127fSCraig Rodrigues #include <err.h> /* XXX for debug output */
279e7c127fSCraig Rodrigues #include <stdio.h> /* XXX for debug output */
2828b524fbSCraig Rodrigues #include <string.h>
299e7c127fSCraig Rodrigues #include <unistd.h>
309e7c127fSCraig Rodrigues #include <stdarg.h>
319e7c127fSCraig Rodrigues
329e7c127fSCraig Rodrigues #include "ber.h"
339e7c127fSCraig Rodrigues
349e7c127fSCraig Rodrigues #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
359e7c127fSCraig Rodrigues
369e7c127fSCraig Rodrigues #define BER_TYPE_CONSTRUCTED 0x20 /* otherwise primitive */
379e7c127fSCraig Rodrigues #define BER_TYPE_SINGLE_MAX 30
389e7c127fSCraig Rodrigues #define BER_TAG_MASK 0x1f
399e7c127fSCraig Rodrigues #define BER_TAG_MORE 0x80 /* more subsequent octets */
409e7c127fSCraig Rodrigues #define BER_TAG_TYPE_MASK 0x7f
419e7c127fSCraig Rodrigues #define BER_CLASS_SHIFT 6
429e7c127fSCraig Rodrigues
439e7c127fSCraig Rodrigues static int ber_dump_element(struct ber *ber, struct ber_element *root);
449e7c127fSCraig Rodrigues static void ber_dump_header(struct ber *ber, struct ber_element *root);
459e7c127fSCraig Rodrigues static void ber_putc(struct ber *ber, u_char c);
469e7c127fSCraig Rodrigues static void ber_write(struct ber *ber, void *buf, size_t len);
479e7c127fSCraig Rodrigues static ssize_t get_id(struct ber *b, unsigned long *tag, int *class,
489e7c127fSCraig Rodrigues int *cstruct);
499e7c127fSCraig Rodrigues static ssize_t get_len(struct ber *b, ssize_t *len);
509e7c127fSCraig Rodrigues static ssize_t ber_read_element(struct ber *ber, struct ber_element *elm);
519e7c127fSCraig Rodrigues static ssize_t ber_readbuf(struct ber *b, void *buf, size_t nbytes);
529e7c127fSCraig Rodrigues static ssize_t ber_getc(struct ber *b, u_char *c);
539e7c127fSCraig Rodrigues static ssize_t ber_read(struct ber *ber, void *buf, size_t len);
549e7c127fSCraig Rodrigues
559e7c127fSCraig Rodrigues #ifdef DEBUG
569e7c127fSCraig Rodrigues #define DPRINTF(...) printf(__VA_ARGS__)
579e7c127fSCraig Rodrigues #else
589e7c127fSCraig Rodrigues #define DPRINTF(...) do { } while (0)
599e7c127fSCraig Rodrigues #endif
609e7c127fSCraig Rodrigues
619e7c127fSCraig Rodrigues struct ber_element *
ber_get_element(unsigned long encoding)629e7c127fSCraig Rodrigues ber_get_element(unsigned long encoding)
639e7c127fSCraig Rodrigues {
649e7c127fSCraig Rodrigues struct ber_element *elm;
659e7c127fSCraig Rodrigues
669e7c127fSCraig Rodrigues if ((elm = calloc(1, sizeof(*elm))) == NULL)
679e7c127fSCraig Rodrigues return NULL;
689e7c127fSCraig Rodrigues
699e7c127fSCraig Rodrigues elm->be_encoding = encoding;
709e7c127fSCraig Rodrigues ber_set_header(elm, BER_CLASS_UNIVERSAL, BER_TYPE_DEFAULT);
719e7c127fSCraig Rodrigues
729e7c127fSCraig Rodrigues return elm;
739e7c127fSCraig Rodrigues }
749e7c127fSCraig Rodrigues
759e7c127fSCraig Rodrigues void
ber_set_header(struct ber_element * elm,int class,unsigned long type)769e7c127fSCraig Rodrigues ber_set_header(struct ber_element *elm, int class, unsigned long type)
779e7c127fSCraig Rodrigues {
789e7c127fSCraig Rodrigues elm->be_class = class & BER_CLASS_MASK;
799e7c127fSCraig Rodrigues if (type == BER_TYPE_DEFAULT)
809e7c127fSCraig Rodrigues type = elm->be_encoding;
819e7c127fSCraig Rodrigues elm->be_type = type;
829e7c127fSCraig Rodrigues }
839e7c127fSCraig Rodrigues
849e7c127fSCraig Rodrigues void
ber_link_elements(struct ber_element * prev,struct ber_element * elm)859e7c127fSCraig Rodrigues ber_link_elements(struct ber_element *prev, struct ber_element *elm)
869e7c127fSCraig Rodrigues {
879e7c127fSCraig Rodrigues if (prev != NULL) {
889e7c127fSCraig Rodrigues if ((prev->be_encoding == BER_TYPE_SEQUENCE ||
899e7c127fSCraig Rodrigues prev->be_encoding == BER_TYPE_SET) &&
909e7c127fSCraig Rodrigues prev->be_sub == NULL)
919e7c127fSCraig Rodrigues prev->be_sub = elm;
929e7c127fSCraig Rodrigues else
939e7c127fSCraig Rodrigues prev->be_next = elm;
949e7c127fSCraig Rodrigues }
959e7c127fSCraig Rodrigues }
969e7c127fSCraig Rodrigues
979e7c127fSCraig Rodrigues struct ber_element *
ber_unlink_elements(struct ber_element * prev)989e7c127fSCraig Rodrigues ber_unlink_elements(struct ber_element *prev)
999e7c127fSCraig Rodrigues {
1009e7c127fSCraig Rodrigues struct ber_element *elm;
1019e7c127fSCraig Rodrigues
1029e7c127fSCraig Rodrigues if ((prev->be_encoding == BER_TYPE_SEQUENCE ||
1039e7c127fSCraig Rodrigues prev->be_encoding == BER_TYPE_SET) &&
1049e7c127fSCraig Rodrigues prev->be_sub != NULL) {
1059e7c127fSCraig Rodrigues elm = prev->be_sub;
1069e7c127fSCraig Rodrigues prev->be_sub = NULL;
1079e7c127fSCraig Rodrigues } else {
1089e7c127fSCraig Rodrigues elm = prev->be_next;
1099e7c127fSCraig Rodrigues prev->be_next = NULL;
1109e7c127fSCraig Rodrigues }
1119e7c127fSCraig Rodrigues
1129e7c127fSCraig Rodrigues return (elm);
1139e7c127fSCraig Rodrigues }
1149e7c127fSCraig Rodrigues
1159e7c127fSCraig Rodrigues void
ber_replace_elements(struct ber_element * prev,struct ber_element * new)1169e7c127fSCraig Rodrigues ber_replace_elements(struct ber_element *prev, struct ber_element *new)
1179e7c127fSCraig Rodrigues {
1189e7c127fSCraig Rodrigues struct ber_element *ber, *next;
1199e7c127fSCraig Rodrigues
1209e7c127fSCraig Rodrigues ber = ber_unlink_elements(prev);
1219e7c127fSCraig Rodrigues next = ber_unlink_elements(ber);
1229e7c127fSCraig Rodrigues ber_link_elements(new, next);
1239e7c127fSCraig Rodrigues ber_link_elements(prev, new);
1249e7c127fSCraig Rodrigues
1259e7c127fSCraig Rodrigues /* cleanup old element */
1269e7c127fSCraig Rodrigues ber_free_elements(ber);
1279e7c127fSCraig Rodrigues }
1289e7c127fSCraig Rodrigues
1299e7c127fSCraig Rodrigues struct ber_element *
ber_add_sequence(struct ber_element * prev)1309e7c127fSCraig Rodrigues ber_add_sequence(struct ber_element *prev)
1319e7c127fSCraig Rodrigues {
1329e7c127fSCraig Rodrigues struct ber_element *elm;
1339e7c127fSCraig Rodrigues
1349e7c127fSCraig Rodrigues if ((elm = ber_get_element(BER_TYPE_SEQUENCE)) == NULL)
1359e7c127fSCraig Rodrigues return NULL;
1369e7c127fSCraig Rodrigues
1379e7c127fSCraig Rodrigues ber_link_elements(prev, elm);
1389e7c127fSCraig Rodrigues
1399e7c127fSCraig Rodrigues return elm;
1409e7c127fSCraig Rodrigues }
1419e7c127fSCraig Rodrigues
1429e7c127fSCraig Rodrigues struct ber_element *
ber_add_set(struct ber_element * prev)1439e7c127fSCraig Rodrigues ber_add_set(struct ber_element *prev)
1449e7c127fSCraig Rodrigues {
1459e7c127fSCraig Rodrigues struct ber_element *elm;
1469e7c127fSCraig Rodrigues
1479e7c127fSCraig Rodrigues if ((elm = ber_get_element(BER_TYPE_SET)) == NULL)
1489e7c127fSCraig Rodrigues return NULL;
1499e7c127fSCraig Rodrigues
1509e7c127fSCraig Rodrigues ber_link_elements(prev, elm);
1519e7c127fSCraig Rodrigues
1529e7c127fSCraig Rodrigues return elm;
1539e7c127fSCraig Rodrigues }
1549e7c127fSCraig Rodrigues
1559e7c127fSCraig Rodrigues struct ber_element *
ber_add_enumerated(struct ber_element * prev,long long val)1569e7c127fSCraig Rodrigues ber_add_enumerated(struct ber_element *prev, long long val)
1579e7c127fSCraig Rodrigues {
1589e7c127fSCraig Rodrigues struct ber_element *elm;
1599e7c127fSCraig Rodrigues u_int i, len = 0;
1609e7c127fSCraig Rodrigues u_char cur, last = 0;
1619e7c127fSCraig Rodrigues
1629e7c127fSCraig Rodrigues if ((elm = ber_get_element(BER_TYPE_ENUMERATED)) == NULL)
1639e7c127fSCraig Rodrigues return NULL;
1649e7c127fSCraig Rodrigues
1659e7c127fSCraig Rodrigues elm->be_numeric = val;
1669e7c127fSCraig Rodrigues
1679e7c127fSCraig Rodrigues for (i = 0; i < sizeof(long long); i++) {
1689e7c127fSCraig Rodrigues cur = val & 0xff;
1699e7c127fSCraig Rodrigues if (cur != 0 && cur != 0xff)
1709e7c127fSCraig Rodrigues len = i;
1719e7c127fSCraig Rodrigues if ((cur == 0 && last & 0x80) ||
1729e7c127fSCraig Rodrigues (cur == 0xff && (last & 0x80) == 0))
1739e7c127fSCraig Rodrigues len = i;
1749e7c127fSCraig Rodrigues val >>= 8;
1759e7c127fSCraig Rodrigues last = cur;
1769e7c127fSCraig Rodrigues }
1779e7c127fSCraig Rodrigues elm->be_len = len + 1;
1789e7c127fSCraig Rodrigues
1799e7c127fSCraig Rodrigues ber_link_elements(prev, elm);
1809e7c127fSCraig Rodrigues
1819e7c127fSCraig Rodrigues return elm;
1829e7c127fSCraig Rodrigues }
1839e7c127fSCraig Rodrigues
1849e7c127fSCraig Rodrigues struct ber_element *
ber_add_integer(struct ber_element * prev,long long val)1859e7c127fSCraig Rodrigues ber_add_integer(struct ber_element *prev, long long val)
1869e7c127fSCraig Rodrigues {
1879e7c127fSCraig Rodrigues struct ber_element *elm;
1889e7c127fSCraig Rodrigues u_int i, len = 0;
1899e7c127fSCraig Rodrigues u_char cur, last = 0;
1909e7c127fSCraig Rodrigues
1919e7c127fSCraig Rodrigues if ((elm = ber_get_element(BER_TYPE_INTEGER)) == NULL)
1929e7c127fSCraig Rodrigues return NULL;
1939e7c127fSCraig Rodrigues
1949e7c127fSCraig Rodrigues elm->be_numeric = val;
1959e7c127fSCraig Rodrigues
1969e7c127fSCraig Rodrigues for (i = 0; i < sizeof(long long); i++) {
1979e7c127fSCraig Rodrigues cur = val & 0xff;
1989e7c127fSCraig Rodrigues if (cur != 0 && cur != 0xff)
1999e7c127fSCraig Rodrigues len = i;
2009e7c127fSCraig Rodrigues if ((cur == 0 && last & 0x80) ||
2019e7c127fSCraig Rodrigues (cur == 0xff && (last & 0x80) == 0))
2029e7c127fSCraig Rodrigues len = i;
2039e7c127fSCraig Rodrigues val >>= 8;
2049e7c127fSCraig Rodrigues last = cur;
2059e7c127fSCraig Rodrigues }
2069e7c127fSCraig Rodrigues elm->be_len = len + 1;
2079e7c127fSCraig Rodrigues
2089e7c127fSCraig Rodrigues ber_link_elements(prev, elm);
2099e7c127fSCraig Rodrigues
2109e7c127fSCraig Rodrigues return elm;
2119e7c127fSCraig Rodrigues }
2129e7c127fSCraig Rodrigues
2139e7c127fSCraig Rodrigues int
ber_get_integer(struct ber_element * elm,long long * n)2149e7c127fSCraig Rodrigues ber_get_integer(struct ber_element *elm, long long *n)
2159e7c127fSCraig Rodrigues {
2169e7c127fSCraig Rodrigues if (elm->be_encoding != BER_TYPE_INTEGER)
2179e7c127fSCraig Rodrigues return -1;
2189e7c127fSCraig Rodrigues
2199e7c127fSCraig Rodrigues *n = elm->be_numeric;
2209e7c127fSCraig Rodrigues return 0;
2219e7c127fSCraig Rodrigues }
2229e7c127fSCraig Rodrigues
2239e7c127fSCraig Rodrigues int
ber_get_enumerated(struct ber_element * elm,long long * n)2249e7c127fSCraig Rodrigues ber_get_enumerated(struct ber_element *elm, long long *n)
2259e7c127fSCraig Rodrigues {
2269e7c127fSCraig Rodrigues if (elm->be_encoding != BER_TYPE_ENUMERATED)
2279e7c127fSCraig Rodrigues return -1;
2289e7c127fSCraig Rodrigues
2299e7c127fSCraig Rodrigues *n = elm->be_numeric;
2309e7c127fSCraig Rodrigues return 0;
2319e7c127fSCraig Rodrigues }
2329e7c127fSCraig Rodrigues
2339e7c127fSCraig Rodrigues
2349e7c127fSCraig Rodrigues struct ber_element *
ber_add_boolean(struct ber_element * prev,int bool)2359e7c127fSCraig Rodrigues ber_add_boolean(struct ber_element *prev, int bool)
2369e7c127fSCraig Rodrigues {
2379e7c127fSCraig Rodrigues struct ber_element *elm;
2389e7c127fSCraig Rodrigues
2399e7c127fSCraig Rodrigues if ((elm = ber_get_element(BER_TYPE_BOOLEAN)) == NULL)
2409e7c127fSCraig Rodrigues return NULL;
2419e7c127fSCraig Rodrigues
2429e7c127fSCraig Rodrigues elm->be_numeric = bool ? 0xff : 0;
2439e7c127fSCraig Rodrigues elm->be_len = 1;
2449e7c127fSCraig Rodrigues
2459e7c127fSCraig Rodrigues ber_link_elements(prev, elm);
2469e7c127fSCraig Rodrigues
2479e7c127fSCraig Rodrigues return elm;
2489e7c127fSCraig Rodrigues }
2499e7c127fSCraig Rodrigues
2509e7c127fSCraig Rodrigues int
ber_get_boolean(struct ber_element * elm,int * b)2519e7c127fSCraig Rodrigues ber_get_boolean(struct ber_element *elm, int *b)
2529e7c127fSCraig Rodrigues {
2539e7c127fSCraig Rodrigues if (elm->be_encoding != BER_TYPE_BOOLEAN)
2549e7c127fSCraig Rodrigues return -1;
2559e7c127fSCraig Rodrigues
2569e7c127fSCraig Rodrigues *b = !(elm->be_numeric == 0);
2579e7c127fSCraig Rodrigues return 0;
2589e7c127fSCraig Rodrigues }
2599e7c127fSCraig Rodrigues
2609e7c127fSCraig Rodrigues struct ber_element *
ber_add_string(struct ber_element * prev,const char * string)2619e7c127fSCraig Rodrigues ber_add_string(struct ber_element *prev, const char *string)
2629e7c127fSCraig Rodrigues {
2639e7c127fSCraig Rodrigues return ber_add_nstring(prev, string, strlen(string));
2649e7c127fSCraig Rodrigues }
2659e7c127fSCraig Rodrigues
2669e7c127fSCraig Rodrigues struct ber_element *
ber_add_nstring(struct ber_element * prev,const char * string0,size_t len)2679e7c127fSCraig Rodrigues ber_add_nstring(struct ber_element *prev, const char *string0, size_t len)
2689e7c127fSCraig Rodrigues {
2699e7c127fSCraig Rodrigues struct ber_element *elm;
2709e7c127fSCraig Rodrigues char *string;
2719e7c127fSCraig Rodrigues
2729e7c127fSCraig Rodrigues if ((string = calloc(1, len)) == NULL)
2739e7c127fSCraig Rodrigues return NULL;
2749e7c127fSCraig Rodrigues if ((elm = ber_get_element(BER_TYPE_OCTETSTRING)) == NULL) {
2759e7c127fSCraig Rodrigues free(string);
2769e7c127fSCraig Rodrigues return NULL;
2779e7c127fSCraig Rodrigues }
2789e7c127fSCraig Rodrigues
2799e7c127fSCraig Rodrigues bcopy(string0, string, len);
2809e7c127fSCraig Rodrigues elm->be_val = string;
2819e7c127fSCraig Rodrigues elm->be_len = len;
2829e7c127fSCraig Rodrigues elm->be_free = 1; /* free string on cleanup */
2839e7c127fSCraig Rodrigues
2849e7c127fSCraig Rodrigues ber_link_elements(prev, elm);
2859e7c127fSCraig Rodrigues
2869e7c127fSCraig Rodrigues return elm;
2879e7c127fSCraig Rodrigues }
2889e7c127fSCraig Rodrigues
2899e7c127fSCraig Rodrigues int
ber_get_string(struct ber_element * elm,char ** s)2909e7c127fSCraig Rodrigues ber_get_string(struct ber_element *elm, char **s)
2919e7c127fSCraig Rodrigues {
2929e7c127fSCraig Rodrigues if (elm->be_encoding != BER_TYPE_OCTETSTRING)
2939e7c127fSCraig Rodrigues return -1;
2949e7c127fSCraig Rodrigues
2959e7c127fSCraig Rodrigues *s = elm->be_val;
2969e7c127fSCraig Rodrigues return 0;
2979e7c127fSCraig Rodrigues }
2989e7c127fSCraig Rodrigues
2999e7c127fSCraig Rodrigues int
ber_get_nstring(struct ber_element * elm,void ** p,size_t * len)3009e7c127fSCraig Rodrigues ber_get_nstring(struct ber_element *elm, void **p, size_t *len)
3019e7c127fSCraig Rodrigues {
3029e7c127fSCraig Rodrigues if (elm->be_encoding != BER_TYPE_OCTETSTRING)
3039e7c127fSCraig Rodrigues return -1;
3049e7c127fSCraig Rodrigues
3059e7c127fSCraig Rodrigues *p = elm->be_val;
3069e7c127fSCraig Rodrigues *len = elm->be_len;
3079e7c127fSCraig Rodrigues return 0;
3089e7c127fSCraig Rodrigues }
3099e7c127fSCraig Rodrigues
3109e7c127fSCraig Rodrigues struct ber_element *
ber_add_bitstring(struct ber_element * prev,const void * v0,size_t len)3119e7c127fSCraig Rodrigues ber_add_bitstring(struct ber_element *prev, const void *v0, size_t len)
3129e7c127fSCraig Rodrigues {
3139e7c127fSCraig Rodrigues struct ber_element *elm;
3149e7c127fSCraig Rodrigues void *v;
3159e7c127fSCraig Rodrigues
3169e7c127fSCraig Rodrigues if ((v = calloc(1, len)) == NULL)
3179e7c127fSCraig Rodrigues return NULL;
3189e7c127fSCraig Rodrigues if ((elm = ber_get_element(BER_TYPE_BITSTRING)) == NULL) {
3199e7c127fSCraig Rodrigues free(v);
3209e7c127fSCraig Rodrigues return NULL;
3219e7c127fSCraig Rodrigues }
3229e7c127fSCraig Rodrigues
3239e7c127fSCraig Rodrigues bcopy(v0, v, len);
3249e7c127fSCraig Rodrigues elm->be_val = v;
3259e7c127fSCraig Rodrigues elm->be_len = len;
3269e7c127fSCraig Rodrigues elm->be_free = 1; /* free string on cleanup */
3279e7c127fSCraig Rodrigues
3289e7c127fSCraig Rodrigues ber_link_elements(prev, elm);
3299e7c127fSCraig Rodrigues
3309e7c127fSCraig Rodrigues return elm;
3319e7c127fSCraig Rodrigues }
3329e7c127fSCraig Rodrigues
3339e7c127fSCraig Rodrigues int
ber_get_bitstring(struct ber_element * elm,void ** v,size_t * len)3349e7c127fSCraig Rodrigues ber_get_bitstring(struct ber_element *elm, void **v, size_t *len)
3359e7c127fSCraig Rodrigues {
3369e7c127fSCraig Rodrigues if (elm->be_encoding != BER_TYPE_BITSTRING)
3379e7c127fSCraig Rodrigues return -1;
3389e7c127fSCraig Rodrigues
3399e7c127fSCraig Rodrigues *v = elm->be_val;
3409e7c127fSCraig Rodrigues *len = elm->be_len;
3419e7c127fSCraig Rodrigues return 0;
3429e7c127fSCraig Rodrigues }
3439e7c127fSCraig Rodrigues
3449e7c127fSCraig Rodrigues struct ber_element *
ber_add_null(struct ber_element * prev)3459e7c127fSCraig Rodrigues ber_add_null(struct ber_element *prev)
3469e7c127fSCraig Rodrigues {
3479e7c127fSCraig Rodrigues struct ber_element *elm;
3489e7c127fSCraig Rodrigues
3499e7c127fSCraig Rodrigues if ((elm = ber_get_element(BER_TYPE_NULL)) == NULL)
3509e7c127fSCraig Rodrigues return NULL;
3519e7c127fSCraig Rodrigues
3529e7c127fSCraig Rodrigues ber_link_elements(prev, elm);
3539e7c127fSCraig Rodrigues
3549e7c127fSCraig Rodrigues return elm;
3559e7c127fSCraig Rodrigues }
3569e7c127fSCraig Rodrigues
3579e7c127fSCraig Rodrigues int
ber_get_null(struct ber_element * elm)3589e7c127fSCraig Rodrigues ber_get_null(struct ber_element *elm)
3599e7c127fSCraig Rodrigues {
3609e7c127fSCraig Rodrigues if (elm->be_encoding != BER_TYPE_NULL)
3619e7c127fSCraig Rodrigues return -1;
3629e7c127fSCraig Rodrigues
3639e7c127fSCraig Rodrigues return 0;
3649e7c127fSCraig Rodrigues }
3659e7c127fSCraig Rodrigues
3669e7c127fSCraig Rodrigues struct ber_element *
ber_add_eoc(struct ber_element * prev)3679e7c127fSCraig Rodrigues ber_add_eoc(struct ber_element *prev)
3689e7c127fSCraig Rodrigues {
3699e7c127fSCraig Rodrigues struct ber_element *elm;
3709e7c127fSCraig Rodrigues
3719e7c127fSCraig Rodrigues if ((elm = ber_get_element(BER_TYPE_EOC)) == NULL)
3729e7c127fSCraig Rodrigues return NULL;
3739e7c127fSCraig Rodrigues
3749e7c127fSCraig Rodrigues ber_link_elements(prev, elm);
3759e7c127fSCraig Rodrigues
3769e7c127fSCraig Rodrigues return elm;
3779e7c127fSCraig Rodrigues }
3789e7c127fSCraig Rodrigues
3799e7c127fSCraig Rodrigues int
ber_get_eoc(struct ber_element * elm)3809e7c127fSCraig Rodrigues ber_get_eoc(struct ber_element *elm)
3819e7c127fSCraig Rodrigues {
3829e7c127fSCraig Rodrigues if (elm->be_encoding != BER_TYPE_EOC)
3839e7c127fSCraig Rodrigues return -1;
3849e7c127fSCraig Rodrigues
3859e7c127fSCraig Rodrigues return 0;
3869e7c127fSCraig Rodrigues }
3879e7c127fSCraig Rodrigues
3889e7c127fSCraig Rodrigues size_t
ber_oid2ber(struct ber_oid * o,u_int8_t * buf,size_t len)3899e7c127fSCraig Rodrigues ber_oid2ber(struct ber_oid *o, u_int8_t *buf, size_t len)
3909e7c127fSCraig Rodrigues {
3919e7c127fSCraig Rodrigues u_int32_t v;
3929e7c127fSCraig Rodrigues u_int i, j = 0, k;
3939e7c127fSCraig Rodrigues
3949e7c127fSCraig Rodrigues if (o->bo_n < BER_MIN_OID_LEN || o->bo_n > BER_MAX_OID_LEN ||
3959e7c127fSCraig Rodrigues o->bo_id[0] > 2 || o->bo_id[1] > 40)
3969e7c127fSCraig Rodrigues return (0);
3979e7c127fSCraig Rodrigues
3989e7c127fSCraig Rodrigues v = (o->bo_id[0] * 40) + o->bo_id[1];
3999e7c127fSCraig Rodrigues for (i = 2, j = 0; i <= o->bo_n; v = o->bo_id[i], i++) {
4009e7c127fSCraig Rodrigues for (k = 28; k >= 7; k -= 7) {
4019e7c127fSCraig Rodrigues if (v >= (u_int)(1 << k)) {
4029e7c127fSCraig Rodrigues if (len)
4039e7c127fSCraig Rodrigues buf[j] = v >> k | BER_TAG_MORE;
4049e7c127fSCraig Rodrigues j++;
4059e7c127fSCraig Rodrigues }
4069e7c127fSCraig Rodrigues }
4079e7c127fSCraig Rodrigues if (len)
4089e7c127fSCraig Rodrigues buf[j] = v & BER_TAG_TYPE_MASK;
4099e7c127fSCraig Rodrigues j++;
4109e7c127fSCraig Rodrigues }
4119e7c127fSCraig Rodrigues
4129e7c127fSCraig Rodrigues return (j);
4139e7c127fSCraig Rodrigues }
4149e7c127fSCraig Rodrigues
4159e7c127fSCraig Rodrigues int
ber_string2oid(const char * oidstr,struct ber_oid * o)4169e7c127fSCraig Rodrigues ber_string2oid(const char *oidstr, struct ber_oid *o)
4179e7c127fSCraig Rodrigues {
4189e7c127fSCraig Rodrigues char *sp, *p, str[BUFSIZ];
4199e7c127fSCraig Rodrigues const char *errstr;
4209e7c127fSCraig Rodrigues
4219e7c127fSCraig Rodrigues if (strlcpy(str, oidstr, sizeof(str)) >= sizeof(str))
4229e7c127fSCraig Rodrigues return (-1);
4239e7c127fSCraig Rodrigues bzero(o, sizeof(*o));
4249e7c127fSCraig Rodrigues
4259e7c127fSCraig Rodrigues /* Parse OID strings in the common forms n.n.n, n_n_n_n, or n-n-n */
4269e7c127fSCraig Rodrigues for (p = sp = str; p != NULL; sp = p) {
4279e7c127fSCraig Rodrigues if ((p = strpbrk(p, "._-")) != NULL)
4289e7c127fSCraig Rodrigues *p++ = '\0';
4299e7c127fSCraig Rodrigues o->bo_id[o->bo_n++] = strtonum(sp, 0, UINT_MAX, &errstr);
4309e7c127fSCraig Rodrigues if (errstr || o->bo_n > BER_MAX_OID_LEN)
4319e7c127fSCraig Rodrigues return (-1);
4329e7c127fSCraig Rodrigues }
4339e7c127fSCraig Rodrigues
4349e7c127fSCraig Rodrigues return (0);
4359e7c127fSCraig Rodrigues }
4369e7c127fSCraig Rodrigues
4379e7c127fSCraig Rodrigues struct ber_element *
ber_add_oid(struct ber_element * prev,struct ber_oid * o)4389e7c127fSCraig Rodrigues ber_add_oid(struct ber_element *prev, struct ber_oid *o)
4399e7c127fSCraig Rodrigues {
4409e7c127fSCraig Rodrigues struct ber_element *elm;
4419e7c127fSCraig Rodrigues u_int8_t *buf;
4429e7c127fSCraig Rodrigues size_t len;
4439e7c127fSCraig Rodrigues
4449e7c127fSCraig Rodrigues if ((elm = ber_get_element(BER_TYPE_OBJECT)) == NULL)
4459e7c127fSCraig Rodrigues return (NULL);
4469e7c127fSCraig Rodrigues
4479e7c127fSCraig Rodrigues if ((len = ber_oid2ber(o, NULL, 0)) == 0)
4489e7c127fSCraig Rodrigues goto fail;
4499e7c127fSCraig Rodrigues
4509e7c127fSCraig Rodrigues if ((buf = calloc(1, len)) == NULL)
4519e7c127fSCraig Rodrigues goto fail;
4529e7c127fSCraig Rodrigues
4539e7c127fSCraig Rodrigues elm->be_val = buf;
4549e7c127fSCraig Rodrigues elm->be_len = len;
4559e7c127fSCraig Rodrigues elm->be_free = 1;
4569e7c127fSCraig Rodrigues
4579e7c127fSCraig Rodrigues if (ber_oid2ber(o, buf, len) != len)
4589e7c127fSCraig Rodrigues goto fail;
4599e7c127fSCraig Rodrigues
4609e7c127fSCraig Rodrigues ber_link_elements(prev, elm);
4619e7c127fSCraig Rodrigues
4629e7c127fSCraig Rodrigues return (elm);
4639e7c127fSCraig Rodrigues
4649e7c127fSCraig Rodrigues fail:
4659e7c127fSCraig Rodrigues ber_free_elements(elm);
4669e7c127fSCraig Rodrigues return (NULL);
4679e7c127fSCraig Rodrigues }
4689e7c127fSCraig Rodrigues
4699e7c127fSCraig Rodrigues struct ber_element *
ber_add_noid(struct ber_element * prev,struct ber_oid * o,int n)4709e7c127fSCraig Rodrigues ber_add_noid(struct ber_element *prev, struct ber_oid *o, int n)
4719e7c127fSCraig Rodrigues {
4729e7c127fSCraig Rodrigues struct ber_oid no;
4739e7c127fSCraig Rodrigues
4749e7c127fSCraig Rodrigues if (n > BER_MAX_OID_LEN)
4759e7c127fSCraig Rodrigues return (NULL);
4769e7c127fSCraig Rodrigues no.bo_n = n;
4779e7c127fSCraig Rodrigues bcopy(&o->bo_id, &no.bo_id, sizeof(no.bo_id));
4789e7c127fSCraig Rodrigues
4799e7c127fSCraig Rodrigues return (ber_add_oid(prev, &no));
4809e7c127fSCraig Rodrigues }
4819e7c127fSCraig Rodrigues
4829e7c127fSCraig Rodrigues struct ber_element *
ber_add_oidstring(struct ber_element * prev,const char * oidstr)4839e7c127fSCraig Rodrigues ber_add_oidstring(struct ber_element *prev, const char *oidstr)
4849e7c127fSCraig Rodrigues {
4859e7c127fSCraig Rodrigues struct ber_oid o;
4869e7c127fSCraig Rodrigues
4879e7c127fSCraig Rodrigues if (ber_string2oid(oidstr, &o) == -1)
4889e7c127fSCraig Rodrigues return (NULL);
4899e7c127fSCraig Rodrigues
4909e7c127fSCraig Rodrigues return (ber_add_oid(prev, &o));
4919e7c127fSCraig Rodrigues }
4929e7c127fSCraig Rodrigues
4939e7c127fSCraig Rodrigues int
ber_get_oid(struct ber_element * elm,struct ber_oid * o)4949e7c127fSCraig Rodrigues ber_get_oid(struct ber_element *elm, struct ber_oid *o)
4959e7c127fSCraig Rodrigues {
4969e7c127fSCraig Rodrigues u_int8_t *buf;
4979e7c127fSCraig Rodrigues size_t len, i = 0, j = 0;
4989e7c127fSCraig Rodrigues
4999e7c127fSCraig Rodrigues if (elm->be_encoding != BER_TYPE_OBJECT)
5009e7c127fSCraig Rodrigues return (-1);
5019e7c127fSCraig Rodrigues
5029e7c127fSCraig Rodrigues buf = elm->be_val;
5039e7c127fSCraig Rodrigues len = elm->be_len;
5049e7c127fSCraig Rodrigues
5059e7c127fSCraig Rodrigues if (!buf[i])
5069e7c127fSCraig Rodrigues return (-1);
5079e7c127fSCraig Rodrigues
5089e7c127fSCraig Rodrigues bzero(o, sizeof(*o));
5099e7c127fSCraig Rodrigues o->bo_id[j++] = buf[i] / 40;
5109e7c127fSCraig Rodrigues o->bo_id[j++] = buf[i++] % 40;
5119e7c127fSCraig Rodrigues for (; i < len && j < BER_MAX_OID_LEN; i++) {
5129e7c127fSCraig Rodrigues o->bo_id[j] = (o->bo_id[j] << 7) + (buf[i] & ~0x80);
5139e7c127fSCraig Rodrigues if (buf[i] & 0x80)
5149e7c127fSCraig Rodrigues continue;
5159e7c127fSCraig Rodrigues j++;
5169e7c127fSCraig Rodrigues }
5179e7c127fSCraig Rodrigues o->bo_n = j;
5189e7c127fSCraig Rodrigues
5199e7c127fSCraig Rodrigues return (0);
5209e7c127fSCraig Rodrigues }
5219e7c127fSCraig Rodrigues
5229e7c127fSCraig Rodrigues struct ber_element *
ber_printf_elements(struct ber_element * ber,char * fmt,...)5239e7c127fSCraig Rodrigues ber_printf_elements(struct ber_element *ber, char *fmt, ...)
5249e7c127fSCraig Rodrigues {
5259e7c127fSCraig Rodrigues va_list ap;
5269e7c127fSCraig Rodrigues int d, class;
5279e7c127fSCraig Rodrigues size_t len;
5289e7c127fSCraig Rodrigues unsigned long type;
5299e7c127fSCraig Rodrigues long long i;
5309e7c127fSCraig Rodrigues char *s;
5319e7c127fSCraig Rodrigues void *p;
5329e7c127fSCraig Rodrigues struct ber_oid *o;
5339e7c127fSCraig Rodrigues struct ber_element *sub = ber, *e;
5349e7c127fSCraig Rodrigues
5359e7c127fSCraig Rodrigues va_start(ap, fmt);
5369e7c127fSCraig Rodrigues while (*fmt) {
5379e7c127fSCraig Rodrigues switch (*fmt++) {
5389e7c127fSCraig Rodrigues case 'B':
5399e7c127fSCraig Rodrigues p = va_arg(ap, void *);
5409e7c127fSCraig Rodrigues len = va_arg(ap, size_t);
5419e7c127fSCraig Rodrigues if ((ber = ber_add_bitstring(ber, p, len)) == NULL)
5429e7c127fSCraig Rodrigues goto fail;
5439e7c127fSCraig Rodrigues break;
5449e7c127fSCraig Rodrigues case 'b':
5459e7c127fSCraig Rodrigues d = va_arg(ap, int);
5469e7c127fSCraig Rodrigues if ((ber = ber_add_boolean(ber, d)) == NULL)
5479e7c127fSCraig Rodrigues goto fail;
5489e7c127fSCraig Rodrigues break;
5499e7c127fSCraig Rodrigues case 'd':
5509e7c127fSCraig Rodrigues d = va_arg(ap, int);
5519e7c127fSCraig Rodrigues if ((ber = ber_add_integer(ber, d)) == NULL)
5529e7c127fSCraig Rodrigues goto fail;
5539e7c127fSCraig Rodrigues break;
5549e7c127fSCraig Rodrigues case 'e':
5559e7c127fSCraig Rodrigues e = va_arg(ap, struct ber_element *);
5569e7c127fSCraig Rodrigues ber_link_elements(ber, e);
5579e7c127fSCraig Rodrigues break;
5589e7c127fSCraig Rodrigues case 'E':
5599e7c127fSCraig Rodrigues i = va_arg(ap, long long);
5609e7c127fSCraig Rodrigues if ((ber = ber_add_enumerated(ber, i)) == NULL)
5619e7c127fSCraig Rodrigues goto fail;
5629e7c127fSCraig Rodrigues break;
5639e7c127fSCraig Rodrigues case 'i':
5649e7c127fSCraig Rodrigues i = va_arg(ap, long long);
5659e7c127fSCraig Rodrigues if ((ber = ber_add_integer(ber, i)) == NULL)
5669e7c127fSCraig Rodrigues goto fail;
5679e7c127fSCraig Rodrigues break;
5689e7c127fSCraig Rodrigues case 'O':
5699e7c127fSCraig Rodrigues o = va_arg(ap, struct ber_oid *);
5709e7c127fSCraig Rodrigues if ((ber = ber_add_oid(ber, o)) == NULL)
5719e7c127fSCraig Rodrigues goto fail;
5729e7c127fSCraig Rodrigues break;
5739e7c127fSCraig Rodrigues case 'o':
5749e7c127fSCraig Rodrigues s = va_arg(ap, char *);
5759e7c127fSCraig Rodrigues if ((ber = ber_add_oidstring(ber, s)) == NULL)
5769e7c127fSCraig Rodrigues goto fail;
5779e7c127fSCraig Rodrigues break;
5789e7c127fSCraig Rodrigues case 's':
5799e7c127fSCraig Rodrigues s = va_arg(ap, char *);
5809e7c127fSCraig Rodrigues if ((ber = ber_add_string(ber, s)) == NULL)
5819e7c127fSCraig Rodrigues goto fail;
5829e7c127fSCraig Rodrigues break;
5839e7c127fSCraig Rodrigues case 't':
5849e7c127fSCraig Rodrigues class = va_arg(ap, int);
5859e7c127fSCraig Rodrigues type = va_arg(ap, unsigned long);
5869e7c127fSCraig Rodrigues ber_set_header(ber, class, type);
5879e7c127fSCraig Rodrigues break;
5889e7c127fSCraig Rodrigues case 'x':
5899e7c127fSCraig Rodrigues s = va_arg(ap, char *);
5909e7c127fSCraig Rodrigues len = va_arg(ap, size_t);
5919e7c127fSCraig Rodrigues if ((ber = ber_add_nstring(ber, s, len)) == NULL)
5929e7c127fSCraig Rodrigues goto fail;
5939e7c127fSCraig Rodrigues break;
5949e7c127fSCraig Rodrigues case '0':
5959e7c127fSCraig Rodrigues if ((ber = ber_add_null(ber)) == NULL)
5969e7c127fSCraig Rodrigues goto fail;
5979e7c127fSCraig Rodrigues break;
5989e7c127fSCraig Rodrigues case '{':
5999e7c127fSCraig Rodrigues if ((ber = sub = ber_add_sequence(ber)) == NULL)
6009e7c127fSCraig Rodrigues goto fail;
6019e7c127fSCraig Rodrigues break;
6029e7c127fSCraig Rodrigues case '(':
6039e7c127fSCraig Rodrigues if ((ber = sub = ber_add_set(ber)) == NULL)
6049e7c127fSCraig Rodrigues goto fail;
6059e7c127fSCraig Rodrigues break;
6069e7c127fSCraig Rodrigues case '}':
6079e7c127fSCraig Rodrigues case ')':
6089e7c127fSCraig Rodrigues ber = sub;
6099e7c127fSCraig Rodrigues break;
6109e7c127fSCraig Rodrigues case '.':
6119e7c127fSCraig Rodrigues if ((e = ber_add_eoc(ber)) == NULL)
6129e7c127fSCraig Rodrigues goto fail;
6139e7c127fSCraig Rodrigues ber = e;
6149e7c127fSCraig Rodrigues break;
6159e7c127fSCraig Rodrigues default:
6169e7c127fSCraig Rodrigues break;
6179e7c127fSCraig Rodrigues }
6189e7c127fSCraig Rodrigues }
6199e7c127fSCraig Rodrigues va_end(ap);
6209e7c127fSCraig Rodrigues
6219e7c127fSCraig Rodrigues return (ber);
6229e7c127fSCraig Rodrigues fail:
623*446bb222SConrad Meyer va_end(ap);
6249e7c127fSCraig Rodrigues return (NULL);
6259e7c127fSCraig Rodrigues }
6269e7c127fSCraig Rodrigues
6279e7c127fSCraig Rodrigues int
ber_scanf_elements(struct ber_element * ber,char * fmt,...)6289e7c127fSCraig Rodrigues ber_scanf_elements(struct ber_element *ber, char *fmt, ...)
6299e7c127fSCraig Rodrigues {
6309e7c127fSCraig Rodrigues #define _MAX_SEQ 128
6319e7c127fSCraig Rodrigues va_list ap;
6329e7c127fSCraig Rodrigues int *d, level = -1;
6339e7c127fSCraig Rodrigues unsigned long *t;
6349e7c127fSCraig Rodrigues long long *i;
6359e7c127fSCraig Rodrigues void **ptr;
6369e7c127fSCraig Rodrigues size_t *len, ret = 0, n = strlen(fmt);
6379e7c127fSCraig Rodrigues char **s;
6389e7c127fSCraig Rodrigues struct ber_oid *o;
6399e7c127fSCraig Rodrigues struct ber_element *parent[_MAX_SEQ], **e;
6409e7c127fSCraig Rodrigues
6419e7c127fSCraig Rodrigues bzero(parent, sizeof(struct ber_element *) * _MAX_SEQ);
6429e7c127fSCraig Rodrigues
6439e7c127fSCraig Rodrigues va_start(ap, fmt);
6449e7c127fSCraig Rodrigues while (*fmt) {
6459e7c127fSCraig Rodrigues switch (*fmt++) {
6469e7c127fSCraig Rodrigues case 'B':
6479e7c127fSCraig Rodrigues ptr = va_arg(ap, void **);
6489e7c127fSCraig Rodrigues len = va_arg(ap, size_t *);
6499e7c127fSCraig Rodrigues if (ber_get_bitstring(ber, ptr, len) == -1)
6509e7c127fSCraig Rodrigues goto fail;
6519e7c127fSCraig Rodrigues ret++;
6529e7c127fSCraig Rodrigues break;
6539e7c127fSCraig Rodrigues case 'b':
6549e7c127fSCraig Rodrigues d = va_arg(ap, int *);
6559e7c127fSCraig Rodrigues if (ber_get_boolean(ber, d) == -1)
6569e7c127fSCraig Rodrigues goto fail;
6579e7c127fSCraig Rodrigues ret++;
6589e7c127fSCraig Rodrigues break;
6599e7c127fSCraig Rodrigues case 'e':
6609e7c127fSCraig Rodrigues e = va_arg(ap, struct ber_element **);
6619e7c127fSCraig Rodrigues *e = ber;
6629e7c127fSCraig Rodrigues ret++;
6639e7c127fSCraig Rodrigues continue;
6649e7c127fSCraig Rodrigues case 'E':
6659e7c127fSCraig Rodrigues i = va_arg(ap, long long *);
6669e7c127fSCraig Rodrigues if (ber_get_enumerated(ber, i) == -1)
6679e7c127fSCraig Rodrigues goto fail;
6689e7c127fSCraig Rodrigues ret++;
6699e7c127fSCraig Rodrigues break;
6709e7c127fSCraig Rodrigues case 'i':
6719e7c127fSCraig Rodrigues i = va_arg(ap, long long *);
6729e7c127fSCraig Rodrigues if (ber_get_integer(ber, i) == -1)
6739e7c127fSCraig Rodrigues goto fail;
6749e7c127fSCraig Rodrigues ret++;
6759e7c127fSCraig Rodrigues break;
6769e7c127fSCraig Rodrigues case 'o':
6779e7c127fSCraig Rodrigues o = va_arg(ap, struct ber_oid *);
6789e7c127fSCraig Rodrigues if (ber_get_oid(ber, o) == -1)
6799e7c127fSCraig Rodrigues goto fail;
6809e7c127fSCraig Rodrigues ret++;
6819e7c127fSCraig Rodrigues break;
6829e7c127fSCraig Rodrigues case 'S':
6839e7c127fSCraig Rodrigues ret++;
6849e7c127fSCraig Rodrigues break;
6859e7c127fSCraig Rodrigues case 's':
6869e7c127fSCraig Rodrigues s = va_arg(ap, char **);
6879e7c127fSCraig Rodrigues if (ber_get_string(ber, s) == -1)
6889e7c127fSCraig Rodrigues goto fail;
6899e7c127fSCraig Rodrigues ret++;
6909e7c127fSCraig Rodrigues break;
6919e7c127fSCraig Rodrigues case 't':
6929e7c127fSCraig Rodrigues d = va_arg(ap, int *);
6939e7c127fSCraig Rodrigues t = va_arg(ap, unsigned long *);
6949e7c127fSCraig Rodrigues *d = ber->be_class;
6959e7c127fSCraig Rodrigues *t = ber->be_type;
6969e7c127fSCraig Rodrigues ret++;
6979e7c127fSCraig Rodrigues continue;
6989e7c127fSCraig Rodrigues case 'x':
6999e7c127fSCraig Rodrigues ptr = va_arg(ap, void **);
7009e7c127fSCraig Rodrigues len = va_arg(ap, size_t *);
7019e7c127fSCraig Rodrigues if (ber_get_nstring(ber, ptr, len) == -1)
7029e7c127fSCraig Rodrigues goto fail;
7039e7c127fSCraig Rodrigues ret++;
7049e7c127fSCraig Rodrigues break;
7059e7c127fSCraig Rodrigues case '0':
7069e7c127fSCraig Rodrigues if (ber->be_encoding != BER_TYPE_NULL)
7079e7c127fSCraig Rodrigues goto fail;
7089e7c127fSCraig Rodrigues ret++;
7099e7c127fSCraig Rodrigues break;
7109e7c127fSCraig Rodrigues case '.':
7119e7c127fSCraig Rodrigues if (ber->be_encoding != BER_TYPE_EOC)
7129e7c127fSCraig Rodrigues goto fail;
7139e7c127fSCraig Rodrigues ret++;
7149e7c127fSCraig Rodrigues break;
7159e7c127fSCraig Rodrigues case '{':
7169e7c127fSCraig Rodrigues case '(':
7179e7c127fSCraig Rodrigues if (ber->be_encoding != BER_TYPE_SEQUENCE &&
7189e7c127fSCraig Rodrigues ber->be_encoding != BER_TYPE_SET)
7199e7c127fSCraig Rodrigues goto fail;
7209e7c127fSCraig Rodrigues if (ber->be_sub == NULL || level >= _MAX_SEQ-1)
7219e7c127fSCraig Rodrigues goto fail;
7229e7c127fSCraig Rodrigues parent[++level] = ber;
7239e7c127fSCraig Rodrigues ber = ber->be_sub;
7249e7c127fSCraig Rodrigues ret++;
7259e7c127fSCraig Rodrigues continue;
7269e7c127fSCraig Rodrigues case '}':
7279e7c127fSCraig Rodrigues case ')':
728a5f63746SDon Lewis if (level < 0 || parent[level] == NULL)
7299e7c127fSCraig Rodrigues goto fail;
7309e7c127fSCraig Rodrigues ber = parent[level--];
7319e7c127fSCraig Rodrigues ret++;
7329e7c127fSCraig Rodrigues continue;
7339e7c127fSCraig Rodrigues default:
7349e7c127fSCraig Rodrigues goto fail;
7359e7c127fSCraig Rodrigues }
7369e7c127fSCraig Rodrigues
7379e7c127fSCraig Rodrigues if (ber->be_next == NULL)
7389e7c127fSCraig Rodrigues continue;
7399e7c127fSCraig Rodrigues ber = ber->be_next;
7409e7c127fSCraig Rodrigues }
7419e7c127fSCraig Rodrigues va_end(ap);
7429e7c127fSCraig Rodrigues return (ret == n ? 0 : -1);
7439e7c127fSCraig Rodrigues
7449e7c127fSCraig Rodrigues fail:
7459e7c127fSCraig Rodrigues va_end(ap);
7469e7c127fSCraig Rodrigues return (-1);
7479e7c127fSCraig Rodrigues
7489e7c127fSCraig Rodrigues }
7499e7c127fSCraig Rodrigues
7509e7c127fSCraig Rodrigues /*
7519e7c127fSCraig Rodrigues * write ber elements to the socket
7529e7c127fSCraig Rodrigues *
7539e7c127fSCraig Rodrigues * params:
7549e7c127fSCraig Rodrigues * ber holds the socket
7559e7c127fSCraig Rodrigues * root fully populated element tree
7569e7c127fSCraig Rodrigues *
7579e7c127fSCraig Rodrigues * returns:
7589e7c127fSCraig Rodrigues * >=0 number of bytes written
7599e7c127fSCraig Rodrigues * -1 on failure and sets errno
7609e7c127fSCraig Rodrigues */
7619e7c127fSCraig Rodrigues int
ber_write_elements(struct ber * ber,struct ber_element * root)7629e7c127fSCraig Rodrigues ber_write_elements(struct ber *ber, struct ber_element *root)
7639e7c127fSCraig Rodrigues {
7649e7c127fSCraig Rodrigues size_t len;
7659e7c127fSCraig Rodrigues
7669e7c127fSCraig Rodrigues /* calculate length because only the definite form is required */
7679e7c127fSCraig Rodrigues len = ber_calc_len(root);
7689e7c127fSCraig Rodrigues DPRINTF("write ber element of %zd bytes length\n", len);
7699e7c127fSCraig Rodrigues
7709e7c127fSCraig Rodrigues if (ber->br_wbuf != NULL && ber->br_wbuf + len > ber->br_wend) {
7719e7c127fSCraig Rodrigues free(ber->br_wbuf);
7729e7c127fSCraig Rodrigues ber->br_wbuf = NULL;
7739e7c127fSCraig Rodrigues }
7749e7c127fSCraig Rodrigues if (ber->br_wbuf == NULL) {
7759e7c127fSCraig Rodrigues if ((ber->br_wbuf = malloc(len)) == NULL)
7769e7c127fSCraig Rodrigues return -1;
7779e7c127fSCraig Rodrigues ber->br_wend = ber->br_wbuf + len;
7789e7c127fSCraig Rodrigues }
7799e7c127fSCraig Rodrigues
7809e7c127fSCraig Rodrigues /* reset write pointer */
7819e7c127fSCraig Rodrigues ber->br_wptr = ber->br_wbuf;
7829e7c127fSCraig Rodrigues
7839e7c127fSCraig Rodrigues if (ber_dump_element(ber, root) == -1)
7849e7c127fSCraig Rodrigues return -1;
7859e7c127fSCraig Rodrigues
7869e7c127fSCraig Rodrigues /* XXX this should be moved to a different function */
7879e7c127fSCraig Rodrigues if (ber->fd != -1)
7889e7c127fSCraig Rodrigues return write(ber->fd, ber->br_wbuf, len);
7899e7c127fSCraig Rodrigues
7909e7c127fSCraig Rodrigues return (len);
7919e7c127fSCraig Rodrigues }
7929e7c127fSCraig Rodrigues
7939e7c127fSCraig Rodrigues /*
7949e7c127fSCraig Rodrigues * read ber elements from the socket
7959e7c127fSCraig Rodrigues *
7969e7c127fSCraig Rodrigues * params:
7979e7c127fSCraig Rodrigues * ber holds the socket and lot more
7989e7c127fSCraig Rodrigues * root if NULL, build up an element tree from what we receive on
7999e7c127fSCraig Rodrigues * the wire. If not null, use the specified encoding for the
8009e7c127fSCraig Rodrigues * elements received.
8019e7c127fSCraig Rodrigues *
8029e7c127fSCraig Rodrigues * returns:
8039e7c127fSCraig Rodrigues * !=NULL, elements read and store in the ber_element tree
8049e7c127fSCraig Rodrigues * NULL, type mismatch or read error
8059e7c127fSCraig Rodrigues */
8069e7c127fSCraig Rodrigues struct ber_element *
ber_read_elements(struct ber * ber,struct ber_element * elm)8079e7c127fSCraig Rodrigues ber_read_elements(struct ber *ber, struct ber_element *elm)
8089e7c127fSCraig Rodrigues {
8099e7c127fSCraig Rodrigues struct ber_element *root = elm;
8109e7c127fSCraig Rodrigues
8119e7c127fSCraig Rodrigues if (root == NULL) {
8129e7c127fSCraig Rodrigues if ((root = ber_get_element(0)) == NULL)
8139e7c127fSCraig Rodrigues return NULL;
8149e7c127fSCraig Rodrigues }
8159e7c127fSCraig Rodrigues
8169e7c127fSCraig Rodrigues DPRINTF("read ber elements, root %p\n", root);
8179e7c127fSCraig Rodrigues
8189e7c127fSCraig Rodrigues if (ber_read_element(ber, root) == -1) {
8199e7c127fSCraig Rodrigues /* Cleanup if root was allocated by us */
8209e7c127fSCraig Rodrigues if (elm == NULL)
8219e7c127fSCraig Rodrigues ber_free_elements(root);
8229e7c127fSCraig Rodrigues return NULL;
8239e7c127fSCraig Rodrigues }
8249e7c127fSCraig Rodrigues
8259e7c127fSCraig Rodrigues return root;
8269e7c127fSCraig Rodrigues }
8279e7c127fSCraig Rodrigues
8289e7c127fSCraig Rodrigues void
ber_free_elements(struct ber_element * root)8299e7c127fSCraig Rodrigues ber_free_elements(struct ber_element *root)
8309e7c127fSCraig Rodrigues {
8319e7c127fSCraig Rodrigues if (root->be_sub && (root->be_encoding == BER_TYPE_SEQUENCE ||
8329e7c127fSCraig Rodrigues root->be_encoding == BER_TYPE_SET))
8339e7c127fSCraig Rodrigues ber_free_elements(root->be_sub);
8349e7c127fSCraig Rodrigues if (root->be_next)
8359e7c127fSCraig Rodrigues ber_free_elements(root->be_next);
8369e7c127fSCraig Rodrigues if (root->be_free && (root->be_encoding == BER_TYPE_OCTETSTRING ||
8379e7c127fSCraig Rodrigues root->be_encoding == BER_TYPE_BITSTRING ||
8389e7c127fSCraig Rodrigues root->be_encoding == BER_TYPE_OBJECT))
8399e7c127fSCraig Rodrigues free(root->be_val);
8409e7c127fSCraig Rodrigues free(root);
8419e7c127fSCraig Rodrigues }
8429e7c127fSCraig Rodrigues
8439e7c127fSCraig Rodrigues size_t
ber_calc_len(struct ber_element * root)8449e7c127fSCraig Rodrigues ber_calc_len(struct ber_element *root)
8459e7c127fSCraig Rodrigues {
8469e7c127fSCraig Rodrigues unsigned long t;
8479e7c127fSCraig Rodrigues size_t s;
8489e7c127fSCraig Rodrigues size_t size = 2; /* minimum 1 byte head and 1 byte size */
8499e7c127fSCraig Rodrigues
8509e7c127fSCraig Rodrigues /* calculate the real length of a sequence or set */
8519e7c127fSCraig Rodrigues if (root->be_sub && (root->be_encoding == BER_TYPE_SEQUENCE ||
8529e7c127fSCraig Rodrigues root->be_encoding == BER_TYPE_SET))
8539e7c127fSCraig Rodrigues root->be_len = ber_calc_len(root->be_sub);
8549e7c127fSCraig Rodrigues
8559e7c127fSCraig Rodrigues /* fix header length for extended types */
8569e7c127fSCraig Rodrigues if (root->be_type > BER_TYPE_SINGLE_MAX)
8579e7c127fSCraig Rodrigues for (t = root->be_type; t > 0; t >>= 7)
8589e7c127fSCraig Rodrigues size++;
8599e7c127fSCraig Rodrigues if (root->be_len >= BER_TAG_MORE)
8609e7c127fSCraig Rodrigues for (s = root->be_len; s > 0; s >>= 8)
8619e7c127fSCraig Rodrigues size++;
8629e7c127fSCraig Rodrigues
8639e7c127fSCraig Rodrigues /* calculate the length of the following elements */
8649e7c127fSCraig Rodrigues if (root->be_next)
8659e7c127fSCraig Rodrigues size += ber_calc_len(root->be_next);
8669e7c127fSCraig Rodrigues
8679e7c127fSCraig Rodrigues /* This is an empty element, do not use a minimal size */
8689e7c127fSCraig Rodrigues if (root->be_type == BER_TYPE_EOC && root->be_len == 0)
8699e7c127fSCraig Rodrigues return (0);
8709e7c127fSCraig Rodrigues
8719e7c127fSCraig Rodrigues return (root->be_len + size);
8729e7c127fSCraig Rodrigues }
8739e7c127fSCraig Rodrigues
8749e7c127fSCraig Rodrigues /*
8759e7c127fSCraig Rodrigues * internal functions
8769e7c127fSCraig Rodrigues */
8779e7c127fSCraig Rodrigues
8789e7c127fSCraig Rodrigues static int
ber_dump_element(struct ber * ber,struct ber_element * root)8799e7c127fSCraig Rodrigues ber_dump_element(struct ber *ber, struct ber_element *root)
8809e7c127fSCraig Rodrigues {
8819e7c127fSCraig Rodrigues unsigned long long l;
8829e7c127fSCraig Rodrigues int i;
8839e7c127fSCraig Rodrigues uint8_t u;
8849e7c127fSCraig Rodrigues
8859e7c127fSCraig Rodrigues ber_dump_header(ber, root);
8869e7c127fSCraig Rodrigues
8879e7c127fSCraig Rodrigues switch (root->be_encoding) {
8889e7c127fSCraig Rodrigues case BER_TYPE_BOOLEAN:
8899e7c127fSCraig Rodrigues case BER_TYPE_INTEGER:
8909e7c127fSCraig Rodrigues case BER_TYPE_ENUMERATED:
8919e7c127fSCraig Rodrigues l = (unsigned long long)root->be_numeric;
8929e7c127fSCraig Rodrigues for (i = root->be_len; i > 0; i--) {
8939e7c127fSCraig Rodrigues u = (l >> ((i - 1) * 8)) & 0xff;
8949e7c127fSCraig Rodrigues ber_putc(ber, u);
8959e7c127fSCraig Rodrigues }
8969e7c127fSCraig Rodrigues break;
8979e7c127fSCraig Rodrigues case BER_TYPE_BITSTRING:
8989e7c127fSCraig Rodrigues return -1;
8999e7c127fSCraig Rodrigues case BER_TYPE_OCTETSTRING:
9009e7c127fSCraig Rodrigues case BER_TYPE_OBJECT:
9019e7c127fSCraig Rodrigues ber_write(ber, root->be_val, root->be_len);
9029e7c127fSCraig Rodrigues break;
9039e7c127fSCraig Rodrigues case BER_TYPE_NULL: /* no payload */
9049e7c127fSCraig Rodrigues case BER_TYPE_EOC:
9059e7c127fSCraig Rodrigues break;
9069e7c127fSCraig Rodrigues case BER_TYPE_SEQUENCE:
9079e7c127fSCraig Rodrigues case BER_TYPE_SET:
9089e7c127fSCraig Rodrigues if (root->be_sub && ber_dump_element(ber, root->be_sub) == -1)
9099e7c127fSCraig Rodrigues return -1;
9109e7c127fSCraig Rodrigues break;
9119e7c127fSCraig Rodrigues }
9129e7c127fSCraig Rodrigues
9139e7c127fSCraig Rodrigues if (root->be_next == NULL)
9149e7c127fSCraig Rodrigues return 0;
9159e7c127fSCraig Rodrigues return ber_dump_element(ber, root->be_next);
9169e7c127fSCraig Rodrigues }
9179e7c127fSCraig Rodrigues
9189e7c127fSCraig Rodrigues static void
ber_dump_header(struct ber * ber,struct ber_element * root)9199e7c127fSCraig Rodrigues ber_dump_header(struct ber *ber, struct ber_element *root)
9209e7c127fSCraig Rodrigues {
9219e7c127fSCraig Rodrigues u_char id = 0, t, buf[8];
9229e7c127fSCraig Rodrigues unsigned long type;
9239e7c127fSCraig Rodrigues size_t size;
9249e7c127fSCraig Rodrigues
9259e7c127fSCraig Rodrigues /* class universal, type encoding depending on type value */
9269e7c127fSCraig Rodrigues /* length encoding */
9279e7c127fSCraig Rodrigues if (root->be_type <= BER_TYPE_SINGLE_MAX) {
9289e7c127fSCraig Rodrigues id = root->be_type | (root->be_class << BER_CLASS_SHIFT);
9299e7c127fSCraig Rodrigues if (root->be_encoding == BER_TYPE_SEQUENCE ||
9309e7c127fSCraig Rodrigues root->be_encoding == BER_TYPE_SET)
9319e7c127fSCraig Rodrigues id |= BER_TYPE_CONSTRUCTED;
9329e7c127fSCraig Rodrigues
9339e7c127fSCraig Rodrigues ber_putc(ber, id);
9349e7c127fSCraig Rodrigues } else {
9359e7c127fSCraig Rodrigues id = BER_TAG_MASK | (root->be_class << BER_CLASS_SHIFT);
9369e7c127fSCraig Rodrigues if (root->be_encoding == BER_TYPE_SEQUENCE ||
9379e7c127fSCraig Rodrigues root->be_encoding == BER_TYPE_SET)
9389e7c127fSCraig Rodrigues id |= BER_TYPE_CONSTRUCTED;
9399e7c127fSCraig Rodrigues
9409e7c127fSCraig Rodrigues ber_putc(ber, id);
9419e7c127fSCraig Rodrigues
9429e7c127fSCraig Rodrigues for (t = 0, type = root->be_type; type > 0; type >>= 7)
9439e7c127fSCraig Rodrigues buf[t++] = type & ~BER_TAG_MORE;
9449e7c127fSCraig Rodrigues
9459e7c127fSCraig Rodrigues while (t-- > 0) {
9469e7c127fSCraig Rodrigues if (t > 0)
9479e7c127fSCraig Rodrigues buf[t] |= BER_TAG_MORE;
9489e7c127fSCraig Rodrigues ber_putc(ber, buf[t]);
9499e7c127fSCraig Rodrigues }
9509e7c127fSCraig Rodrigues }
9519e7c127fSCraig Rodrigues
9529e7c127fSCraig Rodrigues if (root->be_len < BER_TAG_MORE) {
9539e7c127fSCraig Rodrigues /* short form */
9549e7c127fSCraig Rodrigues ber_putc(ber, root->be_len);
9559e7c127fSCraig Rodrigues } else {
9569e7c127fSCraig Rodrigues for (t = 0, size = root->be_len; size > 0; size >>= 8)
9579e7c127fSCraig Rodrigues buf[t++] = size & 0xff;
9589e7c127fSCraig Rodrigues
9599e7c127fSCraig Rodrigues ber_putc(ber, t | BER_TAG_MORE);
9609e7c127fSCraig Rodrigues
9619e7c127fSCraig Rodrigues while (t > 0)
9629e7c127fSCraig Rodrigues ber_putc(ber, buf[--t]);
9639e7c127fSCraig Rodrigues }
9649e7c127fSCraig Rodrigues }
9659e7c127fSCraig Rodrigues
9669e7c127fSCraig Rodrigues static void
ber_putc(struct ber * ber,u_char c)9679e7c127fSCraig Rodrigues ber_putc(struct ber *ber, u_char c)
9689e7c127fSCraig Rodrigues {
9699e7c127fSCraig Rodrigues if (ber->br_wptr + 1 <= ber->br_wend)
9709e7c127fSCraig Rodrigues *ber->br_wptr = c;
9719e7c127fSCraig Rodrigues ber->br_wptr++;
9729e7c127fSCraig Rodrigues }
9739e7c127fSCraig Rodrigues
9749e7c127fSCraig Rodrigues static void
ber_write(struct ber * ber,void * buf,size_t len)9759e7c127fSCraig Rodrigues ber_write(struct ber *ber, void *buf, size_t len)
9769e7c127fSCraig Rodrigues {
9779e7c127fSCraig Rodrigues if (ber->br_wptr + len <= ber->br_wend)
9789e7c127fSCraig Rodrigues bcopy(buf, ber->br_wptr, len);
9799e7c127fSCraig Rodrigues ber->br_wptr += len;
9809e7c127fSCraig Rodrigues }
9819e7c127fSCraig Rodrigues
9829e7c127fSCraig Rodrigues /*
9839e7c127fSCraig Rodrigues * extract a BER encoded tag. There are two types, a short and long form.
9849e7c127fSCraig Rodrigues */
9859e7c127fSCraig Rodrigues static ssize_t
get_id(struct ber * b,unsigned long * tag,int * class,int * cstruct)9869e7c127fSCraig Rodrigues get_id(struct ber *b, unsigned long *tag, int *class, int *cstruct)
9879e7c127fSCraig Rodrigues {
9889e7c127fSCraig Rodrigues u_char u;
9899e7c127fSCraig Rodrigues size_t i = 0;
9909e7c127fSCraig Rodrigues unsigned long t = 0;
9919e7c127fSCraig Rodrigues
9929e7c127fSCraig Rodrigues if (ber_getc(b, &u) == -1)
9939e7c127fSCraig Rodrigues return -1;
9949e7c127fSCraig Rodrigues
9959e7c127fSCraig Rodrigues *class = (u >> BER_CLASS_SHIFT) & BER_CLASS_MASK;
9969e7c127fSCraig Rodrigues *cstruct = (u & BER_TYPE_CONSTRUCTED) == BER_TYPE_CONSTRUCTED;
9979e7c127fSCraig Rodrigues
9989e7c127fSCraig Rodrigues if ((u & BER_TAG_MASK) != BER_TAG_MASK) {
9999e7c127fSCraig Rodrigues *tag = u & BER_TAG_MASK;
10009e7c127fSCraig Rodrigues return 1;
10019e7c127fSCraig Rodrigues }
10029e7c127fSCraig Rodrigues
10039e7c127fSCraig Rodrigues do {
10049e7c127fSCraig Rodrigues if (ber_getc(b, &u) == -1)
10059e7c127fSCraig Rodrigues return -1;
10069e7c127fSCraig Rodrigues t = (t << 7) | (u & ~BER_TAG_MORE);
10079e7c127fSCraig Rodrigues i++;
10089e7c127fSCraig Rodrigues } while (u & BER_TAG_MORE);
10099e7c127fSCraig Rodrigues
10109e7c127fSCraig Rodrigues if (i > sizeof(unsigned long)) {
10119e7c127fSCraig Rodrigues errno = ERANGE;
10129e7c127fSCraig Rodrigues return -1;
10139e7c127fSCraig Rodrigues }
10149e7c127fSCraig Rodrigues
10159e7c127fSCraig Rodrigues *tag = t;
10169e7c127fSCraig Rodrigues return i + 1;
10179e7c127fSCraig Rodrigues }
10189e7c127fSCraig Rodrigues
10199e7c127fSCraig Rodrigues /*
10209e7c127fSCraig Rodrigues * extract length of a ber object -- if length is unknown an error is returned.
10219e7c127fSCraig Rodrigues */
10229e7c127fSCraig Rodrigues static ssize_t
get_len(struct ber * b,ssize_t * len)10239e7c127fSCraig Rodrigues get_len(struct ber *b, ssize_t *len)
10249e7c127fSCraig Rodrigues {
10259e7c127fSCraig Rodrigues u_char u, n;
10269e7c127fSCraig Rodrigues ssize_t s, r;
10279e7c127fSCraig Rodrigues
10289e7c127fSCraig Rodrigues if (ber_getc(b, &u) == -1)
10299e7c127fSCraig Rodrigues return -1;
10309e7c127fSCraig Rodrigues if ((u & BER_TAG_MORE) == 0) {
10319e7c127fSCraig Rodrigues /* short form */
10329e7c127fSCraig Rodrigues *len = u;
10339e7c127fSCraig Rodrigues return 1;
10349e7c127fSCraig Rodrigues }
10359e7c127fSCraig Rodrigues
10369e7c127fSCraig Rodrigues n = u & ~BER_TAG_MORE;
10379e7c127fSCraig Rodrigues if (sizeof(ssize_t) < n) {
10389e7c127fSCraig Rodrigues errno = ERANGE;
10399e7c127fSCraig Rodrigues return -1;
10409e7c127fSCraig Rodrigues }
10419e7c127fSCraig Rodrigues r = n + 1;
10429e7c127fSCraig Rodrigues
10439e7c127fSCraig Rodrigues for (s = 0; n > 0; n--) {
10449e7c127fSCraig Rodrigues if (ber_getc(b, &u) == -1)
10459e7c127fSCraig Rodrigues return -1;
10469e7c127fSCraig Rodrigues s = (s << 8) | u;
10479e7c127fSCraig Rodrigues }
10489e7c127fSCraig Rodrigues
10499e7c127fSCraig Rodrigues if (s < 0) {
10509e7c127fSCraig Rodrigues /* overflow */
10519e7c127fSCraig Rodrigues errno = ERANGE;
10529e7c127fSCraig Rodrigues return -1;
10539e7c127fSCraig Rodrigues }
10549e7c127fSCraig Rodrigues
10559e7c127fSCraig Rodrigues if (s == 0) {
10569e7c127fSCraig Rodrigues /* invalid encoding */
10579e7c127fSCraig Rodrigues errno = EINVAL;
10589e7c127fSCraig Rodrigues return -1;
10599e7c127fSCraig Rodrigues }
10609e7c127fSCraig Rodrigues
10619e7c127fSCraig Rodrigues *len = s;
10629e7c127fSCraig Rodrigues return r;
10639e7c127fSCraig Rodrigues }
10649e7c127fSCraig Rodrigues
10659e7c127fSCraig Rodrigues static ssize_t
ber_read_element(struct ber * ber,struct ber_element * elm)10669e7c127fSCraig Rodrigues ber_read_element(struct ber *ber, struct ber_element *elm)
10679e7c127fSCraig Rodrigues {
10689e7c127fSCraig Rodrigues long long val = 0;
10699e7c127fSCraig Rodrigues struct ber_element *next;
10709e7c127fSCraig Rodrigues unsigned long type;
10719e7c127fSCraig Rodrigues int i, class, cstruct;
10729e7c127fSCraig Rodrigues ssize_t len, r, totlen = 0;
10739e7c127fSCraig Rodrigues u_char c;
10749e7c127fSCraig Rodrigues
10759e7c127fSCraig Rodrigues if ((r = get_id(ber, &type, &class, &cstruct)) == -1)
10769e7c127fSCraig Rodrigues return -1;
10779e7c127fSCraig Rodrigues DPRINTF("ber read got class %d type %lu, %s\n",
10789e7c127fSCraig Rodrigues class, type, cstruct ? "constructive" : "primitive");
10799e7c127fSCraig Rodrigues totlen += r;
10809e7c127fSCraig Rodrigues if ((r = get_len(ber, &len)) == -1)
10819e7c127fSCraig Rodrigues return -1;
10829e7c127fSCraig Rodrigues DPRINTF("ber read element size %zd\n", len);
10839e7c127fSCraig Rodrigues totlen += r + len;
10849e7c127fSCraig Rodrigues
10850e356242SMarcelo Araujo /*
10860e356242SMarcelo Araujo * If using an external buffer and the total size of the element
10870e356242SMarcelo Araujo * is larger, then the external buffer don't bother to continue.
10880e356242SMarcelo Araujo */
10890e356242SMarcelo Araujo if (ber->fd == -1 && len > ber->br_rend - ber->br_rptr) {
10900e356242SMarcelo Araujo errno = ECANCELED;
10910e356242SMarcelo Araujo return -1;
10920e356242SMarcelo Araujo }
10930e356242SMarcelo Araujo
10949e7c127fSCraig Rodrigues elm->be_type = type;
10959e7c127fSCraig Rodrigues elm->be_len = len;
10969e7c127fSCraig Rodrigues elm->be_class = class;
10979e7c127fSCraig Rodrigues
10989e7c127fSCraig Rodrigues if (elm->be_encoding == 0) {
10999e7c127fSCraig Rodrigues /* try to figure out the encoding via class, type and cstruct */
11009e7c127fSCraig Rodrigues if (cstruct)
11019e7c127fSCraig Rodrigues elm->be_encoding = BER_TYPE_SEQUENCE;
11029e7c127fSCraig Rodrigues else if (class == BER_CLASS_UNIVERSAL)
11039e7c127fSCraig Rodrigues elm->be_encoding = type;
11049e7c127fSCraig Rodrigues else if (ber->br_application != NULL) {
11059e7c127fSCraig Rodrigues /*
11069e7c127fSCraig Rodrigues * Ask the application to map the encoding to a
11079e7c127fSCraig Rodrigues * universal type. For example, a SMI IpAddress
11089e7c127fSCraig Rodrigues * type is defined as 4 byte OCTET STRING.
11099e7c127fSCraig Rodrigues */
11109e7c127fSCraig Rodrigues elm->be_encoding = (*ber->br_application)(elm);
11119e7c127fSCraig Rodrigues } else
11129e7c127fSCraig Rodrigues /* last resort option */
11139e7c127fSCraig Rodrigues elm->be_encoding = BER_TYPE_NULL;
11149e7c127fSCraig Rodrigues }
11159e7c127fSCraig Rodrigues
11169e7c127fSCraig Rodrigues switch (elm->be_encoding) {
11179e7c127fSCraig Rodrigues case BER_TYPE_EOC: /* End-Of-Content */
11189e7c127fSCraig Rodrigues break;
11199e7c127fSCraig Rodrigues case BER_TYPE_BOOLEAN:
11209e7c127fSCraig Rodrigues case BER_TYPE_INTEGER:
11219e7c127fSCraig Rodrigues case BER_TYPE_ENUMERATED:
11229e7c127fSCraig Rodrigues if (len > (ssize_t)sizeof(long long))
11239e7c127fSCraig Rodrigues return -1;
11249e7c127fSCraig Rodrigues for (i = 0; i < len; i++) {
11259e7c127fSCraig Rodrigues if (ber_getc(ber, &c) != 1)
11269e7c127fSCraig Rodrigues return -1;
11279e7c127fSCraig Rodrigues val <<= 8;
11289e7c127fSCraig Rodrigues val |= c;
11299e7c127fSCraig Rodrigues }
11309e7c127fSCraig Rodrigues
11319e7c127fSCraig Rodrigues /* sign extend if MSB is set */
11329e7c127fSCraig Rodrigues if (val >> ((i - 1) * 8) & 0x80)
11339e7c127fSCraig Rodrigues val |= ULLONG_MAX << (i * 8);
11349e7c127fSCraig Rodrigues elm->be_numeric = val;
11359e7c127fSCraig Rodrigues break;
11369e7c127fSCraig Rodrigues case BER_TYPE_BITSTRING:
11379e7c127fSCraig Rodrigues elm->be_val = malloc(len);
11389e7c127fSCraig Rodrigues if (elm->be_val == NULL)
11399e7c127fSCraig Rodrigues return -1;
11409e7c127fSCraig Rodrigues elm->be_free = 1;
11419e7c127fSCraig Rodrigues elm->be_len = len;
11429e7c127fSCraig Rodrigues ber_read(ber, elm->be_val, len);
11439e7c127fSCraig Rodrigues break;
11449e7c127fSCraig Rodrigues case BER_TYPE_OCTETSTRING:
11459e7c127fSCraig Rodrigues case BER_TYPE_OBJECT:
11469e7c127fSCraig Rodrigues elm->be_val = malloc(len + 1);
11479e7c127fSCraig Rodrigues if (elm->be_val == NULL)
11489e7c127fSCraig Rodrigues return -1;
11499e7c127fSCraig Rodrigues elm->be_free = 1;
11509e7c127fSCraig Rodrigues elm->be_len = len;
11519e7c127fSCraig Rodrigues ber_read(ber, elm->be_val, len);
11529e7c127fSCraig Rodrigues ((u_char *)elm->be_val)[len] = '\0';
11539e7c127fSCraig Rodrigues break;
11549e7c127fSCraig Rodrigues case BER_TYPE_NULL: /* no payload */
11559e7c127fSCraig Rodrigues if (len != 0)
11569e7c127fSCraig Rodrigues return -1;
11579e7c127fSCraig Rodrigues break;
11589e7c127fSCraig Rodrigues case BER_TYPE_SEQUENCE:
11599e7c127fSCraig Rodrigues case BER_TYPE_SET:
11609e7c127fSCraig Rodrigues if (elm->be_sub == NULL) {
11619e7c127fSCraig Rodrigues if ((elm->be_sub = ber_get_element(0)) == NULL)
11629e7c127fSCraig Rodrigues return -1;
11639e7c127fSCraig Rodrigues }
11649e7c127fSCraig Rodrigues next = elm->be_sub;
11659e7c127fSCraig Rodrigues while (len > 0) {
11669e7c127fSCraig Rodrigues r = ber_read_element(ber, next);
11679e7c127fSCraig Rodrigues if (r == -1)
11689e7c127fSCraig Rodrigues return -1;
11699e7c127fSCraig Rodrigues len -= r;
11709e7c127fSCraig Rodrigues if (len > 0 && next->be_next == NULL) {
11719e7c127fSCraig Rodrigues if ((next->be_next = ber_get_element(0)) ==
11729e7c127fSCraig Rodrigues NULL)
11739e7c127fSCraig Rodrigues return -1;
11749e7c127fSCraig Rodrigues }
11759e7c127fSCraig Rodrigues next = next->be_next;
11769e7c127fSCraig Rodrigues }
11779e7c127fSCraig Rodrigues break;
11789e7c127fSCraig Rodrigues }
11799e7c127fSCraig Rodrigues return totlen;
11809e7c127fSCraig Rodrigues }
11819e7c127fSCraig Rodrigues
11829e7c127fSCraig Rodrigues static ssize_t
ber_readbuf(struct ber * b,void * buf,size_t nbytes)11839e7c127fSCraig Rodrigues ber_readbuf(struct ber *b, void *buf, size_t nbytes)
11849e7c127fSCraig Rodrigues {
11859e7c127fSCraig Rodrigues size_t sz;
11869e7c127fSCraig Rodrigues size_t len;
11879e7c127fSCraig Rodrigues
11889e7c127fSCraig Rodrigues if (b->br_rbuf == NULL)
11899e7c127fSCraig Rodrigues return -1;
11909e7c127fSCraig Rodrigues
11919e7c127fSCraig Rodrigues sz = b->br_rend - b->br_rptr;
11929e7c127fSCraig Rodrigues len = MINIMUM(nbytes, sz);
11939e7c127fSCraig Rodrigues if (len == 0) {
11949e7c127fSCraig Rodrigues errno = ECANCELED;
11959e7c127fSCraig Rodrigues return (-1); /* end of buffer and parser wants more data */
11969e7c127fSCraig Rodrigues }
11979e7c127fSCraig Rodrigues
11989e7c127fSCraig Rodrigues bcopy(b->br_rptr, buf, len);
11999e7c127fSCraig Rodrigues b->br_rptr += len;
12009e7c127fSCraig Rodrigues
12019e7c127fSCraig Rodrigues return (len);
12029e7c127fSCraig Rodrigues }
12039e7c127fSCraig Rodrigues
12049e7c127fSCraig Rodrigues void
ber_set_readbuf(struct ber * b,void * buf,size_t len)12059e7c127fSCraig Rodrigues ber_set_readbuf(struct ber *b, void *buf, size_t len)
12069e7c127fSCraig Rodrigues {
12079e7c127fSCraig Rodrigues b->br_rbuf = b->br_rptr = buf;
12089e7c127fSCraig Rodrigues b->br_rend = (u_int8_t *)buf + len;
12099e7c127fSCraig Rodrigues }
12109e7c127fSCraig Rodrigues
12119e7c127fSCraig Rodrigues ssize_t
ber_get_writebuf(struct ber * b,void ** buf)12129e7c127fSCraig Rodrigues ber_get_writebuf(struct ber *b, void **buf)
12139e7c127fSCraig Rodrigues {
12149e7c127fSCraig Rodrigues if (b->br_wbuf == NULL)
12159e7c127fSCraig Rodrigues return -1;
12169e7c127fSCraig Rodrigues *buf = b->br_wbuf;
12179e7c127fSCraig Rodrigues return (b->br_wend - b->br_wbuf);
12189e7c127fSCraig Rodrigues }
12199e7c127fSCraig Rodrigues
12209e7c127fSCraig Rodrigues void
ber_set_application(struct ber * b,unsigned long (* cb)(struct ber_element *))12219e7c127fSCraig Rodrigues ber_set_application(struct ber *b, unsigned long (*cb)(struct ber_element *))
12229e7c127fSCraig Rodrigues {
12239e7c127fSCraig Rodrigues b->br_application = cb;
12249e7c127fSCraig Rodrigues }
12259e7c127fSCraig Rodrigues
12269e7c127fSCraig Rodrigues void
ber_free(struct ber * b)12279e7c127fSCraig Rodrigues ber_free(struct ber *b)
12289e7c127fSCraig Rodrigues {
12299e7c127fSCraig Rodrigues free(b->br_wbuf);
12309e7c127fSCraig Rodrigues }
12319e7c127fSCraig Rodrigues
12329e7c127fSCraig Rodrigues static ssize_t
ber_getc(struct ber * b,u_char * c)12339e7c127fSCraig Rodrigues ber_getc(struct ber *b, u_char *c)
12349e7c127fSCraig Rodrigues {
12359e7c127fSCraig Rodrigues ssize_t r;
12369e7c127fSCraig Rodrigues /*
12379e7c127fSCraig Rodrigues * XXX calling read here is wrong in many ways. The most obvious one
12389e7c127fSCraig Rodrigues * being that we will block till data arrives.
12399e7c127fSCraig Rodrigues * But for now it is _good enough_ *gulp*
12409e7c127fSCraig Rodrigues */
12419e7c127fSCraig Rodrigues if (b->fd == -1)
12429e7c127fSCraig Rodrigues r = ber_readbuf(b, c, 1);
12439e7c127fSCraig Rodrigues else
12449e7c127fSCraig Rodrigues r = read(b->fd, c, 1);
12459e7c127fSCraig Rodrigues return r;
12469e7c127fSCraig Rodrigues }
12479e7c127fSCraig Rodrigues
12489e7c127fSCraig Rodrigues static ssize_t
ber_read(struct ber * ber,void * buf,size_t len)12499e7c127fSCraig Rodrigues ber_read(struct ber *ber, void *buf, size_t len)
12509e7c127fSCraig Rodrigues {
12519e7c127fSCraig Rodrigues u_char *b = buf;
12529e7c127fSCraig Rodrigues ssize_t r, remain = len;
12539e7c127fSCraig Rodrigues
12549e7c127fSCraig Rodrigues /*
12559e7c127fSCraig Rodrigues * XXX calling read here is wrong in many ways. The most obvious one
12569e7c127fSCraig Rodrigues * being that we will block till data arrives.
12579e7c127fSCraig Rodrigues * But for now it is _good enough_ *gulp*
12589e7c127fSCraig Rodrigues */
12599e7c127fSCraig Rodrigues
12609e7c127fSCraig Rodrigues while (remain > 0) {
12619e7c127fSCraig Rodrigues if (ber->fd == -1)
12629e7c127fSCraig Rodrigues r = ber_readbuf(ber, b, remain);
12639e7c127fSCraig Rodrigues else
12649e7c127fSCraig Rodrigues r = read(ber->fd, b, remain);
12659e7c127fSCraig Rodrigues if (r == -1) {
12669e7c127fSCraig Rodrigues if (errno == EINTR || errno == EAGAIN)
12679e7c127fSCraig Rodrigues continue;
12689e7c127fSCraig Rodrigues return -1;
12699e7c127fSCraig Rodrigues }
12709e7c127fSCraig Rodrigues if (r == 0)
12719e7c127fSCraig Rodrigues return (b - (u_char *)buf);
12729e7c127fSCraig Rodrigues b += r;
12739e7c127fSCraig Rodrigues remain -= r;
12749e7c127fSCraig Rodrigues }
12759e7c127fSCraig Rodrigues return (b - (u_char *)buf);
12769e7c127fSCraig Rodrigues }
1277