예제 #1
0
        public static T GenerateServiceTicket <T>(ServiceTicketRequest request)
            where T : KrbKdcRep, new()
        {
            if (request.EncryptedPartKey == null)
            {
                throw new InvalidOperationException("A client key must be provided to encrypt the response");
            }

            request = GenerateServiceTicket <T>(
                request,
                out KrbEncTicketPart encTicketPart,
                out KrbTicket ticket,
                out KrbEncKdcRepPart encKdcRepPart,
                out KeyUsage keyUsage,
                out MessageType messageType
                );

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

            return(rep);
        }
예제 #2
0
        private static IEnumerable <KrbAuthorizationData> GenerateAuthorizationData(ServiceTicketRequest request)
        {
            // authorization-data is annoying because it's a sequence of
            // ad-if-relevant, which is a sequence of sequences
            // it ends up looking something like
            //
            // [
            //   {
            //      Type = ad-if-relevant,
            //      Data =
            //      [
            //        {
            //           Type = pac,
            //           Data = encoded-pac
            //        },
            //        ...
            //      ],
            //   },
            //   ...
            // ]

            var authz = new List <KrbAuthorizationData>();

            if (request.IncludePac)
            {
                var pac = request.Principal.GeneratePac();

                if (pac != null)
                {
                    pac.ClientInformation = new PacClientInfo
                    {
                        ClientId = RpcFileTime.ConvertWithoutMicroseconds(request.Now),
                        Name     = request.Principal.PrincipalName
                    };

                    var sequence = new KrbAuthorizationDataSequence
                    {
                        AuthorizationData = new[]
                        {
                            new KrbAuthorizationData
                            {
                                Type = AuthorizationDataType.AdWin2kPac,
                                Data = pac.Encode(request.KdcAuthorizationKey, request.ServicePrincipalKey)
                            }
                        }
                    };

                    authz.Add(new KrbAuthorizationData
                    {
                        Type = AuthorizationDataType.AdIfRelevant,
                        Data = sequence.Encode()
                    });
                }
            }

            return(authz);
        }
예제 #3
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));
        }
예제 #4
0
        private static async Task <IEnumerable <KrbAuthorizationData> > GenerateAuthorizationData(
            IKerberosPrincipal principal,
            ServiceTicketRequest request
            )
        {
            // authorization-data is annoying because it's a sequence of
            // ad-if-relevant, which is a sequence of sequences
            // it ends up looking something like
            //
            // [
            //   {
            //      Type = ad-if-relevant,
            //      Data =
            //      [
            //        {
            //           Type = pac,
            //           Data = encoded-pac
            //        },
            //        ...
            //      ],
            //   },
            //   ...
            // ]

            var authz = new List <KrbAuthorizationData>();

            if (request.IncludePac)
            {
                var pac = await principal.GeneratePac();

                if (pac != null)
                {
                    var sequence = new KrbAuthorizationDataSequence
                    {
                        AuthorizationData = new[]
                        {
                            new KrbAuthorizationData
                            {
                                Type = AuthorizationDataType.AdWin2kPac,
                                Data = pac.Encode(request.ServicePrincipalKey, request.ServicePrincipalKey)
                            }
                        }
                    };

                    authz.Add(new KrbAuthorizationData
                    {
                        Type = AuthorizationDataType.AdIfRelevant,
                        Data = sequence.Encode()
                    });
                }
            }

            return(authz);
        }
예제 #5
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 }
            });
        }
예제 #6
0
        public static KrbCred GenerateWrappedServiceTicket(ServiceTicketRequest request)
        {
            GenerateServiceTicket <KrbTgsRep>(
                request,
                out KrbEncTicketPart encTicketPart,
                out KrbTicket ticket,
                out _,
                out _,
                out _
                );

            return(KrbCred.WrapTicket(ticket, encTicketPart));
        }
예제 #7
0
        public static KrbAsRep GenerateTgt(
            ServiceTicketRequest rst,
            IRealmService realmService
            )
        {
            // 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))
            {
                rst.RealmName = realmService.Name;
            }

            if (rst.ServicePrincipal == null)
            {
                rst.ServicePrincipal = realmService.Principals.Find(KrbPrincipalName.WellKnown.Krbtgt());
            }

            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(KrbPrincipalName.WellKnown.Krbtgt());

                rst.KdcAuthorizationKey = krbtgt.RetrieveLongTermCredential();
            }

            var now = realmService.Now();

            rst.Now       = now;
            rst.RenewTill = now + realmService.Settings.MaximumRenewalWindow;
            rst.StartTime = now - realmService.Settings.MaximumSkew;
            rst.EndTime   = now + realmService.Settings.SessionLifetime;

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

            return(GenerateServiceTicket <KrbAsRep>(rst));
        }
예제 #8
0
        private static KrbEncTicketPart CreateEncTicketPart(
            ServiceTicketRequest request,
            KrbAuthorizationData[] authorizationDatas,
            KrbEncryptionKey sessionKey)
        {
            var cname = CreateCNameForTicket(request);

            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 = Array.Empty <KrbHostAddress>();
            }

            var encTicketPart = new KrbEncTicketPart()
            {
                CName             = cname,
                Key               = sessionKey,
                AuthTime          = request.Now,
                StartTime         = request.StartTime,
                EndTime           = request.EndTime,
                CRealm            = request.RealmName,
                Flags             = flags,
                AuthorizationData = authorizationDatas,
                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;
            }

            return(encTicketPart);
        }
예제 #9
0
        public static async Task <KrbAsRep> GenerateTgt(
            ServiceTicketRequest rst,
            IRealmService realmService
            )
        {
            // 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))
            {
                rst.RealmName = realmService.Name;
            }

            if (rst.ServicePrincipal == null)
            {
                rst.ServicePrincipal = await realmService.Principals.RetrieveKrbtgt();
            }

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

            var now = realmService.Now();

            rst.Now       = now;
            rst.RenewTill = now + realmService.Settings.MaximumRenewalWindow;
            rst.StartTime = now - realmService.Settings.MaximumSkew;
            rst.EndTime   = now + realmService.Settings.SessionLifetime;

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

            return(await GenerateServiceTicket <KrbAsRep>(rst));
        }
예제 #10
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);
        }
예제 #11
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);
        }
예제 #12
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);
        }
예제 #13
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);
        }