(**************************************************************************)
(*                                                                        *)
(*  Decoding an ASN.1 coded file                                          *)
(*  Copyright (C) 2024   Peter Moylan                                     *)
(*                                                                        *)
(*  This program is free software: you can redistribute it and/or modify  *)
(*  it under the terms of the GNU General Public License as published by  *)
(*  the Free Software Foundation, either version 3 of the License, or     *)
(*  (at your option) any later version.                                   *)
(*                                                                        *)
(*  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     *)
(*  along with this program.  If not, see <http://www.gnu.org/licenses/>. *)
(*                                                                        *)
(*  To contact author:   http://www.pmoylan.org   peter@pmoylan.org       *)
(*                                                                        *)
(**************************************************************************)

DEFINITION MODULE ASN1;

        (********************************************************)
        (*                                                      *)
        (*   Extracting information from an ASN.1 coded file    *)
        (*                                                      *)
        (*  Programmer:         P. Moylan                       *)
        (*  Started:            29 September 2018               *)
        (*  Last edited:        10 October 2023                 *)
        (*  Status:             OK                              *)
        (*                                                      *)
        (********************************************************)


FROM SYSTEM IMPORT CARD8;

FROM VarStrings IMPORT
    (* type *)  ByteStringPtr, VarStringPtr, ByteStr;

FROM BigNum IMPORT
    (* type *)  BN;

(************************************************************************)
(* NOTE: most procedures in this module that return results of type     *)
(* ByteStr set the "allocated" field in those results to 0.  This is    *)
(* because those results are pointers into the input string, so that    *)
(* no extra copy of the data is created.                                *)
(************************************************************************)


          (************************************************)
          (*    CONVERT BINARY ASN.1 TO HUMAN-READABLE    *)
          (************************************************)

PROCEDURE ASN1toTxt (VAR (*IN*) bindata: ARRAY OF CARD8;  N: CARDINAL;
                            VAR (*OUT*) textptr: VarStringPtr): CARDINAL;

    (* Translates N binary bytes in ASN.1 format to text.  Returns  *)
    (* the number of text characters.                               *)

          (************************************************)
          (*     EXTRACT COMPONENTS FROM ASN.1 STRING     *)
          (************************************************)

PROCEDURE CopyContent (VAR (*IN*) bindata: ARRAY OF CARD8): ByteStr;

    (* Throws away the type infomation of an ASN.1 element, returning   *)
    (* only the content part.  Special case: for a BIT STRING element,  *)
    (* we discard the "unused bits" field, because this is always zero  *)
    (* in the applications I'm interested in.                           *)

    (* NOTE: this returns a copy of the content,  not merely a pointer  *)
    (* to the data.                                                     *)

PROCEDURE GetValueString (VAR (*IN*) bindata: ARRAY OF CARD8): ByteStr;

    (* Throws away the type infomation of an ASN.1 element, returning   *)
    (* only the content part.  Special case: for a BIT STRING element,  *)
    (* we discard the "unused bits" field, because this is always zero  *)
    (* in the applications I'm interested in.                           *)

PROCEDURE GetBool (VAR (*IN*) bindata: ARRAY OF CARD8): BOOLEAN;

    (* Fetches a Boolean value. *)

PROCEDURE GetInteger (VAR (*IN*) bindata: ARRAY OF CARD8): BN;

    (* Assumption: bindata is an ASN.1 encoding of an integer.  If so,  *)
    (* we return the value as a BigNum.  If not, we return zero.        *)

PROCEDURE GetSmallInteger (VAR (*IN*) bindata: ARRAY OF CARD8): INTEGER;

    (* Assumption: bindata is an ASN.1 encoding of an integer.  If so,  *)
    (* we return the value.  If not, we return zero.  The result is     *)
    (* saturated if it overflows.                                       *)

PROCEDURE ExtractParts (VAR (*IN*) bindata: ARRAY OF CARD8;
                        VAR (*OUT*) result: ARRAY OF ByteStr): CARDINAL;

    (* If bindata represents a SEQUENCE or a SET, result[k] contains    *)
    (* a copy of the kth component of the sequence or set.  The         *)
    (* function result is the number of components extracted.           *)
    (* Otherwise, no result is extracted, we return 0 as the function   *)
    (* result.  Note that some components will not be extracted if the  *)
    (* result array is not big enough.                                  *)

    (* In this version we don't make a copy of the result; we simply    *)
    (* point into the original bindata array.                           *)

PROCEDURE GetTaggedItem (VAR (*IN*) bindata: ARRAY OF CARD8;
                        VAR (*OUT*) result: ByteStr): CARDINAL;

    (* Assumption: we have an EXPLICIT tag.  Removes the tag and        *)
    (* length, returning the tag value as well as the result.           *)

PROCEDURE INTEGERtoBN (VAR (*IN*) bindata: ARRAY OF CARD8;  pos: CARDINAL): BN;

    (* Converts an ASN.1 BIT STRING to a Bignum.  Returns zero if an    *)
    (* INTEGER does not start at bindata[pos].                          *)

PROCEDURE BitStringToBN (VAR (*IN*) bindata: ARRAY OF CARD8;  pos: CARDINAL): BN;

    (* Converts an ASN.1 BIT STRING to a Bignum.  Returns zero if a BIT *)
    (* STRING does not start at bindata[pos].                           *)

PROCEDURE GetObjID (VAR (*IN*) bindata: ARRAY OF CARD8;  pos: CARDINAL;
                           VAR (*OUT*) result: ARRAY OF CARDINAL): CARDINAL;

    (* Converts an ASN.1 BIT STRING to an OBJECT ID.  Returns the       *)
    (* number of components, or zero if an object ID does not start at  *)
    (* bindata[pos].                                                    *)

PROCEDURE GetText (VAR (*IN*) bindata: ARRAY OF CARD8;  pos: CARDINAL;
                           VAR (*OUT*) result: ARRAY OF CHAR);

    (* Converts a component that is a textual item.  We trust the       *)
    (* caller to know that the type is appropriate.                     *)

PROCEDURE GetOctetString (VAR (*IN*) bindata: ARRAY OF CARD8;  pos: CARDINAL;
                           VAR (*OUT*) result: ByteStr);

    (* Converts a component that is a string of bytes.  We trust the    *)
    (* caller to know that the type is appropriate.                     *)

PROCEDURE GetNumericArray (VAR (*IN*) buffer: ARRAY OF CARD8;
                            VAR (*OUT*) result: ARRAY OF BN): CARDINAL;

    (* Assumption: bindata represents a SEQUENCE or a SET where each    *)
    (* component is a Bignum integer.  The output result is an array    *)
    (* of those numbers, and the function result is the number of       *)
    (* integers extracted.  If the input assumption is violated, or the *)
    (* result array is not big enough, some results will be zero.       *)

          (************************************************)
          (*        CREATE ASN.1 ENCODING OF DATA         *)
          (************************************************)

PROCEDURE ASNEncodeBitString (VAR (*INOUT*) val: ByteStr;  unusedbits: CARD8);

    (* Produces the ASN.1 encoding of a single bit string.  *)
    (* The result replaces the original data.               *)

PROCEDURE ASNEncodeCharString (type: CARDINAL;  str: ARRAY OF CHAR;
                                        VAR (*OUT*) val: ByteStr);

    (* Produces the ASN.1 encoding of a character string.               *)

    (* The restricted character string types are                        *)
    (*    12  UTF8String      18  NumericString    19  PrintableString  *)
    (*    20  TeletextString  21  VideoTextString  22  IA5String        *)
    (*    25  GraphicString   26  VisibleString    27  GeneralString    *)
    (*    28  UniversalString 30  BMPString                             *)
    (* There is also a unrestricted type   29 CHARACTER STRING          *)

PROCEDURE ASNEncodeSequence (N: CARDINAL;  val: ARRAY OF ByteStr): ByteStr;

    (* Produces the ASN.1 encoding of a sequence of N components.  We   *)
    (* assume that those components have already been created in the    *)
    (* form of valid ASN.1 strings.                                     *)

PROCEDURE ASNEncodeSet (N: CARDINAL;  val: ARRAY OF ByteStr): ByteStr;

    (* Produces the ASN.1 encoding of a set of N components.  We        *)
    (* assume that those components have already been created in the    *)
    (* form of valid ASN.1 strings.                                     *)

PROCEDURE ASNEncodeBNArray (N: CARDINAL;  val: ARRAY OF BN): ByteStr;

    (* Produces the ASN.1 encoding of a sequence of N Bignums.  *)

END ASN1.

