2023-11-10 04:12:02 -08:00
|
|
|
/* $OpenBSD: ber.c,v 1.26 2023/11/10 12:12:02 martijn Exp $ */
|
2018-06-13 08:45:57 -07:00
|
|
|
|
|
|
|
/*
|
2018-06-29 11:28:41 -07:00
|
|
|
* Copyright (c) 2007, 2012 Reyk Floeter <reyk@openbsd.org>
|
2018-06-13 08:45:57 -07:00
|
|
|
* Copyright (c) 2006, 2007 Claudio Jeker <claudio@openbsd.org>
|
|
|
|
* Copyright (c) 2006, 2007 Marc Balmer <mbalmer@openbsd.org>
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <err.h> /* XXX for debug output */
|
|
|
|
#include <stdio.h> /* XXX for debug output */
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
|
|
|
#include "ber.h"
|
|
|
|
|
|
|
|
#define BER_TYPE_CONSTRUCTED 0x20 /* otherwise primitive */
|
|
|
|
#define BER_TYPE_SINGLE_MAX 30
|
|
|
|
#define BER_TAG_MASK 0x1f
|
|
|
|
#define BER_TAG_MORE 0x80 /* more subsequent octets */
|
|
|
|
#define BER_TAG_TYPE_MASK 0x7f
|
|
|
|
#define BER_CLASS_SHIFT 6
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
static int ober_dump_element(struct ber *ber, struct ber_element *root);
|
|
|
|
static void ober_dump_header(struct ber *ber, struct ber_element *root);
|
|
|
|
static void ober_putc(struct ber *ber, u_char c);
|
|
|
|
static void ober_write(struct ber *ber, void *buf, size_t len);
|
2018-07-31 04:02:01 -07:00
|
|
|
static ssize_t get_id(struct ber *b, unsigned int *tag, int *class,
|
2018-06-13 08:45:57 -07:00
|
|
|
int *cstruct);
|
|
|
|
static ssize_t get_len(struct ber *b, ssize_t *len);
|
2019-10-24 05:39:26 -07:00
|
|
|
static ssize_t ober_read_element(struct ber *ber, struct ber_element *elm);
|
|
|
|
static ssize_t ober_getc(struct ber *b, u_char *c);
|
|
|
|
static ssize_t ober_read(struct ber *ber, void *buf, size_t len);
|
2018-06-13 08:45:57 -07:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
#define DPRINTF(...) printf(__VA_ARGS__)
|
|
|
|
#else
|
|
|
|
#define DPRINTF(...) do { } while (0)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
struct ber_element *
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_get_element(unsigned int encoding)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
struct ber_element *elm;
|
|
|
|
|
|
|
|
if ((elm = calloc(1, sizeof(*elm))) == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
elm->be_encoding = encoding;
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_set_header(elm, BER_CLASS_UNIVERSAL, BER_TYPE_DEFAULT);
|
2018-06-13 08:45:57 -07:00
|
|
|
|
|
|
|
return elm;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_set_header(struct ber_element *elm, int class, unsigned int type)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
elm->be_class = class & BER_CLASS_MASK;
|
|
|
|
if (type == BER_TYPE_DEFAULT)
|
|
|
|
type = elm->be_encoding;
|
|
|
|
elm->be_type = type;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_link_elements(struct ber_element *prev, struct ber_element *elm)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
if (prev != NULL) {
|
|
|
|
if ((prev->be_encoding == BER_TYPE_SEQUENCE ||
|
|
|
|
prev->be_encoding == BER_TYPE_SET) &&
|
|
|
|
prev->be_sub == NULL)
|
|
|
|
prev->be_sub = elm;
|
|
|
|
else
|
|
|
|
prev->be_next = elm;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ber_element *
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_unlink_elements(struct ber_element *prev)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
struct ber_element *elm;
|
|
|
|
|
|
|
|
if ((prev->be_encoding == BER_TYPE_SEQUENCE ||
|
|
|
|
prev->be_encoding == BER_TYPE_SET) &&
|
|
|
|
prev->be_sub != NULL) {
|
|
|
|
elm = prev->be_sub;
|
|
|
|
prev->be_sub = NULL;
|
|
|
|
} else {
|
|
|
|
elm = prev->be_next;
|
|
|
|
prev->be_next = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (elm);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_replace_elements(struct ber_element *prev, struct ber_element *new)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
struct ber_element *ber, *next;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
ber = ober_unlink_elements(prev);
|
|
|
|
next = ober_unlink_elements(ber);
|
|
|
|
ober_link_elements(new, next);
|
|
|
|
ober_link_elements(prev, new);
|
2018-06-13 08:45:57 -07:00
|
|
|
|
|
|
|
/* cleanup old element */
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_free_elements(ber);
|
2018-06-13 08:45:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
struct ber_element *
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_add_sequence(struct ber_element *prev)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
struct ber_element *elm;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
if ((elm = ober_get_element(BER_TYPE_SEQUENCE)) == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
return NULL;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_link_elements(prev, elm);
|
2018-06-13 08:45:57 -07:00
|
|
|
|
|
|
|
return elm;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ber_element *
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_add_set(struct ber_element *prev)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
struct ber_element *elm;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
if ((elm = ober_get_element(BER_TYPE_SET)) == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
return NULL;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_link_elements(prev, elm);
|
2018-06-13 08:45:57 -07:00
|
|
|
|
|
|
|
return elm;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ber_element *
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_add_enumerated(struct ber_element *prev, long long val)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
struct ber_element *elm;
|
|
|
|
u_int i, len = 0;
|
|
|
|
u_char cur, last = 0;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
if ((elm = ober_get_element(BER_TYPE_ENUMERATED)) == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
elm->be_numeric = val;
|
|
|
|
|
|
|
|
for (i = 0; i < sizeof(long long); i++) {
|
|
|
|
cur = val & 0xff;
|
|
|
|
if (cur != 0 && cur != 0xff)
|
|
|
|
len = i;
|
|
|
|
if ((cur == 0 && last & 0x80) ||
|
|
|
|
(cur == 0xff && (last & 0x80) == 0))
|
|
|
|
len = i;
|
|
|
|
val >>= 8;
|
|
|
|
last = cur;
|
|
|
|
}
|
|
|
|
elm->be_len = len + 1;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_link_elements(prev, elm);
|
2018-06-13 08:45:57 -07:00
|
|
|
|
|
|
|
return elm;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ber_element *
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_add_integer(struct ber_element *prev, long long val)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
struct ber_element *elm;
|
|
|
|
u_int i, len = 0;
|
|
|
|
u_char cur, last = 0;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
if ((elm = ober_get_element(BER_TYPE_INTEGER)) == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
elm->be_numeric = val;
|
|
|
|
|
|
|
|
for (i = 0; i < sizeof(long long); i++) {
|
|
|
|
cur = val & 0xff;
|
|
|
|
if (cur != 0 && cur != 0xff)
|
|
|
|
len = i;
|
|
|
|
if ((cur == 0 && last & 0x80) ||
|
|
|
|
(cur == 0xff && (last & 0x80) == 0))
|
|
|
|
len = i;
|
|
|
|
val >>= 8;
|
|
|
|
last = cur;
|
|
|
|
}
|
|
|
|
elm->be_len = len + 1;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_link_elements(prev, elm);
|
2018-06-13 08:45:57 -07:00
|
|
|
|
|
|
|
return elm;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_get_integer(struct ber_element *elm, long long *n)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
if (elm->be_encoding != BER_TYPE_INTEGER)
|
|
|
|
return -1;
|
|
|
|
|
2021-02-22 09:15:02 -08:00
|
|
|
if (n != NULL)
|
|
|
|
*n = elm->be_numeric;
|
2018-06-13 08:45:57 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_get_enumerated(struct ber_element *elm, long long *n)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
if (elm->be_encoding != BER_TYPE_ENUMERATED)
|
|
|
|
return -1;
|
|
|
|
|
2021-02-22 09:15:02 -08:00
|
|
|
if (n != NULL)
|
|
|
|
*n = elm->be_numeric;
|
2018-06-13 08:45:57 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ber_element *
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_add_boolean(struct ber_element *prev, int bool)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
struct ber_element *elm;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
if ((elm = ober_get_element(BER_TYPE_BOOLEAN)) == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
elm->be_numeric = bool ? 0xff : 0;
|
|
|
|
elm->be_len = 1;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_link_elements(prev, elm);
|
2018-06-13 08:45:57 -07:00
|
|
|
|
|
|
|
return elm;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_get_boolean(struct ber_element *elm, int *b)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
if (elm->be_encoding != BER_TYPE_BOOLEAN)
|
|
|
|
return -1;
|
|
|
|
|
2021-02-22 09:15:02 -08:00
|
|
|
if (b != NULL)
|
|
|
|
*b = !(elm->be_numeric == 0);
|
2018-06-13 08:45:57 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ber_element *
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_add_string(struct ber_element *prev, const char *string)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
2019-10-24 05:39:26 -07:00
|
|
|
return ober_add_nstring(prev, string, strlen(string));
|
2018-06-13 08:45:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
struct ber_element *
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_add_nstring(struct ber_element *prev, const char *string0, size_t len)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
struct ber_element *elm;
|
|
|
|
char *string;
|
|
|
|
|
2018-06-27 13:11:27 -07:00
|
|
|
if ((string = calloc(1, len + 1)) == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
return NULL;
|
2019-10-24 05:39:26 -07:00
|
|
|
if ((elm = ober_get_element(BER_TYPE_OCTETSTRING)) == NULL) {
|
2018-06-13 08:45:57 -07:00
|
|
|
free(string);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bcopy(string0, string, len);
|
|
|
|
elm->be_val = string;
|
|
|
|
elm->be_len = len;
|
|
|
|
elm->be_free = 1; /* free string on cleanup */
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_link_elements(prev, elm);
|
2018-06-13 08:45:57 -07:00
|
|
|
|
|
|
|
return elm;
|
|
|
|
}
|
|
|
|
|
2018-11-27 04:04:57 -08:00
|
|
|
struct ber_element *
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_add_ostring(struct ber_element *prev, struct ber_octetstring *s)
|
2018-11-27 04:04:57 -08:00
|
|
|
{
|
2019-10-24 05:39:26 -07:00
|
|
|
return ober_add_nstring(prev, s->ostr_val, s->ostr_len);
|
2018-11-27 04:04:57 -08:00
|
|
|
}
|
|
|
|
|
2018-06-13 08:45:57 -07:00
|
|
|
int
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_get_string(struct ber_element *elm, char **s)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
if (elm->be_encoding != BER_TYPE_OCTETSTRING)
|
|
|
|
return -1;
|
2019-05-16 14:12:33 -07:00
|
|
|
/* XXX some components use getstring on binary data containing \0 */
|
2018-11-27 04:04:57 -08:00
|
|
|
#if 0
|
|
|
|
if (memchr(elm->be_val, '\0', elm->be_len) != NULL)
|
|
|
|
return -1;
|
|
|
|
#endif
|
2018-06-13 08:45:57 -07:00
|
|
|
|
2021-02-22 09:15:02 -08:00
|
|
|
if (s != NULL)
|
|
|
|
*s = elm->be_val;
|
2018-06-13 08:45:57 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_get_nstring(struct ber_element *elm, void **p, size_t *len)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
if (elm->be_encoding != BER_TYPE_OCTETSTRING)
|
|
|
|
return -1;
|
|
|
|
|
2021-02-22 09:15:02 -08:00
|
|
|
if (len != NULL)
|
|
|
|
*len = elm->be_len;
|
|
|
|
if (p != NULL) {
|
|
|
|
if (len != NULL)
|
|
|
|
*p = elm->be_val;
|
|
|
|
else
|
|
|
|
*p = NULL;
|
|
|
|
}
|
2018-06-13 08:45:57 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-27 04:04:57 -08:00
|
|
|
int
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_get_ostring(struct ber_element *elm, struct ber_octetstring *s)
|
2018-11-27 04:04:57 -08:00
|
|
|
{
|
|
|
|
if (elm->be_encoding != BER_TYPE_OCTETSTRING)
|
|
|
|
return -1;
|
|
|
|
|
2021-02-22 09:15:02 -08:00
|
|
|
if (s != NULL) {
|
|
|
|
s->ostr_val = elm->be_val;
|
|
|
|
s->ostr_len = elm->be_len;
|
|
|
|
}
|
2018-11-27 04:04:57 -08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-06-13 08:45:57 -07:00
|
|
|
struct ber_element *
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_add_bitstring(struct ber_element *prev, const void *v0, size_t len)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
struct ber_element *elm;
|
|
|
|
void *v;
|
|
|
|
|
|
|
|
if ((v = calloc(1, len)) == NULL)
|
|
|
|
return NULL;
|
2019-10-24 05:39:26 -07:00
|
|
|
if ((elm = ober_get_element(BER_TYPE_BITSTRING)) == NULL) {
|
2018-06-13 08:45:57 -07:00
|
|
|
free(v);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bcopy(v0, v, len);
|
|
|
|
elm->be_val = v;
|
|
|
|
elm->be_len = len;
|
|
|
|
elm->be_free = 1; /* free string on cleanup */
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_link_elements(prev, elm);
|
2018-06-13 08:45:57 -07:00
|
|
|
|
|
|
|
return elm;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_get_bitstring(struct ber_element *elm, void **v, size_t *len)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
if (elm->be_encoding != BER_TYPE_BITSTRING)
|
|
|
|
return -1;
|
|
|
|
|
2021-02-22 09:15:02 -08:00
|
|
|
if (len != NULL)
|
|
|
|
*len = elm->be_len;
|
|
|
|
if (v != NULL) {
|
|
|
|
if (len != NULL)
|
|
|
|
*v = elm->be_val;
|
|
|
|
else
|
|
|
|
*v = NULL;
|
|
|
|
}
|
2018-06-13 08:45:57 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ber_element *
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_add_null(struct ber_element *prev)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
struct ber_element *elm;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
if ((elm = ober_get_element(BER_TYPE_NULL)) == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
return NULL;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_link_elements(prev, elm);
|
2018-06-13 08:45:57 -07:00
|
|
|
|
|
|
|
return elm;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_get_null(struct ber_element *elm)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
if (elm->be_encoding != BER_TYPE_NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ber_element *
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_add_eoc(struct ber_element *prev)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
struct ber_element *elm;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
if ((elm = ober_get_element(BER_TYPE_EOC)) == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
return NULL;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_link_elements(prev, elm);
|
2018-06-13 08:45:57 -07:00
|
|
|
|
|
|
|
return elm;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_get_eoc(struct ber_element *elm)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
if (elm->be_encoding != BER_TYPE_EOC)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_oid2ber(struct ber_oid *o, u_int8_t *buf, size_t len)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
u_int32_t v;
|
|
|
|
u_int i, j = 0, k;
|
|
|
|
|
|
|
|
if (o->bo_n < BER_MIN_OID_LEN || o->bo_n > BER_MAX_OID_LEN ||
|
|
|
|
o->bo_id[0] > 2 || o->bo_id[1] > 40)
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
v = (o->bo_id[0] * 40) + o->bo_id[1];
|
|
|
|
for (i = 2, j = 0; i <= o->bo_n; v = o->bo_id[i], i++) {
|
|
|
|
for (k = 28; k >= 7; k -= 7) {
|
|
|
|
if (v >= (u_int)(1 << k)) {
|
|
|
|
if (len)
|
|
|
|
buf[j] = v >> k | BER_TAG_MORE;
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (len)
|
|
|
|
buf[j] = v & BER_TAG_TYPE_MASK;
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (j);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_string2oid(const char *oidstr, struct ber_oid *o)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
char *sp, *p, str[BUFSIZ];
|
|
|
|
const char *errstr;
|
|
|
|
|
|
|
|
if (strlcpy(str, oidstr, sizeof(str)) >= sizeof(str))
|
|
|
|
return (-1);
|
|
|
|
memset(o, 0, sizeof(*o));
|
|
|
|
|
|
|
|
/* Parse OID strings in the common forms n.n.n, n_n_n_n, or n-n-n */
|
|
|
|
for (p = sp = str; p != NULL; sp = p) {
|
|
|
|
if ((p = strpbrk(p, "._-")) != NULL)
|
|
|
|
*p++ = '\0';
|
|
|
|
o->bo_id[o->bo_n++] = strtonum(sp, 0, UINT_MAX, &errstr);
|
|
|
|
if (errstr || o->bo_n > BER_MAX_OID_LEN)
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2018-07-31 12:38:09 -07:00
|
|
|
int
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_oid_cmp(struct ber_oid *a, struct ber_oid *b)
|
2018-07-31 12:38:09 -07:00
|
|
|
{
|
2021-10-21 01:17:33 -07:00
|
|
|
size_t i, min;
|
|
|
|
|
|
|
|
min = a->bo_n < b->bo_n ? a->bo_n : b->bo_n;
|
|
|
|
for (i = 0; i < min; i++) {
|
|
|
|
if (a->bo_id[i] < b->bo_id[i])
|
2019-08-05 05:38:14 -07:00
|
|
|
return (-1);
|
2021-10-21 01:17:33 -07:00
|
|
|
if (a->bo_id[i] > b->bo_id[i])
|
|
|
|
return (1);
|
2018-07-31 12:38:09 -07:00
|
|
|
}
|
2021-10-21 01:17:33 -07:00
|
|
|
/* a is parent of b */
|
2019-08-05 05:38:14 -07:00
|
|
|
if (a->bo_n < b->bo_n)
|
2021-10-21 01:17:33 -07:00
|
|
|
return (-2);
|
|
|
|
/* a is child of b */
|
2019-08-05 05:38:14 -07:00
|
|
|
if (a->bo_n > b->bo_n)
|
2021-10-21 01:17:33 -07:00
|
|
|
return 2;
|
2018-07-31 12:38:09 -07:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2018-06-13 08:45:57 -07:00
|
|
|
struct ber_element *
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_add_oid(struct ber_element *prev, struct ber_oid *o)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
struct ber_element *elm;
|
|
|
|
u_int8_t *buf;
|
|
|
|
size_t len;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
if ((elm = ober_get_element(BER_TYPE_OBJECT)) == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
return (NULL);
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
if ((len = ober_oid2ber(o, NULL, 0)) == 0)
|
2018-06-13 08:45:57 -07:00
|
|
|
goto fail;
|
|
|
|
|
|
|
|
if ((buf = calloc(1, len)) == NULL)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
elm->be_val = buf;
|
|
|
|
elm->be_len = len;
|
|
|
|
elm->be_free = 1;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
if (ober_oid2ber(o, buf, len) != len)
|
2018-06-13 08:45:57 -07:00
|
|
|
goto fail;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_link_elements(prev, elm);
|
2018-06-13 08:45:57 -07:00
|
|
|
|
|
|
|
return (elm);
|
|
|
|
|
|
|
|
fail:
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_free_elements(elm);
|
2018-06-13 08:45:57 -07:00
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ber_element *
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_add_noid(struct ber_element *prev, struct ber_oid *o, int n)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
struct ber_oid no;
|
|
|
|
|
|
|
|
if (n > BER_MAX_OID_LEN)
|
|
|
|
return (NULL);
|
|
|
|
no.bo_n = n;
|
|
|
|
bcopy(&o->bo_id, &no.bo_id, sizeof(no.bo_id));
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
return (ober_add_oid(prev, &no));
|
2018-06-13 08:45:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
struct ber_element *
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_add_oidstring(struct ber_element *prev, const char *oidstr)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
struct ber_oid o;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
if (ober_string2oid(oidstr, &o) == -1)
|
2018-06-13 08:45:57 -07:00
|
|
|
return (NULL);
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
return (ober_add_oid(prev, &o));
|
2018-06-13 08:45:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_get_oid(struct ber_element *elm, struct ber_oid *o)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
u_int8_t *buf;
|
|
|
|
size_t len, i = 0, j = 0;
|
|
|
|
|
|
|
|
if (elm->be_encoding != BER_TYPE_OBJECT)
|
|
|
|
return (-1);
|
|
|
|
|
2021-02-22 09:15:02 -08:00
|
|
|
if (o == NULL)
|
|
|
|
return 0;
|
|
|
|
|
2018-06-13 08:45:57 -07:00
|
|
|
buf = elm->be_val;
|
|
|
|
len = elm->be_len;
|
|
|
|
|
|
|
|
memset(o, 0, sizeof(*o));
|
|
|
|
o->bo_id[j++] = buf[i] / 40;
|
|
|
|
o->bo_id[j++] = buf[i++] % 40;
|
|
|
|
for (; i < len && j < BER_MAX_OID_LEN; i++) {
|
|
|
|
o->bo_id[j] = (o->bo_id[j] << 7) + (buf[i] & ~0x80);
|
|
|
|
if (buf[i] & 0x80)
|
|
|
|
continue;
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
o->bo_n = j;
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2023-11-10 04:12:02 -08:00
|
|
|
#define _MAX_SEQ 128
|
2018-06-13 08:45:57 -07:00
|
|
|
struct ber_element *
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_printf_elements(struct ber_element *ber, char *fmt, ...)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
va_list ap;
|
2023-11-10 04:12:02 -08:00
|
|
|
int d, class, level = 0;
|
2018-06-13 08:45:57 -07:00
|
|
|
size_t len;
|
2018-07-31 04:02:01 -07:00
|
|
|
unsigned int type;
|
2018-06-13 08:45:57 -07:00
|
|
|
long long i;
|
|
|
|
char *s;
|
|
|
|
void *p;
|
|
|
|
struct ber_oid *o;
|
2023-11-10 04:12:02 -08:00
|
|
|
struct ber_element *parent[_MAX_SEQ], *e;
|
|
|
|
struct ber_element *origber = ber, *firstber = NULL;
|
|
|
|
|
|
|
|
memset(parent, 0, sizeof(struct ber_element *) * _MAX_SEQ);
|
2018-06-13 08:45:57 -07:00
|
|
|
|
|
|
|
va_start(ap, fmt);
|
2023-11-10 04:12:02 -08:00
|
|
|
|
2018-06-13 08:45:57 -07:00
|
|
|
while (*fmt) {
|
|
|
|
switch (*fmt++) {
|
|
|
|
case 'B':
|
|
|
|
p = va_arg(ap, void *);
|
|
|
|
len = va_arg(ap, size_t);
|
2019-10-24 05:39:26 -07:00
|
|
|
if ((ber = ober_add_bitstring(ber, p, len)) == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
goto fail;
|
|
|
|
break;
|
|
|
|
case 'b':
|
|
|
|
d = va_arg(ap, int);
|
2019-10-24 05:39:26 -07:00
|
|
|
if ((ber = ober_add_boolean(ber, d)) == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
goto fail;
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
d = va_arg(ap, int);
|
2019-10-24 05:39:26 -07:00
|
|
|
if ((ber = ober_add_integer(ber, d)) == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
goto fail;
|
|
|
|
break;
|
|
|
|
case 'e':
|
|
|
|
e = va_arg(ap, struct ber_element *);
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_link_elements(ber, e);
|
2018-06-13 08:45:57 -07:00
|
|
|
break;
|
|
|
|
case 'E':
|
|
|
|
i = va_arg(ap, long long);
|
2019-10-24 05:39:26 -07:00
|
|
|
if ((ber = ober_add_enumerated(ber, i)) == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
goto fail;
|
|
|
|
break;
|
|
|
|
case 'i':
|
|
|
|
i = va_arg(ap, long long);
|
2019-10-24 05:39:26 -07:00
|
|
|
if ((ber = ober_add_integer(ber, i)) == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
goto fail;
|
|
|
|
break;
|
|
|
|
case 'O':
|
|
|
|
o = va_arg(ap, struct ber_oid *);
|
2019-10-24 05:39:26 -07:00
|
|
|
if ((ber = ober_add_oid(ber, o)) == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
goto fail;
|
|
|
|
break;
|
|
|
|
case 'o':
|
|
|
|
s = va_arg(ap, char *);
|
2019-10-24 05:39:26 -07:00
|
|
|
if ((ber = ober_add_oidstring(ber, s)) == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
goto fail;
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
s = va_arg(ap, char *);
|
2019-10-24 05:39:26 -07:00
|
|
|
if ((ber = ober_add_string(ber, s)) == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
goto fail;
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
class = va_arg(ap, int);
|
2018-07-31 04:02:01 -07:00
|
|
|
type = va_arg(ap, unsigned int);
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_set_header(ber, class, type);
|
2018-06-13 08:45:57 -07:00
|
|
|
break;
|
|
|
|
case 'x':
|
|
|
|
s = va_arg(ap, char *);
|
|
|
|
len = va_arg(ap, size_t);
|
2019-10-24 05:39:26 -07:00
|
|
|
if ((ber = ober_add_nstring(ber, s, len)) == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
goto fail;
|
|
|
|
break;
|
|
|
|
case '0':
|
2019-10-24 05:39:26 -07:00
|
|
|
if ((ber = ober_add_null(ber)) == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
goto fail;
|
|
|
|
break;
|
|
|
|
case '{':
|
2023-11-10 04:12:02 -08:00
|
|
|
if (level >= _MAX_SEQ-1)
|
|
|
|
goto fail;
|
|
|
|
if ((ber= ober_add_sequence(ber)) == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
goto fail;
|
2023-11-10 04:12:02 -08:00
|
|
|
parent[level++] = ber;
|
2018-06-13 08:45:57 -07:00
|
|
|
break;
|
|
|
|
case '(':
|
2023-11-10 04:12:02 -08:00
|
|
|
if (level >= _MAX_SEQ-1)
|
2018-06-13 08:45:57 -07:00
|
|
|
goto fail;
|
2023-11-10 04:12:02 -08:00
|
|
|
if ((ber = ober_add_set(ber)) == NULL)
|
|
|
|
goto fail;
|
|
|
|
parent[level++] = ber;
|
2018-06-13 08:45:57 -07:00
|
|
|
break;
|
|
|
|
case '}':
|
|
|
|
case ')':
|
2023-11-10 04:12:02 -08:00
|
|
|
if (level <= 0 || parent[level - 1] == NULL)
|
|
|
|
goto fail;
|
|
|
|
ber = parent[--level];
|
2018-06-13 08:45:57 -07:00
|
|
|
break;
|
|
|
|
case '.':
|
2019-10-24 05:39:26 -07:00
|
|
|
if ((e = ober_add_eoc(ber)) == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
goto fail;
|
|
|
|
ber = e;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2023-11-10 04:12:02 -08:00
|
|
|
if (firstber == NULL)
|
|
|
|
firstber = ber;
|
2018-06-13 08:45:57 -07:00
|
|
|
}
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
return (ber);
|
|
|
|
fail:
|
2023-11-10 04:12:02 -08:00
|
|
|
if (origber != NULL)
|
|
|
|
ober_unlink_elements(origber);
|
|
|
|
ober_free_elements(firstber);
|
2018-06-13 08:45:57 -07:00
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_scanf_elements(struct ber_element *ber, char *fmt, ...)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
int *d, level = -1;
|
2018-07-31 04:02:01 -07:00
|
|
|
unsigned int *t;
|
2018-07-03 11:49:10 -07:00
|
|
|
long long *i, l;
|
2018-06-13 08:45:57 -07:00
|
|
|
void **ptr;
|
|
|
|
size_t *len, ret = 0, n = strlen(fmt);
|
|
|
|
char **s;
|
2018-07-03 11:49:10 -07:00
|
|
|
off_t *pos;
|
2018-06-13 08:45:57 -07:00
|
|
|
struct ber_oid *o;
|
|
|
|
struct ber_element *parent[_MAX_SEQ], **e;
|
|
|
|
|
|
|
|
memset(parent, 0, sizeof(struct ber_element *) * _MAX_SEQ);
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
while (*fmt) {
|
2021-01-28 11:56:33 -08:00
|
|
|
if (ber == NULL && *fmt != '$' && *fmt != '}' && *fmt != ')')
|
2019-08-13 21:48:13 -07:00
|
|
|
goto fail;
|
2018-06-13 08:45:57 -07:00
|
|
|
switch (*fmt++) {
|
2021-01-28 11:56:33 -08:00
|
|
|
case '$':
|
|
|
|
if (ber != NULL)
|
|
|
|
goto fail;
|
|
|
|
ret++;
|
|
|
|
continue;
|
2018-06-13 08:45:57 -07:00
|
|
|
case 'B':
|
|
|
|
ptr = va_arg(ap, void **);
|
|
|
|
len = va_arg(ap, size_t *);
|
2019-10-24 05:39:26 -07:00
|
|
|
if (ober_get_bitstring(ber, ptr, len) == -1)
|
2018-06-13 08:45:57 -07:00
|
|
|
goto fail;
|
|
|
|
ret++;
|
|
|
|
break;
|
|
|
|
case 'b':
|
|
|
|
d = va_arg(ap, int *);
|
2019-10-24 05:39:26 -07:00
|
|
|
if (ober_get_boolean(ber, d) == -1)
|
2018-06-13 08:45:57 -07:00
|
|
|
goto fail;
|
|
|
|
ret++;
|
|
|
|
break;
|
2018-07-03 11:49:10 -07:00
|
|
|
case 'd':
|
|
|
|
d = va_arg(ap, int *);
|
2019-10-24 05:39:26 -07:00
|
|
|
if (ober_get_integer(ber, &l) == -1)
|
2018-07-03 11:49:10 -07:00
|
|
|
goto fail;
|
2021-02-22 09:15:02 -08:00
|
|
|
if (d != NULL)
|
|
|
|
*d = l;
|
2018-07-03 11:49:10 -07:00
|
|
|
ret++;
|
|
|
|
break;
|
2018-06-13 08:45:57 -07:00
|
|
|
case 'e':
|
|
|
|
e = va_arg(ap, struct ber_element **);
|
|
|
|
*e = ber;
|
|
|
|
ret++;
|
2019-08-14 23:11:18 -07:00
|
|
|
continue;
|
2018-06-13 08:45:57 -07:00
|
|
|
case 'E':
|
|
|
|
i = va_arg(ap, long long *);
|
2019-10-24 05:39:26 -07:00
|
|
|
if (ober_get_enumerated(ber, i) == -1)
|
2018-06-13 08:45:57 -07:00
|
|
|
goto fail;
|
|
|
|
ret++;
|
|
|
|
break;
|
|
|
|
case 'i':
|
|
|
|
i = va_arg(ap, long long *);
|
2019-10-24 05:39:26 -07:00
|
|
|
if (ober_get_integer(ber, i) == -1)
|
2018-06-13 08:45:57 -07:00
|
|
|
goto fail;
|
|
|
|
ret++;
|
|
|
|
break;
|
|
|
|
case 'o':
|
|
|
|
o = va_arg(ap, struct ber_oid *);
|
2019-10-24 05:39:26 -07:00
|
|
|
if (ober_get_oid(ber, o) == -1)
|
2018-06-13 08:45:57 -07:00
|
|
|
goto fail;
|
|
|
|
ret++;
|
|
|
|
break;
|
|
|
|
case 'S':
|
|
|
|
ret++;
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
s = va_arg(ap, char **);
|
2019-10-24 05:39:26 -07:00
|
|
|
if (ober_get_string(ber, s) == -1)
|
2018-06-13 08:45:57 -07:00
|
|
|
goto fail;
|
|
|
|
ret++;
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
d = va_arg(ap, int *);
|
2018-07-31 04:02:01 -07:00
|
|
|
t = va_arg(ap, unsigned int *);
|
2021-02-22 09:15:02 -08:00
|
|
|
if (d != NULL)
|
|
|
|
*d = ber->be_class;
|
|
|
|
if (t != NULL)
|
|
|
|
*t = ber->be_type;
|
2018-06-13 08:45:57 -07:00
|
|
|
ret++;
|
|
|
|
continue;
|
|
|
|
case 'x':
|
|
|
|
ptr = va_arg(ap, void **);
|
|
|
|
len = va_arg(ap, size_t *);
|
2019-10-24 05:39:26 -07:00
|
|
|
if (ober_get_nstring(ber, ptr, len) == -1)
|
2018-06-13 08:45:57 -07:00
|
|
|
goto fail;
|
|
|
|
ret++;
|
|
|
|
break;
|
|
|
|
case '0':
|
|
|
|
if (ber->be_encoding != BER_TYPE_NULL)
|
|
|
|
goto fail;
|
|
|
|
ret++;
|
|
|
|
break;
|
|
|
|
case '.':
|
|
|
|
if (ber->be_encoding != BER_TYPE_EOC)
|
|
|
|
goto fail;
|
|
|
|
ret++;
|
|
|
|
break;
|
2018-07-03 11:49:10 -07:00
|
|
|
case 'p':
|
|
|
|
pos = va_arg(ap, off_t *);
|
2019-10-24 05:39:26 -07:00
|
|
|
*pos = ober_getpos(ber);
|
2018-07-03 11:49:10 -07:00
|
|
|
ret++;
|
|
|
|
continue;
|
2018-06-13 08:45:57 -07:00
|
|
|
case '{':
|
|
|
|
case '(':
|
|
|
|
if (ber->be_encoding != BER_TYPE_SEQUENCE &&
|
|
|
|
ber->be_encoding != BER_TYPE_SET)
|
|
|
|
goto fail;
|
2023-08-22 05:50:27 -07:00
|
|
|
if (level >= _MAX_SEQ-1)
|
2018-06-13 08:45:57 -07:00
|
|
|
goto fail;
|
|
|
|
parent[++level] = ber;
|
|
|
|
ber = ber->be_sub;
|
|
|
|
ret++;
|
|
|
|
continue;
|
|
|
|
case '}':
|
|
|
|
case ')':
|
2021-01-22 10:27:52 -08:00
|
|
|
if (level < 0 || parent[level] == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
goto fail;
|
|
|
|
ber = parent[level--];
|
|
|
|
ret++;
|
2018-06-29 08:18:03 -07:00
|
|
|
break;
|
2018-06-13 08:45:57 -07:00
|
|
|
default:
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
ber = ber->be_next;
|
|
|
|
}
|
|
|
|
va_end(ap);
|
|
|
|
return (ret == n ? 0 : -1);
|
|
|
|
|
|
|
|
fail:
|
|
|
|
va_end(ap);
|
|
|
|
return (-1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-07-31 12:38:09 -07:00
|
|
|
ssize_t
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_get_writebuf(struct ber *b, void **buf)
|
2018-07-31 12:38:09 -07:00
|
|
|
{
|
|
|
|
if (b->br_wbuf == NULL)
|
|
|
|
return -1;
|
|
|
|
*buf = b->br_wbuf;
|
|
|
|
return (b->br_wend - b->br_wbuf);
|
|
|
|
}
|
|
|
|
|
2018-06-13 08:45:57 -07:00
|
|
|
/*
|
2018-07-13 01:50:38 -07:00
|
|
|
* write ber elements to the write buffer
|
2018-06-13 08:45:57 -07:00
|
|
|
*
|
|
|
|
* params:
|
2018-07-13 01:50:38 -07:00
|
|
|
* ber holds the destination write buffer byte stream
|
2018-06-13 08:45:57 -07:00
|
|
|
* root fully populated element tree
|
|
|
|
*
|
|
|
|
* returns:
|
2018-07-04 06:31:57 -07:00
|
|
|
* >=0 number of bytes written
|
2018-06-13 08:45:57 -07:00
|
|
|
* -1 on failure and sets errno
|
|
|
|
*/
|
2018-08-12 15:04:09 -07:00
|
|
|
ssize_t
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_write_elements(struct ber *ber, struct ber_element *root)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
/* calculate length because only the definite form is required */
|
2019-10-24 05:39:26 -07:00
|
|
|
len = ober_calc_len(root);
|
2018-06-13 08:45:57 -07:00
|
|
|
DPRINTF("write ber element of %zd bytes length\n", len);
|
|
|
|
|
|
|
|
if (ber->br_wbuf != NULL && ber->br_wbuf + len > ber->br_wend) {
|
|
|
|
free(ber->br_wbuf);
|
|
|
|
ber->br_wbuf = NULL;
|
|
|
|
}
|
|
|
|
if (ber->br_wbuf == NULL) {
|
|
|
|
if ((ber->br_wbuf = malloc(len)) == NULL)
|
|
|
|
return -1;
|
|
|
|
ber->br_wend = ber->br_wbuf + len;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* reset write pointer */
|
|
|
|
ber->br_wptr = ber->br_wbuf;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
if (ober_dump_element(ber, root) == -1)
|
2018-06-13 08:45:57 -07:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
return (len);
|
|
|
|
}
|
|
|
|
|
2018-07-31 12:38:09 -07:00
|
|
|
void
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_set_readbuf(struct ber *b, void *buf, size_t len)
|
2018-07-31 12:38:09 -07:00
|
|
|
{
|
|
|
|
b->br_rbuf = b->br_rptr = buf;
|
|
|
|
b->br_rend = (u_int8_t *)buf + len;
|
|
|
|
}
|
|
|
|
|
2018-06-13 08:45:57 -07:00
|
|
|
/*
|
2018-07-13 01:50:38 -07:00
|
|
|
* read ber elements from the read buffer
|
2018-06-13 08:45:57 -07:00
|
|
|
*
|
|
|
|
* params:
|
2018-07-13 01:50:38 -07:00
|
|
|
* ber holds a fully populated read buffer byte stream
|
2018-06-13 08:45:57 -07:00
|
|
|
* root if NULL, build up an element tree from what we receive on
|
|
|
|
* the wire. If not null, use the specified encoding for the
|
|
|
|
* elements received.
|
|
|
|
*
|
|
|
|
* returns:
|
|
|
|
* !=NULL, elements read and store in the ber_element tree
|
|
|
|
* NULL, type mismatch or read error
|
|
|
|
*/
|
|
|
|
struct ber_element *
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_read_elements(struct ber *ber, struct ber_element *elm)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
struct ber_element *root = elm;
|
|
|
|
|
|
|
|
if (root == NULL) {
|
2019-10-24 05:39:26 -07:00
|
|
|
if ((root = ober_get_element(0)) == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
DPRINTF("read ber elements, root %p\n", root);
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
if (ober_read_element(ber, root) == -1) {
|
2018-06-13 08:45:57 -07:00
|
|
|
/* Cleanup if root was allocated by us */
|
|
|
|
if (elm == NULL)
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_free_elements(root);
|
2018-06-13 08:45:57 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return root;
|
|
|
|
}
|
|
|
|
|
2018-07-03 11:49:10 -07:00
|
|
|
off_t
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_getpos(struct ber_element *elm)
|
2018-07-03 11:49:10 -07:00
|
|
|
{
|
|
|
|
return elm->be_offs;
|
|
|
|
}
|
|
|
|
|
2021-08-29 06:27:11 -07:00
|
|
|
struct ber_element *
|
|
|
|
ober_dup(struct ber_element *orig)
|
|
|
|
{
|
|
|
|
struct ber_element *new;
|
|
|
|
|
|
|
|
if ((new = malloc(sizeof(*new))) == NULL)
|
|
|
|
return NULL;
|
|
|
|
memcpy(new, orig, sizeof(*new));
|
|
|
|
new->be_next = NULL;
|
|
|
|
new->be_sub = NULL;
|
|
|
|
|
|
|
|
if (orig->be_next != NULL) {
|
|
|
|
if ((new->be_next = ober_dup(orig->be_next)) == NULL)
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
if (orig->be_encoding == BER_TYPE_SEQUENCE ||
|
|
|
|
orig->be_encoding == BER_TYPE_SET) {
|
|
|
|
if (orig->be_sub != NULL) {
|
|
|
|
if ((new->be_sub = ober_dup(orig->be_sub)) == NULL)
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
} else if (orig->be_encoding == BER_TYPE_OCTETSTRING ||
|
|
|
|
orig->be_encoding == BER_TYPE_BITSTRING ||
|
|
|
|
orig->be_encoding == BER_TYPE_OBJECT) {
|
|
|
|
if (orig->be_val != NULL) {
|
|
|
|
if ((new->be_val = malloc(orig->be_len)) == NULL)
|
|
|
|
goto fail;
|
|
|
|
memcpy(new->be_val, orig->be_val, orig->be_len);
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
new->be_numeric = orig->be_numeric;
|
|
|
|
return new;
|
|
|
|
fail:
|
|
|
|
ober_free_elements(new);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-06-29 08:18:03 -07:00
|
|
|
void
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_free_element(struct ber_element *root)
|
2018-06-29 08:18:03 -07:00
|
|
|
{
|
|
|
|
if (root->be_sub && (root->be_encoding == BER_TYPE_SEQUENCE ||
|
|
|
|
root->be_encoding == BER_TYPE_SET))
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_free_elements(root->be_sub);
|
2018-06-29 08:18:03 -07:00
|
|
|
if (root->be_free && (root->be_encoding == BER_TYPE_OCTETSTRING ||
|
|
|
|
root->be_encoding == BER_TYPE_BITSTRING ||
|
|
|
|
root->be_encoding == BER_TYPE_OBJECT))
|
|
|
|
free(root->be_val);
|
|
|
|
free(root);
|
|
|
|
}
|
|
|
|
|
2018-06-13 08:45:57 -07:00
|
|
|
void
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_free_elements(struct ber_element *root)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
2018-11-19 23:20:21 -08:00
|
|
|
if (root == NULL)
|
|
|
|
return;
|
2018-06-13 08:45:57 -07:00
|
|
|
if (root->be_sub && (root->be_encoding == BER_TYPE_SEQUENCE ||
|
|
|
|
root->be_encoding == BER_TYPE_SET))
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_free_elements(root->be_sub);
|
2018-06-13 08:45:57 -07:00
|
|
|
if (root->be_next)
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_free_elements(root->be_next);
|
2018-06-13 08:45:57 -07:00
|
|
|
if (root->be_free && (root->be_encoding == BER_TYPE_OCTETSTRING ||
|
|
|
|
root->be_encoding == BER_TYPE_BITSTRING ||
|
|
|
|
root->be_encoding == BER_TYPE_OBJECT))
|
|
|
|
free(root->be_val);
|
|
|
|
free(root);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_calc_len(struct ber_element *root)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
2018-07-31 04:02:01 -07:00
|
|
|
unsigned int t;
|
2018-06-13 08:45:57 -07:00
|
|
|
size_t s;
|
|
|
|
size_t size = 2; /* minimum 1 byte head and 1 byte size */
|
|
|
|
|
|
|
|
/* calculate the real length of a sequence or set */
|
|
|
|
if (root->be_sub && (root->be_encoding == BER_TYPE_SEQUENCE ||
|
|
|
|
root->be_encoding == BER_TYPE_SET))
|
2019-10-24 05:39:26 -07:00
|
|
|
root->be_len = ober_calc_len(root->be_sub);
|
2018-06-13 08:45:57 -07:00
|
|
|
|
|
|
|
/* fix header length for extended types */
|
|
|
|
if (root->be_type > BER_TYPE_SINGLE_MAX)
|
|
|
|
for (t = root->be_type; t > 0; t >>= 7)
|
|
|
|
size++;
|
|
|
|
if (root->be_len >= BER_TAG_MORE)
|
|
|
|
for (s = root->be_len; s > 0; s >>= 8)
|
|
|
|
size++;
|
|
|
|
|
|
|
|
/* calculate the length of the following elements */
|
|
|
|
if (root->be_next)
|
2019-10-24 05:39:26 -07:00
|
|
|
size += ober_calc_len(root->be_next);
|
2018-06-13 08:45:57 -07:00
|
|
|
|
|
|
|
/* This is an empty element, do not use a minimal size */
|
2018-06-27 06:22:17 -07:00
|
|
|
if (root->be_class == BER_CLASS_UNIVERSAL &&
|
|
|
|
root->be_type == BER_TYPE_EOC && root->be_len == 0)
|
2018-06-13 08:45:57 -07:00
|
|
|
return (0);
|
|
|
|
|
|
|
|
return (root->be_len + size);
|
|
|
|
}
|
|
|
|
|
2018-07-31 12:38:09 -07:00
|
|
|
void
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_set_application(struct ber *b, unsigned int (*cb)(struct ber_element *))
|
2018-07-31 12:38:09 -07:00
|
|
|
{
|
|
|
|
b->br_application = cb;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_set_writecallback(struct ber_element *elm, void (*cb)(void *, size_t),
|
2018-07-31 12:38:09 -07:00
|
|
|
void *arg)
|
|
|
|
{
|
|
|
|
elm->be_cb = cb;
|
|
|
|
elm->be_cbarg = arg;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_free(struct ber *b)
|
2018-07-31 12:38:09 -07:00
|
|
|
{
|
|
|
|
free(b->br_wbuf);
|
|
|
|
}
|
|
|
|
|
2018-06-13 08:45:57 -07:00
|
|
|
/*
|
|
|
|
* internal functions
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_dump_element(struct ber *ber, struct ber_element *root)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
unsigned long long l;
|
|
|
|
int i;
|
|
|
|
uint8_t u;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_dump_header(ber, root);
|
2018-07-03 11:49:10 -07:00
|
|
|
if (root->be_cb)
|
|
|
|
root->be_cb(root->be_cbarg, ber->br_wptr - ber->br_wbuf);
|
2018-06-13 08:45:57 -07:00
|
|
|
|
|
|
|
switch (root->be_encoding) {
|
|
|
|
case BER_TYPE_BOOLEAN:
|
|
|
|
case BER_TYPE_INTEGER:
|
|
|
|
case BER_TYPE_ENUMERATED:
|
|
|
|
l = (unsigned long long)root->be_numeric;
|
|
|
|
for (i = root->be_len; i > 0; i--) {
|
|
|
|
u = (l >> ((i - 1) * 8)) & 0xff;
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_putc(ber, u);
|
2018-06-13 08:45:57 -07:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BER_TYPE_BITSTRING:
|
|
|
|
case BER_TYPE_OCTETSTRING:
|
|
|
|
case BER_TYPE_OBJECT:
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_write(ber, root->be_val, root->be_len);
|
2018-06-13 08:45:57 -07:00
|
|
|
break;
|
|
|
|
case BER_TYPE_NULL: /* no payload */
|
|
|
|
case BER_TYPE_EOC:
|
|
|
|
break;
|
|
|
|
case BER_TYPE_SEQUENCE:
|
|
|
|
case BER_TYPE_SET:
|
2019-10-24 05:39:26 -07:00
|
|
|
if (root->be_sub && ober_dump_element(ber, root->be_sub) == -1)
|
2018-06-13 08:45:57 -07:00
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (root->be_next == NULL)
|
|
|
|
return 0;
|
2019-10-24 05:39:26 -07:00
|
|
|
return ober_dump_element(ber, root->be_next);
|
2018-06-13 08:45:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_dump_header(struct ber *ber, struct ber_element *root)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
2018-07-31 04:02:01 -07:00
|
|
|
u_char id = 0, t, buf[5];
|
|
|
|
unsigned int type;
|
2018-06-13 08:45:57 -07:00
|
|
|
size_t size;
|
|
|
|
|
|
|
|
/* class universal, type encoding depending on type value */
|
|
|
|
/* length encoding */
|
|
|
|
if (root->be_type <= BER_TYPE_SINGLE_MAX) {
|
|
|
|
id = root->be_type | (root->be_class << BER_CLASS_SHIFT);
|
|
|
|
if (root->be_encoding == BER_TYPE_SEQUENCE ||
|
|
|
|
root->be_encoding == BER_TYPE_SET)
|
|
|
|
id |= BER_TYPE_CONSTRUCTED;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_putc(ber, id);
|
2018-06-13 08:45:57 -07:00
|
|
|
} else {
|
|
|
|
id = BER_TAG_MASK | (root->be_class << BER_CLASS_SHIFT);
|
|
|
|
if (root->be_encoding == BER_TYPE_SEQUENCE ||
|
|
|
|
root->be_encoding == BER_TYPE_SET)
|
|
|
|
id |= BER_TYPE_CONSTRUCTED;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_putc(ber, id);
|
2018-06-13 08:45:57 -07:00
|
|
|
|
|
|
|
for (t = 0, type = root->be_type; type > 0; type >>= 7)
|
|
|
|
buf[t++] = type & ~BER_TAG_MORE;
|
|
|
|
|
|
|
|
while (t-- > 0) {
|
|
|
|
if (t > 0)
|
|
|
|
buf[t] |= BER_TAG_MORE;
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_putc(ber, buf[t]);
|
2018-06-13 08:45:57 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (root->be_len < BER_TAG_MORE) {
|
|
|
|
/* short form */
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_putc(ber, root->be_len);
|
2018-06-13 08:45:57 -07:00
|
|
|
} else {
|
|
|
|
for (t = 0, size = root->be_len; size > 0; size >>= 8)
|
|
|
|
buf[t++] = size & 0xff;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_putc(ber, t | BER_TAG_MORE);
|
2018-06-13 08:45:57 -07:00
|
|
|
|
|
|
|
while (t > 0)
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_putc(ber, buf[--t]);
|
2018-06-13 08:45:57 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_putc(struct ber *ber, u_char c)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
if (ber->br_wptr + 1 <= ber->br_wend)
|
|
|
|
*ber->br_wptr = c;
|
|
|
|
ber->br_wptr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_write(struct ber *ber, void *buf, size_t len)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
if (ber->br_wptr + len <= ber->br_wend)
|
|
|
|
bcopy(buf, ber->br_wptr, len);
|
|
|
|
ber->br_wptr += len;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* extract a BER encoded tag. There are two types, a short and long form.
|
|
|
|
*/
|
|
|
|
static ssize_t
|
2018-07-31 04:02:01 -07:00
|
|
|
get_id(struct ber *b, unsigned int *tag, int *class, int *cstruct)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
u_char u;
|
|
|
|
size_t i = 0;
|
2018-07-31 04:02:01 -07:00
|
|
|
unsigned int t = 0;
|
2018-06-13 08:45:57 -07:00
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
if (ober_getc(b, &u) == -1)
|
2018-06-13 08:45:57 -07:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
*class = (u >> BER_CLASS_SHIFT) & BER_CLASS_MASK;
|
|
|
|
*cstruct = (u & BER_TYPE_CONSTRUCTED) == BER_TYPE_CONSTRUCTED;
|
|
|
|
|
|
|
|
if ((u & BER_TAG_MASK) != BER_TAG_MASK) {
|
|
|
|
*tag = u & BER_TAG_MASK;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
2019-10-24 05:39:26 -07:00
|
|
|
if (ober_getc(b, &u) == -1)
|
2018-06-13 08:45:57 -07:00
|
|
|
return -1;
|
2019-05-12 10:50:32 -07:00
|
|
|
|
|
|
|
/* enforce minimal number of octets for tag > 30 */
|
|
|
|
if (i == 0 && (u & ~BER_TAG_MORE) == 0) {
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-06-13 08:45:57 -07:00
|
|
|
t = (t << 7) | (u & ~BER_TAG_MORE);
|
|
|
|
i++;
|
2018-07-31 04:02:01 -07:00
|
|
|
if (i > sizeof(unsigned int)) {
|
2018-07-13 01:30:10 -07:00
|
|
|
errno = ERANGE;
|
|
|
|
return -1;
|
|
|
|
}
|
2018-06-13 08:45:57 -07:00
|
|
|
} while (u & BER_TAG_MORE);
|
|
|
|
|
|
|
|
*tag = t;
|
|
|
|
return i + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* extract length of a ber object -- if length is unknown an error is returned.
|
|
|
|
*/
|
|
|
|
static ssize_t
|
|
|
|
get_len(struct ber *b, ssize_t *len)
|
|
|
|
{
|
|
|
|
u_char u, n;
|
|
|
|
ssize_t s, r;
|
|
|
|
|
2019-10-24 05:39:26 -07:00
|
|
|
if (ober_getc(b, &u) == -1)
|
2018-06-13 08:45:57 -07:00
|
|
|
return -1;
|
|
|
|
if ((u & BER_TAG_MORE) == 0) {
|
|
|
|
/* short form */
|
|
|
|
*len = u;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-06-29 08:18:03 -07:00
|
|
|
if (u == 0x80) {
|
|
|
|
/* Indefinite length not supported. */
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-05-12 10:42:14 -07:00
|
|
|
if (u == 0xff) {
|
|
|
|
/* Reserved for future use. */
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-06-13 08:45:57 -07:00
|
|
|
n = u & ~BER_TAG_MORE;
|
2019-06-01 12:40:05 -07:00
|
|
|
/*
|
|
|
|
* Limit to a decent size that works on all of our architectures.
|
|
|
|
*/
|
|
|
|
if (sizeof(int32_t) < n) {
|
2018-06-13 08:45:57 -07:00
|
|
|
errno = ERANGE;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
r = n + 1;
|
|
|
|
|
|
|
|
for (s = 0; n > 0; n--) {
|
2019-10-24 05:39:26 -07:00
|
|
|
if (ober_getc(b, &u) == -1)
|
2018-06-13 08:45:57 -07:00
|
|
|
return -1;
|
|
|
|
s = (s << 8) | u;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s < 0) {
|
|
|
|
/* overflow */
|
|
|
|
errno = ERANGE;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*len = s;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_read_element(struct ber *ber, struct ber_element *elm)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
|
|
|
long long val = 0;
|
|
|
|
struct ber_element *next;
|
2018-07-31 04:02:01 -07:00
|
|
|
unsigned int type;
|
2018-08-02 18:51:28 -07:00
|
|
|
int i, class, cstruct, elements = 0;
|
2018-06-13 08:45:57 -07:00
|
|
|
ssize_t len, r, totlen = 0;
|
2019-05-12 13:13:08 -07:00
|
|
|
u_char c, last = 0;
|
2018-06-13 08:45:57 -07:00
|
|
|
|
|
|
|
if ((r = get_id(ber, &type, &class, &cstruct)) == -1)
|
|
|
|
return -1;
|
2018-07-31 04:37:18 -07:00
|
|
|
DPRINTF("ber read got class %d type %u, %s\n",
|
2018-07-01 13:03:48 -07:00
|
|
|
class, type, cstruct ? "constructed" : "primitive");
|
2018-06-13 08:45:57 -07:00
|
|
|
totlen += r;
|
|
|
|
if ((r = get_len(ber, &len)) == -1)
|
|
|
|
return -1;
|
|
|
|
DPRINTF("ber read element size %zd\n", len);
|
|
|
|
totlen += r + len;
|
|
|
|
|
2019-05-12 11:11:51 -07:00
|
|
|
/* The encoding of boolean, integer, enumerated, and null values
|
|
|
|
* must be primitive. */
|
|
|
|
if (class == BER_CLASS_UNIVERSAL)
|
|
|
|
if (type == BER_TYPE_BOOLEAN ||
|
|
|
|
type == BER_TYPE_INTEGER ||
|
|
|
|
type == BER_TYPE_ENUMERATED ||
|
|
|
|
type == BER_TYPE_NULL)
|
|
|
|
if (cstruct) {
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-06-27 13:38:10 -07:00
|
|
|
/* If the total size of the element is larger than the buffer
|
|
|
|
* don't bother to continue. */
|
2018-06-13 08:45:57 -07:00
|
|
|
if (len > ber->br_rend - ber->br_rptr) {
|
|
|
|
errno = ECANCELED;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
elm->be_type = type;
|
|
|
|
elm->be_len = len;
|
2018-07-03 11:49:10 -07:00
|
|
|
elm->be_offs = ber->br_offs; /* element position within stream */
|
2018-06-13 08:45:57 -07:00
|
|
|
elm->be_class = class;
|
|
|
|
|
|
|
|
if (elm->be_encoding == 0) {
|
|
|
|
/* try to figure out the encoding via class, type and cstruct */
|
|
|
|
if (cstruct)
|
|
|
|
elm->be_encoding = BER_TYPE_SEQUENCE;
|
|
|
|
else if (class == BER_CLASS_UNIVERSAL)
|
|
|
|
elm->be_encoding = type;
|
|
|
|
else if (ber->br_application != NULL) {
|
|
|
|
/*
|
|
|
|
* Ask the application to map the encoding to a
|
|
|
|
* universal type. For example, a SMI IpAddress
|
|
|
|
* type is defined as 4 byte OCTET STRING.
|
|
|
|
*/
|
|
|
|
elm->be_encoding = (*ber->br_application)(elm);
|
|
|
|
} else
|
|
|
|
/* last resort option */
|
|
|
|
elm->be_encoding = BER_TYPE_NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (elm->be_encoding) {
|
|
|
|
case BER_TYPE_EOC: /* End-Of-Content */
|
|
|
|
break;
|
|
|
|
case BER_TYPE_BOOLEAN:
|
2019-05-12 11:11:51 -07:00
|
|
|
if (len != 1) {
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
2018-06-13 08:45:57 -07:00
|
|
|
case BER_TYPE_INTEGER:
|
|
|
|
case BER_TYPE_ENUMERATED:
|
2021-01-21 19:20:56 -08:00
|
|
|
if (len < 1) {
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
2020-09-03 12:09:57 -07:00
|
|
|
if (len > (ssize_t)sizeof(long long)) {
|
|
|
|
errno = ERANGE;
|
2018-06-13 08:45:57 -07:00
|
|
|
return -1;
|
2020-09-03 12:09:57 -07:00
|
|
|
}
|
2018-06-13 08:45:57 -07:00
|
|
|
for (i = 0; i < len; i++) {
|
2019-10-24 05:39:26 -07:00
|
|
|
if (ober_getc(ber, &c) != 1)
|
2018-06-13 08:45:57 -07:00
|
|
|
return -1;
|
2019-05-12 13:13:08 -07:00
|
|
|
|
|
|
|
/* smallest number of contents octets only */
|
2019-05-21 06:29:44 -07:00
|
|
|
if ((i == 1 && last == 0 && (c & 0x80) == 0) ||
|
2020-09-03 10:01:15 -07:00
|
|
|
(i == 1 && last == 0xff && (c & 0x80) != 0)) {
|
|
|
|
errno = EINVAL;
|
2019-05-12 13:13:08 -07:00
|
|
|
return -1;
|
2020-09-03 10:01:15 -07:00
|
|
|
}
|
2019-05-12 13:13:08 -07:00
|
|
|
|
2018-06-13 08:45:57 -07:00
|
|
|
val <<= 8;
|
|
|
|
val |= c;
|
2019-05-12 13:13:08 -07:00
|
|
|
last = c;
|
2018-06-13 08:45:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* sign extend if MSB is set */
|
2019-04-27 07:58:14 -07:00
|
|
|
if (len < (ssize_t)sizeof(long long) &&
|
|
|
|
(val >> ((len - 1) * 8) & 0x80))
|
|
|
|
val |= ULLONG_MAX << (len * 8);
|
2018-06-13 08:45:57 -07:00
|
|
|
elm->be_numeric = val;
|
|
|
|
break;
|
|
|
|
case BER_TYPE_BITSTRING:
|
|
|
|
elm->be_val = malloc(len);
|
|
|
|
if (elm->be_val == NULL)
|
|
|
|
return -1;
|
|
|
|
elm->be_free = 1;
|
|
|
|
elm->be_len = len;
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_read(ber, elm->be_val, len);
|
2018-06-13 08:45:57 -07:00
|
|
|
break;
|
|
|
|
case BER_TYPE_OCTETSTRING:
|
|
|
|
case BER_TYPE_OBJECT:
|
|
|
|
elm->be_val = malloc(len + 1);
|
|
|
|
if (elm->be_val == NULL)
|
|
|
|
return -1;
|
|
|
|
elm->be_free = 1;
|
|
|
|
elm->be_len = len;
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_read(ber, elm->be_val, len);
|
2018-06-13 08:45:57 -07:00
|
|
|
((u_char *)elm->be_val)[len] = '\0';
|
|
|
|
break;
|
|
|
|
case BER_TYPE_NULL: /* no payload */
|
2020-09-03 10:01:15 -07:00
|
|
|
if (len != 0) {
|
|
|
|
errno = EINVAL;
|
2018-06-13 08:45:57 -07:00
|
|
|
return -1;
|
2020-09-03 10:01:15 -07:00
|
|
|
}
|
2018-06-13 08:45:57 -07:00
|
|
|
break;
|
|
|
|
case BER_TYPE_SEQUENCE:
|
|
|
|
case BER_TYPE_SET:
|
2022-11-03 10:58:10 -07:00
|
|
|
if (len > 0 && elm->be_sub == NULL) {
|
2019-10-24 05:39:26 -07:00
|
|
|
if ((elm->be_sub = ober_get_element(0)) == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
next = elm->be_sub;
|
|
|
|
while (len > 0) {
|
2018-08-02 18:51:28 -07:00
|
|
|
/*
|
|
|
|
* Prevent stack overflow from excessive recursion
|
2019-10-24 05:39:26 -07:00
|
|
|
* depth in ober_free_elements().
|
2018-08-02 18:51:28 -07:00
|
|
|
*/
|
|
|
|
if (elements >= BER_MAX_SEQ_ELEMENTS) {
|
|
|
|
errno = ERANGE;
|
|
|
|
return -1;
|
|
|
|
}
|
2019-10-24 05:39:26 -07:00
|
|
|
r = ober_read_element(ber, next);
|
2022-11-03 10:58:10 -07:00
|
|
|
if (r == -1) {
|
|
|
|
/* sub-element overflows sequence/set */
|
|
|
|
if (errno == ECANCELED)
|
|
|
|
errno = EINVAL;
|
2018-06-13 08:45:57 -07:00
|
|
|
return -1;
|
2022-11-03 10:58:10 -07:00
|
|
|
}
|
|
|
|
if (r > len) {
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
2018-08-02 18:51:28 -07:00
|
|
|
elements++;
|
2018-06-13 08:45:57 -07:00
|
|
|
len -= r;
|
|
|
|
if (len > 0 && next->be_next == NULL) {
|
2022-11-03 10:58:10 -07:00
|
|
|
next->be_next = ober_get_element(0);
|
|
|
|
if (next->be_next == NULL)
|
2018-06-13 08:45:57 -07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
next = next->be_next;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return totlen;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_getc(struct ber *b, u_char *c)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
2019-10-24 05:39:26 -07:00
|
|
|
return ober_read(b, c, 1);
|
2018-06-13 08:45:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t
|
2019-10-24 05:39:26 -07:00
|
|
|
ober_read(struct ber *ber, void *buf, size_t len)
|
2018-06-13 08:45:57 -07:00
|
|
|
{
|
2018-07-09 02:21:26 -07:00
|
|
|
size_t sz;
|
2018-06-13 08:45:57 -07:00
|
|
|
|
2020-09-03 10:01:15 -07:00
|
|
|
if (ber->br_rbuf == NULL) {
|
|
|
|
errno = ENOBUFS;
|
2018-07-09 02:21:26 -07:00
|
|
|
return -1;
|
2020-09-03 10:01:15 -07:00
|
|
|
}
|
2018-07-09 02:21:26 -07:00
|
|
|
|
|
|
|
sz = ber->br_rend - ber->br_rptr;
|
|
|
|
if (len > sz) {
|
|
|
|
errno = ECANCELED;
|
|
|
|
return -1; /* parser wants more data than available */
|
2018-06-13 08:45:57 -07:00
|
|
|
}
|
2018-07-09 02:21:26 -07:00
|
|
|
|
|
|
|
bcopy(ber->br_rptr, buf, len);
|
|
|
|
ber->br_rptr += len;
|
|
|
|
ber->br_offs += len;
|
|
|
|
|
|
|
|
return len;
|
2018-07-03 11:49:10 -07:00
|
|
|
}
|