static void ParseErrorResponseUDP(KerberosData KerbData, TDSReader ByteReader)
        {
            int TagID = 0, TagLen = 0;

            do
            {
                TagID  = ByteReader.ReadByte() & (int)0x1F;
                TagLen = ReadAsnLen(ByteReader, false);

                switch (TagID)
                {
                case 4:     //skip Tag4->Stime,
                case 5:     //skip Tag5->SuSec
                {
                    ByteReader.ReadBytes(TagLen);
                    break;
                }

                case 6:
                {
                    ReadAsnLen(ByteReader);
                    KerbData.errorCode = ByteReader.ReadByte();
                    KerbData.ErrorDesc = GetErrorDesc((ErrorCodes)KerbData.errorCode);
                    return;
                }

                default:
                {
                    //throw new Exception("Unexpected Tag " + TagID + " found in  KERB UDP error response");
                    break;
                }
                }
            }while (TagID < 6); //Total 12 tags expected, but we are reading only 6 tags until error code
        }
        static void ParseNonErrorResponseTCP(KerberosData KerbData, TDSReader ByteReader)
        {
            //Tag4-TagC
            //int TagID = 0, TagLen = 0;

            //do
            //{
            //    TagID = ByteReader.ReadByte();
            //    TagLen = ReadAsnLen(ByteReader, false);
            //    TagID = (TagID & (int)0x1F);


            //    switch (TagID)
            //    {
            //        case 0:
            //        case 1:
            //        case 2:
            //        case 3:
            //        case 4:
            //        case 5:
            //        case 6:
            //            {
            //                ByteReader.ReadBytes(TagLen); // Skip 'Crealm', 'Cname', 'Ticket' and 'EncPart'
            //                break;
            //            }
            //        default:
            //            {
            //                throw new Exception("Unexpected Tag " + TagID + " found in KERB TCP error response" );
            //            }
            //    }

            //}
            //while (TagID < 6); //total 6 tags expected
        }
        static MessageTypes GetMessageType(KerberosData KerbData, TDSReader ByteReader)
        {
            int Len = ReadAsnLen(ByteReader);

            int MsgType = ByteReader.ReadByte();

            if (Len == 1)
            {
                if (MsgType == (int)MessageTypes.KRB_TGS_REQ)
                {
                    KerbData.RequestType = MessageTypes.KRB_TGS_REQ;
                }
                else if (MsgType == (int)MessageTypes.KRB_ERROR)
                {
                    KerbData.ResponseType = MessageTypes.KRB_ERROR;
                }
                else if (MsgType == (int)MessageTypes.KRB_TGS_REP)
                {
                    KerbData.ResponseType = MessageTypes.KRB_TGS_REP;
                }

                return((MessageTypes)MsgType);
            }
            else // bug in the code if we get here ...
            {
                throw new Exception("Invalid KERB Request length: " + Len);
            }
        }
        static void GetVersion(KerberosData KerbData, TDSReader ByteReader)
        {
            int Length = ReadAsnLen(ByteReader);

            if (Length == 1)
            {
                KerbData.Version = ByteReader.ReadByte();
            }

            if ((Length != 1) || (KerbData.Version != 5))
            {
                throw new Exception("Invalid Kerberos version and unexpected version or unexpected number of bytes are used for storing the version ");
            }
        }
        public static void Process(NetworkTrace trace)
        {
            foreach (ConversationData c in trace.conversations)
            {
                if (c.sourcePort == 88)
                {
                    TDSParser.reverseSourceDest(c);
                }


                if (c.destPort != 88)
                {
                    continue;
                }


                KerberosData KerbData = null;

                try
                {
                    if (c.isUDP) // UDP
                    {
                        KerbData = ProcessUDP(c);
                    }
                    else        // TCP
                    {
                        KerbData = ProcessTCP(c);
                    }
                    // ignore non KRB_TGS requests
                    // ignore responses without an associated request - we don't want to log errors for unidentified request types
                    // ignore SNames we don't know what they are ... or how to read them
                    //if (KerbData.RequestType == MessageTypes.KRB_TGS_REQ
                    //   && (KerbData.SNameType == 2 || KerbData.SNameType == 10))
                    if (KerbData.RequestType == MessageTypes.KRB_TGS_REQ)
                    {
                        trace.KerbResponses.Add(KerbData);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Exception during Kerberos processing." + "\r\n" + ex.Message + "\r\n" + ex.StackTrace);
                    Program.logDiagnostic("Exception during Kerberos processing." + "\r\n" + ex.Message + "\r\n" + ex.StackTrace);
                } // catch
            }     // foreach
        }         // void Process(...)
        static void ParseErrorResponseTCP(KerberosData KerbData, TDSReader ByteReader)
        {
            //Tag4-TagC
            int TagID = 0, TagLen = 0;

            do
            {
                TagID  = ByteReader.ReadByte();
                TagLen = ReadAsnLen(ByteReader, false);

                TagID = (TagID & (int)0x1F);
                switch (TagID)
                {
                case 4:
                case 5:
                case 9:
                case 10:
                case 12:
                {
                    ByteReader.ReadBytes(TagLen);         // Skip 'STime', 'SuSec', 'Realm'
                    break;
                }

                case 6:
                {
                    ReadAsnLen(ByteReader);
                    KerbData.errorCode = ByteReader.ReadByte();
                    KerbData.ErrorDesc = GetErrorDesc((ErrorCodes)KerbData.errorCode);
                    return;
                }

                default:
                {
                    break;
                    //return;
                    //throw new Exception("Unexpected Tag" + TagID + " found in  KERB TCP response");
                }
                }
            }while (TagID < 6); //Total 12 tags expected, but we are reading only 6 tags until error code
        }
        static KerberosData ParseErrorResponseUDP(TDSReader ByteReader)
        {
            int TagID = 10, TagLen = 0, DataLen = 0;

            KerberosData KerbData = new KerberosData();

            ReadAsnLen(ByteReader); //Skip over 4 bytes 'ApplicationTag'
            ReadAsnLen(ByteReader); //Skip over 4 bytes 'SequenceHeader'
            do
            {
                TagID  = ByteReader.ReadByte();
                TagLen = ReadAsnLen(ByteReader, false);
                switch (TagID & 0x1F)
                {
                case 0:
                case 1:
                case 4:
                case 5:
                case 9:
                    break;

                case 6:
                {
                    DataLen = ReadAsnLen(ByteReader, false);
                    if (DataLen == 1)
                    {
                        KerbData.errorCode = ByteReader.ReadByte();
                        KerbData.ErrorDesc = GetErrorDesc((ErrorCodes)KerbData.errorCode);
                    }

                    return(KerbData);
                }
                } //Switch
            }while ((TagID & (int)0x1F) <= 9);


            return(KerbData);
        }
        public static KerberosData ProcessUDP(ConversationData c)
        {
            KerberosData KerbData = new KerberosData();

            KerbData.SourcePort = c.sourcePort;
            KerbData.convData   = c;

            int    Len2   = 0;
            int    TagLen = 0;
            string SPN    = null;
            int    TagID  = 0;

            bool IsContinueToNextFrame = false;

            foreach (FrameData fd in c.frames)
            {
                if (fd.payloadLength <= 1)
                {
                    continue;
                }


                TDSReader ByteReader = new TDSReader(fd.payload, 0, -1, fd.payloadLength);

                //Skip over 4 bytes 'ApplicationTag'
                ReadAsnLen(ByteReader);

                //Skip over 4 bytes 'KdcReq->SequenceHeader'
                ReadAsnLen(ByteReader);

                //Init vars after every frame processing

                Len2   = 0;
                TagLen = 0;
                SPN    = null;

                TagID = 0;

                do
                {
                    TagID  = ByteReader.ReadByte();
                    TagLen = ReadAsnLen(ByteReader, false);

                    TagID = TagID & 0x1F;
                    switch (TagID) //Lower 5 bits
                    {
                    case 0:        // version# in Tag 0 for KRB_TGS_REP (response)
                    case 1:
                    case 2:
                    {
                        if ((fd.isFromClient && TagID == 1) || (!fd.isFromClient && TagID == 0))
                        {
                            GetVersion(KerbData, ByteReader);
                        }
                        else if ((!fd.isFromClient && TagID == 1) || (fd.isFromClient && TagID == 2))
                        {
                            MessageTypes MsgType = GetMessageType(KerbData, ByteReader);
                            KerbData.frameNo = fd.frameNo;

                            if (MsgType == MessageTypes.KRB_TGS_REP)
                            {
                                //ParseNonErrorResponseUDP(KerbData, ByteReader);
                                IsContinueToNextFrame = true;
                            }
                            else if (MsgType == MessageTypes.KRB_ERROR)
                            {
                                ParseErrorResponseUDP(KerbData, ByteReader);
                                IsContinueToNextFrame = true;
                            }
                        }
                        break;
                    }

                    case 3:

                    {
                        //ByteReader.ReadByte();
                        Len2 = ReadAsnLen(ByteReader);
                        ByteReader.ReadBytes(Len2);         // skip the padata tag.
                        break;
                    }

                    case 4:
                    {
                        //ByteReader.ReadByte(); //skip sequence header of ReqBody
                        ReadAsnLen(ByteReader);
                        int TagId2 = 0;
                        do
                        {
                            TagId2 = ByteReader.ReadByte();
                            Len2   = ReadAsnLen(ByteReader, false);
                            TagId2 = TagId2 & 0x1F;
                            switch (TagId2)
                            {
                            case 0:
                            {
                                ByteReader.ReadByte();
                                int Len3 = ReadAsnLen(ByteReader, false);

                                //Read and skip 'padding'
                                ByteReader.ReadBytes(Len3 - 4);

                                KerbData.IsForwardable = (ByteReader.ReadByte() & 0x40) != 0;

                                //Read remaining three bytes
                                ByteReader.ReadBytes(3);
                                break;
                            }

                            case 1:
                            case 2:
                            case 4:
                            case 5:
                            case 7:
                            case 8:            //skip these tags.
                            {
                                ByteReader.ReadBytes(Len2);
                                break;
                            }

                            case 3:
                            {
                                // UDP SName implementation - replacing with TCP implementation

                                // ReadAsnLen(ByteReader);             //Skip sequence header  of sname
                                // int Len3 = ReadAsnLen(ByteReader);  //Skip Tag0  of sname
                                // ByteReader.ReadBytes(Len3);         //skip nametype
                                // ReadAsnLen(ByteReader);             //Skip  Tag1 of sname
                                // Len3 = ReadAsnLen(ByteReader);      //Skip sequence header  of sname->Tag1
                                // Len3 = ReadAsnLen(ByteReader);      // Read SPN Length - same as the TCP implementation
                                // SPN = ByteReader.ReadAnsiString(Len3);
                                // KerbData.SPNRequested = SPN;

                                // TCP SName implementation

                                ReadAsnLen(ByteReader);                 //Skip sequence header  of sname
                                int Len3 = ReadAsnLen(ByteReader);      //Skip Tag0  of sname
                                //
                                // Read the Name Type:
                                //
                                //  2 = NT-SRV-INST   - has two Strings: Service and Instance. '/' separater is implied
                                // 10 = NT-ENTERPRISE - has one String
                                //
                                // Throw error on all other values
                                //
                                Len3 = ReadAsnLen(ByteReader);
                                if (Len3 != 1)
                                {
                                    throw new Exception("Unexpected length (" + Len3 + ") reading SName Name Type.");
                                }
                                byte NameType = ByteReader.ReadByte();
                                KerbData.SNameType = NameType;
                                if (NameType != 2 && NameType != 10)
                                {
                                    IsContinueToNextFrame = true;
                                    break;
                                }

                                ReadAsnLen(ByteReader);                 //Skip  Tag1 of sname
                                Len3 = ReadAsnLen(ByteReader);          //Skip sequenceheader  of sname.

                                SPN = "";
                                if (NameType == 2)                 // read service type
                                {
                                    Len3 = ReadAsnLen(ByteReader);
                                    SPN  = ByteReader.ReadAnsiString(Len3) + "/";
                                }
                                Len3 = ReadAsnLen(ByteReader);                 // read SPN length
                                SPN += ByteReader.ReadAnsiString(Len3);
                                KerbData.SPNRequested = SPN;

                                break;
                            }

                            default:
                            {
                                throw new Exception("Unknonw tag in kerberos packet");
                            }
                            }
                        } while (TagId2 < 3);

                        break;
                    }

                    default:
                    {
                        // throw new Exception("Un expected tags in kerberos request/response/ problem in parseing");
                        break;
                    }
                    }
                }while ((TagID < 4) && (!IsContinueToNextFrame));
            }

            return(KerbData);
        }
        public static KerberosData ProcessTCP(ConversationData c)
        {
            KerberosData KerbData = new KerberosData();

            KerbData.SourcePort = c.sourcePort;
            KerbData.convData   = c;

            ReassembleFrames(c);
            foreach (FrameData fd in c.frames)
            {
                TDSReader ByteReader = null;

                if ((fd.payloadLength <= 1) && (fd.reassembledPayLoadLength <= 1))
                {
                    continue;
                }

                if ((fd.flags & (int)(TCPFlag.PUSH)) == 0)
                {
                    continue;
                }



                if (fd.reassembledPayLoad != null)
                {
                    ByteReader = new TDSReader(fd.reassembledPayLoad, 0, -1, fd.reassembledPayLoad.Length);
                }
                else
                {
                    ByteReader = new TDSReader(fd.payload, 0, -1, fd.payloadLength);
                }


                //Read or skip 4 bytes
                ByteReader.ReadByte();
                ByteReader.ReadByte();
                ByteReader.ReadByte();
                ByteReader.ReadByte();

                //Skip over 4 bytes 'ApplicationTag'
                ReadAsnLen(ByteReader);

                //Skip over 4 bytes 'KdcReq->SequenceHeader'
                ReadAsnLen(ByteReader);

                int    Len2 = 0, TagLen = 0, TagID = 0;
                string SPN = null;

                KerbData.convData = c;
                bool IsContinueToNextFrame = false;

                do
                {
                    TagID  = ByteReader.ReadByte();
                    TagLen = ReadAsnLen(ByteReader, false);
                    TagID  = TagID & 0x1F;


                    switch (TagID) //Lower 5 bits
                    {
                    case 0:        // Version# is in Tago in error response.
                    {
                        GetVersion(KerbData, ByteReader);
                        break;
                    }

                    case 1:
                    {
                        //Tag1 contains request type for error and non-error response.
                        //So, read the response type and break.
                        if (!fd.isFromClient)         // could KERB error response or normal response
                        {
                            GetMessageType(KerbData, ByteReader);
                            KerbData.frameNo   = fd.frameNo;
                            KerbData.TimeStamp = new DateTime(((FrameData)c.frames[c.frames.Count - 1]).ticks).ToString(utility.TIME_FORMAT);
                            if (KerbData.ResponseType == MessageTypes.KRB_ERROR)
                            {
                                //Console.WriteLine(fd.frameNo.ToString());
                                ParseErrorResponseTCP(KerbData, ByteReader);

                                IsContinueToNextFrame = true;
                            }
                            else if (KerbData.ResponseType == MessageTypes.KRB_TGS_REP)
                            {
                                //ParseNonErrorResponseTCP(KerbData, ByteReader);
                                IsContinueToNextFrame = true;
                                KerbData.ErrorDesc    = "No Error.";
                            }

                            //
                            // Looks like a bug here if the Message type is not 12 or 13. e.g. in my trace, it is KRB_AS_REP (11)
                            // We don't go down either of the above paths and then try to parse TAG 2 next time around the loop, which has a different meaning (padata) and then crash.
                            //
                            // Suggested fix:
                            //
                            else
                            {
                                IsContinueToNextFrame = true;          // must abort parsing if unexpected message type
                            }
                            //

                            break;
                        }
                        else
                        {
                            GetVersion(KerbData, ByteReader);          //Extract version# from KERB TCP request.
                            break;
                        }
                    }

                    case 2:
                    {
                        // Tag2 present only in the request and not in the response and error responses.
                        // Console.WriteLine(fd.frameNo.ToString());
                        if (GetMessageType(KerbData, ByteReader) != MessageTypes.KRB_TGS_REQ)
                        {
                            return(KerbData);                                                                           // if not a TGS_REQ, ignore rest of conversation and exit
                        }
                        // IsContinueToNextFrame = true;
                        break;
                    }

                    case 3:
                    {
                        // skip the padata tag. Tag3 present in requet and response.
                        //But we should not hit this case for response and only for request
                        ByteReader.ReadBytes(TagLen);
                        break;
                    }

                    case 4:
                    {
                        //Skip over 4 bytes 'SequenceHeader'
                        ReadAsnLen(ByteReader);
                        int Id2    = 0;
                        int TagNum = 0;
                        do
                        {
                            Id2  = ByteReader.ReadByte();
                            Len2 = ReadAsnLen(ByteReader, false);

                            TagNum = Id2 & 0x1F;

                            switch (TagNum)
                            {
                            case 0:
                            {
                                ByteReader.ReadByte();
                                int Len3 = ReadAsnLen(ByteReader, false);

                                //Read and skip 'padding'
                                ByteReader.ReadBytes(Len3 - 4);

                                KerbData.IsForwardable = (ByteReader.ReadByte() & 0x40) != 0;

                                //Read remaining three bytes
                                ByteReader.ReadBytes(3);
                                break;
                            }

                            case 1:
                            case 2:
                            case 4:
                            case 5:
                            case 7:
                            case 8:
                            case 9:
                            case 10:
                            {
                                ByteReader.ReadBytes(Len2);
                                break;
                            }

                            case 3:                                // outer tag 4 inner tag 3 - Request:SNAME
                            {
                                ReadAsnLen(ByteReader);            //Skip sequence header  of sname
                                int Len3 = ReadAsnLen(ByteReader); //Skip Tag0  of sname
                                //
                                // Read the Name Type:
                                //
                                //  2 = NT-SRV-INST   - has two Strings: Service and Instance. '/' separater is implied
                                // 10 = NT-ENTERPRISE - has one String
                                //
                                // Throw error on all other values
                                //
                                Len3 = ReadAsnLen(ByteReader);
                                if (Len3 != 1)
                                {
                                    throw new Exception("Unexpected length (" + Len3 + ") reading SName Name Type.");
                                }
                                byte NameType = ByteReader.ReadByte();
                                KerbData.SNameType = NameType;
                                //if (NameType != 2 && NameType != 10)
                                //{
                                //    IsContinueToNextFrame = true;
                                //    break;
                                //}

                                ReadAsnLen(ByteReader);                 //Skip  Tag1 of sname
                                Len3 = ReadAsnLen(ByteReader);          //Skip sequenceheader  of sname.

                                SPN = "";
                                if (NameType == 2)                 // read service type
                                {
                                    Len3 = ReadAsnLen(ByteReader);
                                    SPN  = ByteReader.ReadAnsiString(Len3) + "/";
                                }
                                Len3 = ReadAsnLen(ByteReader);                 // read SPN length
                                SPN += ByteReader.ReadAnsiString(Len3);
                                KerbData.SPNRequested = SPN;
                                //Console.WriteLine("SPN=\t" + SPN);
                                break;
                            }

                            default:
                            {
                                //throw new Exception("Unexpected TAG (" + TagNum + ") found in the KERB TCP request, frame: " + fd.frameNo.ToString());
                                break;
                            }
                            }
                        } while (TagNum < 3);         //Because, we are reading only 1st three tags of requestbody and skip the rest

                        break;
                    }

                    default:
                    {
                        // throw new Exception("Un expected tags in kerberos request/response/ problem in parseing");
                        break;
                    }
                    }
                }while ((TagID < 4) && (!IsContinueToNextFrame));
            }

            return(KerbData);
        }
 static void ParseNonErrorResponseUDP(KerberosData KerbData, TDSReader ByteReader)
 {
     /*
      * int TagID = 0, TagLen = 0;
      * return;
      *
      * do
      * {
      *  TagID = ByteReader.ReadByte();
      *  TagLen = ReadAsnLen(ByteReader, false);
      *
      *  TagID = (TagID & (int)0x1F);
      *  switch (TagID)
      *  {
      *
      *      case 3:
      *      case 4:
      *          {
      *              ByteReader.ReadBytes(TagLen); // Skip 'Crealm', 'Cname',
      *              break;
      *          }
      *      case 5:
      *          {
      *              //Skip Tag5->Ticket->ApplicationTag
      *              ReadAsnLen(ByteReader);
      *
      *              //Skip Tag5->Ticket->SequenceHeader
      *              ReadAsnLen(ByteReader);
      *
      *              int InnerTagID = -1;
      *              int InnerTagLen = 0;
      *
      *              do
      *              {
      *                  InnerTagID = ByteReader.ReadByte() & (int)0x1F;
      *                  InnerTagLen = ReadAsnLen(ByteReader, false);
      *
      *
      *                  switch (InnerTagID)
      *                  {
      *
      *                      case 0: //Tag0->TktVno
      *                      case 1: //Skip Tag1->Realm
      *                          {
      *                              ByteReader.ReadBytes(InnerTagLen);
      *                              break;
      *                          }
      *                      case 2: //Ticket->Sname
      *                          {
      *                              //int Length = ReadAsnLen(ByteReader); //Skip sequenceheader  of sname.
      *                              //ByteReader.ReadByte();
      *
      *
      *                              //Skip Tag5->Ticket->Sname->SequenceHeader
      *                              ReadAsnLen(ByteReader);
      *                              int IInnerTagID = -1;
      *                              int IInnerTagLen = 0;
      *
      *                              do
      *                              {
      *                                  IInnerTagID = ByteReader.ReadByte() & (int)0x1F;
      *                                  IInnerTagLen = ReadAsnLen(ByteReader, false);
      *                                  switch (IInnerTagID)
      *                                  {
      *                                      case 0:
      *                                          {
      *                                              ByteReader.ReadBytes(IInnerTagLen);
      *                                              break;
      *                                          }
      *                                      case 1:
      *                                          {
      *                                              ByteReader.ReadByte();
      *                                              ByteReader.ReadByte();
      *
      *                                              ByteReader.ReadByte();
      *
      *                                              int Length = ByteReader.ReadByte();
      *                                              String Class = ByteReader.ReadAnsiString(Length);
      *
      *                                              ByteReader.ReadByte();
      *                                              Length = ByteReader.ReadByte();
      *                                              KerbData.SPNRequested = Class + "/" + ByteReader.ReadAnsiString(Length);
      *                                              break;
      *                                          }
      *
      *                                  }
      *                              } while (IInnerTagID < 1);
      *                              //KerbData.SPNRequested = ByteReader.ReadAnsiString(InnerTagLen);
      *                              break;
      *                          }
      *                  }
      *              }
      *              while (InnerTagID < 2); // Read until Sname
      *
      *              break;
      *          }
      *      default:
      *          {
      *              throw new Exception("Unexpected Tag " + TagID + " found in  KERB TCP response");
      *          }
      *  }
      *
      * }
      * while (TagID < 5);
      */
 }