예제 #1
0
        private static DecryptedKrbApReq CreateDecryptedApReq(DateTimeOffset now, DateTimeOffset notBefore, DateTimeOffset notAfter, DateTimeOffset renewUntil)
        {
            var key = new KerberosKey(key: new byte[16], etype: EncryptionType.AES128_CTS_HMAC_SHA1_96);

            var tgsRep = KrbKdcRep.GenerateServiceTicket <KrbTgsRep>(new ServiceTicketRequest
            {
                EncryptedPartKey    = key,
                Principal           = new FakeKerberosPrincipal("*****@*****.**"),
                ServicePrincipal    = new FakeKerberosPrincipal("host/test.com"),
                ServicePrincipalKey = key,
                IncludePac          = false,
                RealmName           = "test.com",
                Now       = now,
                StartTime = notBefore,
                EndTime   = notAfter,
                RenewTill = renewUntil,
                Flags     = TicketFlags.Renewable
            });

            var encKdcRepPart = tgsRep.EncPart.Decrypt(
                key,
                KeyUsage.EncTgsRepPartSessionKey,
                d => KrbEncTgsRepPart.DecodeApplication(d)
                );

            var apReq = KrbApReq.CreateApReq(tgsRep, encKdcRepPart.Key.AsKey(), default, out KrbAuthenticator authenticator);
예제 #2
0
 public async Task CreateServiceTicket_NullEncPartKey()
 {
     await KrbKdcRep.GenerateServiceTicket <KrbTgsRep>(new ServiceTicketRequest
     {
         EncryptedPartKey = null
     });
 }
예제 #3
0
 public void CreateServiceTicket_NullEncPartKey()
 {
     KrbKdcRep.GenerateServiceTicket <KrbTgsRep>(new ServiceTicketRequest
     {
         EncryptedPartKey = null
     });
 }
예제 #4
0
        public async Task CreateServiceTicket_NullServicePrincipalKey()
        {
            var key = KrbEncryptionKey.Generate(EncryptionType.AES128_CTS_HMAC_SHA1_96).AsKey();

            await KrbKdcRep.GenerateServiceTicket <KrbTgsRep>(new ServiceTicketRequest
            {
                EncryptedPartKey = key,
                ServicePrincipal = new FakeKerberosPrincipal("*****@*****.**")
            });
        }
예제 #5
0
        public void CreateServiceTicket_NullServicePrincipal()
        {
            var key = KrbEncryptionKey.Generate(EncryptionType.AES128_CTS_HMAC_SHA1_96).AsKey();

            KrbKdcRep.GenerateServiceTicket <KrbTgsRep>(new ServiceTicketRequest
            {
                EncryptedPartKey = key,
                ServicePrincipal = null
            });
        }
예제 #6
0
        public async Task CreateServiceTicket()
        {
            var key = KrbEncryptionKey.Generate(EncryptionType.AES128_CTS_HMAC_SHA1_96).AsKey();

            var ticket = await KrbKdcRep.GenerateServiceTicket <KrbTgsRep>(new ServiceTicketRequest
            {
                EncryptedPartKey    = key,
                ServicePrincipal    = new FakeKerberosPrincipal("*****@*****.**"),
                ServicePrincipalKey = key,
                Principal           = new FakeKerberosPrincipal("*****@*****.**"),
                RealmName           = "blah.com"
            });

            Assert.IsNotNull(ticket);
        }
예제 #7
0
        public void CreateServiceTicketOnCompatibilitySetting(string realm, KerberosCompatibilityFlags compatibilityFlags, string expectedRealm)
        {
            var key = KrbEncryptionKey.Generate(EncryptionType.AES128_CTS_HMAC_SHA1_96).AsKey();

            var ticket = KrbKdcRep.GenerateServiceTicket <KrbTgsRep>(new ServiceTicketRequest
            {
                EncryptedPartKey    = key,
                ServicePrincipal    = new FakeKerberosPrincipal("*****@*****.**"),
                ServicePrincipalKey = key,
                Principal           = new FakeKerberosPrincipal("*****@*****.**"),
                RealmName           = realm,
                Compatibility       = compatibilityFlags,
            });

            Assert.IsNotNull(ticket);
            Assert.AreEqual(expectedRealm, ticket.CRealm);
        }
예제 #8
0
        public override async Task <ReadOnlyMemory <byte> > ExecuteCore(IKerberosMessage message, PreAuthenticationContext context)
        {
            // the logic for a TGS-REQ is relatively simple in the primary case where you have a TGT and want
            // to get a ticket to another service. It gets a bit more complicated when you need to do something
            // like a U2U exchange, renew, or get a referral to another realm. Realm referral isn't supported yet.

            // 1. Get the ApReq (TGT) from the PA-Data of the request
            // 2. Decrypt the TGT and extract the client calling identity
            // 3. Find the requested service principal
            // 4. Evaluate whether the client identity should get a ticket to the service
            // 5. Evaluate whether it should do U2U and if so extract that key instead
            // 6. Generate a service ticket for the calling client to the service
            // 7. return to client

            var tgsReq = (KrbTgsReq)message;

            logger.LogInformation("TGS-REQ incoming. SPN = {SPN}", tgsReq.Body.SName.FullyQualifiedName);

            var krbtgtIdentity = await RealmService.Principals.RetrieveKrbtgt();

            var krbtgtKey = await krbtgtIdentity.RetrieveLongTermCredential();

            var servicePrincipal = await RealmService.Principals.Find(tgsReq.Body.SName.FullyQualifiedName);

            // renewal is an odd case here because the SName will be krbtgt
            // does this need to be validated more than the Decrypt call?

            await EvaluateSecurityPolicy(context.Principal, servicePrincipal);

            KerberosKey serviceKey;

            if (tgsReq.Body.KdcOptions.HasFlag(KdcOptions.EncTktInSkey))
            {
                serviceKey = GetUserToUserTicketKey(tgsReq.Body.AdditionalTickets, krbtgtKey);
            }
            else
            {
                serviceKey = await servicePrincipal.RetrieveLongTermCredential();
            }

            var now = RealmService.Now();

            TicketFlags flags = 0;

            if (tgsReq.Body.KdcOptions.HasFlag(KdcOptions.Forwardable))
            {
                flags |= TicketFlags.Forwardable;
            }

            if (context.Ticket.Flags.HasFlag(TicketFlags.PreAuthenticated))
            {
                flags |= TicketFlags.PreAuthenticated;
            }

            var tgsRep = await KrbKdcRep.GenerateServiceTicket <KrbTgsRep>(
                new ServiceTicketRequest
            {
                Principal           = context.Principal,
                EncryptedPartKey    = context.EncryptedPartKey,
                ServicePrincipal    = servicePrincipal,
                ServicePrincipalKey = serviceKey,
                RealmName           = RealmService.Name,
                Addresses           = tgsReq.Body.Addresses,
                RenewTill           = context.Ticket.RenewTill,
                StartTime           = now - RealmService.Settings.MaximumSkew,
                EndTime             = now + RealmService.Settings.SessionLifetime,
                Flags      = flags,
                Now        = now,
                Nonce      = tgsReq.Body.Nonce,
                IncludePac = context.Ticket.AuthorizationData.Any(a => a.Type == AuthorizationDataType.AdIfRelevant)
            }
                );

            return(tgsRep.EncodeApplication());
        }
예제 #9
0
        public override ReadOnlyMemory <byte> ExecuteCore(PreAuthenticationContext context)
        {
            // Now that we know who is requesting the ticket we can issue the ticket
            //
            // 3. Find the requested service principal
            // 4. Determine if the requested service principal is in another realm and if so refer them
            // 5. Evaluate whether the client identity should get a ticket to the service
            // 6. Evaluate whether it should do U2U and if so extract that key instead
            // 7. Generate a service ticket for the calling client to the service
            // 8. return to client

            var tgsReq = (KrbTgsReq)context.Message;

            if (context.ServicePrincipal == null)
            {
                // we can't find what they're asking for, but maybe it's in a realm we can transit?

                context.ServicePrincipal = ProposeTransitedRealm(tgsReq, context);
            }

            if (context.ServicePrincipal == null)
            {
                // we have no idea what service they're asking for and
                // there isn't a realm we can refer them to that can issue a ticket

                return(GenerateError(
                           KerberosErrorCode.KDC_ERR_S_PRINCIPAL_UNKNOWN,
                           "",
                           RealmService.Name,
                           tgsReq.Body.SName.FullyQualifiedName
                           ));
            }

            // renewal is an odd case here because the SName will be krbtgt
            // does this need to be validated more than the Decrypt call?

            EvaluateSecurityPolicy(context.Principal, context.ServicePrincipal);

            KerberosKey serviceKey;

            if (tgsReq.Body.KdcOptions.HasFlag(KdcOptions.EncTktInSkey))
            {
                serviceKey = GetUserToUserTicketKey(tgsReq.Body.AdditionalTickets, context);
            }
            else
            {
                serviceKey = context.ServicePrincipal.RetrieveLongTermCredential();
            }

            var now = RealmService.Now();

            TicketFlags flags = 0;

            if (tgsReq.Body.KdcOptions.HasFlag(KdcOptions.Forwardable))
            {
                flags |= TicketFlags.Forwardable;
            }

            if (context.Ticket.Flags.HasFlag(TicketFlags.PreAuthenticated))
            {
                flags |= TicketFlags.PreAuthenticated;
            }

            var includePac = DetectPacRequirement(tgsReq);

            if (includePac == null)
            {
                includePac = context.Ticket?.AuthorizationData?.Any(a => a.Type == AuthorizationDataType.AdIfRelevant) ?? false;
            }

            var tgsRep = KrbKdcRep.GenerateServiceTicket <KrbTgsRep>(
                new ServiceTicketRequest
            {
                KdcAuthorizationKey = context.EvidenceTicketKey,
                Principal           = context.Principal,
                EncryptedPartKey    = context.EncryptedPartKey,
                ServicePrincipal    = context.ServicePrincipal,
                ServicePrincipalKey = serviceKey,
                RealmName           = RealmService.Name,
                Addresses           = tgsReq.Body.Addresses,
                RenewTill           = context.Ticket.RenewTill,
                StartTime           = now - RealmService.Settings.MaximumSkew,
                EndTime             = now + RealmService.Settings.SessionLifetime,
                Flags      = flags,
                Now        = now,
                Nonce      = tgsReq.Body.Nonce,
                IncludePac = includePac ?? false
            }
                );

            return(tgsRep.EncodeApplication());
        }
예제 #10
0
        public override ReadOnlyMemory <byte> ExecuteCore(PreAuthenticationContext context)
        {
            // Now that we know who is requesting the ticket we can issue the ticket
            //
            // 3. Find the requested service principal
            // 4. Determine if the requested service principal is in another realm and if so refer them
            // 5. Evaluate whether the client identity should get a ticket to the service
            // 6. Evaluate whether it should do U2U and if so extract that key instead
            // 7. Generate a service ticket for the calling client to the service
            // 8. return to client

            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var tgsReq = (KrbTgsReq)context.Message;

            if (context.ServicePrincipal == null)
            {
                // we can't find what they're asking for, but maybe it's in a realm we can transit?

                context.ServicePrincipal = this.ProposeTransitedRealm(tgsReq, context);
            }

            if (context.ServicePrincipal == null)
            {
                // we have no idea what service they're asking for and
                // there isn't a realm we can refer them to that can issue a ticket

                return(GenerateError(
                           KerberosErrorCode.KDC_ERR_S_PRINCIPAL_UNKNOWN,
                           string.Empty,
                           tgsReq.Body.Realm,
                           tgsReq.Body.SName.FullyQualifiedName
                           ));
            }

            // renewal is an odd case here because the SName will be krbtgt
            // does this need to be validated more than the Decrypt call?

            this.EvaluateSecurityPolicy(context.Principal, context.ServicePrincipal);

            KerberosKey serviceKey;

            if (tgsReq.Body.KdcOptions.HasFlag(KdcOptions.EncTktInSkey))
            {
                serviceKey = GetUserToUserTicketKey(tgsReq.Body.AdditionalTickets, context);
            }
            else
            {
                serviceKey = context.ServicePrincipal.RetrieveLongTermCredential();
            }

            var now = this.RealmService.Now();

            TicketFlags flags = 0;

            if (tgsReq.Body.KdcOptions.HasFlag(KdcOptions.Forwardable))
            {
                flags |= TicketFlags.Forwardable;
            }

            if (context.Ticket.Flags.HasFlag(TicketFlags.PreAuthenticated))
            {
                flags |= TicketFlags.PreAuthenticated;
            }

            if (context.IncludePac == null)
            {
                context.IncludePac = DetectPacRequirement(tgsReq);

                if (context.IncludePac == null)
                {
                    context.IncludePac = context.Ticket?.AuthorizationData?.Any(a => a.Type == AuthorizationDataType.AdIfRelevant) ?? false;
                }
            }

            var rst = new ServiceTicketRequest
            {
                KdcAuthorizationKey   = context.EvidenceTicketKey,
                Principal             = context.Principal,
                EncryptedPartKey      = context.EncryptedPartKey,
                EncryptedPartEType    = context.EncryptedPartEType,
                ServicePrincipal      = context.ServicePrincipal,
                ServicePrincipalKey   = serviceKey,
                RealmName             = tgsReq.Body.Realm,
                Addresses             = tgsReq.Body.Addresses,
                RenewTill             = context.Ticket.RenewTill,
                StartTime             = tgsReq.Body.From ?? DateTimeOffset.MinValue,
                EndTime               = tgsReq.Body.Till,
                MaximumTicketLifetime = this.RealmService.Settings.SessionLifetime,
                Flags                = flags,
                Now                  = now,
                Nonce                = tgsReq.Body.Nonce,
                IncludePac           = context.IncludePac ?? false,
                PreferredClientEType = GetPreferredEType(
                    tgsReq.Body.EType,
                    this.RealmService.Configuration.Defaults.PermittedEncryptionTypes,
                    this.RealmService.Configuration.Defaults.AllowWeakCrypto
                    ),
                Compatibility = this.RealmService.Settings.Compatibility,
            };

            if (tgsReq.Body.KdcOptions.HasFlag(KdcOptions.Canonicalize))
            {
                rst.SamAccountName = context.GetState <TgsState>(PaDataType.PA_TGS_REQ).DecryptedApReq.Ticket.CName.FullyQualifiedName;
            }

            // this is set here instead of in GenerateServiceTicket because GST is used by unit tests to
            // generate tickets with weird lifetimes for scenario testing and we don't want to break that

            rst.ClampLifetime();

            var tgsRep = KrbKdcRep.GenerateServiceTicket <KrbTgsRep>(rst);

            return(tgsRep.EncodeApplication());
        }
예제 #11
0
        protected override async Task <ReadOnlyMemory <byte> > ExecuteCore(IKerberosMessage message)
        {
            // the logic for a TGS-REQ is relatively simple in the primary case where you have a TGT and want
            // to get a ticket to another service. It gets a bit more complicated when you need to do something
            // like a U2U exchange, renew, or get a referral to another realm. Realm referral isn't supported yet.

            // 1. Get the ApReq (TGT) from the PA-Data of the request
            // 2. Decrypt the TGT and extract the client calling identity
            // 3. Find the requested service principal
            // 4. Evaluate whether the client identity should get a ticket to the service
            // 5. Evaluate whether it should do U2U and if so extract that key instead
            // 6. Generate a service ticket for the calling client to the service
            // 7. return to client

            var tgsReq = (KrbTgsReq)message;

            var apReq = ExtractApReq(tgsReq);

            var krbtgtIdentity = await RealmService.Principals.RetrieveKrbtgt();

            var krbtgtKey = await krbtgtIdentity.RetrieveLongTermCredential();

            var krbtgtApReqDecrypted = DecryptApReq(apReq, krbtgtKey);

            var principal = await RealmService.Principals.Find(krbtgtApReqDecrypted.Ticket.CName.FullyQualifiedName);

            var servicePrincipal = await RealmService.Principals.Find(tgsReq.Body.SName.FullyQualifiedName);

            // renewal is an odd case here because the SName will be krbtgt
            // does this need to be validated more than the Decrypt call?

            await EvaluateSecurityPolicy(principal, servicePrincipal, krbtgtApReqDecrypted);

            KerberosKey serviceKey;

            if (tgsReq.Body.KdcOptions.HasFlag(KdcOptions.EncTktInSkey))
            {
                serviceKey = GetUserToUserTicketKey(tgsReq.Body.AdditionalTickets, krbtgtKey);
            }
            else
            {
                serviceKey = await servicePrincipal.RetrieveLongTermCredential();
            }

            var now = RealmService.Now();

            var tgsRep = await KrbKdcRep.GenerateServiceTicket <KrbTgsRep>(
                new ServiceTicketRequest
            {
                Principal           = principal,
                EncryptedPartKey    = krbtgtApReqDecrypted.SessionKey,
                ServicePrincipal    = servicePrincipal,
                ServicePrincipalKey = serviceKey,
                RealmName           = RealmService.Name,
                Addresses           = tgsReq.Body.Addresses,
                RenewTill           = krbtgtApReqDecrypted.Ticket.RenewTill,
                StartTime           = now - RealmService.Settings.MaximumSkew,
                EndTime             = now + RealmService.Settings.SessionLifetime,
                Flags = KrbKdcRep.DefaultFlags,
                Now   = now
            }
                );

            return(tgsRep.EncodeApplication());
        }