/* Beholder RMON ethernet network monitor,Copyright (C) 1993 DNPAP group */
/* See file COPYING 'GNU General Public Licence' for copyright details   */
/************************************************************************
** MODULE INFORMATION*
**********************
**     FILE     NAME:       asn1.c
**     SYSTEM   NAME:       ASN1 Basic Encoding
**     ORIGINAL AUTHOR(S):  Dirk Wisse
**     VERSION  NUMBER:     1
**     CREATION DATE:       1990/11/22
**
** DESCRIPTION: ASN1 Basic Encoding Rules.
**              Encoding takes place from end to begin. A normal
**              procedure for definite encoding is:
**
**              Asn1Opn (Asn1, Buf, sizeof (Buf), ASN_ENC);
**              Asn1EocEnc (Asn1, &EndOfSeq);
**              Asn1IntEnc (Asn1, &EndOfInt, 3);
**              Asn1HdrEnc (Asn1, EndOfInt, ASN_UNI, ASN_PRI, ASN_INT);
**              Asn1OtsEnc (Asn1, &EndOfOts, "String", 6);
**              Asn1HdrEnc (Asn1, EndOfOts, ASN_UNI, ASN_PRI, ASN_OTS);
**              Asn1HdrEnc (Asn1, EndOfSeq, ASN_UNI, ASN_CON, ASN_SEQ);
**              Asn1Cls (Asn1, &BufBeg, &BufLen);
**
**              To decode this we must do:
**
**              Asn1Opn (Asn1, BufBeg, BufLen, ASN_DEC);
**              Asn1HdrDec (Asn1, &EndOfSeq, Cls, Con, Tag);
**              Asn1HdrDec (Asn1, &EndOfOts, Cls, Con, Tag);
**              Asn1OtsDec (Asn1, EndOfOts, String, sizeof (String), Length);
**              Asn1HdrDec (Asn1, &EndOfInt, Cls, Con, Tag);
**              Asn1IntDec (Asn1, EndOfInt, &Integer);
**              Asn1EocDec (Asn1, EndOfSeq);
**              Asn1Cls (Asn1, &BufBeg, &BufLen);
**              
**              For indefinite encoding EndOfSeq and &EndOfSeq in the
**              example above should be replaced by NULL.
**              For indefinite decoding nothing has to be changed.
**              This can be very useful if you want to decode both
**              definite and indefinite encodings.
**
*************************************************************************
** CHANGES INFORMATION **
*************************
** REVISION:    $Revision$
** WORKFILE:    $Workfile$
** LOGINFO:     $Log$
*************************************************************************/
#include "dnpap.h"
#include "asn1.h"

/**************************************************************
** NAME:        Asn1Opn                                   [API]
** SYNOPSIS:    void Asn1Opn
**                  (
**                      ASN1_SCK    *Asn1,
**                      BYTE        *Buf,
**                      unsigned    Len,
**                      unsigned    Mde
**                  )
** DESCRIPTION: Opens an ASN1 socket.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Buf: Character buffer for encoding.
**              Len: Length of character buffer.
**              Mde: Encoding, Decoding (ASN_ENC, ASN_DEC).
**              Encoding starts at the end of the buffer, and
**              proceeds to the beginning.
** RETURNS:     void
**************************************************************/
void Asn1Opn(ASN1_SCK *Asn1, BYTE *Buf, unsigned Len, unsigned Mde)
{
    Asn1->Begin = Buf;
    Asn1->End = Buf + Len;
    Asn1->Pointer = (Mde == ASN1_ENC) ? Buf + Len : Buf;
}

/**************************************************************
** NAME:        Asn1Cls                                   [API]
** SYNOPSIS:    void Asn1Cls
**                  (
**                      ASN1_SCK    *Asn1,
**                      BYTE        **Buf,
**                      unsigned    *Len
**                  )
** DESCRIPTION: Closes an ASN1 socket.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Buf: Pointer to beginning of encoding.
**              Len: Length of encoding.
** RETURNS:     void
**************************************************************/
void Asn1Cls(ASN1_SCK *Asn1, BYTE **Buf, unsigned *Len)
{
    *Buf = Asn1->Pointer;
    *Len = Asn1->End - Asn1->Pointer;
}



/**************************************************************
** NAME:        Asn1OctEnc
** SYNOPSIS:    BOOLEAN Asn1OctEnc
**                  (
**                      ASN1_SCK        *Asn1,
**                      BYTE            Chr
**                  )
** DESCRIPTION: Encodes an octet.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1OctEnc(ASN1_SCK *Asn1, BYTE Chr)
{
    if (Asn1->Pointer <= Asn1->Begin)
        return FALSE;
    *--(Asn1->Pointer) = Chr;
    return TRUE;
}

/**************************************************************
** NAME:        Asn1OctDec
** SYNOPSIS:    BOOLEAN Asn1OctDec
**                  (
**                      ASN1_SCK        *Asn1,
**                      BYTE            *Chr
**                  )
** DESCRIPTION: Decodes an octet.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1OctDec(ASN1_SCK *Asn1, BYTE *Chr)
{
    if (Asn1->Pointer >= Asn1->End)
        return FALSE;
    *Chr = *(Asn1->Pointer)++;
    return TRUE;
}

/**************************************************************
** NAME:        Asn1TagEnc
** SYNOPSIS:    BOOLEAN Asn1TagEnc
**                  (
**                      ASN1_SCK         *Asn1,
**                      unsigned        Tag
**                  )
** DESCRIPTION: Encodes a tag.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1TagEnc(ASN1_SCK *Asn1, unsigned Tag)
{
    BYTE        Chr;

    Chr = (BYTE) (Tag & 0x7F);
    Tag >>= 7;
    if (!Asn1OctEnc (Asn1, Chr))
        return FALSE;
    while (Tag > 0)
    {
        Chr = (BYTE) (Tag | 0x80);
        Tag >>= 7;
        if (!Asn1OctEnc (Asn1, Chr))
            return FALSE;
    }
    return TRUE;
}

/**************************************************************
** NAME:        Asn1TagDec
** SYNOPSIS:    BOOLEAN Asn1TagDec
**                  (
**                      ASN1_SCK         *Asn1,
**                      unsigned        *Tag
**                  )
** DESCRIPTION: Decodes a tag.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1TagDec(ASN1_SCK *Asn1, unsigned *Tag)
{
    BYTE        Chr;

    *Tag = 0;
    do
    {
        if (!Asn1OctDec (Asn1, &Chr))
            return FALSE;
        *Tag <<= 7;
        *Tag |= Chr & 0x7F;
    }
    while ((Chr & 0x80) == 0x80);
    return TRUE;
}

/**************************************************************
** NAME:        Asn1IdrEnc
** SYNOPSIS:    BOOLEAN Asn1IdrEnc
**                  (
**                      ASN1_SCK     *Asn1,
**                      unsigned    Cls,
**                      unsigned    Con,
**                      unsigned    Tag
**                  )
** DESCRIPTION: Encodes an identifier.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1IdrEnc(ASN1_SCK *Asn1, unsigned Cls, unsigned Con,
        unsigned Tag)
{
    BYTE        Chr;

    if (Tag >= 0x1F)
    {
        if (!Asn1TagEnc (Asn1, Tag))
            return FALSE;
        Tag = 0x1F;
    }
    Chr = (BYTE) ((Cls << 6) | (Con << 5) | (Tag));
    if (!Asn1OctEnc (Asn1, Chr))
        return FALSE;
    return TRUE;
}

/**************************************************************
** NAME:        Asn1IdrDec
** SYNOPSIS:    BOOLEAN Asn1IdrDec
**                  (
**                      ASN1_SCK     *Asn1,
**                      unsigned    *Cls,
**                      unsigned    *Con,
**                      unsigned    *Tag
**                  )
** DESCRIPTION: Decodes an identifier.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1IdrDec(ASN1_SCK *Asn1, unsigned *Cls, unsigned *Con,
        unsigned *Tag)
{
    BYTE        Chr;

    if (!Asn1OctDec (Asn1, &Chr))
        return FALSE;
    *Cls = (Chr & 0xC0) >> 6;
    *Con = (Chr & 0x20) >> 5;
    *Tag = (Chr & 0x1F);
    if (*Tag == 0x1F)
    {
        if (!Asn1TagDec (Asn1, Tag))
            return FALSE;
    }
    return TRUE;
}

/**************************************************************
** NAME:        Asn1LenEnc
** SYNOPSIS:    BOOLEAN Asn1LenEnc
**                  (
**                      ASN1_SCK     *Asn1,
**                      unsigned    Def,
**                      unsigned    Len
**                  )
** DESCRIPTION: Encodes a definite or indefinite length.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1LenEnc(ASN1_SCK *Asn1, unsigned Def, unsigned Len)
{
    BYTE        Chr,Cnt;

    if (!Def)
        Chr = 0x80;
    else
    {
        if (Len < 0x80)
            Chr = (BYTE) Len;
        else
        {
            Cnt = 0;
            while (Len > 0)
            {
                Chr = (BYTE) Len;
                Len >>= 8;
                if (!Asn1OctEnc (Asn1, Chr))
                    return FALSE;
                Cnt++;
            }
            Chr = (BYTE) (Cnt | 0x80);
        }
    }
    if (!Asn1OctEnc (Asn1, Chr))
        return FALSE;
    return TRUE;
}

/**************************************************************
** NAME:        Asn1LenDec
** SYNOPSIS:    BOOLEAN Asn1LenDec
**                  (
**                      ASN1_SCK     *Asn1,
**                      unsigned    Def,
**                      unsigned    Len
**                  )
** DESCRIPTION: Decodes a definite or indefinite length.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1LenDec(ASN1_SCK *Asn1, unsigned *Def, unsigned *Len)
{
    BYTE        Chr,Cnt;

    if (!Asn1OctDec (Asn1, &Chr))
        return FALSE;
    if (Chr == 0x80)
        *Def = 0;
    else
    {
        *Def = 1;
        if (Chr < 0x80)
            *Len = Chr;
        else
        {
            Cnt = (BYTE) (Chr & 0x7F);
            *Len = 0;
            while (Cnt > 0)
            {
                if (!Asn1OctDec (Asn1, &Chr))
                    return FALSE;
                *Len <<= 8;
                *Len |= Chr;
                Cnt--;
            }
        }
    }
    return TRUE;
}

/**************************************************************
** NAME:        Asn1HdrEnc                                [API]
** SYNOPSIS:    BOOLEAN Asn1HdrEnc
**                  (
**                      ASN1_SCK    *Asn1,
**                      BYTE        *Eoc,
**                      unsigned    Cls,
**                      unsigned    Con,
**                      unsigned    Tag
**                  )
** DESCRIPTION: Encodes an ASN1 header.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Eoc: Pointer to end of encoding or NULL if
**                   indefinite.
**              Cls: Class (see asn1.h)
**              Con: Primitive, Constructed (ASN_PRI, ASN_CON)
**              Tag: Tag (see asn1.h)
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1HdrEnc(ASN1_SCK *Asn1, BYTE *Eoc, unsigned Cls,
        unsigned Con, unsigned Tag)
{
    unsigned
        Def,
        Len;

    if (Eoc == 0)
    {
        Def = 0;
        Len = 0;
    }
    else
    {
        Def = 1;
        Len = Eoc - Asn1->Pointer;
    }
    if (!Asn1LenEnc (Asn1, Def, Len))
        return FALSE;
    if (!Asn1IdrEnc (Asn1, Cls, Con, Tag))
        return FALSE;
    return TRUE;
}

/**************************************************************
** NAME:        Asn1HdrDec                                [API]
** SYNOPSIS:    BOOLEAN Asn1HdrDec
**                  (
**                      ASN1_SCK    *Asn1,
**                      BYTE        **Eoc,
**                      unsigned    *Cls,
**                      unsigned    *Con,
**                      unsigned    *Tag
**                  )
** DESCRIPTION: Decodes an ASN1 header.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Eoc: Pointer to end of encoding or 0 if
**                   indefinite.
**              Cls: Class (see asn1.h)
**              Con: Primitive, Constructed (ASN_PRI, ASN_CON)
**              Tag: Tag (see asn1.h)
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1HdrDec(ASN1_SCK *Asn1, BYTE **Eoc, unsigned *Cls,
        unsigned *Con, unsigned *Tag)
{
    unsigned
        Def,
        Len;

    if (!Asn1IdrDec (Asn1, Cls, Con, Tag))
        return FALSE;
    if (!Asn1LenDec (Asn1, &Def, &Len))
        return FALSE;
    if (Def)
        *Eoc = Asn1->Pointer + Len;
    else
        *Eoc = 0;
    return TRUE;
}


/**************************************************************
** NAME:        Asn1Eoc                                   [API]
** SYNOPSIS:    BOOLEAN Asn1Eoc
**                  (
**                      ASN1_SCK    *Asn1,
**                      BYTE        *Eoc
**                  )
** DESCRIPTION: Checks if decoding is at End Of Contents.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Eoc: Pointer to end of encoding or 0 if
**                   indefinite.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1Eoc
    (
        ASN1_SCK *Asn1,
        BYTE     *Eoc
    )
{
    if (Eoc == 0)
        return (Asn1->Pointer [0] == 0x00 && Asn1->Pointer [1] == 0x00);
    else
        return (Asn1->Pointer >= Eoc);
}

/**************************************************************
** NAME:        Asn1EocEnc                                [API]
** SYNOPSIS:    BOOLEAN Asn1EocEnc
**                  (
**                      ASN1_SCK    *Asn1,
**                      BYTE        **Eoc
**                  )
** DESCRIPTION: Encodes End Of Contents.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Eoc: Pointer to end of encoding or 0 if
**                   indefinite.
**              If Eoc is 0 it encodes an ASN1 End Of
**              Contents (0x00 0x00), so it produces an
**              indefinite length encoding. If Eoc points to
**              a character pointer, Eoc is filled with the
**              pointer to the last encoded octet. This pointer
**              can be used in the next Asn1HdrEnc to determine
**              the length of the encoding. This produces a
**              definite length encoding.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1EocEnc
    (
        ASN1_SCK *Asn1,
        BYTE     **Eoc
    )        
{
    if (Eoc == 0)
    {
        if (!Asn1OctEnc (Asn1, 0x00))
            return FALSE;
        if (!Asn1OctEnc (Asn1, 0x00))
            return FALSE;
        return TRUE;
    }
    else
    {
        *Eoc = Asn1->Pointer;
        return TRUE;
    }
}

/**************************************************************
** NAME:        Asn1EocDec                                [API]
** SYNOPSIS:    BOOLEAN Asn1EocDec
**                  (
**                      ASN1_SCK    *Asn1,
**                      BYTE        *Eoc
**                  )
** DESCRIPTION: Decodes End Of Contents.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Eoc: Pointer to end of encoding or 0 if
**                   indefinite.
**              If Eoc is 0 it decodes an ASN1 End Of
**              Contents (0x00 0x00), so it has to be an
**              indefinite length encoding. If Eoc is a
**              character pointer, it probably was filled by
**              Asn1HdrDec, and should point to the octet
**              after the last of the encoding. It is checked
**              if this pointer points to the octet to be
**              decoded. This only takes place in decoding a
**              definite length encoding.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1EocDec
    (
        ASN1_SCK *Asn1,
        BYTE     *Eoc
    )
{
    BYTE        Chr;

    if (Eoc == 0)
    {
        if (!Asn1OctDec (Asn1, &Chr))
            return FALSE;
        if (Chr != 0x00)
            return FALSE;
        if (!Asn1OctDec (Asn1, &Chr))
            return FALSE;
        if (Chr != 0x00)
            return FALSE;
        return TRUE;
    }
    else
    {
        if (Asn1->Pointer != Eoc)
            return FALSE;
        return TRUE;
    }
}

/**************************************************************
** NAME:        Asn1NulEnc                                [API]
** SYNOPSIS:    BOOLEAN Asn1NulEnc
**                  (
**                      ASN1_SCK    *Asn1,
**                      BYTE        **Eoc
**                  )
** DESCRIPTION: Encodes Null.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Eoc: Pointer to end of encoding.
**              Encodes nothing but can be used to fill Eoc.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1NulEnc
    (
        ASN1_SCK *Asn1,
        BYTE     **Eoc
    )
{
    *Eoc = Asn1->Pointer;
    return TRUE;
}

/**************************************************************
** NAME:        Asn1NulDec                                [API]
** SYNOPSIS:    BOOLEAN Asn1NulDec
**                  (
**                      ASN1_SCK    *Asn1,
**                      BYTE        *Eoc
**                  )
** DESCRIPTION: Decodes Null.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Eoc: Pointer to end of encoding or 0 if
**                   indefinite.
**              Decodes anything up to Eoc.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1NulDec
    (
        ASN1_SCK *Asn1,
        BYTE    *Eoc
    )
{
    Asn1->Pointer = Eoc;
    return TRUE;
}

/**************************************************************
** NAME:        Asn1BolEnc                                [API]
** SYNOPSIS:    BOOLEAN Asn1BolEnc
**                  (
**                      ASN1_SCK    *Asn1,
**                      BYTE        **Eoc,
**                      BOOLEAN     Bol
**                  )
** DESCRIPTION: Encodes Boolean.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Eoc: Pointer to end of encoding.
**              Bol: FALSE, TRUE (0, !0).
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1BolEnc
    (
        ASN1_SCK *Asn1,
        BYTE    **Eoc,
        BOOLEAN     Bol
    )
{
    BYTE        Chr;

    *Eoc = Asn1->Pointer;
    Chr = (BYTE) (Bol ? 0xFF : 0x00);
    if (!Asn1OctEnc (Asn1, Chr))
        return FALSE;
    return TRUE;
}

/**************************************************************
** NAME:        Asn1BolDec                                [API]
** SYNOPSIS:    BOOLEAN Asn1BolDec
**                  (
**                      ASN1_SCK    *Asn1,
**                      BYTE        *Eoc
**                      BOOLEAN     *Bol
**                  )
** DESCRIPTION: Decodes Boolean.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Eoc: Pointer to end of encoding or 0 if
**                   indefinite.
**              Bol: False, True (0, !0).
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1BolDec
    (
        ASN1_SCK *Asn1,
        BYTE    *Eoc,
        BOOLEAN     *Bol
    )
{
    BYTE        Chr;

    if (!Asn1OctDec (Asn1, &Chr))
        return FALSE;
    *Bol = Chr ? 1 : 0;
    if (Asn1->Pointer != Eoc)
        return FALSE;
    return TRUE;
}

/**************************************************************
** NAME:        Asn1IntEnc                                [API]
** SYNOPSIS:    BOOLEAN Asn1IntEnc
**                  (
**                      ASN1_SCK    *Asn1,
**                      BYTE        **Eoc,
**                      int         Int
**                  )
** DESCRIPTION: Encodes Integer.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Eoc: Pointer to end of encoding.
**              Int: Integer.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1IntEnc
    (
        ASN1_SCK *Asn1,
        BYTE    **Eoc,
        int     Int
    )
{
    BYTE        Chr,Sgn;
    int
        Lim;

    *Eoc = Asn1->Pointer;
    if (Int < 0)
    {
        Lim = -1;
        Sgn = 0x80;
    }
    else
    {
        Lim = 0;
        Sgn = 0x00;
    }
    do
    {
        Chr = (BYTE) Int;
        Int >>= 8;
        if (!Asn1OctEnc (Asn1, Chr))
            return FALSE;
    }
    while ((Int != Lim) || (BYTE) (Chr & 0x80) != Sgn);
    return TRUE;
}

/**************************************************************
** NAME:        Asn1IntDec                                [API]
** SYNOPSIS:    BOOLEAN Asn1IntDec
**                  (
**                      ASN1_SCK    *Asn1,
**                      BYTE        *Eoc
**                      int         *Int
**                  )
** DESCRIPTION: Decodes Integer.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Eoc: Pointer to end of encoding or 0 if
**                   indefinite.
**              Int: Integer.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1IntDec
    (
        ASN1_SCK *Asn1,
        BYTE     *Eoc,
        int     *Int
    )
{
    BYTE
        Chr;
    unsigned
        Len;

    if (!Asn1OctDec (Asn1, &Chr))
        return FALSE;
    *Int = (int) Chr;
    Len = 1;
    while (Asn1->Pointer < Eoc)
    {
        if (++Len > sizeof (int))
            return FALSE;
        if (!Asn1OctDec (Asn1, &Chr))
            return FALSE;
        *Int <<= 8;
        *Int |= Chr;
    }
    return TRUE;
}

/**************************************************************
** NAME:        Asn1IntEncLng                             [API]
** SYNOPSIS:    BOOLEAN Asn1IntEncLng
**                  (
**                      ASN1_SCK    *Asn1,
**                      BYTE        **Eoc,
**                      long        Int
**                  )
** DESCRIPTION: Encodes Long Integer.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Eoc: Pointer to end of encoding.
**              Int: Integer.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1IntEncLng
    (
        ASN1_SCK *Asn1,
        BYTE     **Eoc,
        long    Int
    )
{
    BYTE
        Chr,
        Sgn;
    long
        Lim;

    *Eoc = Asn1->Pointer;
    if (Int < 0)
    {
        Lim = -1;
        Sgn = 0x80;
    }
    else
    {
        Lim = 0;
        Sgn = 0x00;
    }
    do
    {
        Chr = (BYTE) Int;
        Int >>= 8;
        if (!Asn1OctEnc (Asn1, Chr))
            return FALSE;
    }
    while ((Int != Lim) || (BYTE) (Chr & 0x80) != Sgn);
    return TRUE;
}

/**************************************************************
** NAME:        Asn1IntDecLng                             [API]
** SYNOPSIS:    BOOLEAN Asn1IntDecLng
**                  (
**                      ASN1_SCK    *Asn1,
**                      BYTE        *Eoc,
**                      long        *Int
**                  )
** DESCRIPTION: Decodes Long Integer.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Eoc: Pointer to end of encoding or 0 if
**                   indefinite.
**              Int: Integer.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1IntDecLng
    (
        ASN1_SCK *Asn1,
        BYTE    *Eoc,
        long    *Int
    )
{
    BYTE
        Chr;
    unsigned
        Len;

    if (!Asn1OctDec (Asn1, &Chr))
        return FALSE;
    *Int = (signed char) Chr;
    Len = 1;
    while (Asn1->Pointer < Eoc)
    {
        if (++Len > sizeof (long))
            return FALSE;
        if (!Asn1OctDec (Asn1, &Chr))
            return FALSE;
        *Int <<= 8;
        *Int |= Chr;
    }
    return TRUE;
}

/**************************************************************
** NAME:        Asn1IntEncUns                             [API]
** SYNOPSIS:    BOOLEAN Asn1IntEncUns
**                  (
**                      ASN1_SCK    *Asn1,
**                      BYTE        **Eoc,
**                      unsigned    Int
**                  )
** DESCRIPTION: Encodes Unsigned Integer.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Eoc: Pointer to end of encoding.
**              Int: Integer.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1IntEncUns
    (
        ASN1_SCK     *Asn1,
        BYTE        **Eoc,
        unsigned    Int
    )
{
    BYTE
        Chr;

    *Eoc = Asn1->Pointer;
    do
    {
        Chr = (BYTE) Int;
        Int >>= 8;
        if (!Asn1OctEnc (Asn1, Chr))
            return FALSE;
    }
    while ((Int != 0) || (Chr & 0x80) != 0x00);
    return TRUE;
}

/**************************************************************
** NAME:        Asn1IntDecUns                             [API]
** SYNOPSIS:    BOOLEAN An1IntDecUns
**                  (
**                      ASN1_SCK    *Asn1,
**                      BYTE        *Eoc,
**                      unsigned    *Int
**                  )
** DESCRIPTION: Decodes Unsigned Integer.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Eoc: Pointer to end of encoding or 0 if
**                   indefinite.
**              Int: Integer.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1IntDecUns
    (
        ASN1_SCK     *Asn1,
        BYTE        *Eoc,
        unsigned    *Int
    )
{
    BYTE
        Chr;
    unsigned
        Len;

    if (!Asn1OctDec (Asn1, &Chr))
        return FALSE;
    *Int = Chr;
    if (Chr == 0)
        Len = 0;
    else
        Len = 1;
    while (Asn1->Pointer < Eoc)
    {
        if (++Len > sizeof (int))
            return FALSE;
        if (!Asn1OctDec (Asn1, &Chr))
            return FALSE;
        *Int <<= 8;
        *Int |= Chr;
    }
    return TRUE;
}

/**************************************************************
** NAME:        Asn1IntEncLngUns                          [API]
** SYNOPSIS:    BOOLEAN Asn1IntEncLngUns
**                  (
**                      ASN1_SCK        *Asn1,
**                      BYTE            **Eoc,
**                      long unsigned   Int
**                  )
** DESCRIPTION: Encodes Long Unsigned Integer.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Eoc: Pointer to end of encoding.
**              Int: Integer.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1IntEncLngUns
    (
        ASN1_SCK         *Asn1,
        BYTE            **Eoc,
        unsigned long   Int
    )
{
    BYTE
        Chr;

    *Eoc = Asn1->Pointer;
    do
    {
        Chr = (BYTE) Int;
        Int >>= 8;
        if (!Asn1OctEnc (Asn1, Chr))
            return FALSE;
    }
    while ((Int != 0) || (Chr & 0x80) != 0x00);
    return TRUE;
}

/**************************************************************
** NAME:        Asn1IntDecLngUns                          [API]
** SYNOPSIS:    BOOLEAN Asn1IntDecLngUns
**                  (
**                      ASN1_SCK        *Asn1,
**                      BYTE            *Eoc,
**                      long unsigned   *Int
**                  )
** DESCRIPTION: Decodes Long Unsigned Integer.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Eoc: Pointer to end of encoding or 0 if
**                   indefinite.
**              Int: Integer.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1IntDecLngUns
    (
        ASN1_SCK         *Asn1,
        BYTE            *Eoc,
        unsigned long   *Int
    )
{
    BYTE
        Chr;
    unsigned
        Len;

    if (!Asn1OctDec (Asn1, &Chr))
        return FALSE;
    *Int = Chr;
    if (Chr == 0)
        Len = 0;
    else
        Len = 1;
    while (Asn1->Pointer < Eoc)
    {
        if (++Len > sizeof (long))
            return FALSE;
        if (!Asn1OctDec (Asn1, &Chr))
            return FALSE;
        *Int <<= 8;
        *Int |= Chr;
    }
    return TRUE;
}

/**************************************************************
** NAME:        Asn1BtsEnc                                [API]
** SYNOPSIS:    BOOLEAN Asn1BtsEnc
**                  (
**                      ASN1_SCK    *Asn1,
**                      BYTE        **Eoc,
**                      BYTE        *Bts,
**                      unsigned    BtsLen,
**                      BYTE        BtsUnu
**                  )
** DESCRIPTION: Encodes Bit String.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Eoc: Pointer to end of encoding.
**              Bts: Pointer to begin of Bit String.
**              BtsLen: Length of Bit String in characters.
**              BtsUnu: Number of unused bits in last character.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1BtsEnc
    (
        ASN1_SCK     	*Asn1,
        BYTE        	**Eoc,
        BYTE        	*Bts,
        unsigned    	BtsLen,
        BYTE   BtsUnu
    )
{
    *Eoc = Asn1->Pointer;
    Bts += BtsLen;
    while (BtsLen-- > 0)
    {
        if (!Asn1OctEnc (Asn1, *--Bts))
            return FALSE;
    }
    if (!Asn1OctEnc (Asn1, BtsUnu))
        return FALSE;
    return TRUE;
}

/**************************************************************
** NAME:        Asn1BtsDec                                [API]
** SYNOPSIS:    BOOLEAN Asn1BtsDec
**                  (
**                      ASN1_SCK     	*Asn1,
**                      BYTE        	*Eoc,
**                      BYTE        	*Bts,
**                      unsigned    	BtsSze,
**                      unsigned    	*BtsLen,
**                      BYTE   *BtsUnu
**                  )
** DESCRIPTION: Decodes Bit String.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Eoc: Pointer to end of encoding or 0 if
**                   indefinite.
**              Bts: Pointer to begin of Bit String.
**              BtsSze: Size of Bit String in characters.
**              BtsLen: Length of Bit String in characters.
**              BtsUnu: Number of unused bits in last character.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1BtsDec
    (
        ASN1_SCK     	*Asn1,
        BYTE        	*Eoc,
        BYTE		    *Bts,
        unsigned    	BtsSze,
        unsigned    	*BtsLen,
        BYTE  	*BtsUnu
    )
{
    if (!Asn1OctDec (Asn1, BtsUnu))
        return FALSE;
    *BtsLen = 0;
    while (Asn1->Pointer < Eoc)
    {
        if (++(*BtsLen) > BtsSze)
            return FALSE;
        if (!Asn1OctDec (Asn1, (BYTE *)Bts++))
            return FALSE;
    }
    return TRUE;
}

/**************************************************************
** NAME:        Asn1OtsEnc                                [API]
** SYNOPSIS:    BOOLEAN Asn1OtsEnc
**                  (
**                      ASN1_SCK    *Asn1,
**                      BYTE        **Eoc,
**                      BYTE        *Ots,
**                      unsigned    OtsLen
**                  )
** DESCRIPTION: Encodes Octet String.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Eoc: Pointer to end of encoding.
**              Ots: Pointer to begin of Octet String.
**              OtsLen: Length of Octet String in characters.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1OtsEnc
    (
        ASN1_SCK     *Asn1,
        BYTE        **Eoc,
        BYTE        *Ots,
        unsigned    OtsLen
    )
{
    *Eoc = Asn1->Pointer;
    Ots += OtsLen;
    while (OtsLen-- > 0)
    {
        if (!Asn1OctEnc (Asn1, *--Ots))
            return FALSE;
    }
    return TRUE;
}

/**************************************************************
** NAME:        Asn1OtsDec                                [API]
** SYNOPSIS:    BOOLEAN Asn1OtsDec
**                  (
**                      ASN1_SCK    *Asn1,
**                      BYTE        *Eoc,
**                      BYTE        *Ots,
**                      unsigned    OtsSze,
**                      unsigned    *OtsLen
**                  )
** DESCRIPTION: Decodes Octet String.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Eoc: Pointer to end of encoding or 0 if
**                   indefinite.
**              Ots: Pointer to begin of Octet String.
**              OtsSze: Size of Octet String in characters.
**              OtsLen: Length of Octet String in characters.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1OtsDec
    (
        ASN1_SCK     *Asn1,
        BYTE        *Eoc,
        BYTE        *Ots,
        unsigned    OtsSze,
        unsigned    *OtsLen
    )
{
    *OtsLen = 0;
    while (Asn1->Pointer < Eoc)
    {
        if (++(*OtsLen) > OtsSze)
            return FALSE;
        if (!Asn1OctDec (Asn1, (BYTE *)Ots++))
            return FALSE;
    }
    return TRUE;
}

/**************************************************************
** NAME:        Asn1SbiEnc
** SYNOPSIS:    BOOLEAN Asn1SbiEnc
**                  (
**                      ASN1_SCK        *Asn1,
**                      unsigned long   Sbi
**                  )
** DESCRIPTION: Encodes Sub Identifier.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Sbi: Sub Identifier.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1SbiEnc
    (
        ASN1_SCK      *Asn1,
        unsigned long Sbi
    )
{
    BYTE
        Chr;

    Chr = (BYTE) (Sbi & 0x7F);
    Sbi >>= 7;
    if (!Asn1OctEnc (Asn1, Chr))
        return FALSE;
    while (Sbi > 0)
    {
        Chr = (BYTE) (Sbi | 0x80);
        Sbi >>= 7;
        if (!Asn1OctEnc (Asn1, Chr))
            return FALSE;
    }
    return TRUE;
}

/**************************************************************
** NAME:        Asn1SbiDec
** SYNOPSIS:    BOOLEAN Asn1SbiDec
**                  (
**                      ASN1_SCK        *Asn1,
**                      unsigned long   *Sbi
**                  )
** DESCRIPTION: Encodes Sub Identifier.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Sbi: Sub Identifier.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1SbiDec
    (
        ASN1_SCK      *Asn1,
        unsigned long *Sbi
    )
{
    BYTE
        Chr;

    *Sbi = 0;
    do
    {
        if (!Asn1OctDec (Asn1, &Chr))
            return FALSE;
        *Sbi <<= 7;
        *Sbi |= Chr & 0x7F;
    }
    while ((Chr & 0x80) == 0x80);
    return TRUE;
}

/**************************************************************
** NAME:        Asn1OjiEnc                                [API]
** SYNOPSIS:    BOOLEAN Asn1OjiEnc
**                  (
**                      ASN1_SCK        *Asn1,
**                      char            **Eoc,
**                      unsigned long   *Oji,
**                      unsigned        OjiLen
**                  )
** DESCRIPTION: Encodes Obect Identifier.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Eoc: Pointer to end of encoding.
**              Oji: Pointer to begin of Object Identifier.
**              OjiLen: Length of Object Identifier in unsigneds.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1OjiEnc
    (
        ASN1_SCK        *Asn1,
        BYTE            **Eoc,
        unsigned long   *Oji,
        unsigned        OjiLen
    )
{
    unsigned long
        Sbi;

    *Eoc = Asn1->Pointer;
    if (OjiLen < 2)
        return FALSE;
    Sbi = Oji [1] + Oji [0] * 40;
    Oji += OjiLen;
    while (OjiLen-- > 2)
    {
        if (!Asn1SbiEnc (Asn1, *--Oji))
            return FALSE;
    }
    if (!Asn1SbiEnc (Asn1, Sbi))
        return FALSE;
    return TRUE;
}

/**************************************************************
** NAME:        Asn1OjiDec                                [API]
** SYNOPSIS:    BOOLEAN Asn1OjiDec
**                  (
**                      ASN1_SCK        *Asn1,
**                      char            *Eoc,
**                      unsigned long   *Oji,
**                      unsigned        OjiSze,
**                      unsigned        *OjiLen
**                  )
** DESCRIPTION: Decodes Obect Identifier.
**              Parameters:
**              Asn1: Pointer to ASN1 socket.
**              Eoc: Pointer to end of encoding or 0 if
**                   indefinite.
**              Oji: Pointer to begin of Object Identifier.
**              OjiSze: Size of Obect Identifier in unsigneds
**              OjiLen: Length of Object Identifier in unsigneds.
** RETURNS:     BOOLEAN success.
**************************************************************/
BOOLEAN Asn1OjiDec
    (
        ASN1_SCK      *Asn1,
        BYTE          *Eoc,
        unsigned long *Oji,
        unsigned      OjiSze,
        unsigned      *OjiLen
    )
{
    unsigned long
        Sbi;

    if (OjiSze < 2)
        return FALSE;
    if (!Asn1SbiDec (Asn1, &Sbi))
        return FALSE;
    if (Sbi < 40)
    {
        Oji [0] = 0;
        Oji [1] = Sbi;
    }
    else if (Sbi < 80)
    {
        Oji [0] = 1;
        Oji [1] = Sbi - 40;
    }
    else
    {
        Oji [0] = 2;
        Oji [1] = Sbi - 80;
    }
    *OjiLen = 2;
    Oji += 2;
    while (Asn1->Pointer < Eoc)
    {
        if (++(*OjiLen) > OjiSze)
            return FALSE;
        if (!Asn1SbiDec (Asn1, Oji++))
            return FALSE;
    }
    return TRUE;
}

