summaryrefslogtreecommitdiffstats
path: root/framework/src/suricata/src/util-decode-asn1.c
diff options
context:
space:
mode:
authorAshlee Young <ashlee@onosfw.com>2015-09-09 22:21:41 -0700
committerAshlee Young <ashlee@onosfw.com>2015-09-09 22:21:41 -0700
commit8879b125d26e8db1a5633de5a9c692eb2d1c4f83 (patch)
treec7259d85a991b83dfa85ab2e339360669fc1f58e /framework/src/suricata/src/util-decode-asn1.c
parent13d05bc8458758ee39cb829098241e89616717ee (diff)
suricata checkin based on commit id a4bce14770beee46a537eda3c3f6e8e8565d5d0a
Change-Id: I9a214fa0ee95e58fc640e50bd604dac7f42db48f
Diffstat (limited to 'framework/src/suricata/src/util-decode-asn1.c')
-rw-r--r--framework/src/suricata/src/util-decode-asn1.c904
1 files changed, 904 insertions, 0 deletions
diff --git a/framework/src/suricata/src/util-decode-asn1.c b/framework/src/suricata/src/util-decode-asn1.c
new file mode 100644
index 00000000..3372b517
--- /dev/null
+++ b/framework/src/suricata/src/util-decode-asn1.c
@@ -0,0 +1,904 @@
+/* Copyright (C) 2007-2013 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ *
+ * \author Pablo Rincon Crespo <pablo.rincon.crespo@gmail.com>
+ *
+ * Implements ASN1 decoding (needed for the asn1 keyword, BER, CER & DER)
+ */
+
+#include "suricata.h"
+#include "suricata-common.h"
+#include "decode.h"
+#include "util-debug.h"
+#include "util-unittest.h"
+#include "util-print.h"
+
+#include "util-decode-asn1.h"
+#include "conf.h"
+
+uint16_t asn1_max_frames_config = ASN1_MAX_FRAMES;
+
+void SCAsn1LoadConfig()
+{
+ intmax_t value = 0;
+
+ /** set config defaults */
+ if ((ConfGetInt("asn1-max-frames", &value)) == 1) {
+ asn1_max_frames_config = (uint16_t)value;
+ SCLogDebug("Max stack frame set to %"PRIu16, asn1_max_frames_config);
+ }
+
+}
+
+/**
+ * \brief Decode and check the identifier information of the
+ * current node that is in extended format
+ *
+ * \param ac pointer to the ASN1 Context data
+ *
+ * \retval byte of the status of the parser
+ */
+uint8_t SCAsn1GetHighTagNumber(Asn1Ctx *ac)
+{
+ uint8_t ret = 0;
+ uint32_t tag_num = 0;
+
+ /* If we have a high tag num, skip the id octet */
+ ac->iter++;
+
+ Asn1Node *node = ASN1CTX_CUR_NODE(ac);
+
+ ret = SCAsn1CheckBounds(ac);
+ if (ret == ASN1_PARSER_ERR) {
+ ac->parser_status |= ASN1_STATUS_INVALID | ASN1_STATUS_OOB;
+ return ret;
+ }
+
+ uint8_t raw_id = *ac->iter;
+
+ tag_num += ASN1_BER_GET_HIGH_TAG_NUM(raw_id);
+
+ if (ASN1_BER_GET_HIGH_TAG_NUM(raw_id) == 0) {
+ /* Set event, invalid id */
+ node->flags |= ASN1_BER_EVENT_INVALID_ID;
+ ac->parser_status |= ASN1_STATUS_INVALID;
+ return ASN1_PARSER_ERR;
+ }
+
+ ac->iter++;
+ if (!ASN1_BER_IS_HIGH_TAG_END(raw_id)) {
+ do {
+ ret = SCAsn1CheckBounds(ac);
+ if (ret == ASN1_PARSER_ERR) {
+ ac->parser_status |= ASN1_STATUS_INVALID | ASN1_STATUS_OOB;
+ return ret;
+ }
+
+ raw_id = *ac->iter;
+
+ if ((uint64_t) ((uint64_t)tag_num +
+ (uint64_t)ASN1_BER_GET_HIGH_TAG_NUM(raw_id)) > UINT32_MAX)
+ {
+ node->flags |= ASN1_BER_EVENT_ID_TOO_LONG;
+ ac->parser_status |= ASN1_STATUS_INVALID;
+ return ASN1_PARSER_ERR;
+ }
+
+ tag_num += ASN1_BER_GET_HIGH_TAG_NUM(raw_id);
+ ac->iter++;
+ } while (!ASN1_BER_IS_HIGH_TAG_END(raw_id));
+ }
+ node->id.tag_num = tag_num;
+
+ return ASN1_PARSER_OK;
+}
+
+/**
+ * \brief Decode and check the length, of the current node
+ * in definite but extended format, that we are parsing,
+ * checking invalid opts
+ *
+ * \param ac pointer to the ASN1 Context data
+ *
+ * \retval byte of the status of the parser
+ */
+uint32_t SCAsn1GetLengthLongForm(Asn1Ctx *ac)
+{
+ uint8_t raw_len = *ac->iter;
+ uint8_t ret = 0;
+ uint32_t content_len = 0;
+ uint8_t oct_len = ASN1_BER_GET_LONG_LEN_OCTETS(raw_len);
+ uint8_t i = 0;
+
+ Asn1Node *node = ASN1CTX_CUR_NODE(ac);
+
+ for (; i < oct_len; i++) {
+ ac->iter++;
+
+ ret = SCAsn1CheckBounds(ac);
+ if (ret == ASN1_PARSER_ERR) {
+ ac->parser_status |= ASN1_STATUS_INVALID | ASN1_STATUS_OOB;
+ return ASN1_PARSER_ERR;
+ }
+
+ raw_len = *ac->iter;
+ if (raw_len == 0xFF && ac->iter == node->len.ptr + 1) {
+ /* 8.1.3.5, 0xFF shall not be used */
+ node->flags |= ASN1_BER_EVENT_INVALID_LEN;
+ ac->parser_status = ASN1_STATUS_INVALID;
+ return ASN1_PARSER_ERR;
+ }
+
+ if ((uint64_t) ((uint64_t)content_len +
+ (uint64_t) ASN1_BER_GET_HIGH_TAG_NUM(raw_len)) > UINT32_MAX)
+ {
+ node->flags |= ASN1_BER_EVENT_LEN_TOO_LONG;
+ ac->parser_status = ASN1_STATUS_INVALID;
+ return ASN1_PARSER_ERR;
+ }
+
+ content_len += raw_len;
+ }
+
+ ac->iter++;
+
+ node->len.len = content_len;
+ return ASN1_PARSER_OK;
+}
+
+
+/**
+ * \brief Check the content length and perform other inspections
+ * and decodings if necessary
+ *
+ * \param ac pointer to the ASN1 Context data
+ *
+ * \retval byte of the status of the parser
+ */
+uint8_t SCAsn1DecodeContent(Asn1Ctx *ac)
+{
+
+ Asn1Node *node = ASN1CTX_CUR_NODE(ac);
+
+ /* Uops, if we are done, we break here */
+ if (node->flags & ASN1_NODE_IS_EOC)
+ return ASN1_PARSER_OK;
+
+ /* First check the form of length (BER, DER, CER)
+ * and if we are on a zero length */
+ if (node->len.form != ASN1_BER_LEN_INDEFINITE &&
+ node->len.len == 0)
+ {
+ node->data.len = 0;
+ return ASN1_PARSER_OK;
+ }
+
+ node->data.ptr = ac->iter;
+ /* If we have a complete length, check that
+ * it is in bounds */
+ if (ac->iter + node->len.len > ac->end) {
+ /* We do not have all the content octets! */
+ node->data.len = ac->end - ac->iter;
+ } else {
+ /* We have all the content octets */
+ node->data.len = node->len.len;
+ }
+
+ return ASN1_PARSER_OK;
+}
+
+/**
+ * \brief Decode and check the length, of the current node
+ * that we are parsing, also check invalid opts
+ *
+ * \param ac pointer to the ASN1 Context data
+ *
+ * \retval byte of the status of the parser
+ */
+uint8_t SCAsn1DecodeLength(Asn1Ctx *ac)
+{
+ uint8_t ret = 0;
+ ret = SCAsn1CheckBounds(ac);
+ if (ret == ASN1_PARSER_ERR) {
+ ac->parser_status |= ASN1_STATUS_INVALID | ASN1_STATUS_OOB;
+ return ASN1_PARSER_ERR;
+ }
+
+ Asn1Node *node = ASN1CTX_CUR_NODE(ac);
+ /* Store the position */
+ node->len.ptr = ac->iter;
+
+ uint8_t len_byte = *ac->iter;
+
+ //SCPrintByteBin(len_byte);
+
+ if (*node->id.ptr == 0 && len_byte == 0) {
+ node->flags |= ASN1_NODE_IS_EOC;
+ ac->iter++;
+ return ASN1_PARSER_OK;
+ }
+
+ if (ASN1_BER_IS_INDEFINITE_LEN(len_byte)) {
+ node->len.form = ASN1_BER_LEN_INDEFINITE;
+ node->len.len = 0;
+ ac->iter++;
+
+ uint8_t *tmp_iter = ac->iter;
+
+ /* Check that e-o-c is in bounds */
+ for (; tmp_iter < ac->end - 1; tmp_iter++) {
+ if (ASN1_BER_IS_EOC(tmp_iter)) {
+ node->data.len = tmp_iter - ac->iter;
+ node->len.len = tmp_iter - ac->iter;
+ return ASN1_PARSER_OK;
+ }
+ }
+
+ /* EOC Not found */
+ ac->parser_status |= ASN1_STATUS_INVALID;
+ node->flags |= ASN1_BER_EVENT_EOC_NOT_FOUND;
+
+ return ASN1_PARSER_ERR;
+
+ } else {
+ /* Look which form we get (and if it apply to the id type) */
+ if (ASN1_BER_IS_SHORT_LEN(len_byte)) {
+ node->len.form = ASN1_BER_LEN_SHORT;
+ node->len.len = ASN1_BER_GET_SHORT_LEN(len_byte);
+ ac->iter++;
+ } else {
+ node->len.form = ASN1_BER_LEN_LONG;
+
+ /* Ok, let's parse the long form */
+ return SCAsn1GetLengthLongForm(ac);
+ }
+
+ }
+ return ASN1_PARSER_OK;
+}
+
+/**
+ * \brief Decode and check the identifier information of the
+ * current node that we are parsing, also check invalid opts
+ *
+ * \param ac pointer to the ASN1 Context data
+ *
+ * \retval byte of the status of the parser
+ */
+uint8_t SCAsn1DecodeIdentifier(Asn1Ctx *ac)
+{
+ uint8_t ret = 0;
+ ret = SCAsn1CheckBounds(ac);
+ if (ret == ASN1_PARSER_ERR) {
+ ac->parser_status |= ASN1_STATUS_INVALID | ASN1_STATUS_OOB;
+ return ret;
+ }
+
+ Asn1Node *node = ASN1CTX_CUR_NODE(ac);
+ /* Store the position */
+ node->id.ptr = ac->iter;
+
+ //SCPrintByteBin(*ac->iter);
+
+ node->id.class_tag = ASN1_BER_GET_CLASS_TAG(*ac->iter);
+ node->id.tag_type = ASN1_BER_IS_CONSTRUCTED(*ac->iter);
+
+ if (ASN1_BER_IS_HIGH_TAG(*ac->iter)) {
+ return SCAsn1GetHighTagNumber(ac);
+ } else {
+ node->id.tag_num = ASN1_BER_GET_LOW_TAG_NUM(*ac->iter);
+ ac->iter++;
+ }
+
+ return ASN1_PARSER_OK;
+}
+
+/**
+ * \brief Helper function that print the bits of a byte
+ * to check encoding internals
+ * \param byte value of the byte
+ */
+void SCPrintByteBin(uint8_t byte)
+{
+ uint8_t i = 0;
+ for (i = 8; i > 0; i--) {
+ printf("%"PRIu8, (uint8_t)((byte >> (i - 1)) & 0x01));
+ if (i == 5)
+ printf(" ");
+ }
+ printf("\n");
+}
+
+/**
+ * \brief check if we have remaining data available,
+ * otherwise the parser should stop
+ * \param ac Asn1Ctx pointer initialized
+ * \retval 1 if we are out of bounds, 0 if not
+ */
+uint8_t SCAsn1CheckBounds(Asn1Ctx *ac)
+{
+ return (ac->iter < ac->end && ac->iter >= ac->data)? ASN1_PARSER_OK : ASN1_PARSER_ERR;
+}
+
+
+/**
+ * \brief Create a new ASN1 Parsing context
+ *
+ * \retval Asn1Ctx pointer to the new ctx
+ */
+Asn1Ctx *SCAsn1CtxNew(void)
+{
+ Asn1Ctx *ac = SCMalloc(sizeof(Asn1Ctx));
+
+ if (unlikely(ac == NULL)) {
+ SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
+ return NULL;
+ }
+ memset(ac, 0, sizeof(Asn1Ctx));
+
+ ac->asn1_stack = SCMalloc(sizeof(Asn1Node *) * asn1_max_frames_config);
+ if (ac->asn1_stack == NULL) {
+ SCFree(ac);
+ return NULL;
+ }
+ memset(ac->asn1_stack, 0, sizeof(Asn1Node *) * asn1_max_frames_config);
+
+ return ac;
+}
+
+/**
+ * \brief Destroy an ASN1 Parsing context
+ *
+ * \param Asn1Ctx pointer to the new ctx
+ */
+void SCAsn1CtxDestroy(Asn1Ctx *ac)
+{
+ if (ac == NULL)
+ return;
+
+ uint16_t i = 0;
+ for (; i < ac->cur_frame; i++) {
+ Asn1Node *node = ASN1CTX_GET_NODE(ac, i);
+ if (node != NULL) {
+ SCFree(node);
+ }
+ }
+ SCFree(ac);
+}
+
+/**
+ * \brief Create a new node at the array stack of frames in the ctx
+ *
+ * \param ac pointer to the ASN1 ctx
+ * \param node index of the frame that we are going to allocate
+ * at the asn1 stack in the parser
+ *
+ * \retval Asn1Node pointer to the new node allocated
+ */
+Asn1Node *SCAsn1CtxNewFrame(Asn1Ctx *ac, uint16_t node)
+{
+ if (node >= asn1_max_frames_config) {
+ return NULL;
+ }
+
+ if (ac->asn1_stack[node] == NULL)
+ ac->asn1_stack[node] = SCMalloc(sizeof(Asn1Node));
+
+ if (ac->asn1_stack[node] == NULL)
+ return NULL;
+
+ memset(ac->asn1_stack[node], 0, sizeof(Asn1Node));
+ return ac->asn1_stack[node];
+}
+
+/**
+ * \brief Initialize the data of the ASN1 parser ctx with the asn1 raw buffer
+ *
+ * \param ac pointer to the ASN1 ctx
+ * \param data pointer to the data to process (binary raw of asn1)
+ * \param length length of the asn1 raw buffer
+ *
+ * \retval void
+ */
+void SCAsn1CtxInit(Asn1Ctx *ac, uint8_t *data, uint16_t length)
+{
+ ac->data = data;
+ ac->iter = data;
+ ac->len = length;
+ ac->end = data + length;
+ ac->parser_status = ASN1_STATUS_OK;
+}
+
+/**
+ * \brief Decode the nodes/frames located at certain position/level
+ *
+ * \param ac pointer to the ASN1 ctx
+ * \param node_id node index at the asn1 stack of the ctx
+ *
+ * \retval byte of parser status
+ */
+uint8_t SCAsn1Decode(Asn1Ctx *ac, uint16_t node_id)
+{
+ Asn1Node *node = NULL;
+ uint8_t ret = 0;
+
+ /* while remaining data, and no fatal error, or end, or max stack frames */
+ while (ac->iter < ac->end
+ && !(ac->parser_status & ASN1_STATUS_DONE)
+ && ac->cur_frame < asn1_max_frames_config)
+ {
+ /* Prepare a new frame */
+ if (SCAsn1CtxNewFrame(ac, node_id) == NULL)
+ break;
+
+ ac->cur_frame = node_id;
+ node = ASN1CTX_GET_NODE(ac, node_id);
+
+ SCLogDebug("ASN1 Getting ID, cur:%x remaining %"PRIu32, (uint8_t)*ac->iter, (uint32_t)(ac->end - ac->iter));
+
+ /* Get identifier/tag */
+ ret = SCAsn1DecodeIdentifier(ac);
+ if (ret == ASN1_PARSER_ERR) {
+ SCLogDebug("Error parsing identifier");
+
+ node->flags |= ASN1_BER_EVENT_INVALID_ID;
+ ac->ctx_flags |= node->flags;
+
+ break;
+ }
+
+ SCLogDebug("ASN1 Getting LEN");
+
+ /* Get length of content */
+ ret = SCAsn1DecodeLength(ac);
+ if (ret == ASN1_PARSER_ERR) {
+ SCLogDebug("Error parsing length");
+
+ node->flags |= ASN1_BER_EVENT_INVALID_LEN;
+ ac->ctx_flags |= node->flags;
+
+ break;
+ }
+
+ if ( !(node->flags & ASN1_NODE_IS_EOC)) {
+ SCLogDebug("ASN1 Getting CONTENT");
+
+ /* Inspect content */
+ ret = SCAsn1DecodeContent(ac);
+ if (ret == ASN1_PARSER_ERR) {
+ SCLogDebug("Error parsing content");
+
+ break;
+ }
+
+ /* Skip to the next record (if any) */
+ if (node->id.tag_type != ASN1_TAG_TYPE_CONSTRUCTED)
+ /* Is primitive, skip it all (no need to decode it)*/
+ ac->iter += node->data.len;
+ }
+
+ /* Check if we are done with data */
+ ret = SCAsn1CheckBounds(ac);
+ if (ret == ASN1_PARSER_ERR) {
+
+ ac->parser_status |= ASN1_STATUS_DONE;
+ /* There's no more data available */
+ ret = ASN1_PARSER_OK;
+
+ break;
+ }
+#if 0
+ printf("Tag Num: %"PRIu32", Tag Type: %"PRIu8", Class:%"PRIu8", Length: %"PRIu32"\n", node->id.tag_num, node->id.tag_type, node->id.class_tag, node->len.len);
+ printf("Data: \n");
+ PrintRawDataFp(stdout, node->data.ptr, node->len.len);
+ printf(" -- EOD --\n");
+#endif
+
+ /* Stack flags/events here, so we have the resume at the ctx flags */
+ ac->ctx_flags |= node->flags;
+
+ /* Check if it's not a primitive type,
+ * then we need to decode contents */
+ if (node->id.tag_type == ASN1_TAG_TYPE_CONSTRUCTED) {
+ ret = SCAsn1Decode(ac, node_id + 1);
+ } /* Else we have reached a primitive type and stop the recursion,
+ * look if we have other branches at the same level */
+
+ /* But first check if it's a constructed node, and the sum of child
+ * lengths was more than the length of this frame
+ * this would mean that we have an overflow at the attributes */
+ if (ac->iter > node->data.ptr + node->data.len + 1) {
+ /* We decoded more length on this frame */
+ }
+
+ node_id = ac->cur_frame + 1;
+ }
+
+ return ret;
+}
+
+/* ----------------------- Unit tests ------------------------ */
+#ifdef UNITTESTS
+
+/**
+ * \test Check we handle extended identifiers correctly
+ */
+int DecodeAsn1Test01(void)
+{
+ uint8_t *str = (uint8_t *) "\x3F\x84\x06";
+
+ Asn1Ctx *ac = SCAsn1CtxNew();
+ if (ac == NULL)
+ return 0;
+ uint8_t ret = 1;
+
+ uint16_t len = 3;
+
+ SCAsn1CtxInit(ac, str, len);
+
+ SCAsn1Decode(ac, ac->cur_frame);
+ Asn1Node *node = ASN1CTX_GET_NODE(ac, 0);
+ if (node->id.tag_num != 10) {
+ ret = 0;
+ printf("Error, expected tag_num 10, got %"PRIu32" :", node->id.tag_num);
+ goto end;
+ }
+
+end:
+ SCAsn1CtxDestroy(ac);
+ return ret;
+}
+
+/**
+ * \test Check we handle extended identifiers correctly
+ */
+int DecodeAsn1Test02(void)
+{
+ uint8_t *str = (uint8_t *) "\x3F\x81\x81\x81\x81\x06";
+
+ Asn1Ctx *ac = SCAsn1CtxNew();
+ if (ac == NULL)
+ return 0;
+ uint8_t ret = 1;
+
+ uint16_t len = 6;
+
+ SCAsn1CtxInit(ac, str, len);
+
+ SCAsn1Decode(ac, ac->cur_frame);
+ Asn1Node *node = ASN1CTX_GET_NODE(ac, 0);
+ if (node->id.tag_num != 10) {
+ ret = 0;
+ printf("Error, expected tag_num 10, got %"PRIu32": ", node->id.tag_num);
+ goto end;
+ }
+
+end:
+ SCAsn1CtxDestroy(ac);
+ return ret;
+}
+
+/**
+ * \test Check we handle short identifiers correctly
+ */
+int DecodeAsn1Test03(void)
+{
+ uint8_t *str = (uint8_t *) "\x28";
+
+ Asn1Ctx *ac = SCAsn1CtxNew();
+ if (ac == NULL)
+ return 0;
+ uint8_t ret = 1;
+
+ uint16_t len = 1;
+
+ SCAsn1CtxInit(ac, str, len);
+
+ SCAsn1Decode(ac, ac->cur_frame);
+ Asn1Node *node = ASN1CTX_GET_NODE(ac, 0);
+ if (node->id.tag_num != 8) {
+ ret = 0;
+ printf("Error, expected tag_num 10, got %"PRIu32": ", node->id.tag_num);
+ goto end;
+ }
+
+end:
+ SCAsn1CtxDestroy(ac);
+ return ret;
+}
+
+/**
+ * \test Check we handle extended lengths correctly with indefinite form
+ */
+int DecodeAsn1Test04(void)
+{
+ uint8_t *str = (uint8_t *) "\x3F\x84\x06\x80\x12\x12\x12\x00\x00";
+
+ Asn1Ctx *ac = SCAsn1CtxNew();
+ if (ac == NULL)
+ return 0;
+ uint8_t ret = 1;
+
+ uint16_t len = 9;
+
+ SCAsn1CtxInit(ac, str, len);
+
+ SCAsn1Decode(ac, ac->cur_frame);
+ Asn1Node *node = ASN1CTX_GET_NODE(ac, 0);
+ if (node->len.len != 3) {
+ ret = 0;
+ printf("Error, expected length 3, got %"PRIu32": ", node->len.len);
+ goto end;
+ }
+
+end:
+ SCAsn1CtxDestroy(ac);
+ return ret;
+}
+
+/**
+ * \test Check we handle extended lengths correctly
+ * in the definite form
+ */
+int DecodeAsn1Test05(void)
+{
+ uint8_t *str = (uint8_t *) "\x3F\x84\x06\x82\x10\x10";
+
+ Asn1Ctx *ac = SCAsn1CtxNew();
+ if (ac == NULL)
+ return 0;
+ uint8_t ret = 1;
+
+ uint16_t len = 6;
+
+ SCAsn1CtxInit(ac, str, len);
+
+ SCAsn1Decode(ac, ac->cur_frame);
+ Asn1Node *node = ASN1CTX_GET_NODE(ac, 0);
+ if (node->len.len!= 32) {
+ ret = 0;
+ printf("Error, expected length 10, got %"PRIu32": ", node->len.len);
+ goto end;
+ }
+
+end:
+ SCAsn1CtxDestroy(ac);
+ return ret;
+}
+
+/**
+ * \test Check we handle short lengths correctly
+ */
+int DecodeAsn1Test06(void)
+{
+ uint8_t *str = (uint8_t *) "\x3F\x84\x06\x26";
+
+ Asn1Ctx *ac = SCAsn1CtxNew();
+ if (ac == NULL)
+ return 0;
+ uint8_t ret = 1;
+
+ uint16_t len = 4;
+
+ SCAsn1CtxInit(ac, str, len);
+
+ SCAsn1Decode(ac, ac->cur_frame);
+ Asn1Node *node = ASN1CTX_GET_NODE(ac, 0);
+ if (node->len.len != 38) {
+ ret = 0;
+ printf("Error, expected length 10, got %"PRIu32": ", node->len.len);
+ goto end;
+ }
+
+end:
+ SCAsn1CtxDestroy(ac);
+ return ret;
+}
+
+/**
+ * \test Check we handle events correctly
+ */
+int DecodeAsn1Test07(void)
+{
+ uint8_t *str = (uint8_t *) "\x3F\x00\x84\x06";
+
+ Asn1Ctx *ac = SCAsn1CtxNew();
+ if (ac == NULL)
+ return 0;
+ uint8_t ret = 1;
+
+ uint16_t len = 4;
+
+ SCAsn1CtxInit(ac, str, len);
+
+ SCAsn1Decode(ac, ac->cur_frame);
+ Asn1Node *node = ASN1CTX_GET_NODE(ac, 0);
+ if ( !(ac->ctx_flags & ASN1_BER_EVENT_INVALID_ID)
+ || !(node->flags & ASN1_BER_EVENT_INVALID_ID))
+ {
+ ret = 0;
+ printf("Error, expected invalid id, got flags %"PRIu8": ", ac->ctx_flags);
+ goto end;
+ }
+
+end:
+ SCAsn1CtxDestroy(ac);
+ return ret;
+}
+
+/**
+ * \test Check we handle events correctly
+ */
+int DecodeAsn1Test08(void)
+{
+ uint8_t *str = (uint8_t *) "\x3F\x84\x06\x81\xFF";
+
+ Asn1Ctx *ac = SCAsn1CtxNew();
+ if (ac == NULL)
+ return 0;
+ uint8_t ret = 1;
+
+ uint16_t len = 5;
+
+ SCAsn1CtxInit(ac, str, len);
+
+ SCAsn1Decode(ac, ac->cur_frame);
+ Asn1Node *node = ASN1CTX_GET_NODE(ac, 0);
+ if ( !(ac->ctx_flags & ASN1_BER_EVENT_INVALID_LEN)
+ || !(node->flags & ASN1_BER_EVENT_INVALID_LEN))
+ {
+ ret = 0;
+ printf("Error, expected invalid length, got flags %"PRIu8": ", ac->ctx_flags);
+ goto end;
+ }
+
+end:
+ SCAsn1CtxDestroy(ac);
+ return ret;
+}
+
+/**
+ * \test Check we handle events correctly
+ */
+int DecodeAsn1Test09(void)
+{
+ uint8_t *str = (uint8_t *) "\x3F\x84\x06\x80\xAB\xCD\xEF";
+
+ Asn1Ctx *ac = SCAsn1CtxNew();
+ if (ac == NULL)
+ return 0;
+ uint8_t ret = 1;
+
+ uint16_t len = 7;
+
+ SCAsn1CtxInit(ac, str, len);
+
+ SCAsn1Decode(ac, ac->cur_frame);
+ Asn1Node *node = ASN1CTX_GET_NODE(ac, 0);
+ if ( !(ac->ctx_flags & ASN1_BER_EVENT_EOC_NOT_FOUND)
+ || !(node->flags & ASN1_BER_EVENT_EOC_NOT_FOUND))
+ {
+ ret = 0;
+ printf("Error, expected eoc not found, got flags %"PRIu8": ", ac->ctx_flags);
+ goto end;
+ }
+
+end:
+ SCAsn1CtxDestroy(ac);
+ return ret;
+}
+
+/**
+ * \test Decode a big chunk of data
+ */
+int DecodeAsn1Test10(void)
+{
+ // Example from the specification X.690-0207 Appendix A.3
+ uint8_t *str = (uint8_t *) "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01"
+ "P""\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director"
+ "\x42\x01\x33\xA1\x0A\x43\x08""19710917"
+ "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05"
+ "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01"
+ "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111"
+ "\x31\x1F\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05"
+ "Jones""\xA0\x0A\x43\x08""19590717"
+ "\x60\x81\x85\x61\x10\x1A\x04""John""\x1A\x01""P"
+ "\x1A\x05""Smith""\xA0\x0A\x1A\x08""Director"
+ "\x42\x01\x33\xA1\x0A\x43\x08""19710917"
+ "\xA2\x12\x61\x10\x1A\x04""Mary""\x1A\x01""T""\x1A\x05"
+ "Smith""\xA3\x42\x31\x1F\x61\x11\x1A\x05""Ralph""\x1A\x01"
+ "T""\x1A\x05""Smith""\xA0\x0A\x43\x08""19571111""\x31\x1F"
+ "\x61\x11\x1A\x05""Susan""\x1A\x01""B""\x1A\x05""Jones"
+ "\xA0\x0A\x43\x08""19590717";
+
+ Asn1Ctx *ac = SCAsn1CtxNew();
+ if (ac == NULL)
+ return 0;
+ uint8_t ret = 1;
+
+ uint16_t len = strlen((char *)str)-1;
+
+ SCAsn1CtxInit(ac, str, len);
+
+ ret = SCAsn1Decode(ac, ac->cur_frame);
+
+ /* General checks */
+ if (ret != ASN1_PARSER_OK) {
+ printf("Error decoding asn1 data: ");
+ ret = 0;
+ goto end;
+ }
+
+ if (ac->cur_frame != 59) {
+ printf("Error decoding asn1 data, not all the nodes"
+ "were correctly decoded: ");
+ ret = 0;
+ goto end;
+ }
+
+ if (ac->iter != ac->end) {
+ printf("Error decoding asn1 data, not all the nodes"
+ "were correctly decoded: ");
+ ret = 0;
+ goto end;
+ }
+
+ Asn1Node *node = ASN1CTX_GET_NODE(ac, 0);
+ if (node->len.len != 133) {
+ printf("Error decoding asn1 data, not all the nodes"
+ "were correctly decoded: ");
+ ret = 0;
+ goto end;
+ }
+
+ node = ASN1CTX_GET_NODE(ac, 30);
+ if (node->len.len != 133) {
+ printf("Error decoding asn1 data, not all the nodes"
+ "were correctly decoded: ");
+ ret = 0;
+ goto end;
+ }
+
+end:
+ SCAsn1CtxDestroy(ac);
+ return ret;
+}
+
+#endif
+
+void DecodeAsn1RegisterTests(void)
+{
+#ifdef UNITTESTS
+ UtRegisterTest("DecodeAsn1Test01", DecodeAsn1Test01, 1);
+ UtRegisterTest("DecodeAsn1Test02", DecodeAsn1Test02, 1);
+ UtRegisterTest("DecodeAsn1Test03", DecodeAsn1Test03, 1);
+
+ UtRegisterTest("DecodeAsn1Test04", DecodeAsn1Test04, 1);
+ UtRegisterTest("DecodeAsn1Test05", DecodeAsn1Test05, 1);
+ UtRegisterTest("DecodeAsn1Test06", DecodeAsn1Test06, 1);
+
+ UtRegisterTest("DecodeAsn1Test07", DecodeAsn1Test07, 1);
+ UtRegisterTest("DecodeAsn1Test08", DecodeAsn1Test08, 1);
+ UtRegisterTest("DecodeAsn1Test09", DecodeAsn1Test09, 1);
+
+ UtRegisterTest("DecodeAsn1Test10", DecodeAsn1Test10, 1);
+#endif
+}
+