Commit ba45095c authored by Richard Mudgett's avatar Richard Mudgett

ROSE ASN.1 facility encode and decode rewrite of existing messages.

Several components are now parsed correctly.  Most notably:
PartyNumber and Q.SIG Name.


git-svn-id: https://origsvn.digium.com/svn/libpri/branches/1.4@766 2fbb986a-6c06-0410-b554-c9c1f0a7f128
parent 18fa4716
......@@ -41,8 +41,42 @@ SONAME:=1.4
STATIC_LIBRARY=libpri.a
DYNAMIC_LIBRARY:=libpri.so.$(SONAME)
STATIC_OBJS=copy_string.o pri.o q921.o prisched.o q931.o pri_facility.o version.o
DYNAMIC_OBJS=copy_string.lo pri.lo q921.lo prisched.lo q931.lo pri_facility.lo version.lo
STATIC_OBJS= \
copy_string.o \
pri.o \
q921.o \
prisched.o \
q931.o \
pri_facility.o \
asn1_primitive.o \
rose.o \
rose_address.o \
rose_etsi_aoc.o \
rose_other.o \
rose_q931.o \
rose_qsig_ct.o \
rose_qsig_diversion.o \
rose_qsig_mwi.o \
rose_qsig_name.o \
version.o
DYNAMIC_OBJS= \
copy_string.lo \
pri.lo \
q921.lo \
prisched.lo \
q931.lo \
pri_facility.lo \
asn1_primitive.lo \
rose.lo \
rose_address.lo \
rose_etsi_aoc.lo \
rose_other.lo \
rose_q931.lo \
rose_qsig_ct.lo \
rose_qsig_diversion.lo \
rose_qsig_mwi.lo \
rose_qsig_name.lo \
version.lo
CFLAGS=-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -g -fPIC $(ALERTING) $(LIBPRI_COUNTERS)
INSTALL_PREFIX=$(DESTDIR)
INSTALL_BASE=/usr
......@@ -132,6 +166,9 @@ testprilib: testprilib.o
pridump: pridump.o
$(CC) -o pridump pridump.o -L. -lpri $(CFLAGS)
rosetest: rosetest.o
$(CC) -o rosetest rosetest.o -L. -lpri $(CFLAGS)
MAKE_DEPS= -MD -MT $@ -MF .$(subst /,_,$@).d -MP
%.o: %.c
......
/*
* libpri: An implementation of Primary Rate ISDN
*
* Copyright (C) 2009 Digium, Inc.
*
* Richard Mudgett <rmudgett@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2 as published by the
* Free Software Foundation. See the LICENSE file included with
* this program for more details.
*
* In addition, when this program is distributed with Asterisk in
* any form that would qualify as a 'combined work' or as a
* 'derivative work' (but not mere aggregation), you can redistribute
* and/or modify the combination under the terms of the license
* provided with that copy of Asterisk, instead of the license
* terms granted here.
*/
/*!
* \file
* \brief ASN.1 definitions and prototypes
*
* \details
* This file contains all ASN.1 primitive data structures and
* definitions needed for ROSE component encoding and decoding.
*
* ROSE - Remote Operations Service Element
* ASN.1 - Abstract Syntax Notation 1
* APDU - Application Protocol Data Unit
*
* \author Richard Mudgett <rmudgett@digium.com>
*/
#ifndef _LIBPRI_ASN1_H
#define _LIBPRI_ASN1_H
#include <string.h>
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/* ------------------------------------------------------------------- */
/*! ASN.1 Identifier Octet - Tag class bits */
#define ASN1_CLASS_MASK 0xc0
#define ASN1_CLASS_UNIVERSAL 0x00 /*!< Universal primitive data types */
#define ASN1_CLASS_APPLICATION 0x40 /*!< Application wide data tag */
#define ASN1_CLASS_CONTEXT_SPECIFIC 0x80 /*!< Context specifc data tag */
#define ASN1_CLASS_PRIVATE 0xc0 /*!< Private organization data tag */
/*! ASN.1 Identifier Octet - Primitive/Constructor bit */
#define ASN1_PC_MASK 0x20
#define ASN1_PC_PRIMITIVE 0x00
#define ASN1_PC_CONSTRUCTED 0x20
/*! ASN.1 Identifier Octet - Universal data types */
#define ASN1_TYPE_MASK 0x1f
#define ASN1_TYPE_INDEF_TERM 0x00 /* 0 */
#define ASN1_TYPE_BOOLEAN 0x01 /* 1 */
#define ASN1_TYPE_INTEGER 0x02 /* 2 */
#define ASN1_TYPE_BIT_STRING 0x03 /* 3 */
#define ASN1_TYPE_OCTET_STRING 0x04 /* 4 */
#define ASN1_TYPE_NULL 0x05 /* 5 */
#define ASN1_TYPE_OBJECT_IDENTIFIER 0x06 /* 6 */
#define ASN1_TYPE_OBJECT_DESCRIPTOR 0x07 /* 7 */
#define ASN1_TYPE_EXTERN 0x08 /* 8 */
#define ASN1_TYPE_REAL 0x09 /* 9 */
#define ASN1_TYPE_ENUMERATED 0x0a /* 10 */
#define ASN1_TYPE_EMBEDDED_PDV 0x0b /* 11 */
#define ASN1_TYPE_UTF8_STRING 0x0c /* 12 */
#define ASN1_TYPE_RELATIVE_OID 0x0d /* 13 */
/* 0x0e & 0x0f are reserved for future ASN.1 editions */
#define ASN1_TYPE_SEQUENCE 0x10 /* 16 */
#define ASN1_TYPE_SET 0x11 /* 17 */
#define ASN1_TYPE_NUMERIC_STRING 0x12 /* 18 */
#define ASN1_TYPE_PRINTABLE_STRING 0x13 /* 19 */
#define ASN1_TYPE_TELETEX_STRING 0x14 /* 20 */
#define ASN1_TYPE_VIDEOTEX_STRING 0x15 /* 21 */
#define ASN1_TYPE_IA5_STRING 0x16 /* 22 */
#define ASN1_TYPE_UTC_TIME 0x17 /* 23 */
#define ASN1_TYPE_GENERALIZED_TIME 0x18 /* 24 */
#define ASN1_TYPE_GRAPHIC_STRING 0x19 /* 25 */
#define ASN1_TYPE_VISIBLE_STRING 0x1a /* 26 */
#define ASN1_TYPE_ISO646_STRING 0x1a /* 26 */
#define ASN1_TYPE_GENERAL_STRING 0x1b /* 27 */
#define ASN1_TYPE_UNIVERSAL_STRING 0x1c /* 28 */
#define ASN1_TYPE_CHAR_STRING 0x1d /* 29 */
#define ASN1_TYPE_BMP_STRING 0x1e /* 30 */
#define ASN1_TYPE_EXTENSION 0x1f /* 31 */
#define ASN1_TAG_SEQUENCE (ASN1_CLASS_UNIVERSAL | ASN1_PC_CONSTRUCTED | ASN1_TYPE_SEQUENCE)
#define ASN1_TAG_SET (ASN1_CLASS_UNIVERSAL | ASN1_PC_CONSTRUCTED | ASN1_TYPE_SET)
#define ASN1_INDEF_TERM (ASN1_CLASS_UNIVERSAL | ASN1_PC_PRIMITIVE | ASN1_TYPE_INDEF_TERM)
#define ASN1_INDEF_TERM_LEN 2
struct asn1_oid {
/*! \brief Number of subidentifier values in OID list */
u_int16_t num_values;
/*!
* \brief OID subidentifier value list
* \note The first value is really the first two OID subidentifiers.
* They are compressed using this formula:
* First_Value = (First_Subidentifier * 40) + Second_Subidentifier
*/
u_int16_t value[10];
};
#define ASN1_CALL(new_pos, do_it) \
do \
{ \
(new_pos) = (do_it); \
if (!(new_pos)) { \
return NULL; \
} \
} while (0)
/*! \brief Determine the ending position of the set or sequence to verify the length. */
#define ASN1_END_SETUP(component_end, offset, length, pos, end) \
do { \
if ((length) < 0) { \
(offset) = ASN1_INDEF_TERM_LEN; \
(component_end) = (end); \
} else { \
(offset) = 0; \
(component_end) = (pos) + (length); \
} \
} while (0)
/*! \brief Account for the indefinite length terminator of the set or sequence. */
#define ASN1_END_FIXUP(ctrl, pos, offset, component_end, end) \
do { \
if (offset) { \
ASN1_CALL((pos), asn1_dec_indef_end_fixup((ctrl), (pos), (end))); \
} else if ((pos) != (component_end)) { \
if ((ctrl)->debug & PRI_DEBUG_APDU) { \
pri_message((ctrl), \
" Skipping unused constructed component octets!\n"); \
} \
(pos) = (component_end); \
} \
} while (0)
#define ASN1_DID_NOT_EXPECT_TAG(ctrl, tag) \
do { \
if ((ctrl)->debug & PRI_DEBUG_APDU) { \
pri_message((ctrl), " Did not expect: %s\n", asn1_tag2str(tag)); \
} \
} while (0)
#define ASN1_CHECK_TAG(ctrl, actual_tag, match_tag, expected_tag) \
do { \
if ((match_tag) != (expected_tag)) { \
ASN1_DID_NOT_EXPECT_TAG((ctrl), (actual_tag)); \
return NULL; \
} \
} while (0)
const unsigned char *asn1_dec_tag(const unsigned char *tag_pos, const unsigned char *end,
unsigned *tag);
const unsigned char *asn1_dec_length(const unsigned char *len_pos,
const unsigned char *end, int *length);
const unsigned char *asn1_dec_indef_end_fixup(struct pri *ctrl, const unsigned char *pos,
const unsigned char *end);
const unsigned char *asn1_dec_boolean(struct pri *ctrl, const char *name, unsigned tag,
const unsigned char *pos, const unsigned char *end, int32_t *value);
const unsigned char *asn1_dec_int(struct pri *ctrl, const char *name, unsigned tag,
const unsigned char *pos, const unsigned char *end, int32_t *value);
const unsigned char *asn1_dec_null(struct pri *ctrl, const char *name, unsigned tag,
const unsigned char *pos, const unsigned char *end);
const unsigned char *asn1_dec_oid(struct pri *ctrl, const char *name, unsigned tag,
const unsigned char *pos, const unsigned char *end, struct asn1_oid *oid);
const unsigned char *asn1_dec_string_bin(struct pri *ctrl, const char *name,
unsigned tag, const unsigned char *pos, const unsigned char *end, size_t buf_size,
unsigned char *str, size_t *str_len);
const unsigned char *asn1_dec_string_max(struct pri *ctrl, const char *name,
unsigned tag, const unsigned char *pos, const unsigned char *end, size_t buf_size,
unsigned char *str, size_t *str_len);
const char *asn1_tag2str(unsigned tag);
void asn1_dump(struct pri *ctrl, const unsigned char *start_asn1,
const unsigned char *end);
#define ASN1_LEN_FORM_SHORT 1 /*!< Hint that the final length will be less than 128 octets */
#define ASN1_LEN_FORM_LONG_U8 2 /*!< Hint that the final length will be less than 256 octets */
#define ASN1_LEN_FORM_LONG_U16 3 /*!< Hint that the final length will be less than 65536 octets */
#define ASN1_LEN_INIT(len_pos, end, form_hint) \
do { \
if ((end) < (len_pos) + (form_hint)) { \
return NULL; \
} \
*(len_pos) = (form_hint); \
(len_pos) += (form_hint); \
} while (0)
#define ASN1_LEN_FIXUP(len_pos, component_end, end) \
ASN1_CALL((component_end), asn1_enc_length_fixup((len_pos), (component_end), (end)))
/*! \brief Use to begin encoding explicit tags, SET, and SEQUENCE constructed groupings. */
#define ASN1_CONSTRUCTED_BEGIN(len_pos_save, pos, end, tag) \
do { \
if ((end) < (pos) + (1 + ASN1_LEN_FORM_SHORT)) { \
return NULL; \
} \
*(pos)++ = (tag) | ASN1_PC_CONSTRUCTED; \
(len_pos_save) = (pos); \
*(pos) = ASN1_LEN_FORM_SHORT; \
(pos) += ASN1_LEN_FORM_SHORT; \
} while (0)
/*! \brief Use to end encoding explicit tags, SET, and SEQUENCE constructed groupings. */
#define ASN1_CONSTRUCTED_END(len_pos, component_end, end) \
ASN1_CALL((component_end), asn1_enc_length_fixup((len_pos), (component_end), (end)))
#define ASN1_ENC_ERROR(ctrl, msg) \
pri_error((ctrl), "%s error: %s\n", __FUNCTION__, (msg))
unsigned char *asn1_enc_length(unsigned char *len_pos, unsigned char *end,
size_t str_len);
unsigned char *asn1_enc_length_fixup(unsigned char *len_pos,
unsigned char *component_end, unsigned char *end);
unsigned char *asn1_enc_boolean(unsigned char *pos, unsigned char *end, unsigned tag,
int32_t value);
unsigned char *asn1_enc_int(unsigned char *pos, unsigned char *end, unsigned tag,
int32_t value);
unsigned char *asn1_enc_null(unsigned char *pos, unsigned char *end, unsigned tag);
unsigned char *asn1_enc_oid(unsigned char *pos, unsigned char *end, unsigned tag,
const struct asn1_oid *oid);
unsigned char *asn1_enc_string_bin(unsigned char *pos, unsigned char *end, unsigned tag,
const unsigned char *str, size_t str_len);
unsigned char *asn1_enc_string_max(unsigned char *pos, unsigned char *end, unsigned tag,
const unsigned char *str, size_t max_len);
/* ------------------------------------------------------------------- */
#ifdef __cplusplus
}
#endif
#endif /* _LIBPRI_ASN1_H */
/* ------------------------------------------------------------------- */
/* end asn1.h */
/*
* libpri: An implementation of Primary Rate ISDN
*
* Copyright (C) 2009 Digium, Inc.
*
* Richard Mudgett <rmudgett@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2 as published by the
* Free Software Foundation. See the LICENSE file included with
* this program for more details.
*
* In addition, when this program is distributed with Asterisk in
* any form that would qualify as a 'combined work' or as a
* 'derivative work' (but not mere aggregation), you can redistribute
* and/or modify the combination under the terms of the license
* provided with that copy of Asterisk, instead of the license
* terms granted here.
*/
/*!
* \file
* \brief ASN.1 BER encode/decode primitives
*
* \author Richard Mudgett <rmudgett@digium.com>
*/
#include <stdio.h>
#include "compat.h"
#include "libpri.h"
#include "pri_internal.h"
#include "asn1.h"
/* ------------------------------------------------------------------- */
/*!
* \internal
* \brief Dump the memory contents indicated.
*
* \param ctrl D channel controller for any diagnostic messages.
* \param indent Number of spaces to indent for each new memory dump line.
* \param pos Dump memory starting position.
* \param length Number of bytes to dump.
*
* \return Nothing
*/
static void asn1_dump_mem(struct pri *ctrl, unsigned indent, const unsigned char *pos,
unsigned length)
{
const unsigned char *end;
unsigned delimiter;
unsigned count;
end = pos + length;
if (pos < end) {
delimiter = '<';
for (;;) {
pri_message(ctrl, "%*s", indent, "");
for (count = 0; count++ < 16 && pos < end;) {
pri_message(ctrl, "%c%02X", delimiter, *pos++);
delimiter = (count == 8) ? '-' : ' ';
}
if (end <= pos) {
break;
}
pri_message(ctrl, "\n");
}
} else {
pri_message(ctrl, "%*s<", indent, "");
}
pri_message(ctrl, ">\n");
}
/*!
* \brief Convert the given tag value to a descriptive string.
*
* \param tag Component tag value to convert to a string.
*
* \return Converted tag string.
*/
const char *asn1_tag2str(unsigned tag)
{
static const char *primitives[32] = {
[ASN1_TYPE_INDEF_TERM] = "Indefinite length terminator",
[ASN1_TYPE_BOOLEAN] = "Boolean",
[ASN1_TYPE_INTEGER] = "Integer",
[ASN1_TYPE_BIT_STRING] = "Bit String",
[ASN1_TYPE_OCTET_STRING] = "Octet String",
[ASN1_TYPE_NULL] = "NULL",
[ASN1_TYPE_OBJECT_IDENTIFIER] = "OID",
[ASN1_TYPE_OBJECT_DESCRIPTOR] = "Object Descriptor",
[ASN1_TYPE_EXTERN] = "External",
[ASN1_TYPE_REAL] = "Real",
[ASN1_TYPE_ENUMERATED] = "Enumerated",
[ASN1_TYPE_EMBEDDED_PDV] = "Embedded PDV",
[ASN1_TYPE_UTF8_STRING] = "UTF8 String",
[ASN1_TYPE_RELATIVE_OID] = "Relative OID",
[ASN1_TYPE_SEQUENCE] = "Sequence",
[ASN1_TYPE_SET] = "Set",
[ASN1_TYPE_NUMERIC_STRING] = "Numeric String",
[ASN1_TYPE_PRINTABLE_STRING] = "Printable String",
[ASN1_TYPE_TELETEX_STRING] = "Teletex String",
[ASN1_TYPE_VIDEOTEX_STRING] = "Videotex String",
[ASN1_TYPE_IA5_STRING] = "IA5 String",
[ASN1_TYPE_UTC_TIME] = "UTC Time",
[ASN1_TYPE_GENERALIZED_TIME] = "Generalized Time",
[ASN1_TYPE_GRAPHIC_STRING] = "Graphic String",
[ASN1_TYPE_VISIBLE_STRING] = "Visible/ISO646 String",
[ASN1_TYPE_GENERAL_STRING] = "General String",
[ASN1_TYPE_UNIVERSAL_STRING] = "Universal String",
[ASN1_TYPE_CHAR_STRING] = "Character String",
[ASN1_TYPE_BMP_STRING] = "BMP String",
[ASN1_TYPE_EXTENSION] = "Type Extension",
};
static char buf[64];
const char *description;
unsigned asn1_constructed; /*! TRUE if the tag is constructed. */
unsigned asn1_type;
asn1_constructed = ((tag & ASN1_PC_MASK) == ASN1_PC_CONSTRUCTED);
asn1_type = tag & ASN1_TYPE_MASK;
switch (tag & ASN1_CLASS_MASK) {
case ASN1_CLASS_UNIVERSAL:
if (tag == (ASN1_CLASS_UNIVERSAL | ASN1_PC_CONSTRUCTED | ASN1_TYPE_INDEF_TERM)) {
description = NULL;
} else {
description = primitives[asn1_type];
}
if (!description) {
description = "Reserved";
}
snprintf(buf, sizeof(buf), "%s%s(%u 0x%02X)", description,
asn1_constructed ? "/C" : "", tag, tag);
return buf;
case ASN1_CLASS_APPLICATION:
description = "Application";
break;
case ASN1_CLASS_CONTEXT_SPECIFIC:
description = "Context Specific";
break;
case ASN1_CLASS_PRIVATE:
description = "Private";
break;
default:
snprintf(buf, sizeof(buf), "Unknown tag (%u 0x%02X)", tag, tag);
return buf;
}
snprintf(buf, sizeof(buf), "%s%s [%u 0x%02X]", description,
asn1_constructed ? "/C" : "", asn1_type, asn1_type);
return buf;
}
/*!
* \brief Decode the ASN.1 tag value.
*
* \param tag_pos ASN.1 tag starting position.
* \param end End of ASN.1 encoded data buffer.
* \param tag Decoded tag value returned on success.
*
* \retval Next octet after the tag on success.
* \retval NULL on error.
*/
const unsigned char *asn1_dec_tag(const unsigned char *tag_pos, const unsigned char *end,
unsigned *tag)
{
unsigned extended_tag;
if (end <= tag_pos) {
return NULL;
}
*tag = *tag_pos++;
if ((*tag & ASN1_TYPE_MASK) == ASN1_TYPE_EXTENSION) {
/* Extract the extended tag value */
extended_tag = 0;
do {
if (end <= tag_pos) {
return NULL;
}
extended_tag <<= 7;
extended_tag |= *tag_pos & ~0x80;
} while (*tag_pos++ & 0x80);
if (extended_tag && extended_tag < ASN1_TYPE_EXTENSION) {
/*
* The sender did not need to use the extended format.
* This is an encoding error on their part, but we will
* accept it anyway.
*
* Note we cannot return a null tag value from this path.
* We would misinterpret the indefinite length
* terminator.
*/
*tag &= ~ASN1_TYPE_MASK;
*tag |= extended_tag;
}
}
return tag_pos;
}
/*!
* \brief Decode the length of an ASN.1 component length.
*
* \param len_pos Starting position of the ASN.1 component length.
* \param end End of ASN.1 decoding data buffer.
* \param length Decoded length value returned on success. (-1 if indefinite)
*
* \retval Next octet after the length on success.
* \retval NULL on error.
*
* \note The decoded length is checked to see if there is enough buffer
* left for the component body.
*/
const unsigned char *asn1_dec_length(const unsigned char *len_pos,
const unsigned char *end, int *length)
{
unsigned length_size;
if (end <= len_pos) {
/* Not enough buffer to determine how the length is encoded */
return NULL;
}
if (*len_pos < 0x80) {
/* Short length encoding */
*length = *len_pos++;
} else if (*len_pos == 0x80) {
/* Indefinite length encoding */
*length = -1;
++len_pos;
if (end < len_pos + ASN1_INDEF_TERM_LEN) {
/* Not enough buffer for the indefinite length terminator */
return NULL;
}
return len_pos;
} else {
/* Long length encoding */
length_size = *len_pos++ & 0x7f;
if (length_size == 0x7f) {
/* Reserved extension encoding that has not been defined. */
return NULL;
}
if (end < len_pos + length_size) {
/* Not enough buffer for the length value */
return NULL;
}
*length = 0;
while (length_size--) {
*length = (*length << 8) | *len_pos++;
}
}
if (end < len_pos + *length) {
/* Not enough buffer for the component body. */
return NULL;
}
return len_pos;
}
/*!
* \internal
* \brief Skip to the end of an indefinite length constructed component helper.
*
* \param pos ASN.1 tag starting position.
* \param end End of ASN.1 decoding data buffer.
*
* \retval Start of the next ASN.1 component on success.
* \retval NULL on error.
*/
static const unsigned char *asn1_dec_indef_end_fixup_helper(const unsigned char *pos,
const unsigned char *end)
{
unsigned tag;
int length;
while (pos < end && *pos != ASN1_INDEF_TERM) {
ASN1_CALL(pos, asn1_dec_tag(pos, end, &tag));
ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
if (length < 0) {
/* Skip over indefinite length sub-component */
if ((tag & ASN1_PC_MASK) == ASN1_PC_CONSTRUCTED
|| tag == (ASN1_CLASS_UNIVERSAL | ASN1_PC_PRIMITIVE | ASN1_TYPE_SET)
|| tag ==
(ASN1_CLASS_UNIVERSAL | ASN1_PC_PRIMITIVE | ASN1_TYPE_SEQUENCE)) {
/* This is an ITU encoded indefinite length component. */
ASN1_CALL(pos, asn1_dec_indef_end_fixup_helper(pos, end));
} else {
/* This is a non-ITU encoded indefinite length component. */
while (pos < end && *pos != ASN1_INDEF_TERM) {
++pos;
}
pos += ASN1_INDEF_TERM_LEN;
}
} else {
/* Skip over defininte length sub-component */
pos += length;
}
}
if (end < pos + ASN1_INDEF_TERM_LEN) {
return NULL;
}
return pos + ASN1_INDEF_TERM_LEN;
}
/*!
* \brief Skip to the end of an indefinite length constructed component.
*
* \param ctrl D channel controller for any diagnostic messages.
* \param pos ASN.1 tag starting position.
* \param end End of ASN.1 decoding data buffer.
*
* \retval Start of the next ASN.1 component on success.
* \retval NULL on error.
*/
const unsigned char *asn1_dec_indef_end_fixup(struct pri *ctrl, const unsigned char *pos,
const unsigned char *end)
{
if (pos < end && *pos != ASN1_INDEF_TERM && (ctrl->debug & PRI_DEBUG_APDU)) {
pri_message(ctrl,
" Skipping unused indefinite length constructed component octets!\n");
}
return asn1_dec_indef_end_fixup_helper(pos, end);
}
/*!
* \brief Decode the boolean primitive.
*
* \param ctrl D channel controller for any diagnostic messages.
* \param name Field name
* \param tag Component tag that identified this primitive.
* \param pos Starting position of the ASN.1 component length.
* \param end End of ASN.1 decoding data buffer.
* \param value Decoded boolean value.
*
* \retval Start of the next ASN.1 component on success.
* \retval NULL on error.
*/
const unsigned char *asn1_dec_boolean(struct pri *ctrl, const char *name, unsigned tag,
const unsigned char *pos, const unsigned char *end, int32_t *value)
{
int length;
ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
if (length != 1) {
/*
* The encoding rules say the length can only be one.
* It is rediculus to get anything else anyway.
*/
return NULL;
}
*value = *pos++ ? 1 : 0;
if (ctrl->debug & PRI_DEBUG_APDU) {
pri_message(ctrl, " %s %s = %d\n", name, asn1_tag2str(tag), *value);
}
return pos;
}
/*!
* \brief Decode the integer type primitive.
*
* \param ctrl D channel controller for any diagnostic messages.
* \param name Field name
* \param tag Component tag that identified this primitive.
* \param pos Starting position of the ASN.1 component length.
* \param end End of ASN.1 decoding data buffer.
* \param value Decoded integer type value.
*
* \retval Start of the next ASN.1 component on success.
* \retval NULL on error.
*/
const unsigned char *asn1_dec_int(struct pri *ctrl, const char *name, unsigned tag,
const unsigned char *pos, const unsigned char *end, int32_t *value)
{
int length;
ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
if (length <= 0) {
/*
* The encoding rules say the length can not be indefinite.
* It cannot be empty for that matter either.
*/
return NULL;
}
#if 1
/* Read value as signed */
if (*pos & 0x80) {
/* The value is negative */
*value = -1;
} else {
*value = 0;
}
#else
/* Read value as unsigned */
*value = 0;
#endif
while (length--) {
*value = (*value << 8) | *pos;
pos++;
}
if (ctrl->debug & PRI_DEBUG_APDU) {
pri_message(ctrl, " %s %s = %d 0x%04X\n", name, asn1_tag2str(tag), *value,
*value);
}
return pos;
}
/*!
* \brief Decode the null primitive.
*
* \param ctrl D channel controller for any diagnostic messages.
* \param name Field name
* \param tag Component tag that identified this primitive.
* \param pos Starting position of the ASN.1 component length.
* \param end End of ASN.1 decoding data buffer.
*
* \retval Start of the next ASN.1 component on success.
* \retval NULL on error.
*/
const unsigned char *asn1_dec_null(struct pri *ctrl, const char *name, unsigned tag,
const unsigned char *pos, const unsigned char *end)
{
int length;
ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
if (length != 0) {
/*
* The encoding rules say the length can only be zero.
* It is rediculus to get anything else anyway.
*/