⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 asn1.c

📁 Linux snort-2.4.4源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/****  @file       asn1.c****  @author     Daniel Roelker <droelker@sourcefire.com>****  @brief      ASN.1 Decoding API for BER and DER encodings.****  Copyright (C) 2004, Daniel Roelker and Sourcefire, Inc.****  ASN.1 decoding functions that incorporate an internal stack for**  processing.  That way we don't have to worry about attackers trying**  to overload the machine stack.****  Handles both DER and BER encodings, and also the indefinite encoding **  that BER supports.  Lots of functionality can be added on top of**  this library.  SNMP will probably be the first.****  NOTES:**    - Stop using global variables so we can have multiple instances,**      but we don't need that functionality right now.*/  #include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <sys/types.h>#ifdef WIN32#include <winsock.h>#endif#include "asn1.h"/***  Macros*/#define SF_ASN1_CLASS(c)   (((u_char)c) & SF_ASN1_CLASS_MASK)#define SF_ASN1_FLAG(c)    (((u_char)c) & SF_ASN1_FLAG_MASK)#define SF_ASN1_TAG(c)     (((u_char)c) & SF_ASN1_TAG_MASK)#define SF_ASN1_LEN_EXT(c) (((u_char)c) & SF_BER_LEN_MASK)#define ASN1_OOB(s,e,d)      (!(((s) <= (d)) && ((d) < (e))))#define ASN1_FATAL_ERR(e)    ((e) < 0)#define ASN1_NONFATAL_ERR(e) ((e) > 0)#define ASN1_MAX_STACK 128static ASN1_TYPE *g_asn1_mem        = NULL;static int        g_asn1_max_nodes  = 0;static int        g_asn1_node_index = 0;/***  NAME**    asn1_init_node_index::*//****  This function should get called whenever we decode a new ASN.1**  string to initialize the memory.****  @return void*/static void asn1_init_node_index(void){    g_asn1_node_index = 0;    return;}/***  NAME**    asn1_node_alloc::*//****  Allocate an ASN1_NODE.****  @return ASN1_TYPE *****  @retval NULL memory allocation failed**  @retval !NULL function successful*/static ASN1_TYPE *asn1_node_alloc(void){    if(!g_asn1_mem || (g_asn1_max_nodes <= g_asn1_node_index))        return NULL;    return &g_asn1_mem[g_asn1_node_index++];}/***  NAME**    asn1_init_mem::*//****  This function initializes the number of nodes that we want to track in**  an ASN.1 decode.  Pass in the max number of nodes for an ASN.1 decode and**  we will track that many.****  @return integer****  @retval ASN1_OK function successful**  @retval ASN1_ERR_MEM_ALLOC memory allocation failed**  @retval ASN1_ERR_INVALID_ARG invalid argument*/int asn1_init_mem(int iNodes){    if(iNodes <= 0)        return ASN1_ERR_INVALID_ARG;    /*    **  This makes sure that we don't initialize multiple times.    */    if(g_asn1_mem && g_asn1_max_nodes > 0)        return ASN1_OK;            g_asn1_mem = (ASN1_TYPE *)malloc(sizeof(ASN1_TYPE)*iNodes);    if(!g_asn1_mem)        return ASN1_ERR_MEM_ALLOC;    g_asn1_max_nodes = iNodes;    return ASN1_OK;}/***  NAME**    asn1_decode_tag_num_ext::*//****  This routine decodes extended tag numbers and checks for overlong**  tag numbers, etc.****  @param ASN1_DATA ptr to data**  @param u_int ptr to tag num****  @return integer****  @retval ASN1_OK function successful**  @retval ASN1_ERR_OVERLONG_LEN tag number too large**  @retval ASN1_ERR_OOB encoding goes out of bounds**  @retval ASN1_ERR_NULL_MEM function arguments are NULL*/static int asn1_decode_tag_num_ext(ASN1_DATA *asn1_data, u_int *tag_num){    int   iExtension = 0;    u_int new_tag_num;    if(!asn1_data || !tag_num)        return ASN1_ERR_NULL_MEM;    *tag_num = 0;    /*    **  Loop through the tag type while extension bit is set    */    do    {        /*        **  Is this an extension byte?        */        iExtension = SF_ASN1_LEN_EXT(*asn1_data->data);        new_tag_num = ((*tag_num << 7) | (*asn1_data->data & 0x7f));        if(*tag_num != 0 && new_tag_num <= *tag_num)        {            return ASN1_ERR_OVERLONG_LEN;        }        *tag_num = new_tag_num;        asn1_data->data++;        if(ASN1_OOB(asn1_data->start, asn1_data->end, asn1_data->data))        {            return ASN1_ERR_OOB;        }            } while(iExtension);    return ASN1_OK;}/***  NAME**    asn1_decode_ident::*//****  This function decodes the identifier byte(s) of an ASN.1 structure.**  We handle long tag numbers and check for overflows in the extended**  tag numbers.****  @return integer****  @retval ASN1_ERR_NULL_MEM function arguments are NULL**  @retval ASN1_ERR_OOB buffer out of bounds**  @retval ASN1_ERR_INVALID_BER_TAG_LEN tag num too large or bad encoding**  @retval ASN1_OK function ok*/static int asn1_decode_ident(ASN1_TYPE *asn1_type, ASN1_DATA *asn1_data){    ASN1_IDENT *ident;    int iRet;    if(!asn1_type || !asn1_data)        return ASN1_ERR_NULL_MEM;    ident = &asn1_type->ident;    ident->class = SF_ASN1_CLASS(*asn1_data->data);    ident->flag  = SF_ASN1_FLAG(*asn1_data->data);    ident->tag   = SF_ASN1_TAG(*asn1_data->data);    asn1_data->data++;    if(ASN1_OOB(asn1_data->start, asn1_data->end, asn1_data->data))    {        //printf("** decode_ident:  oob\n");        return ASN1_ERR_OOB;    }    /*    **  Is tag extended?    */    if(ident->tag == SF_ASN1_TAG_EXTENSION)    {        ident->tag_type = SF_ASN1_TAG_EXTENSION;        iRet = asn1_decode_tag_num_ext(asn1_data, &ident->tag);        if(iRet)        {            //printf("** decode_ident: ext_len error\n");            return ASN1_ERR_INVALID_BER_TAG_LEN;        }    }    return ASN1_OK;}/***  NAME**    asn1_decode_len_type::*//****  Determine the type of len encoding.  Could be short, long or**  indeterminate.****  @return integer****  @retval SF_BER_LEN_DEF_LONG extended length**  @retval SF_BER_LEN_DEF_SHORT one byte length < 127**  @retval SF_BER_LEN_INDEF indeterminate length*/static int asn1_decode_len_type(u_char *data){    int iExt;    iExt = SF_ASN1_LEN_EXT(*data);    if(iExt)    {        if(*data & 0x7f)        {            return SF_BER_LEN_DEF_LONG;        }        else        {            return SF_BER_LEN_INDEF;        }    }    return SF_BER_LEN_DEF_SHORT;}/***  NAME**    asn1_decode_len_ext::*//****  Decode the extended length version.  Basically we read the first**  byte for the number of bytes in the extended length.  We then read**  that number of bytes to determine the length.  If the number of bytes**  in the length is greater than our variable, then we return **  ASN1_ERR_OVERLONG_LEN, and exit decoding.****  @return integer****  @retval ASN1_ERR_NULL_MEM function arguments NULL**  @retval ASN1_ERR_OVERLONG_LEN length to long for us to decode**  @retval ASN1_ERR_OOB out of bounds condition**  @retval ASN1_OK function successful*/static int asn1_decode_len_ext(ASN1_DATA *asn1_data, u_int *size){    int iBytes;    int iCtr;    u_int new_size;    if(!asn1_data || !size)        return ASN1_ERR_NULL_MEM;    *size = 0;    iBytes = (*asn1_data->data & 0x7f);        asn1_data->data++;    if(ASN1_OOB(asn1_data->start, asn1_data->end, asn1_data->data))    {        return ASN1_ERR_OOB;    }    for(iCtr = 0; iCtr < iBytes; iCtr++)    {        new_size = ((*size << 8) | (*asn1_data->data));        /*        **  If we've just added some data to the size, and        **  we are still the same or less than the previous        **  size, we've just overflowed our variable        */        if(*size != 0 && new_size <= *size)        {            return ASN1_ERR_OVERLONG_LEN;        }        *size = new_size;        asn1_data->data++;        if(ASN1_OOB(asn1_data->start, asn1_data->end, asn1_data->data))        {            /*            **  Check to see if this was just an extended length that was zero at             **  the end of the buffer.  If it was, then return normal.            */            if(*size == 0 && (iCtr+1) == iBytes)                break;            return ASN1_ERR_OOB;        }    }    return ASN1_OK;}/***  NAME**    asn1_decode_len::*//****  This function decodes the ASN.1 type length.  Determines what type of**  BER encoding is used for the length and decodes that length.****  @return integer****  @retval ASN1_ERR_NULL_MEM function arguments NULL**  @retval ASN1_ERR_FATAL should never get this**  @retval ASN1_ERR_OOB out of bounds condition**  @retval ASN1_OK function successful*/static int asn1_decode_len(ASN1_TYPE *asn1_type, ASN1_DATA *asn1_data){    ASN1_LEN *len;    int iRet;    if(!asn1_type || !asn1_data)        return ASN1_ERR_NULL_MEM;    len = &asn1_type->len;    len->type = asn1_decode_len_type(asn1_data->data);    switch(len->type)    {        case SF_BER_LEN_DEF_SHORT:            len->size = *asn1_data->data;                        (asn1_data->data)++;            if(ASN1_OOB(asn1_data->start, asn1_data->end, asn1_data->data))            {                /*                **  Only return OOB if the short length wasn't zero.  Otherwise,                **  it's a valid encoding.                */                if(len->size != 0)                    return ASN1_ERR_OOB;            }            break;        case SF_BER_LEN_DEF_LONG:            iRet = asn1_decode_len_ext(asn1_data, &len->size);            if(iRet)                return iRet;            break;        case SF_BER_LEN_INDEF:            /*            **  Not sure what to do here, so we'll just set the length            **  to 0 and proceed for now.            */            len->size = 0;            asn1_data->data++;            if(ASN1_OOB(asn1_data->start, asn1_data->end, asn1_data->data))                return ASN1_ERR_OOB;            break;                    default:            /*            **  This should be one of the three values.  So we are in            **  error condition.            */            return ASN1_ERR_FATAL;    }    return ASN1_OK;}/***  NAME**    asn1_is_eoc::*//****  This function checks and ASN1_TYPE for end-of-content encoding.  This**  doesn't determine that this is what it is, but what it could be.****  @return int****  @retval 0 not EOC**  @retval 1 is EOC*/static int asn1_is_eoc(ASN1_TYPE *asn1){    if(!asn1)        return 0;    if(asn1->ident.class == 0x00 && asn1->ident.flag == 0x00 &&        asn1->ident.tag == 0x00 && asn1->len.type == SF_BER_LEN_DEF_SHORT &&       asn1->len.size == 0)    {        return 1;    }    return 0;}/***  NAME**    asn1_decode_type::*//****  This function decodes an ASN1_TYPE structure.  It processes the type in**  three parts.****  1) Identifier**  2) Length**  3) Data****  The data processing skips over primitive data (if it can) and processes**  construct data (if it can).****  This function also updates the data and len ptrs so we continue moving**  through the data.****  @return integer****  @retval ASN1_OK function successful**  @retval ASN1_ERR_MEM_ALLOC memory allocation failed**  @retval ASN1_ERR_INVALID_INDEF_LEN invalid indefinite encoding**  @retval ASN1_ERR_INVALID_ARG invalid argument**  @retval ASN1_ERR_OOB out of bounds*/static int asn1_decode_type(u_char **data, u_int *len, ASN1_TYPE **asn1_type){    ASN1_DATA asn1data;    u_int uiRawLen;    int iRet;    if(!*data)        return ASN1_ERR_INVALID_ARG;    *asn1_type = NULL;    /*    **  Check len first, because if it's 0, then we already decoded a valid    **  construct.  We let the caller know this, by returning OK, but setting    **  the asn1_type ptr to NULL.    */    if(*len == 0)        return ASN1_OK;    if(ASN1_OOB(*data, (*data) + *len, *data))        return ASN1_ERR_OOB;    *asn1_type = asn1_node_alloc();    if(*asn1_type == NULL)    {        return ASN1_ERR_MEM_ALLOC;    }    memset(*asn1_type, 0x00, sizeof(ASN1_TYPE));        asn1data.start = *data;    asn1data.end   = (*data) + *len;    asn1data.data  = *data;    iRet = asn1_decode_ident(*asn1_type, &asn1data);    if(iRet)    {        return iRet;    }    iRet = asn1_decode_len(*asn1_type, &asn1data);    if(iRet)    {        return iRet;    }    /*    **  Set this varible here, so we can set the data_len for    **  indeterminate constructs.    */    uiRawLen = asn1data.end - asn1data.data;    /*    **  This is an important check.  If the length is zero, it means that    **  we've either hit a zero length type or we've hit a BER indefinite    **  encoding (hate those).    **    **  Standard says that only constructs can have the indefinite length    **  encoding, but we still need to "prove" that.  Thanks M$.    */    if(!(*asn1_type)->len.size)    {        if((*asn1_type)->len.type != SF_BER_LEN_INDEF ||           (*asn1_type)->ident.flag == SF_ASN1_FLAG_CONSTRUCT)        {            (*asn1_type)->data = asn1data.data;            if((*asn1_type)->len.type == SF_BER_LEN_INDEF)            {                (*asn1_type)->data_len = uiRawLen;            }            else            {                /*                **  If we're not an indefinite type, then we check to                **  see if we are an eoc, so we don't have to check again.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -