/// <summary>
        /// Create an verification trailer with commands parameter passed in to the method.
        /// </summary>
        /// <param name="commands">
        /// A list of commands to be contained in the verification trailer.<para/>
        /// Flag SEC_VT_COMMAND_END is ignored by input, and will be added to 
        /// the last command automatically.
        /// </param>
        /// <returns>
        /// Created verification trailer. Pad is not added until appending to stub.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown when commands is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// Thrown when a SEC_VT_COMMAND is invalid, or NDR/NDR64 was not negotiated.
        /// </exception>
        public verification_trailer_t CreateVerificationTrailer(
            params SEC_VT_COMMAND[] commands)
        {
            if (commands == null)
            {
                throw new ArgumentNullException("commands");
            }

            verification_trailer_t verificationTrailer = new verification_trailer_t();
            verificationTrailer.header = new rpc_sec_verification_trailer();
            verificationTrailer.header.signature = BitConverter.GetBytes(verification_trailer_t.SIGNATURE);
            List<SEC_VT> secVtList = new List<SEC_VT>();
            for (int i = 0; i < commands.Length; i++)
            {
                switch (commands[i]
                    & ~(SEC_VT_COMMAND.SEC_VT_COMMAND_END | SEC_VT_COMMAND.SEC_VT_MUST_PROCESS_COMMAND))
                {
                    case SEC_VT_COMMAND.SEC_VT_COMMAND_BITMASK_1:
                        rpc_sec_vt_bitmask secVtBitmask = new rpc_sec_vt_bitmask();
                        secVtBitmask.command = commands[i];
                        //length: MUST be 0x0004.
                        secVtBitmask.length = verification_trailer_t.SEC_VT_BITMASK_LENGTH;
                        //bits: The bits field is a bitmask.
                        //A server MUST ignore bits it does not understand.
                        //Currently, there is only one bit defined: CLIENT_SUPPORT_HEADER_SIGNING
                        //(bitmask of 0x00000001). If this bit is set, the PFC_SUPPORT_HEADER_SIGN
                        //bit, as specified in section 2.2.2.3, MUST be present in the PDU header
                        //for the bind PDU on this connection.
                        secVtBitmask.bits = context.SupportsHeaderSign ? (uint)0x00000001 : 0;
                        secVtList.Add(secVtBitmask);
                        break;

                    case SEC_VT_COMMAND.SEC_VT_COMMAND_HEADER2:
                        rpc_sec_vt_header2 secVtHeader2 = new rpc_sec_vt_header2();
                        secVtHeader2.command = commands[i];
                        //length: MUST be 0x0010.
                        secVtHeader2.length = verification_trailer_t.SEC_VT_HEADER2_LENGTH;
                        //PTYPE: MUST be the same as the PTYPE field in the request PDU header.
                        secVtHeader2.PTYPE = PTYPE;
                        secVtHeader2.reserved1 = 0;
                        secVtHeader2.reserved2 = 0;
                        secVtHeader2.drep = packed_drep;
                        secVtHeader2.call_id = call_id;
                        secVtHeader2.p_cont_id = p_cont_id;
                        secVtHeader2.opnum = opnum;
                        secVtList.Add(secVtHeader2);
                        break;

                    case SEC_VT_COMMAND.SEC_VT_COMMAND_PCONTEXT:
                        rpc_sec_vt_pcontext secVtPcontext = new rpc_sec_vt_pcontext();
                        secVtPcontext.command = commands[i];
                        //length: MUST be set to 0x28.
                        secVtPcontext.length = verification_trailer_t.SEC_VT_PCONTEXT_LENGTH;
                        secVtPcontext.interfaceId = new p_syntax_id_t();
                        secVtPcontext.interfaceId.if_uuid = context.InterfaceId;
                        secVtPcontext.interfaceId.if_vers_major = context.InterfaceMajorVersion;
                        secVtPcontext.interfaceId.if_vers_minor = context.InterfaceMinorVersion;
                        secVtPcontext.transferSyntax = new p_syntax_id_t();
                        if (context.NdrVersion == RpceNdrVersion.NDR)
                        {
                            secVtPcontext.transferSyntax.if_uuid = RpceUtility.NDR_INTERFACE_UUID;
                            secVtPcontext.transferSyntax.if_vers_major = RpceUtility.NDR_INTERFACE_MAJOR_VERSION;
                            secVtPcontext.transferSyntax.if_vers_minor = RpceUtility.NDR_INTERFACE_MINOR_VERSION;
                        }
                        else if (context.NdrVersion == RpceNdrVersion.NDR64)
                        {
                            secVtPcontext.transferSyntax.if_uuid = RpceUtility.NDR64_INTERFACE_UUID;
                            secVtPcontext.transferSyntax.if_vers_major = RpceUtility.NDR64_INTERFACE_MAJOR_VERSION;
                            secVtPcontext.transferSyntax.if_vers_minor = RpceUtility.NDR64_INTERFACE_MINOR_VERSION;
                        }
                        else
                        {
                            throw new InvalidOperationException("Neither NDR nore NDR64 was negotiated.");
                        }
                        secVtList.Add(secVtPcontext);
                        break;

                    default:
                        throw new InvalidOperationException("Invalid SEC_VT_COMMAND.");
                }
            }
            verificationTrailer.commands = secVtList.ToArray();

            return verificationTrailer;
        }
        /// <summary>
        /// Unmarshal a verification trailer from byte array.
        /// </summary>
        /// <param name="verificationTrailerBuffer">byte array.</param>
        public void FromBytes(byte[] verificationTrailerBuffer)
        {
            int padLength = -1;
            for (int i = 0; i < verificationTrailerBuffer.Length; i++)
            {
                if ((verificationTrailerBuffer.Length - i) >= Marshal.SizeOf(verification_trailer_t.SIGNATURE)
                    && BitConverter.ToUInt64(verificationTrailerBuffer, i) == verification_trailer_t.SIGNATURE)
                {
                    padLength = i;
                }
            }
            if (padLength < 0)
            {
                throw new InvalidOperationException("verification_trailer not found.");
            }

            using (BinaryReader reader = new BinaryReader(new MemoryStream(verificationTrailerBuffer)))
            {
                pad = reader.ReadBytes(padLength);
                header.signature = reader.ReadBytes(sizeof(ulong));

                List<SEC_VT> secVtList = new List<SEC_VT>();
                while (reader.BaseStream.Position < verificationTrailerBuffer.Length)
                {
                    if ((verificationTrailerBuffer.Length - reader.BaseStream.Position) < SEC_VT_HEADER_LENGTH)
                    {
                        break;
                    }

                    SEC_VT_COMMAND command = (SEC_VT_COMMAND)reader.ReadUInt16();
                    ushort length = reader.ReadUInt16();

                    if ((verificationTrailerBuffer.Length - reader.BaseStream.Position) < length)
                    {
                        //length of remain bytes is less than expected.
                        break;
                    }

                    switch (command
                        & ~(SEC_VT_COMMAND.SEC_VT_MUST_PROCESS_COMMAND | SEC_VT_COMMAND.SEC_VT_COMMAND_END))
                    {
                        case SEC_VT_COMMAND.SEC_VT_COMMAND_BITMASK_1:
                            rpc_sec_vt_bitmask secVtBitmask = new rpc_sec_vt_bitmask();
                            secVtBitmask.command = command;
                            secVtBitmask.length = length;
                            secVtBitmask.bits = reader.ReadUInt32();

                            secVtList.Add(secVtBitmask);
                            break;

                        case SEC_VT_COMMAND.SEC_VT_COMMAND_PCONTEXT:
                            rpc_sec_vt_pcontext secVtPcontext = new rpc_sec_vt_pcontext();
                            secVtPcontext.command = command;
                            secVtPcontext.length = length;
                            secVtPcontext.interfaceId = new p_syntax_id_t();
                            secVtPcontext.interfaceId.if_uuid = new Guid(reader.ReadBytes(RpceUtility.GUID_SIZE));
                            secVtPcontext.interfaceId.if_vers_major = reader.ReadUInt16();
                            secVtPcontext.interfaceId.if_vers_minor = reader.ReadUInt16();
                            secVtPcontext.transferSyntax = new p_syntax_id_t();
                            secVtPcontext.transferSyntax.if_uuid = new Guid(reader.ReadBytes(RpceUtility.GUID_SIZE));
                            secVtPcontext.transferSyntax.if_vers_major = reader.ReadUInt16();
                            secVtPcontext.transferSyntax.if_vers_minor = reader.ReadUInt16();

                            secVtList.Add(secVtPcontext);
                            break;

                        case SEC_VT_COMMAND.SEC_VT_COMMAND_HEADER2:
                            rpc_sec_vt_header2 secVtHeader2 = new rpc_sec_vt_header2();
                            secVtHeader2.command = command;
                            secVtHeader2.length = length;
                            secVtHeader2.PTYPE = (RpcePacketType)reader.ReadByte();
                            secVtHeader2.reserved1 = reader.ReadByte();
                            secVtHeader2.reserved2 = reader.ReadUInt16();
                            secVtHeader2.drep = new DataRepresentationFormatLabel();
                            secVtHeader2.drep.dataRepFormat = (RpceDataRepresentationFormat)reader.ReadUInt16();
                            secVtHeader2.drep.reserved = reader.ReadUInt16();
                            secVtHeader2.call_id = reader.ReadUInt32();
                            secVtHeader2.p_cont_id = reader.ReadUInt16();
                            secVtHeader2.opnum = reader.ReadUInt16();

                            secVtList.Add(secVtHeader2);
                            break;

                        default:
                            //do nothing
                            break;
                    }
                }

                commands = secVtList.ToArray();
            }
        }