From 8879b125d26e8db1a5633de5a9c692eb2d1c4f83 Mon Sep 17 00:00:00 2001 From: Ashlee Young Date: Wed, 9 Sep 2015 22:21:41 -0700 Subject: suricata checkin based on commit id a4bce14770beee46a537eda3c3f6e8e8565d5d0a Change-Id: I9a214fa0ee95e58fc640e50bd604dac7f42db48f --- framework/src/suricata/src/util-decode-asn1.c | 904 ++++++++++++++++++++++++++ 1 file changed, 904 insertions(+) create mode 100644 framework/src/suricata/src/util-decode-asn1.c (limited to 'framework/src/suricata/src/util-decode-asn1.c') 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 + * + * 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 +} + -- cgit 1.2.3-korg