private static KrbApReq CreateApReq(KrbKdcRep kdcRep, KrbEncryptionKey tgtSessionKey, KrbChecksum checksum, out KrbEncryptionKey sessionKey) { var tgt = kdcRep.Ticket; var authenticator = new KrbAuthenticator { CName = kdcRep.CName, Realm = kdcRep.CRealm, SequenceNumber = KerberosConstants.GetNonce(), Checksum = checksum }; sessionKey = KrbEncryptionKey.Generate(tgtSessionKey.EType); sessionKey.Usage = KeyUsage.EncTgsRepPartSubSessionKey; authenticator.Subkey = sessionKey; KerberosConstants.Now(out authenticator.CTime, out authenticator.CuSec); var encryptedAuthenticator = KrbEncryptedData.Encrypt( authenticator.EncodeApplication(), tgtSessionKey.AsKey(), KeyUsage.PaTgsReqAuthenticator ); var apReq = new KrbApReq { Ticket = tgt, Authenticator = encryptedAuthenticator }; return(apReq); }
private static KrbApReq CreateApReq(KrbKdcRep kdcRep, KrbEncryptionKey tgtSessionKey) { var tgt = kdcRep.Ticket; KerberosConstants.Now(out DateTimeOffset time, out int usec); var authenticator = new KrbAuthenticator { CName = kdcRep.CName, CTime = time, Cusec = usec, Realm = tgt.Realm, SequenceNumber = KerberosConstants.GetNonce(), Subkey = tgtSessionKey, AuthenticatorVersionNumber = 5 }; var encryptedAuthenticator = KrbEncryptedData.Encrypt( authenticator.EncodeApplication(), tgtSessionKey.AsKey(), KeyUsage.PaTgsReqAuthenticator ); var apReq = new KrbApReq { Ticket = tgt, Authenticator = encryptedAuthenticator }; return(apReq); }
public static KrbApReq CreateApReq( KrbKdcRep tgsRep, KerberosKey authenticatorKey, ApOptions options, out KrbAuthenticator authenticator ) { var ticket = tgsRep.Ticket; authenticator = new KrbAuthenticator { CName = tgsRep.CName, Realm = ticket.Realm, SequenceNumber = KerberosConstants.GetNonce(), Subkey = KrbEncryptionKey.Generate(authenticatorKey.EncryptionType), Checksum = KrbChecksum.EncodeDelegationChecksum(new DelegationInfo()) }; KerberosConstants.Now(out authenticator.CTime, out authenticator.CuSec); var apReq = new KrbApReq { Ticket = ticket, ApOptions = options, Authenticator = KrbEncryptedData.Encrypt( authenticator.EncodeApplication(), authenticatorKey, KeyUsage.ApReqAuthenticator ) }; return(apReq); }
internal static void Decode <T>(AsnReader reader, Asn1Tag expectedTag, out T decoded) where T : KrbEncApRepPart, new() { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } decoded = new T(); AsnReader sequenceReader = reader.ReadSequence(expectedTag); AsnReader explicitReader; explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0)); decoded.CTime = explicitReader.ReadGeneralizedTime(); explicitReader.ThrowIfNotEmpty(); explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1)); if (!explicitReader.TryReadInt32(out decoded.CuSec)) { explicitReader.ThrowIfNotEmpty(); } explicitReader.ThrowIfNotEmpty(); if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 2))) { explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 2)); KrbEncryptionKey tmpSubSessionKey; KrbEncryptionKey.Decode <KrbEncryptionKey>(explicitReader, out tmpSubSessionKey); decoded.SubSessionKey = tmpSubSessionKey; 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 tmpSequenceNumber)) { decoded.SequenceNumber = tmpSequenceNumber; } else { explicitReader.ThrowIfNotEmpty(); } explicitReader.ThrowIfNotEmpty(); } sequenceReader.ThrowIfNotEmpty(); }
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); }
public static KrbApReq CreateApReq( KrbKdcRep tgsRep, KerberosKey authenticatorKey, RequestServiceTicket rst, out KrbAuthenticator authenticator ) { if (tgsRep == null) { throw new ArgumentNullException(nameof(tgsRep)); } if (authenticatorKey == null) { throw new ArgumentNullException(nameof(authenticatorKey)); } var ticket = tgsRep.Ticket; authenticator = new KrbAuthenticator { CName = tgsRep.CName, Realm = ticket.Realm, SequenceNumber = KerberosConstants.GetNonce(), Subkey = KrbEncryptionKey.Generate(authenticatorKey.EncryptionType), Checksum = KrbChecksum.EncodeDelegationChecksum(new DelegationInfo(rst)) }; KerberosConstants.Now(out DateTimeOffset ctime, out int usec); authenticator.CTime = ctime; authenticator.CuSec = usec; var apReq = new KrbApReq { Ticket = ticket, ApOptions = rst.ApOptions, Authenticator = KrbEncryptedData.Encrypt( authenticator.EncodeApplication(), authenticatorKey, KeyUsage.ApReqAuthenticator ) }; return(apReq); }
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); }
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); }
public static KrbTgsReq CreateTgsReq( RequestServiceTicket rst, KrbEncryptionKey tgtSessionKey, KrbKdcRep kdcRep, out KrbEncryptionKey sessionKey ) { var sname = rst.ServicePrincipalName.Split('/', '@'); var tgt = kdcRep.Ticket; var additionalTickets = new List <KrbTicket>(); if (rst.KdcOptions.HasFlag(KdcOptions.EncTktInSkey) && rst.UserToUserTicket != null) { additionalTickets.Add(rst.UserToUserTicket); } if (!string.IsNullOrWhiteSpace(rst.S4uTarget)) { rst.KdcOptions |= KdcOptions.Forwardable; } if (rst.S4uTicket != null) { rst.KdcOptions |= KdcOptions.ConstrainedDelegation; additionalTickets.Add(rst.S4uTicket); } var body = new KrbKdcReqBody { EType = KerberosConstants.ETypes.ToArray(), KdcOptions = rst.KdcOptions, Nonce = KerberosConstants.GetNonce(), Realm = rst.Realm, SName = new KrbPrincipalName() { Type = PrincipalNameType.NT_SRV_INST, Name = sname }, Till = KerberosConstants.EndOfTime, CName = rst.CNameHint }; if (additionalTickets.Count > 0) { body.AdditionalTickets = additionalTickets.ToArray(); } var bodyChecksum = KrbChecksum.Create( body.Encode(), tgtSessionKey.AsKey(), KeyUsage.PaTgsReqChecksum ); var tgtApReq = CreateApReq(kdcRep, tgtSessionKey, bodyChecksum, out sessionKey); 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 } }; if (!string.IsNullOrWhiteSpace(rst.S4uTarget)) { paData.Add(new KrbPaData { Type = PaDataType.PA_FOR_USER, Value = EncodeS4URequest(rst.S4uTarget, tgt.Realm, tgtSessionKey) }); } var tgs = new KrbTgsReq { PaData = paData.ToArray(), Body = body }; return(tgs); }
private static ReadOnlyMemory <byte> EncodeS4URequest(string s4u, X509Certificate2 certificate, int nonce, string realm, KrbEncryptionKey sessionKey) { var userId = new KrbS4uUserId() { CName = new KrbPrincipalName { Type = PrincipalNameType.NT_ENTERPRISE, Name = new[] { s4u } }, Nonce = nonce, Realm = realm }; if (certificate != null) { userId.SubjectCertificate = certificate.RawData; } var paX509 = new KrbPaS4uX509User { UserId = userId, Checksum = KrbChecksum.Create(userId.Encode(), sessionKey.AsKey(), (KeyUsage)26) }; return(paX509.Encode()); }
private static ReadOnlyMemory <byte> EncodeS4URequest(string s4u, string realm, KrbEncryptionKey sessionKey) { var paS4u = new KrbPaForUser { AuthPackage = "Kerberos", UserName = new KrbPrincipalName { Type = PrincipalNameType.NT_ENTERPRISE, Name = new[] { s4u } }, UserRealm = realm }; paS4u.GenerateChecksum(sessionKey.AsKey()); return(paS4u.Encode()); }
public static KrbTgsReq CreateTgsReq( RequestServiceTicket rst, KrbEncryptionKey tgtSessionKey, KrbKdcRep kdcRep, out KrbEncryptionKey sessionKey ) { if (kdcRep == null) { throw new ArgumentNullException(nameof(kdcRep)); } if (tgtSessionKey == null) { throw new ArgumentNullException(nameof(tgtSessionKey)); } if (string.IsNullOrWhiteSpace(rst.ServicePrincipalName)) { throw new ArgumentNullException(nameof(rst.ServicePrincipalName)); } var sname = rst.ServicePrincipalName.Split('/', '@'); var tgt = kdcRep.Ticket; var additionalTickets = new List <KrbTicket>(); if (rst.KdcOptions.HasFlag(KdcOptions.EncTktInSkey) && rst.UserToUserTicket != null) { additionalTickets.Add(rst.UserToUserTicket); } if (!string.IsNullOrWhiteSpace(rst.S4uTarget) && rst.S4uTicket != null) { throw new InvalidOperationException(SR.Resource("S4uTargetTicketBothPresent")); } if (!string.IsNullOrWhiteSpace(rst.S4uTarget)) { rst.KdcOptions |= KdcOptions.Forwardable; } if (rst.S4uTicket != null) { rst.KdcOptions |= KdcOptions.ConstrainedDelegation; additionalTickets.Add(rst.S4uTicket); } var config = rst.Configuration ?? Krb5Config.Default(); var body = new KrbKdcReqBody { EType = GetPreferredETypes(config.Defaults.DefaultTgsEncTypes, config.Defaults.AllowWeakCrypto).ToArray(), KdcOptions = rst.KdcOptions, Nonce = GetNonce(), Realm = rst.Realm, SName = new KrbPrincipalName() { Type = PrincipalNameType.NT_SRV_INST, Name = sname }, Till = EndOfTime, CName = rst.CNameHint }; if (additionalTickets.Count > 0) { body.AdditionalTickets = additionalTickets.ToArray(); } var bodyChecksum = KrbChecksum.Create( body.Encode(), tgtSessionKey.AsKey(), KeyUsage.PaTgsReqChecksum ); var tgtApReq = CreateApReq(kdcRep, tgtSessionKey, bodyChecksum, out sessionKey); 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 } }; if (!string.IsNullOrWhiteSpace(rst.S4uTarget)) { if (tgtSessionKey.EType == EncryptionType.RC4_HMAC_NT) { paData.Add(new KrbPaData { Type = PaDataType.PA_FOR_USER, Value = EncodeS4ULegacyRequest(rst.S4uTarget, tgt.Realm, tgtSessionKey) }); } else { paData.Add(new KrbPaData { Type = PaDataType.PA_FOR_X509_USER, Value = EncodeS4URequest(rst.S4uTarget, rst.S4uTargetCertificate, body.Nonce, tgt.Realm, sessionKey) }); } } var tgs = new KrbTgsReq { PaData = paData.ToArray(), Body = body }; return(tgs); }
internal static void Decode <T>(AsnReader reader, Asn1Tag expectedTag, out T decoded) where T : KrbAuthenticator, new() { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } decoded = new T(); AsnReader sequenceReader = reader.ReadSequence(expectedTag); AsnReader explicitReader; AsnReader collectionReader; explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0)); if (!explicitReader.TryReadInt32(out int tmpAuthenticatorVersionNumber)) { explicitReader.ThrowIfNotEmpty(); } decoded.AuthenticatorVersionNumber = tmpAuthenticatorVersionNumber; explicitReader.ThrowIfNotEmpty(); explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1)); decoded.Realm = explicitReader.ReadCharacterString(UniversalTagNumber.GeneralString); explicitReader.ThrowIfNotEmpty(); explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 2)); KrbPrincipalName.Decode <KrbPrincipalName>(explicitReader, out KrbPrincipalName tmpCName); decoded.CName = tmpCName; explicitReader.ThrowIfNotEmpty(); if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 3))) { explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 3)); KrbChecksum.Decode <KrbChecksum>(explicitReader, out KrbChecksum tmpChecksum); decoded.Checksum = tmpChecksum; explicitReader.ThrowIfNotEmpty(); } explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 4)); if (!explicitReader.TryReadInt32(out int tmpCuSec)) { explicitReader.ThrowIfNotEmpty(); } decoded.CuSec = tmpCuSec; explicitReader.ThrowIfNotEmpty(); explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 5)); decoded.CTime = explicitReader.ReadGeneralizedTime(); explicitReader.ThrowIfNotEmpty(); if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 6))) { explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 6)); KrbEncryptionKey.Decode <KrbEncryptionKey>(explicitReader, out KrbEncryptionKey tmpSubkey); decoded.Subkey = tmpSubkey; explicitReader.ThrowIfNotEmpty(); } if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 7))) { explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 7)); if (explicitReader.TryReadInt32(out int tmpSequenceNumber)) { decoded.SequenceNumber = tmpSequenceNumber; } else { explicitReader.ThrowIfNotEmpty(); } explicitReader.ThrowIfNotEmpty(); } if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 8))) { explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 8)); // Decode SEQUENCE OF for AuthorizationData { collectionReader = explicitReader.ReadSequence(); var tmpList = new List <KrbAuthorizationData>(); KrbAuthorizationData tmpItem; while (collectionReader.HasData) { KrbAuthorizationData.Decode <KrbAuthorizationData>(collectionReader, out KrbAuthorizationData tmp); tmpItem = tmp; tmpList.Add(tmpItem); } decoded.AuthorizationData = tmpList.ToArray(); } explicitReader.ThrowIfNotEmpty(); } sequenceReader.ThrowIfNotEmpty(); }
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); }
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); }
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); }
public static KrbApReq CreateApReq( KrbKdcRep tgsRep, KerberosKey authenticatorKey, RequestServiceTicket rst, out KrbAuthenticator authenticator ) { if (tgsRep == null) { throw new ArgumentNullException(nameof(tgsRep)); } if (authenticatorKey == null) { throw new ArgumentNullException(nameof(authenticatorKey)); } authenticator = new KrbAuthenticator { CName = tgsRep.CName, Realm = tgsRep.CRealm }; if (rst.AuthenticatorChecksum != null) { authenticator.Checksum = rst.AuthenticatorChecksum; } else if (!rst.AuthenticatorChecksumSource.IsEmpty) { authenticator.Checksum = KrbChecksum.Create( rst.AuthenticatorChecksumSource, authenticatorKey, KeyUsage.AuthenticatorChecksum ); } else if (rst.GssContextFlags != GssContextEstablishmentFlag.GSS_C_NONE) { authenticator.Checksum = KrbChecksum.EncodeDelegationChecksum(new DelegationInfo(rst)); } if (rst.IncludeSequenceNumber ?? true) { authenticator.SequenceNumber = GetNonce(); } if (rst.ApOptions.HasFlag(ApOptions.MutualRequired)) { authenticator.Subkey = KrbEncryptionKey.Generate(authenticatorKey.EncryptionType); } Now(out DateTimeOffset ctime, out int usec); authenticator.CTime = ctime; authenticator.CuSec = usec; var apReq = new KrbApReq { Ticket = tgsRep.Ticket, ApOptions = rst.ApOptions, Authenticator = KrbEncryptedData.Encrypt( authenticator.EncodeApplication(), authenticatorKey, KeyUsage.ApReqAuthenticator ) }; return(apReq); }
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 : KrbFastResponse, 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 PaData { collectionReader = explicitReader.ReadSequence(); var tmpList = new List <KrbPaData>(); KrbPaData tmpItem; while (collectionReader.HasData) { KrbPaData.Decode <KrbPaData>(collectionReader, out KrbPaData tmp); tmpItem = tmp; tmpList.Add(tmpItem); } decoded.PaData = tmpList.ToArray(); } explicitReader.ThrowIfNotEmpty(); if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1))) { explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1)); KrbEncryptionKey.Decode <KrbEncryptionKey>(explicitReader, out KrbEncryptionKey tmpStrengthenKey); decoded.StrengthenKey = tmpStrengthenKey; explicitReader.ThrowIfNotEmpty(); } if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 2))) { explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 2)); KrbFastFinished.Decode <KrbFastFinished>(explicitReader, out KrbFastFinished tmpFinished); decoded.Finished = tmpFinished; explicitReader.ThrowIfNotEmpty(); } explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 3)); if (!explicitReader.TryReadInt32(out int tmpNonce)) { explicitReader.ThrowIfNotEmpty(); } decoded.Nonce = tmpNonce; explicitReader.ThrowIfNotEmpty(); sequenceReader.ThrowIfNotEmpty(); }