示例#1
0
        private static KrbChecksum GenerateChecksum(KerberosKey key, KrbPrincipalName userName, string userRealm, string authPackage)
        {
            var dataLength = 0;

            dataLength += 4;

            foreach (var name in userName.Name)
            {
                dataLength += name.Length;
            }

            dataLength += userRealm.Length;
            dataLength += authPackage.Length;

            var checksumData = new Memory <byte>(new byte[dataLength]);

            BinaryPrimitives.WriteInt32LittleEndian(checksumData.Span, (int)userName.Type);

            var position = 4;

            for (var i = 0; i < userName.Name.Length; i++)
            {
                Concat(checksumData, userName.Name[i], ref position);
            }

            Concat(checksumData, userRealm, ref position);
            Concat(checksumData, authPackage, ref position);

            return(KrbChecksum.Create(checksumData, key, KeyUsage.PaForUserChecksum, PaForUserChecksumType));
        }
示例#2
0
        private static KrbChecksum GenerateChecksum(KerberosKey key, KrbPrincipalName userName, string userRealm, string authPackage)
        {
            var dataLength = 0;

            dataLength += 4;

            foreach (var name in userName.Name)
            {
                dataLength += name.Length;
            }

            dataLength += userRealm.Length;
            dataLength += authPackage.Length;

            var checksumData = new Memory <byte>(new byte[dataLength]);

            Endian.ConvertToLittleEndian((int)userName.Type, checksumData);

            var position = 4;

            for (var i = 0; i < userName.Name.Length; i++)
            {
                Concat(checksumData, ref position, ref userName.Name[i]);
            }

            Concat(checksumData, ref position, ref userRealm);
            Concat(checksumData, ref position, ref authPackage);

            return(KrbChecksum.Create(checksumData, key, KeyUsage.PaForUserChecksum, PaForUserChecksumType));
        }
示例#3
0
        internal static void Decode <T>(AsnReader reader, Asn1Tag expectedTag, out T decoded)
            where T : KrbPaSvrReferralData, new()
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            decoded = new T();
            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
            AsnReader explicitReader;


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
                KrbPrincipalName tmpReferredName;
                KrbPrincipalName.Decode <KrbPrincipalName>(explicitReader, out tmpReferredName);
                decoded.ReferredName = tmpReferredName;

                explicitReader.ThrowIfNotEmpty();
            }


            explicitReader        = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
            decoded.ReferredRealm = explicitReader.ReadCharacterString(UniversalTagNumber.GeneralString);
            explicitReader.ThrowIfNotEmpty();


            sequenceReader.ThrowIfNotEmpty();
        }
示例#4
0
        internal static void Decode <T>(AsnReader reader, Asn1Tag expectedTag, out T decoded)
            where T : KrbPaForUser, new()
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            decoded = new T();
            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
            AsnReader explicitReader;


            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
            KrbPrincipalName.Decode <KrbPrincipalName>(explicitReader, out decoded.UserName);
            explicitReader.ThrowIfNotEmpty();


            explicitReader    = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
            decoded.UserRealm = explicitReader.ReadCharacterString(UniversalTagNumber.GeneralString);
            explicitReader.ThrowIfNotEmpty();


            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
            KrbChecksum.Decode <KrbChecksum>(explicitReader, out decoded.Checksum);
            explicitReader.ThrowIfNotEmpty();


            explicitReader      = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 3));
            decoded.AuthPackage = explicitReader.ReadCharacterString(UniversalTagNumber.GeneralString);
            explicitReader.ThrowIfNotEmpty();


            sequenceReader.ThrowIfNotEmpty();
        }
示例#5
0
        public static KrbAsReq CreateAsReq(KerberosCredential credential, AuthenticationOptions options)
        {
            var kdcOptions = (KdcOptions)(options & ~AuthenticationOptions.AllAuthentication);

            var hostAddress = Environment.MachineName;

            var pacRequest = new KrbPaPacRequest
            {
                IncludePac = options.HasFlag(AuthenticationOptions.IncludePacRequest)
            };

            var padata = new List <KrbPaData>()
            {
                new KrbPaData
                {
                    Type  = PaDataType.PA_PAC_REQUEST,
                    Value = pacRequest.Encode()
                }
            };

            var asreq = new KrbAsReq()
            {
                MessageType = MessageType.KRB_AS_REQ,
                Body        = new KrbKdcReqBody
                {
                    Addresses = new[] {
                        new KrbHostAddress {
                            AddressType = AddressType.NetBios,
                            Address     = Encoding.ASCII.GetBytes(hostAddress.PadRight(16, ' '))
                        }
                    },
                    CName = KrbPrincipalName.FromString(
                        credential.UserName,
                        PrincipalNameType.NT_ENTERPRISE,
                        credential.Domain
                        ),
                    EType      = KerberosConstants.ETypes.ToArray(),
                    KdcOptions = kdcOptions,
                    Nonce      = KerberosConstants.GetNonce(),
                    RTime      = KerberosConstants.EndOfTime,
                    Realm      = credential.Domain,
                    SName      = new KrbPrincipalName
                    {
                        Type = PrincipalNameType.NT_SRV_INST,
                        Name = new[] { "krbtgt", credential.Domain }
                    },
                    Till = KerberosConstants.EndOfTime
                },
                PaData = padata.ToArray()
            };

            if (options.HasFlag(AuthenticationOptions.PreAuthenticate))
            {
                credential.TransformKdcReq(asreq);
            }

            return(asreq);
        }
示例#6
0
        public static KrbAsRep GenerateTgt(
            ServiceTicketRequest rst,
            IRealmService realmService
            )
        {
            if (realmService == null)
            {
                throw new ArgumentNullException(nameof(realmService));
            }

            rst.Compatibility = realmService.Settings.Compatibility;

            // This is approximately correct such that a client doesn't barf on it
            // The krbtgt Ticket structure is probably correct as far as AD thinks
            // Modulo the PAC, at least.

            if (string.IsNullOrWhiteSpace(rst.RealmName))
            {
                // TODO: Possible bug. Realm service now has multiple krbtgt's so the name is always set
                // to the name of our (cloud) KDC name. Will this be an issue for trust ticket or mcticket?
                rst.RealmName = realmService.Name;
            }

            KrbPrincipalName krbtgtName = KrbPrincipalName.WellKnown.Krbtgt(rst.RealmName);

            if (rst.ServicePrincipal == null)
            {
                rst.ServicePrincipal = realmService.Principals.Find(krbtgtName, rst.RealmName);
            }

            if (rst.ServicePrincipalKey == null)
            {
                rst.ServicePrincipalKey = rst.ServicePrincipal.RetrieveLongTermCredential();
            }

            if (rst.KdcAuthorizationKey == null)
            {
                // Not using rst.ServicePrincipal because it may not actually be krbtgt

                var krbtgt = realmService.Principals.Find(krbtgtName, rst.RealmName);

                rst.KdcAuthorizationKey = krbtgt.RetrieveLongTermCredential();
            }

            rst.Now = realmService.Now();
            rst.MaximumTicketLifetime = realmService.Settings.SessionLifetime;
            rst.MaximumRenewalWindow  = realmService.Settings.MaximumRenewalWindow;

            if (rst.Flags == 0)
            {
                rst.Flags = DefaultFlags;
            }

            return(GenerateServiceTicket <KrbAsRep>(rst));
        }
示例#7
0
        private static KrbPrincipalName CreateCNameForTicket(ServiceTicketRequest request)
        {
            if (string.IsNullOrEmpty(request.SamAccountName))
            {
                return(KrbPrincipalName.FromPrincipal(request.Principal, realm: request.RealmName));
            }

            return(new KrbPrincipalName
            {
                Type = PrincipalNameType.NT_PRINCIPAL,
                Name = new[] { request.SamAccountName }
            });
        }
示例#8
0
        private static KrbPrincipalName ExtractCName(KerberosCredential credential)
        {
            var principalName = KrbPrincipalName.FromString(credential.UserName);

            if (principalName.IsServiceName)
            {
                return(principalName);
            }

            return(KrbPrincipalName.FromString(
                       credential.UserName,
                       PrincipalNameType.NT_ENTERPRISE,
                       credential.Domain
                       ));
        }
示例#9
0
        public static PrincipalName FromKrbPrincipalName(KrbPrincipalName name, string realm = null)
        {
            if (name.Name.Length > 2)
            {
                var possibleRealm = name.Name[2];

                if (string.IsNullOrWhiteSpace(realm))
                {
                    realm     = possibleRealm;
                    name.Name = new[] { name.Name[0], name.Name[1] };
                }
            }

            return(new PrincipalName(name.Type, realm, name.Name));
        }
示例#10
0
        internal static void Decode <T>(AsnReader reader, Asn1Tag expectedTag, out T decoded)
            where T : KrbFastFinished, new()
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            decoded = new T();

            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
            AsnReader explicitReader;

            explicitReader    = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
            decoded.Timestamp = explicitReader.ReadGeneralizedTime();

            explicitReader.ThrowIfNotEmpty();

            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1));

            if (!explicitReader.TryReadInt32(out int tmpUSec))
            {
                explicitReader.ThrowIfNotEmpty();
            }

            decoded.USec = tmpUSec;

            explicitReader.ThrowIfNotEmpty();

            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
            decoded.CRealm = explicitReader.ReadCharacterString(UniversalTagNumber.GeneralString);

            explicitReader.ThrowIfNotEmpty();

            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 3));
            KrbPrincipalName.Decode <KrbPrincipalName>(explicitReader, out KrbPrincipalName tmpCName);
            decoded.CName = tmpCName;

            explicitReader.ThrowIfNotEmpty();

            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 4));
            KrbChecksum.Decode <KrbChecksum>(explicitReader, out KrbChecksum tmpTicketChecksum);
            decoded.TicketChecksum = tmpTicketChecksum;

            explicitReader.ThrowIfNotEmpty();

            sequenceReader.ThrowIfNotEmpty();
        }
示例#11
0
        internal static void Decode <T>(AsnReader reader, Asn1Tag expectedTag, out T decoded)
            where T : KrbTicket, new()
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            decoded = new T();

            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
            AsnReader explicitReader;

            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));

            if (!explicitReader.TryReadInt32(out int tmpTicketNumber))
            {
                explicitReader.ThrowIfNotEmpty();
            }

            decoded.TicketNumber = tmpTicketNumber;

            explicitReader.ThrowIfNotEmpty();

            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
            decoded.Realm  = explicitReader.ReadCharacterString(UniversalTagNumber.GeneralString);

            explicitReader.ThrowIfNotEmpty();

            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
            KrbPrincipalName.Decode <KrbPrincipalName>(explicitReader, out KrbPrincipalName tmpSName);
            decoded.SName = tmpSName;

            explicitReader.ThrowIfNotEmpty();

            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 3));
            KrbEncryptedData.Decode <KrbEncryptedData>(explicitReader, out KrbEncryptedData tmpEncryptedPart);
            decoded.EncryptedPart = tmpEncryptedPart;

            explicitReader.ThrowIfNotEmpty();

            sequenceReader.ThrowIfNotEmpty();
        }
示例#12
0
        internal static void Decode <T>(AsnReader reader, Asn1Tag expectedTag, out T decoded)
            where T : KrbError, new()
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            decoded = new T();
            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
            AsnReader explicitReader;


            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));

            if (!explicitReader.TryReadInt32(out decoded.ProtocolVersionNumber))
            {
                explicitReader.ThrowIfNotEmpty();
            }

            explicitReader.ThrowIfNotEmpty();


            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1));

            if (!explicitReader.TryReadInt32(out decoded.MessageType))
            {
                explicitReader.ThrowIfNotEmpty();
            }

            explicitReader.ThrowIfNotEmpty();


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 2)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
                decoded.CTime  = explicitReader.ReadGeneralizedTime();
                explicitReader.ThrowIfNotEmpty();
            }


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 3)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 3));

                if (explicitReader.TryReadInt32(out int tmpCusec))
                {
                    decoded.Cusec = tmpCusec;
                }
                else
                {
                    explicitReader.ThrowIfNotEmpty();
                }

                explicitReader.ThrowIfNotEmpty();
            }


            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 4));
            decoded.STime  = explicitReader.ReadGeneralizedTime();
            explicitReader.ThrowIfNotEmpty();


            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 5));

            if (!explicitReader.TryReadInt32(out decoded.Susc))
            {
                explicitReader.ThrowIfNotEmpty();
            }

            explicitReader.ThrowIfNotEmpty();


            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 6));

            if (!explicitReader.TryReadInt32(out decoded.ErrorCode))
            {
                explicitReader.ThrowIfNotEmpty();
            }

            explicitReader.ThrowIfNotEmpty();


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 7)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 7));
                decoded.CRealm = explicitReader.ReadCharacterString(UniversalTagNumber.GeneralString);
                explicitReader.ThrowIfNotEmpty();
            }


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 8)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 8));
                KrbPrincipalName tmpCName;
                KrbPrincipalName.Decode <KrbPrincipalName>(explicitReader, out tmpCName);
                decoded.CName = tmpCName;

                explicitReader.ThrowIfNotEmpty();
            }


            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 9));
            decoded.Realm  = explicitReader.ReadCharacterString(UniversalTagNumber.GeneralString);
            explicitReader.ThrowIfNotEmpty();


            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 10));
            KrbPrincipalName.Decode <KrbPrincipalName>(explicitReader, out decoded.SName);
            explicitReader.ThrowIfNotEmpty();


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 11)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 11));
                decoded.EText  = explicitReader.ReadCharacterString(UniversalTagNumber.GeneralString);
                explicitReader.ThrowIfNotEmpty();
            }


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 12)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 12));

                if (explicitReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory <byte> tmpEData))
                {
                    decoded.EData = tmpEData;
                }
                else
                {
                    decoded.EData = explicitReader.ReadOctetString();
                }

                explicitReader.ThrowIfNotEmpty();
            }


            sequenceReader.ThrowIfNotEmpty();
        }
示例#13
0
        internal static void Decode <T>(AsnReader reader, Asn1Tag expectedTag, out T decoded)
            where T : KrbKdcRep, new()
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            decoded = new T();
            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
            AsnReader explicitReader;
            AsnReader collectionReader;


            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));

            if (!explicitReader.TryReadInt32(out decoded.ProtocolVersionNumber))
            {
                explicitReader.ThrowIfNotEmpty();
            }

            explicitReader.ThrowIfNotEmpty();


            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1));

            if (!explicitReader.TryReadInt32(out decoded.MessageType))
            {
                explicitReader.ThrowIfNotEmpty();
            }

            explicitReader.ThrowIfNotEmpty();


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 2)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 2));

                // Decode SEQUENCE OF for PaData
                {
                    collectionReader = explicitReader.ReadSequence();
                    var       tmpList = new List <KrbPaData>();
                    KrbPaData tmpItem;

                    while (collectionReader.HasData)
                    {
                        KrbPaData.Decode <KrbPaData>(collectionReader, out tmpItem);
                        tmpList.Add(tmpItem);
                    }

                    decoded.PaData = tmpList.ToArray();
                }

                explicitReader.ThrowIfNotEmpty();
            }


            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 3));
            decoded.CRealm = explicitReader.ReadCharacterString(UniversalTagNumber.GeneralString);
            explicitReader.ThrowIfNotEmpty();


            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 4));
            KrbPrincipalName.Decode <KrbPrincipalName>(explicitReader, out decoded.CName);
            explicitReader.ThrowIfNotEmpty();


            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 5));
            KrbTicket.Decode <KrbTicket>(explicitReader, out decoded.Ticket);
            explicitReader.ThrowIfNotEmpty();


            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 6));
            KrbEncryptedData.Decode <KrbEncryptedData>(explicitReader, out decoded.EncPart);
            explicitReader.ThrowIfNotEmpty();


            sequenceReader.ThrowIfNotEmpty();
        }
        internal static void Decode <T>(AsnReader reader, Asn1Tag expectedTag, out T decoded)
            where T : KrbAuthenticator, new()
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            decoded = new T();

            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
            AsnReader explicitReader;
            AsnReader collectionReader;

            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));

            if (!explicitReader.TryReadInt32(out int tmpAuthenticatorVersionNumber))
            {
                explicitReader.ThrowIfNotEmpty();
            }

            decoded.AuthenticatorVersionNumber = tmpAuthenticatorVersionNumber;

            explicitReader.ThrowIfNotEmpty();

            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
            decoded.Realm  = explicitReader.ReadCharacterString(UniversalTagNumber.GeneralString);

            explicitReader.ThrowIfNotEmpty();

            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
            KrbPrincipalName.Decode <KrbPrincipalName>(explicitReader, out KrbPrincipalName tmpCName);
            decoded.CName = tmpCName;

            explicitReader.ThrowIfNotEmpty();

            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 3)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 3));

                KrbChecksum.Decode <KrbChecksum>(explicitReader, out KrbChecksum tmpChecksum);
                decoded.Checksum = tmpChecksum;
                explicitReader.ThrowIfNotEmpty();
            }

            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 4));

            if (!explicitReader.TryReadInt32(out int tmpCuSec))
            {
                explicitReader.ThrowIfNotEmpty();
            }

            decoded.CuSec = tmpCuSec;

            explicitReader.ThrowIfNotEmpty();

            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 5));
            decoded.CTime  = explicitReader.ReadGeneralizedTime();

            explicitReader.ThrowIfNotEmpty();

            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 6)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 6));

                KrbEncryptionKey.Decode <KrbEncryptionKey>(explicitReader, out KrbEncryptionKey tmpSubkey);
                decoded.Subkey = tmpSubkey;
                explicitReader.ThrowIfNotEmpty();
            }

            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 7)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 7));

                if (explicitReader.TryReadInt32(out int tmpSequenceNumber))
                {
                    decoded.SequenceNumber = tmpSequenceNumber;
                }
                else
                {
                    explicitReader.ThrowIfNotEmpty();
                }

                explicitReader.ThrowIfNotEmpty();
            }

            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 8)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 8));

                // Decode SEQUENCE OF for AuthorizationData
                {
                    collectionReader = explicitReader.ReadSequence();
                    var tmpList = new List <KrbAuthorizationData>();
                    KrbAuthorizationData tmpItem;

                    while (collectionReader.HasData)
                    {
                        KrbAuthorizationData.Decode <KrbAuthorizationData>(collectionReader, out KrbAuthorizationData tmp);
                        tmpItem = tmp;
                        tmpList.Add(tmpItem);
                    }

                    decoded.AuthorizationData = tmpList.ToArray();
                }
                explicitReader.ThrowIfNotEmpty();
            }

            sequenceReader.ThrowIfNotEmpty();
        }
示例#15
0
        public static async Task <T> GenerateServiceTicket <T>(ServiceTicketRequest request)
            where T : KrbKdcRep, new()
        {
            if (request.EncryptedPartKey == null)
            {
                throw new ArgumentException("A session key must be provided to encrypt the response", nameof(request.EncryptedPartKey));
            }

            if (request.Principal == null)
            {
                throw new ArgumentException("A Principal identity must be provided", nameof(request.Principal));
            }

            if (request.ServicePrincipal == null)
            {
                throw new ArgumentException("A service principal must be provided", nameof(request.ServicePrincipal));
            }

            if (request.ServicePrincipalKey == null)
            {
                throw new ArgumentException("A service principal key must be provided", nameof(request.ServicePrincipalKey));
            }

            var authz = await GenerateAuthorizationData(request.Principal, request);

            var sessionKey = KrbEncryptionKey.Generate(request.ServicePrincipalKey.EncryptionType);

            var encTicketPart = CreateEncTicketPart(request, authz.ToArray(), sessionKey);

            var ticket = new KrbTicket()
            {
                Realm = request.RealmName,
                SName = KrbPrincipalName.FromPrincipal(
                    request.ServicePrincipal,
                    PrincipalNameType.NT_SRV_INST,
                    request.RealmName
                    ),
                EncryptedPart = KrbEncryptedData.Encrypt(
                    encTicketPart.EncodeApplication(),
                    request.ServicePrincipalKey,
                    KeyUsage.Ticket
                    )
            };

            KrbEncKdcRepPart encKdcRepPart;

            KeyUsage keyUsage;

            if (typeof(T) == typeof(KrbAsRep))
            {
                encKdcRepPart = new KrbEncAsRepPart();
                keyUsage      = KeyUsage.EncAsRepPart;
            }
            else if (typeof(T) == typeof(KrbTgsRep))
            {
                encKdcRepPart = new KrbEncTgsRepPart();

                keyUsage = request.EncryptedPartKey.Usage ?? KeyUsage.EncTgsRepPartSessionKey;
            }
            else
            {
                throw new InvalidOperationException($"Requested Service Ticket type is neither KrbAsRep nor KrbTgsRep. Type: {typeof(T)}");
            }

            encKdcRepPart.AuthTime      = encTicketPart.AuthTime;
            encKdcRepPart.StartTime     = encTicketPart.StartTime;
            encKdcRepPart.EndTime       = encTicketPart.EndTime;
            encKdcRepPart.RenewTill     = encTicketPart.RenewTill;
            encKdcRepPart.KeyExpiration = request.Principal.Expires;
            encKdcRepPart.Realm         = request.RealmName;
            encKdcRepPart.SName         = ticket.SName;
            encKdcRepPart.Flags         = encTicketPart.Flags;
            encKdcRepPart.CAddr         = encTicketPart.CAddr;
            encKdcRepPart.Key           = sessionKey;
            encKdcRepPart.Nonce         = request.Nonce;
            encKdcRepPart.LastReq       = new[] { new KrbLastReq {
                                                      Type = 0, Value = request.Now
                                                  } };
            encKdcRepPart.EncryptedPaData = new KrbMethodData
            {
                MethodData = new[]
                {
                    new KrbPaData
                    {
                        Type  = PaDataType.PA_SUPPORTED_ETYPES,
                        Value = request.Principal.SupportedEncryptionTypes.AsReadOnly(littleEndian: true).AsMemory()
                    }
                }
            };

            var cname = KrbPrincipalName.FromPrincipal(request.Principal, realm: request.RealmName);

            var rep = new T
            {
                CName       = cname,
                CRealm      = request.RealmName,
                MessageType = MessageType.KRB_AS_REP,
                Ticket      = ticket,
                EncPart     = KrbEncryptedData.Encrypt(
                    encKdcRepPart.EncodeApplication(),
                    request.EncryptedPartKey,
                    keyUsage
                    )
            };

            return(rep);
        }
示例#16
0
        public static async Task <T> GenerateServiceTicket <T>(ServiceTicketRequest request)
            where T : KrbKdcRep, new()
        {
            if (request.EncryptedPartKey == null)
            {
                throw new ArgumentException("A session key must be provided to encrypt the response", nameof(request.EncryptedPartKey));
            }

            if (request.Principal == null)
            {
                throw new ArgumentException("A Principal identity must be provided", nameof(request.Principal));
            }

            if (request.ServicePrincipal == null)
            {
                throw new ArgumentException("A service principal must be provided", nameof(request.ServicePrincipal));
            }

            if (request.ServicePrincipalKey == null)
            {
                throw new ArgumentException("A service principal key must be provided", nameof(request.ServicePrincipalKey));
            }

            var authz = await GenerateAuthorizationData(request.Principal, request);

            var cname = KrbPrincipalName.FromPrincipal(request.Principal, realm: request.RealmName);

            var sessionKey = KrbEncryptionKey.Generate(request.ServicePrincipalKey.EncryptionType);

            var flags = request.Flags;

            if (request.PreAuthenticationData?.Any(r => r.Type == PaDataType.PA_REQ_ENC_PA_REP) ?? false)
            {
                flags |= TicketFlags.EncryptedPreAuthentication;
            }

            var addresses = request.Addresses;

            if (addresses == null)
            {
                addresses = new KrbHostAddress[0];
            }

            var encTicketPart = new KrbEncTicketPart()
            {
                CName             = cname,
                Key               = sessionKey,
                AuthTime          = request.Now,
                StartTime         = request.StartTime,
                EndTime           = request.EndTime,
                CRealm            = request.RealmName,
                Flags             = flags,
                AuthorizationData = authz.ToArray(),
                CAddr             = addresses.ToArray(),
                Transited         = new KrbTransitedEncoding()
            };

            if (flags.HasFlag(TicketFlags.Renewable))
            {
                // RenewTill should never increase if it was set previously even if this is a renewal pass

                encTicketPart.RenewTill = request.RenewTill;
            }

            var ticket = new KrbTicket()
            {
                Realm = request.RealmName,
                SName = KrbPrincipalName.FromPrincipal(
                    request.ServicePrincipal,
                    PrincipalNameType.NT_SRV_INST,
                    request.RealmName
                    ),
                EncryptedPart = KrbEncryptedData.Encrypt(
                    encTicketPart.EncodeApplication(),
                    request.ServicePrincipalKey,
                    KeyUsage.Ticket
                    )
            };

            KrbEncKdcRepPart encKdcRepPart;

            if (typeof(T) == typeof(KrbAsRep))
            {
                encKdcRepPart = new KrbEncAsRepPart();
            }
            else if (typeof(T) == typeof(KrbTgsRep))
            {
                encKdcRepPart = new KrbEncTgsRepPart();
            }
            else
            {
                throw new InvalidOperationException($"Requested Service Ticket type is neither KrbAsRep nor KrbTgsRep. Type: {typeof(T)}");
            }

            encKdcRepPart.AuthTime      = encTicketPart.AuthTime;
            encKdcRepPart.StartTime     = encTicketPart.StartTime;
            encKdcRepPart.EndTime       = encTicketPart.EndTime;
            encKdcRepPart.RenewTill     = encTicketPart.RenewTill;
            encKdcRepPart.KeyExpiration = request.Principal.Expires;
            encKdcRepPart.Realm         = request.RealmName;
            encKdcRepPart.SName         = ticket.SName;
            encKdcRepPart.Flags         = encTicketPart.Flags;
            encKdcRepPart.CAddr         = encTicketPart.CAddr;
            encKdcRepPart.Key           = sessionKey;
            encKdcRepPart.Nonce         = request.Nonce;
            encKdcRepPart.LastReq       = new[] { new KrbLastReq {
                                                      Type = 0, Value = request.Now
                                                  } };
            encKdcRepPart.EncryptedPaData = new KrbMethodData
            {
                MethodData = new[]
                {
                    new KrbPaData
                    {
                        Type  = PaDataType.PA_SUPPORTED_ETYPES,
                        Value = request.Principal.SupportedEncryptionTypes.AsReadOnly(littleEndian: true).AsMemory()
                    }
                }
            };

            var rep = new T
            {
                CName       = cname,
                CRealm      = request.RealmName,
                MessageType = MessageType.KRB_AS_REP,
                Ticket      = ticket,
                EncPart     = KrbEncryptedData.Encrypt(
                    encKdcRepPart.EncodeApplication(),
                    request.EncryptedPartKey,
                    encKdcRepPart.KeyUsage
                    )
            };

            return(rep);
        }
        internal static void Decode <T>(AsnReader reader, Asn1Tag expectedTag, out T decoded)
            where T : KrbKdcReqBody, new()
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            decoded = new T();

            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
            AsnReader explicitReader;
            AsnReader collectionReader;

            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));

            if (explicitReader.TryReadPrimitiveBitStringValue(out _, out ReadOnlyMemory <byte> tmpKdcOptions))
            {
                decoded.KdcOptions = (KdcOptions)tmpKdcOptions.AsLong();
            }
            else
            {
                decoded.KdcOptions = (KdcOptions)explicitReader.ReadBitString(out _).AsLong();
            }


            explicitReader.ThrowIfNotEmpty();

            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1));

                KrbPrincipalName.Decode <KrbPrincipalName>(explicitReader, out KrbPrincipalName tmpCName);
                decoded.CName = tmpCName;
                explicitReader.ThrowIfNotEmpty();
            }

            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
            decoded.Realm  = explicitReader.ReadCharacterString(UniversalTagNumber.GeneralString);

            explicitReader.ThrowIfNotEmpty();

            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 3)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 3));

                KrbPrincipalName.Decode <KrbPrincipalName>(explicitReader, out KrbPrincipalName tmpSName);
                decoded.SName = tmpSName;
                explicitReader.ThrowIfNotEmpty();
            }

            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 4)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 4));

                decoded.From = explicitReader.ReadGeneralizedTime();
                explicitReader.ThrowIfNotEmpty();
            }

            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 5));
            decoded.Till   = explicitReader.ReadGeneralizedTime();

            explicitReader.ThrowIfNotEmpty();

            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 6)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 6));

                decoded.RTime = explicitReader.ReadGeneralizedTime();
                explicitReader.ThrowIfNotEmpty();
            }

            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 7));

            if (!explicitReader.TryReadInt32(out int tmpNonce))
            {
                explicitReader.ThrowIfNotEmpty();
            }

            decoded.Nonce = tmpNonce;

            explicitReader.ThrowIfNotEmpty();

            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 8));
            // Decode SEQUENCE OF for EType
            {
                collectionReader = explicitReader.ReadSequence();
                var            tmpList = new List <EncryptionType>();
                EncryptionType tmpItem;

                while (collectionReader.HasData)
                {
                    if (!collectionReader.TryReadInt32(out EncryptionType tmp))
                    {
                        collectionReader.ThrowIfNotEmpty();
                    }

                    tmpItem = tmp;
                    tmpList.Add(tmpItem);
                }

                decoded.EType = tmpList.ToArray();
            }

            explicitReader.ThrowIfNotEmpty();

            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 9)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 9));

                // Decode SEQUENCE OF for Addresses
                {
                    collectionReader = explicitReader.ReadSequence();
                    var            tmpList = new List <KrbHostAddress>();
                    KrbHostAddress tmpItem;

                    while (collectionReader.HasData)
                    {
                        KrbHostAddress.Decode <KrbHostAddress>(collectionReader, out KrbHostAddress tmp);
                        tmpItem = tmp;
                        tmpList.Add(tmpItem);
                    }

                    decoded.Addresses = tmpList.ToArray();
                }
                explicitReader.ThrowIfNotEmpty();
            }

            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 10)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 10));

                KrbEncryptedData.Decode <KrbEncryptedData>(explicitReader, out KrbEncryptedData tmpEncAuthorizationData);
                decoded.EncAuthorizationData = tmpEncAuthorizationData;
                explicitReader.ThrowIfNotEmpty();
            }

            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 11)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 11));

                // Decode SEQUENCE OF for AdditionalTickets
                {
                    collectionReader = explicitReader.ReadSequence();
                    var       tmpList = new List <KrbTicket>();
                    KrbTicket tmpItem;

                    while (collectionReader.HasData)
                    {
                        KrbTicket.Decode <KrbTicket>(collectionReader, out KrbTicket tmp);
                        tmpItem = tmp;
                        tmpList.Add(tmpItem);
                    }

                    decoded.AdditionalTickets = tmpList.ToArray();
                }
                explicitReader.ThrowIfNotEmpty();
            }

            sequenceReader.ThrowIfNotEmpty();
        }
示例#18
0
        public static async Task <T> GenerateServiceTicket <T>(ServiceTicketRequest request)
            where T : KrbKdcRep, new()
        {
            var sessionKey = KrbEncryptionKey.Generate(request.ServicePrincipalKey.EncryptionType);

            var authz = await GenerateAuthorizationData(request.Principal, request.ServicePrincipalKey);

            var cname = KrbPrincipalName.FromPrincipal(request.Principal, realm: request.RealmName);

            var flags = request.Flags;

            if (request.Principal.SupportedPreAuthenticationTypes.Any())
            {
                // This is not strictly an accurate way of detecting if the user was pre-authenticated.
                // If pre-auth handlers are registered and the principal has PA-Types available, a request
                // will never make it to this point without getting authenticated.
                //
                // However if no pre-auth handlers are registered, then the PA check is skipped
                // and this isn't technically accurate anymore.
                //
                // TODO: this should tie into the make-believe policy check being used in the
                // auth handler section

                flags |= TicketFlags.EncryptedPreAuthentication | TicketFlags.PreAuthenticated;
            }

            var addresses = request.Addresses;

            if (addresses == null)
            {
                addresses = new KrbHostAddress[0];
            }

            var encTicketPart = new KrbEncTicketPart()
            {
                CName             = cname,
                Key               = sessionKey,
                AuthTime          = request.Now,
                StartTime         = request.StartTime,
                EndTime           = request.EndTime,
                CRealm            = request.RealmName,
                Flags             = flags,
                AuthorizationData = authz.ToArray(),
                CAddr             = addresses.ToArray(),
                Transited         = new KrbTransitedEncoding()
            };

            if (flags.HasFlag(TicketFlags.Renewable))
            {
                // RenewTill should never increase if it was set previously even if this is a renewal pass

                encTicketPart.RenewTill = request.RenewTill;
            }

            var ticket = new KrbTicket()
            {
                Realm = request.RealmName,
                SName = KrbPrincipalName.FromPrincipal(
                    request.ServicePrincipal,
                    PrincipalNameType.NT_SRV_INST,
                    request.RealmName
                    ),
                EncryptedPart = KrbEncryptedData.Encrypt(
                    encTicketPart.EncodeApplication(),
                    request.ServicePrincipalKey,
                    KeyUsage.Ticket
                    )
            };

            KrbEncKdcRepPart encKdcRepPart;

            if (typeof(T) == typeof(KrbAsRep))
            {
                encKdcRepPart = new KrbEncAsRepPart();
            }
            else if (typeof(T) == typeof(KrbTgsRep))
            {
                encKdcRepPart = new KrbEncTgsRepPart();
            }
            else
            {
                throw new InvalidOperationException($"Requested Service Ticket type is neither KrbAsRep nor KrbTgsRep. Type: {typeof(T)}");
            }

            encKdcRepPart.AuthTime      = encTicketPart.AuthTime;
            encKdcRepPart.StartTime     = encTicketPart.StartTime;
            encKdcRepPart.EndTime       = encTicketPart.EndTime;
            encKdcRepPart.RenewTill     = encTicketPart.RenewTill;
            encKdcRepPart.KeyExpiration = request.Principal.Expires;
            encKdcRepPart.Realm         = request.RealmName;
            encKdcRepPart.SName         = ticket.SName;
            encKdcRepPart.Flags         = encTicketPart.Flags;
            encKdcRepPart.CAddr         = encTicketPart.CAddr;
            encKdcRepPart.Key           = sessionKey;
            encKdcRepPart.Nonce         = KerberosConstants.GetNonce();
            encKdcRepPart.LastReq       = new[] { new KrbLastReq {
                                                      Type = 0, Value = request.Now
                                                  } };
            encKdcRepPart.EncryptedPaData = new KrbMethodData
            {
                MethodData = new[]
                {
                    new KrbPaData
                    {
                        Type  = PaDataType.PA_SUPPORTED_ETYPES,
                        Value = request.Principal.SupportedEncryptionTypes.AsReadOnly(littleEndian: true).AsMemory()
                    }
                }
            };

            encKdcRepPart.EncodeApplication();

            var rep = new T
            {
                CName       = cname,
                CRealm      = request.RealmName,
                MessageType = MessageType.KRB_AS_REP,
                Ticket      = ticket,
                EncPart     = KrbEncryptedData.Encrypt(
                    encKdcRepPart.EncodeApplication(),
                    request.EncryptedPartKey,
                    encKdcRepPart.KeyUsage
                    )
            };

            return(rep);
        }
示例#19
0
        private static ServiceTicketRequest GenerateServiceTicket <T>(
            ServiceTicketRequest request,
            out KrbEncTicketPart encTicketPart,
            out KrbTicket ticket,
            out KrbEncKdcRepPart encKdcRepPart,
            out KeyUsage keyUsage,
            out MessageType messageType
            )
            where T : KrbKdcRep, new()
        {
            if (request.Principal == null)
            {
                throw new InvalidOperationException("A Principal identity must be provided");
            }

            if (request.ServicePrincipal == null)
            {
                throw new InvalidOperationException("A service principal must be provided");
            }

            if (request.ServicePrincipalKey == null)
            {
                throw new InvalidOperationException("A service principal key must be provided");
            }

            var authz = GenerateAuthorizationData(request);

            var sessionKey = KrbEncryptionKey.Generate(request.PreferredClientEType ?? request.ServicePrincipalKey.EncryptionType);

            encTicketPart = CreateEncTicketPart(request, authz.ToArray(), sessionKey);
            bool appendRealm = false;

            if (request.ServicePrincipal.PrincipalName.Contains("/"))
            {
                appendRealm = true;
            }

            ticket = new KrbTicket()
            {
                Realm = request.RealmName,
                SName = KrbPrincipalName.FromPrincipal(
                    request.ServicePrincipal,
                    PrincipalNameType.NT_SRV_INST,
                    appendRealm ? null : request.RealmName
                    ),
                EncryptedPart = KrbEncryptedData.Encrypt(
                    encTicketPart.EncodeApplication(),
                    request.ServicePrincipalKey,
                    KeyUsage.Ticket
                    )
            };
            if (typeof(T) == typeof(KrbAsRep))
            {
                encKdcRepPart = new KrbEncAsRepPart();
                keyUsage      = KeyUsage.EncAsRepPart;
                messageType   = MessageType.KRB_AS_REP;
            }
            else if (typeof(T) == typeof(KrbTgsRep))
            {
                encKdcRepPart = new KrbEncTgsRepPart();
                keyUsage      = request.EncryptedPartKey?.Usage ?? KeyUsage.EncTgsRepPartSessionKey;
                messageType   = MessageType.KRB_TGS_REP;
            }
            else
            {
                throw new InvalidOperationException($"Requested Service Ticket type is neither KrbAsRep nor KrbTgsRep. Type: {typeof(T)}");
            }

            encKdcRepPart.AuthTime      = encTicketPart.AuthTime;
            encKdcRepPart.StartTime     = encTicketPart.StartTime;
            encKdcRepPart.EndTime       = encTicketPart.EndTime;
            encKdcRepPart.RenewTill     = encTicketPart.RenewTill;
            encKdcRepPart.KeyExpiration = request.Principal.Expires;
            encKdcRepPart.Realm         = request.RealmName;
            encKdcRepPart.SName         = ticket.SName;
            encKdcRepPart.Flags         = encTicketPart.Flags;
            encKdcRepPart.CAddr         = encTicketPart.CAddr;
            encKdcRepPart.Key           = sessionKey;
            encKdcRepPart.Nonce         = request.Nonce;
            encKdcRepPart.LastReq       = new[] { new KrbLastReq {
                                                      Type = 0, Value = request.Now
                                                  } };
            encKdcRepPart.EncryptedPaData = new KrbMethodData
            {
                MethodData = new[]
                {
                    new KrbPaData
                    {
                        Type  = PaDataType.PA_SUPPORTED_ETYPES,
                        Value = request.Principal.SupportedEncryptionTypes.AsReadOnly(littleEndian: true).AsMemory()
                    }
                }
            };
            return(request);
        }
示例#20
0
        internal static void Decode <T>(AsnReader reader, Asn1Tag expectedTag, out T decoded)
            where T : KrbEncTicketPart, new()
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            decoded = new T();
            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
            AsnReader explicitReader;
            AsnReader collectionReader;


            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));

            if (explicitReader.TryReadPrimitiveBitStringValue(out _, out ReadOnlyMemory <byte> tmpFlags))
            {
                decoded.Flags = (TicketFlags)tmpFlags.AsLong();
            }
            else
            {
                decoded.Flags = (TicketFlags)explicitReader.ReadBitString(out _).AsLong();
            }

            explicitReader.ThrowIfNotEmpty();


            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
            KrbEncryptionKey.Decode <KrbEncryptionKey>(explicitReader, out decoded.Key);
            explicitReader.ThrowIfNotEmpty();


            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
            decoded.CRealm = explicitReader.ReadCharacterString(UniversalTagNumber.GeneralString);
            explicitReader.ThrowIfNotEmpty();


            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 3));
            KrbPrincipalName.Decode <KrbPrincipalName>(explicitReader, out decoded.CName);
            explicitReader.ThrowIfNotEmpty();


            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 4));
            KrbTransitedEncoding.Decode <KrbTransitedEncoding>(explicitReader, out decoded.Transited);
            explicitReader.ThrowIfNotEmpty();


            explicitReader   = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 5));
            decoded.AuthTime = explicitReader.ReadGeneralizedTime();
            explicitReader.ThrowIfNotEmpty();


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 6)))
            {
                explicitReader    = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 6));
                decoded.StartTime = explicitReader.ReadGeneralizedTime();
                explicitReader.ThrowIfNotEmpty();
            }


            explicitReader  = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 7));
            decoded.EndTime = explicitReader.ReadGeneralizedTime();
            explicitReader.ThrowIfNotEmpty();


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 8)))
            {
                explicitReader    = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 8));
                decoded.RenewTill = explicitReader.ReadGeneralizedTime();
                explicitReader.ThrowIfNotEmpty();
            }


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 9)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 9));

                // Decode SEQUENCE OF for CAddr
                {
                    collectionReader = explicitReader.ReadSequence();
                    var            tmpList = new List <KrbHostAddress>();
                    KrbHostAddress tmpItem;

                    while (collectionReader.HasData)
                    {
                        KrbHostAddress.Decode <KrbHostAddress>(collectionReader, out tmpItem);
                        tmpList.Add(tmpItem);
                    }

                    decoded.CAddr = tmpList.ToArray();
                }

                explicitReader.ThrowIfNotEmpty();
            }


            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 10)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 10));

                // Decode SEQUENCE OF for AuthorizationData
                {
                    collectionReader = explicitReader.ReadSequence();
                    var tmpList = new List <KrbAuthorizationData>();
                    KrbAuthorizationData tmpItem;

                    while (collectionReader.HasData)
                    {
                        KrbAuthorizationData.Decode <KrbAuthorizationData>(collectionReader, out tmpItem);
                        tmpList.Add(tmpItem);
                    }

                    decoded.AuthorizationData = tmpList.ToArray();
                }

                explicitReader.ThrowIfNotEmpty();
            }


            sequenceReader.ThrowIfNotEmpty();
        }
        internal static void Decode <T>(AsnReader reader, Asn1Tag expectedTag, out T decoded)
            where T : KrbS4uUserId, new()
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            decoded = new T();

            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
            AsnReader explicitReader;

            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));

            if (!explicitReader.TryReadInt32(out int tmpNonce))
            {
                explicitReader.ThrowIfNotEmpty();
            }

            decoded.Nonce = tmpNonce;

            explicitReader.ThrowIfNotEmpty();

            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1));

                KrbPrincipalName.Decode <KrbPrincipalName>(explicitReader, out KrbPrincipalName tmpCName);
                decoded.CName = tmpCName;
                explicitReader.ThrowIfNotEmpty();
            }

            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
            decoded.Realm  = explicitReader.ReadCharacterString(UniversalTagNumber.GeneralString);

            explicitReader.ThrowIfNotEmpty();

            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 3)))
            {
                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 3));


                if (explicitReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory <byte> tmpSubjectCertificate))
                {
                    decoded.SubjectCertificate = tmpSubjectCertificate;
                }
                else
                {
                    decoded.SubjectCertificate = explicitReader.ReadOctetString();
                }
                explicitReader.ThrowIfNotEmpty();
            }

            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 4));

            if (explicitReader.TryReadPrimitiveBitStringValue(out _, out ReadOnlyMemory <byte> tmpOptions))
            {
                decoded.Options = (S4uOptions)tmpOptions.AsLong();
            }
            else
            {
                decoded.Options = (S4uOptions)explicitReader.ReadBitString(out _).AsLong();
            }


            explicitReader.ThrowIfNotEmpty();

            sequenceReader.ThrowIfNotEmpty();
        }