mirror of https://github.com/OISF/suricata
				
				
				
			ASN1 decoder and keyword implementation
							parent
							
								
									6b49a90353
								
							
						
					
					
						commit
						3fa3229e01
					
				@ -0,0 +1,855 @@
 | 
			
		||||
/* Copyright (C) 2007-2010 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 decode-asn1.c
 | 
			
		||||
 *
 | 
			
		||||
 * \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 "decode-asn1.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \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, ((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 (ac == NULL)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    memset(ac, 0, sizeof(Asn1Ctx));
 | 
			
		||||
    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 (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)
 | 
			
		||||
    {
 | 
			
		||||
        /* 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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,218 @@
 | 
			
		||||
/* Copyright (C) 2007-2010 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 decode-asn1.h
 | 
			
		||||
 *
 | 
			
		||||
 * \author Pablo Rincon Crespo <pablo.rincon.crespo@gmail.com>
 | 
			
		||||
 *
 | 
			
		||||
 * Implements ASN1 decoding (needed for the asn1 keyword)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __DECODE_ASN1_H__
 | 
			
		||||
#define __DECODE_ASN1_H__
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#define ASN1_MAX_FRAMES 128
 | 
			
		||||
 | 
			
		||||
/* For future enconding type implementations */
 | 
			
		||||
enum {
 | 
			
		||||
    ASN1_BER_ENC,
 | 
			
		||||
    ASN1_ENC_UNKNOWN
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Class of tag */
 | 
			
		||||
#define ASN1_BER_CLASS_UNIV                 0
 | 
			
		||||
#define ASN1_BER_CLASS_APP                  1
 | 
			
		||||
#define ASN1_BER_CLASS_CTX_SPECIFIC         2
 | 
			
		||||
#define ASN1_BER_CLASS_PRIV                 3
 | 
			
		||||
 | 
			
		||||
/* For low tag numbers */
 | 
			
		||||
#define ASN1_BER_GET_CLASS_TAG(id_octet)    \
 | 
			
		||||
             ((id_octet >> 6) & 0x03)           /* (8.1.2.2a) */
 | 
			
		||||
#define ASN1_BER_IS_CONSTRUCTED(id_octet)   \
 | 
			
		||||
             ((id_octet >> 5) & 0x01)           /* (8.1.2.5) Constructed Tag */
 | 
			
		||||
#define ASN1_BER_IS_PRIMITIVE(id_octet)     \
 | 
			
		||||
             (((id_octet >> 5) & 0x01)?0:1)     /* (8.1.2.5) Primitive Tag */
 | 
			
		||||
#define ASN1_BER_IS_LOW_TAG(id_octet)       \
 | 
			
		||||
             ASN1_BER_IS_PRIMITIVE(id_octet)    /* (8.1.2.5) Is Low Tag
 | 
			
		||||
                                                             Number */
 | 
			
		||||
#define ASN1_BER_GET_LOW_TAG_NUM(id_octet)  \
 | 
			
		||||
             (id_octet & 0x1F)                  /* (8.1.2.2c) Get LowTag Number */
 | 
			
		||||
 | 
			
		||||
/* For high tag numbers */
 | 
			
		||||
#define ASN1_BER_IS_HIGH_TAG(id_octet)      \
 | 
			
		||||
        ((ASN1_BER_GET_LOW_TAG_NUM(id_octet) == 0x1F) && \
 | 
			
		||||
        ASN1_BER_IS_CONSTRUCTED(id_octet))      /* (8.1.2.4) High Tag Number */
 | 
			
		||||
#define ASN1_BER_IS_HIGH_TAG_END(id_octet)  \
 | 
			
		||||
        ( !((id_octet >> 7) & 0x01))            /* (8.1.2.4) Is End of Tag Num */
 | 
			
		||||
#define ASN1_BER_GET_HIGH_TAG_NUM(id_octet) \
 | 
			
		||||
        (id_octet & 0x7F)                       /* (8.1.2.4) Part of High Tag
 | 
			
		||||
                                                             Number */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define ASN1_BER_IS_SHORT_LEN(id_octet)        \
 | 
			
		||||
             ( !((id_octet >> 7) & 0x01))        /* (8.1.3.3) Is short form */
 | 
			
		||||
#define ASN1_BER_GET_SHORT_LEN(id_octet)       \
 | 
			
		||||
             (id_octet & 0x7F)                   /* (8.1.3.3) length value */
 | 
			
		||||
#define ASN1_BER_GET_LONG_LEN_OCTETS(id_octet) \
 | 
			
		||||
             (id_octet & 0x7F)                   /* (8.1.3.5) the number of
 | 
			
		||||
                                                              bytes */
 | 
			
		||||
#define ASN1_BER_GET_LONG_LEN(id_octet) \
 | 
			
		||||
             (id_octet)                          /* (8.1.3.5) the byte itself*/
 | 
			
		||||
#define ASN1_BER_LONG_LEN_HAS_NEXT(id_octet)   \
 | 
			
		||||
             ( !((id_octet >> 7) & 0x01))        /* (8.1.3.5) Has next octets
 | 
			
		||||
                                                              lenght */
 | 
			
		||||
#define ASN1_BER_IS_INDEFINITE_LEN(id_octet)   \
 | 
			
		||||
             (id_octet == 0x80)                /* (8.1.3.6) Need end-of-ccontent */
 | 
			
		||||
#define ASN1_BER_IS_EOC(tmp_iter) (*tmp_iter == 0 && *(tmp_iter + 1) == 0)
 | 
			
		||||
 | 
			
		||||
/* Return the current node/frame that we are filling */
 | 
			
		||||
#define ASN1CTX_CUR_NODE(ac) (ac->asn1_stack[ac->cur_frame])
 | 
			
		||||
#define ASN1CTX_GET_NODE(ac, node) (ac->asn1_stack[node])
 | 
			
		||||
 | 
			
		||||
/* BER Universal tags */
 | 
			
		||||
#define ASN1_UNITAG_EOC                  0   /* EOC */
 | 
			
		||||
#define ASN1_UNITAG_BOOLEAN              1
 | 
			
		||||
#define ASN1_UNITAG_INTEGER              2
 | 
			
		||||
#define ASN1_UNITAG_BIT_STRING           3
 | 
			
		||||
#define ASN1_UNITAG_OCTET_STRING         4
 | 
			
		||||
#define ASN1_UNITAG_NULL                 5
 | 
			
		||||
#define ASN1_UNITAG_OID                  6
 | 
			
		||||
#define ASN1_UNITAG_OBJECT_DESCRIPTOR    7
 | 
			
		||||
#define ASN1_UNITAG_EXTERNAL             8
 | 
			
		||||
#define ASN1_UNITAG_REAL                 9
 | 
			
		||||
#define ASN1_UNITAG_ENUMERATED           10
 | 
			
		||||
#define ASN1_UNITAG_EMBEDDED_PDV         11
 | 
			
		||||
#define ASN1_UNITAG_UTF8_STRING          12
 | 
			
		||||
#define ASN1_UNITAG_RELATIVE_OID         13
 | 
			
		||||
#define ASN1_UNITAG_SEQUENCE             16
 | 
			
		||||
#define ASN1_UNITAG_SET                  17
 | 
			
		||||
#define ASN1_UNITAG_NUMERIC_STRING       18
 | 
			
		||||
#define ASN1_UNITAG_PRINTABLE_STRING     19
 | 
			
		||||
#define ASN1_UNITAG_TELETEX_STRING       20
 | 
			
		||||
#define ASN1_UNITAG_VIDEOTEX_STRING      21
 | 
			
		||||
#define ASN1_UNITAG_IA5_STRING           22
 | 
			
		||||
#define ASN1_UNITAG_UTCTIME              23
 | 
			
		||||
#define ASN1_UNITAG_GENERALIZED_TIME     24
 | 
			
		||||
#define ASN1_UNITAG_GRAPHIC_STRING       25
 | 
			
		||||
#define ASN1_UNITAG_VISIBLE_STRING       26
 | 
			
		||||
#define ASN1_UNITAG_GENERAL_STRING       27
 | 
			
		||||
#define ASN1_UNITAG_UNIVERSAL_STRING     28
 | 
			
		||||
#define ASN1_UNITAG_CHARACTER_STRING     29
 | 
			
		||||
#define ASN1_UNITAG_BMP_STRING           30
 | 
			
		||||
 | 
			
		||||
/* Length form */
 | 
			
		||||
#define ASN1_BER_LEN_SHORT          0
 | 
			
		||||
#define ASN1_BER_LEN_LONG           1
 | 
			
		||||
#define ASN1_BER_LEN_INDEFINITE     2
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Error events/flags */
 | 
			
		||||
#define ASN1_BER_EVENT_ID_TOO_LONG            0x01
 | 
			
		||||
#define ASN1_BER_EVENT_INVALID_ID             0x02 /* (8.1.2.4.2c) First subsequent
 | 
			
		||||
                                                      id val (from bit 7 to 0) Shall
 | 
			
		||||
                                                      not be 0 */
 | 
			
		||||
#define ASN1_BER_EVENT_INVALID_LEN            0x04 /* (8.1.3.2a) we expect a simple
 | 
			
		||||
                                                      form, or (8.1.3.5c) we got
 | 
			
		||||
                                                      0xFF, or not enough data */
 | 
			
		||||
#define ASN1_BER_EVENT_LEN_TOO_LONG           0x08
 | 
			
		||||
#define ASN1_BER_EVENT_EOC_NOT_FOUND          0x10 /* EOC not found */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Helper flags */
 | 
			
		||||
#define ASN1_NODE_IS_EOC 1
 | 
			
		||||
#define ASN1_TAG_TYPE_PRIMITIVE 0
 | 
			
		||||
#define ASN1_TAG_TYPE_CONSTRUCTED 1
 | 
			
		||||
 | 
			
		||||
typedef struct Asn1Len_ {
 | 
			
		||||
    uint8_t form;
 | 
			
		||||
    uint32_t len;
 | 
			
		||||
    uint8_t *ptr;
 | 
			
		||||
} Asn1Len;
 | 
			
		||||
 | 
			
		||||
typedef struct Asn1Id_ {
 | 
			
		||||
    uint8_t *ptr;
 | 
			
		||||
    uint8_t class_tag;
 | 
			
		||||
    uint8_t tag_type;
 | 
			
		||||
    uint32_t tag_num;
 | 
			
		||||
} Asn1Id;
 | 
			
		||||
 | 
			
		||||
typedef struct Asn1Data_ {
 | 
			
		||||
    uint8_t *ptr;
 | 
			
		||||
    uint32_t len;
 | 
			
		||||
    uint8_t type;
 | 
			
		||||
} Asn1Data;
 | 
			
		||||
 | 
			
		||||
typedef struct Asn1Node_ {
 | 
			
		||||
    uint8_t *raw_str;
 | 
			
		||||
    uint8_t data_len;
 | 
			
		||||
    Asn1Len len;
 | 
			
		||||
    Asn1Id id;
 | 
			
		||||
    Asn1Data data;
 | 
			
		||||
    uint8_t flags;
 | 
			
		||||
} Asn1Node;
 | 
			
		||||
 | 
			
		||||
typedef struct Asn1Ctx_ {
 | 
			
		||||
    uint8_t *data;
 | 
			
		||||
    uint8_t *end;
 | 
			
		||||
    uint16_t len;
 | 
			
		||||
 | 
			
		||||
    uint8_t *iter;
 | 
			
		||||
 | 
			
		||||
    uint8_t cur_frame;
 | 
			
		||||
    Asn1Node *asn1_stack[ASN1_MAX_FRAMES];
 | 
			
		||||
 | 
			
		||||
    uint8_t parser_status;
 | 
			
		||||
 | 
			
		||||
    uint8_t ctx_flags;
 | 
			
		||||
} Asn1Ctx;
 | 
			
		||||
 | 
			
		||||
/* Return codes of the decoder */
 | 
			
		||||
#define ASN1_PARSER_OK          0x01 /* Everything ok */
 | 
			
		||||
#define ASN1_PARSER_ERR         0x02 /* Internal error, fatal error, we can't continue decoding */
 | 
			
		||||
 | 
			
		||||
/* Status of the parser  */
 | 
			
		||||
#define ASN1_STATUS_OK          0x00 /* On the road */
 | 
			
		||||
#define ASN1_STATUS_INVALID     0x01 /* We found something weird/invalid by the specification, but we can try to continue parsing */
 | 
			
		||||
#define ASN1_STATUS_OOB         0x02 /* We don't have enough data or ran out of bounds */
 | 
			
		||||
#define ASN1_STATUS_DONE        0x04 /* We have finished cleanly */
 | 
			
		||||
 | 
			
		||||
void SCPrintByteBin(uint8_t);
 | 
			
		||||
 | 
			
		||||
Asn1Ctx *SCAsn1CtxNew(void);
 | 
			
		||||
void SCAsn1CtxInit(Asn1Ctx *, uint8_t *, uint16_t);
 | 
			
		||||
void SCAsn1CtxDestroy(Asn1Ctx *);
 | 
			
		||||
 | 
			
		||||
uint8_t SCAsn1Decode(Asn1Ctx *, uint16_t);
 | 
			
		||||
uint8_t SCAsn1DecodeIdentifier(Asn1Ctx *);
 | 
			
		||||
uint8_t SCAsn1DecodeLength(Asn1Ctx *);
 | 
			
		||||
uint8_t SCAsn1DecodeContent(Asn1Ctx *);
 | 
			
		||||
 | 
			
		||||
uint8_t SCAsn1CheckBounds(Asn1Ctx *);
 | 
			
		||||
 | 
			
		||||
void DecodeAsn1RegisterTests(void);
 | 
			
		||||
 | 
			
		||||
#endif /* __DECODE_ASN1_H__ */
 | 
			
		||||
 | 
			
		||||
											
												
													File diff suppressed because it is too large
													Load Diff
												
											
										
									
								@ -0,0 +1,47 @@
 | 
			
		||||
/* Copyright (C) 2007-2010 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 detect-asn1.h
 | 
			
		||||
 *
 | 
			
		||||
 * \author Pablo Rincon Crespo <pablo.rincon.crespo@gmail.com>
 | 
			
		||||
 *
 | 
			
		||||
 * Implements "asn1" keyword
 | 
			
		||||
 */
 | 
			
		||||
#ifndef __DETECT_ASN1_H__
 | 
			
		||||
#define __DETECT_ASN1_H__
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Function check flags */
 | 
			
		||||
#define         ASN1_BITSTRING_OVF       0x01
 | 
			
		||||
#define         ASN1_DOUBLE_OVF          0x02
 | 
			
		||||
#define         ASN1_OVERSIZE_LEN        0x04
 | 
			
		||||
#define         ASN1_ABSOLUTE_OFFSET     0x10
 | 
			
		||||
#define         ASN1_RELATIVE_OFFSET     0x20
 | 
			
		||||
 | 
			
		||||
typedef struct DetectAsn1Data_ {
 | 
			
		||||
    uint8_t flags;     /* flags indicating the checks loaded */
 | 
			
		||||
    uint32_t oversize_length;   /* Length argument if needed */
 | 
			
		||||
    int32_t absolute_offset;   /* Length argument if needed */
 | 
			
		||||
    int32_t relative_offset;   /* Length argument if needed */
 | 
			
		||||
} DetectAsn1Data;
 | 
			
		||||
 | 
			
		||||
/* prototypes */
 | 
			
		||||
void DetectAsn1Register (void);
 | 
			
		||||
 | 
			
		||||
#endif /* __DETECT_ASN1_H__ */
 | 
			
		||||
 | 
			
		||||
					Loading…
					
					
				
		Reference in New Issue