Exemplo n.º 1
0
        public static KrbCred WrapTicket(KrbTicket ticket, KrbCredInfo credInfo)
        {
            if (ticket is null)
            {
                throw new ArgumentNullException(nameof(ticket));
            }

            if (credInfo is null)
            {
                throw new ArgumentNullException(nameof(credInfo));
            }

            Now(out DateTimeOffset timestamp, out int usec);

            var encPart = new KrbEncKrbCredPart
            {
                Timestamp  = timestamp,
                USec       = usec,
                TicketInfo = new[] { credInfo }
            };

            var cred = new KrbCred
            {
                EncryptedPart = new KrbEncryptedData {
                    Cipher = encPart.EncodeApplication()
                },
                Tickets = new[] { ticket },
            };

            return(cred);
        }
Exemplo n.º 2
0
        internal static void Decode <T>(AsnReader reader, Asn1Tag expectedTag, out T decoded)
            where T : KrbApReq, 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();


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

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

            explicitReader.ThrowIfNotEmpty();


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


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


            sequenceReader.ThrowIfNotEmpty();
        }
Exemplo n.º 3
0
        public static KrbTgsReq CreateTgsReq(
            string spn,
            KrbEncryptionKey tgtSessionKey,
            KrbKdcRep kdcRep,
            KdcOptions options,
            KrbTicket user2UserTicket = null
            )
        {
            var tgtApReq = CreateApReq(kdcRep, tgtSessionKey);

            var pacOptions = new KrbPaPacOptions
            {
                Flags = PacOptions.ResourceBasedConstrainedDelegation | PacOptions.Claims | PacOptions.BranchAware
            }.Encode();

            var paData = new List <KrbPaData>()
            {
                new KrbPaData {
                    Type  = PaDataType.PA_TGS_REQ,
                    Value = tgtApReq.EncodeApplication()
                },
                new KrbPaData {
                    Type  = PaDataType.PA_PAC_OPTIONS,
                    Value = pacOptions.AsMemory()
                }
            };

            var tgt = kdcRep.Ticket;

            var sname = spn.Split('/', '@');

            var tgs = new KrbTgsReq
            {
                PaData = paData.ToArray(),
                Body   = new KrbKdcReqBody
                {
                    EType      = KerberosConstants.ETypes.ToArray(),
                    KdcOptions = options,
                    Nonce      = KerberosConstants.GetNonce(),
                    Realm      = tgt.Realm,
                    SName      = new KrbPrincipalName()
                    {
                        Type = PrincipalNameType.NT_SRV_HST,
                        Name = sname
                    },
                    Till = KerberosConstants.EndOfTime
                },
            };

            if (options.HasFlag(KdcOptions.EncTktInSkey) && user2UserTicket != null)
            {
                tgs.Body.AdditionalTickets = new[] {
                    user2UserTicket
                };
            }

            return(tgs);
        }
Exemplo n.º 4
0
        public static KrbCred WrapTicket(KrbTicket ticket, KrbEncTicketPart encTicketPart)
        {
            if (ticket is null)
            {
                throw new ArgumentNullException(nameof(ticket));
            }

            if (encTicketPart is null)
            {
                throw new ArgumentNullException(nameof(encTicketPart));
            }

            KerberosConstants.Now(out DateTimeOffset timestamp, out int usec);

            var encPart = new KrbEncKrbCredPart
            {
                Timestamp  = timestamp,
                USec       = usec,
                TicketInfo = new[]
                {
                    new KrbCredInfo
                    {
                        Key       = encTicketPart.Key,
                        AuthTime  = encTicketPart.AuthTime,
                        EndTime   = encTicketPart.EndTime,
                        Flags     = encTicketPart.Flags,
                        PName     = encTicketPart.CName,
                        Realm     = encTicketPart.CRealm,
                        RenewTill = encTicketPart.RenewTill,
                        SName     = ticket.SName,
                        SRealm    = ticket.Realm,
                        StartTime = encTicketPart.StartTime,
                    }
                }
            };

            var cred = new KrbCred
            {
                EncryptedPart = new KrbEncryptedData {
                    Cipher = encPart.EncodeApplication()
                },
                Tickets = new[] { ticket },
            };

            return(cred);
        }
Exemplo n.º 5
0
 public static KrbCred WrapTicket(KrbTicket ticket, KrbEncTicketPart encTicketPart)
 {
     return(WrapTicket(
                ticket,
                new KrbCredInfo
     {
         Key = encTicketPart.Key,
         AuthTime = encTicketPart.AuthTime,
         EndTime = encTicketPart.EndTime,
         Flags = encTicketPart.Flags,
         PName = encTicketPart.CName,
         Realm = encTicketPart.CRealm,
         RenewTill = encTicketPart.RenewTill,
         SName = ticket.SName,
         SRealm = ticket.Realm,
         StartTime = encTicketPart.StartTime,
     }
                ));
 }
Exemplo n.º 6
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);
        }
Exemplo n.º 7
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();
        }
Exemplo n.º 8
0
        internal static void Decode <T>(AsnReader reader, Asn1Tag expectedTag, out T decoded)
            where T : KrbCred, 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 tmpProtocolVersionNumber))
            {
                explicitReader.ThrowIfNotEmpty();
            }

            decoded.ProtocolVersionNumber = tmpProtocolVersionNumber;

            explicitReader.ThrowIfNotEmpty();

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

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

            decoded.MessageType = tmpMessageType;

            explicitReader.ThrowIfNotEmpty();

            explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
            // Decode SEQUENCE OF for Tickets
            {
                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.Tickets = tmpList.ToArray();
            }

            explicitReader.ThrowIfNotEmpty();

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

            explicitReader.ThrowIfNotEmpty();

            sequenceReader.ThrowIfNotEmpty();
        }
Exemplo n.º 9
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);
        }
Exemplo n.º 10
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);
        }
Exemplo n.º 11
0
        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();
        }
Exemplo n.º 12
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);
        }