private static KrbHostAddress[] IncludeAddresses(Krb5Config config) { if (config.Defaults.NoAddresses) { return(null); } var addresses = new List <KrbHostAddress> { KrbHostAddress.ParseAddress(Environment.MachineName.PadRight(16, ' ')) }; if (config.Defaults?.ExtraAddresses?.Any() ?? false) { addresses.AddRange(config.Defaults.ExtraAddresses.Select(a => KrbHostAddress.ParseAddress(a))); } return(addresses.ToArray()); }
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 : KrbEncKrbCredPart, 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)); // Decode SEQUENCE OF for TicketInfo { collectionReader = explicitReader.ReadSequence(); var tmpList = new List <KrbCredInfo>(); KrbCredInfo tmpItem; while (collectionReader.HasData) { KrbCredInfo.Decode <KrbCredInfo>(collectionReader, out KrbCredInfo tmp); tmpItem = tmp; tmpList.Add(tmpItem); } decoded.TicketInfo = tmpList.ToArray(); } explicitReader.ThrowIfNotEmpty(); if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1))) { explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1)); if (explicitReader.TryReadInt32(out int tmpNonce)) { decoded.Nonce = tmpNonce; } else { explicitReader.ThrowIfNotEmpty(); } explicitReader.ThrowIfNotEmpty(); } if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 2))) { explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 2)); decoded.Timestamp = 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 tmpUSec)) { decoded.USec = tmpUSec; } else { explicitReader.ThrowIfNotEmpty(); } explicitReader.ThrowIfNotEmpty(); } if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 4))) { explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 4)); KrbHostAddress.Decode <KrbHostAddress>(explicitReader, out KrbHostAddress tmpSAddress); decoded.SAddress = tmpSAddress; explicitReader.ThrowIfNotEmpty(); } if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 5))) { explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 5)); KrbHostAddress.Decode <KrbHostAddress>(explicitReader, out KrbHostAddress tmpRAddress); decoded.RAddress = tmpRAddress; explicitReader.ThrowIfNotEmpty(); } sequenceReader.ThrowIfNotEmpty(); }
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); }
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(); }
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); }