private void UpdateContext(KerberosTgsResponse response) { if (response.Response != null) { if (response.Response.padata != null && response.Response.padata.Elements != null) { foreach (PA_DATA paData in response.Response.padata.Elements) { var parsedPaData = PaDataParser.ParseRepPaData(paData); if (parsedPaData is PaFxFastRep) { var armoredRep = ((PaFxFastRep)parsedPaData).GetArmoredRep(); var kerbRep = ((PaFxFastRep)parsedPaData).GetKerberosFastRep(Context.FastArmorkey); var strKey = kerbRep.FastResponse.strengthen_key; Context.ReplyKey = KerberosUtility.KrbFxCf2(strKey, Context.ReplyKey, "strengthenkey", "replykey"); } } } KeyUsageNumber usage = Context.Subkey == null ? KeyUsageNumber.TGS_REP_encrypted_part : KeyUsageNumber.TGS_REP_encrypted_part_subkey; response.DecryptTgsResponse(Context.ReplyKey.keyvalue.ByteArrayValue, usage); Context.SessionKey = response.EncPart.key; //Fix me: when hide-client-names is set to true, response.Response.cname is not the real CName. Context.Ticket = new KerberosTicket(response.Response.ticket, response.Response.cname, response.EncPart.key); Context.SelectedEType = (EncryptionType)Context.Ticket.Ticket.enc_part.etype.Value; } }
/// <summary> /// Updated context based on Kerberos pdu /// </summary> /// <param name="pdu">Kerberos pdu</param> public override void UpdateContext(KerberosPdu pdu) { if (pdu is KerberosAsRequest) { KerberosAsRequest request = (KerberosAsRequest)pdu; UpdateContext(request); } if (pdu is KerberosKrbError) { KerberosKrbError error = (KerberosKrbError)pdu; UpdateContext(error); } if (pdu is KerberosAsResponse) { KerberosAsResponse response = (KerberosAsResponse)pdu; UpdateContext(response); } if (pdu is KerberosTgsRequest) { KerberosTgsRequest request = pdu as KerberosTgsRequest; UpdateContext(request); } if (pdu is KerberosTgsResponse) { KerberosTgsResponse response = pdu as KerberosTgsResponse; UpdateContext(response); } this.expectedPduType = null; }
private KerberosTgsResponse ExpectTgsResponse(KeyUsageNumber usage = KeyUsageNumber.TGS_REP_encrypted_part) { var response = this.client.ExpectPdu(KerberosConstValue.TIMEOUT_DEFAULT, typeof(KerberosTgsResponse)); if (response == null || !(response is KerberosTgsResponse)) { throw new Exception("Expected KerberosAsResponse data is null"); } KerberosTgsResponse tgsResponse = response as KerberosTgsResponse; if (this.Context.ReplyKey == null) { throw new Exception("Reply key is null"); } tgsResponse.DecryptTgsResponse(this.Context.ReplyKey.keyvalue.ByteArrayValue, usage); return(tgsResponse); }
/// <summary> /// Kerberos Client Initialize without server token /// </summary> private void ClientInitialize() { this.ApRequestAuthenticator = null; // Create and send AS request for pre-authentication KdcOptions options = KdcOptions.FORWARDABLE | KdcOptions.CANONICALIZE | KdcOptions.RENEWABLE; KerberosTicket ticket = this.GetTGTCachedToken(this.credential, this.serverName); if (ticket == null) { this.SendAsRequest(options, null); // Expect recieve preauthentication required error METHOD_DATA methodData; this.ExpectPreauthRequiredError(out methodData); // Create sequence of PA data string timeStamp = KerberosUtility.CurrentKerberosTime.Value; PaEncTimeStamp paEncTimeStamp = new PaEncTimeStamp(timeStamp, 0, this.Context.SelectedEType, this.Context.CName.Password, this.Context.CName.Salt); PaPacRequest paPacRequest = new PaPacRequest(true); PaPacOptions paPacOptions = new PaPacOptions(PacOptions.Claims | PacOptions.ForwardToFullDc); Asn1SequenceOf <PA_DATA> seqOfPaData_AS = new Asn1SequenceOf <PA_DATA>(new PA_DATA[] { paEncTimeStamp.Data, paPacRequest.Data, paPacOptions.Data }); // Create and send AS request for TGT KerberosAsRequest asRequest = this.SendAsRequest(options, seqOfPaData_AS); // Expect TGT(AS) Response from KDC KerberosAsResponse asResponse = this.ExpectAsResponse(); // Create and send TGS request Asn1SequenceOf <PA_DATA> seqOfPaData_TGS = new Asn1SequenceOf <PA_DATA>(new PA_DATA[] { paPacRequest.Data, paPacOptions.Data }); this.SendTgsRequest(this.serverName, options, seqOfPaData_TGS); // Expect TGS Response from KDC KerberosTgsResponse tgsResponse = this.ExpectTgsResponse(); this.UpdateTGTCachedToken(this.Context.Ticket); } else { // Restore SessionKey and Ticket from cache this.Context.SessionKey = ticket.SessionKey; this.Context.ApSessionKey = ticket.SessionKey; this.Context.Ticket = ticket; this.Context.SelectedEType = (EncryptionType)Context.Ticket.Ticket.enc_part.etype.Value; } // cache this.Context.Ticket; ApOptions apOption; GetFlagsByContextAttribute(out apOption); AuthorizationData data = null; EncryptionKey subkey = KerberosUtility.GenerateKey(this.client.Context.ContextKey); this.token = this.CreateGssApiToken(apOption, data, subkey, this.Context.ChecksumFlag, KerberosConstValue.GSSToken.GSSAPI); bool isMutualAuth = (contextAttribute & ClientSecurityContextAttribute.MutualAuth) == ClientSecurityContextAttribute.MutualAuth; bool isDceStyle = (contextAttribute & ClientSecurityContextAttribute.DceStyle) == ClientSecurityContextAttribute.DceStyle; if (isMutualAuth || isDceStyle) { this.needContinueProcessing = true; } else { this.needContinueProcessing = false; } }
//Get the expected Kerberos PDU from byte array private KerberosPdu getExpectedPduFromBytes( byte[] receivedBytes, out int consumedLength, out int expectedLength) { // initialize lengths consumedLength = 0; expectedLength = 0; if (null == receivedBytes || 0 == receivedBytes.Length) { return(null); } // TCP has a 4 bytes length header, while UDP has not byte[] pduBytes = receivedBytes; if ((this.Context.TransportType == TransportType.TCP)) { // insufficient data, needs to receive more if (receivedBytes.Length < sizeof(int)) { return(null); } // get pdu data length byte[] lengthBytes = ArrayUtility.SubArray(receivedBytes, 0, sizeof(int)); Array.Reverse(lengthBytes); int pduLength = BitConverter.ToInt32(lengthBytes, 0); // insufficient data, needs to receive more expectedLength = sizeof(int) + pduLength; if (receivedBytes.Length < expectedLength) { return(null); } // remove length header from pdu bytes pduBytes = ArrayUtility.SubArray <byte>(receivedBytes, sizeof(int), pduLength); } else { // UDP has no length header expectedLength = pduBytes.Length; } // decode according to message type consumedLength = expectedLength; // get message type // (the lower 5 bits indicates its kile message type) MsgType kileMessageType = (MsgType)(pduBytes[0] & 0x1f); KerberosPdu pdu = null; switch (kileMessageType) { case MsgType.KRB_AS_REQ: pdu = new KerberosAsRequest(); break; case MsgType.KRB_AS_RESP: pdu = new KerberosAsResponse(); break; case MsgType.KRB_TGS_REQ: pdu = new KerberosTgsRequest(); break; case MsgType.KRB_TGS_RESP: pdu = new KerberosTgsResponse(); break; case MsgType.KRB_ERROR: pdu = new KerberosKrbError(); break; default: throw new FormatException( "Unsupported Message Type: " + kileMessageType.ToString()); } pdu.FromBytes(pduBytes); // update context if (this.expectedPduType == null || this.expectedPduType == pdu.GetType()) { this.UpdateContext(pdu); } return(pdu); }
private void UpdateContext(KerberosTgsResponse response) { if (response.Response != null) { if (response.Response.padata != null && response.Response.padata.Elements != null) { foreach (PA_DATA paData in response.Response.padata.Elements) { var parsedPaData = PaDataParser.ParseRepPaData(paData); if (parsedPaData is PaFxFastRep) { var armoredRep = ((PaFxFastRep)parsedPaData).GetArmoredRep(); var kerbRep = ((PaFxFastRep)parsedPaData).GetKerberosFastRep(Context.FastArmorkey); var strKey = kerbRep.FastResponse.strengthen_key; Context.ReplyKey = KerberosUtility.KrbFxCf2(strKey, Context.ReplyKey, "strengthenkey", "replykey"); } } } KeyUsageNumber usage = Context.Subkey == null ? KeyUsageNumber.TGS_REP_encrypted_part : KeyUsageNumber.TGS_REP_encrypted_part_subkey; response.DecryptTgsResponse(Context.ReplyKey.keyvalue.ByteArrayValue, usage); Context.SessionKey = response.EncPart.key; //Fix me: when hide-client-names is set to true, response.Response.cname is not the real CName. Context.Ticket = new KerberosTicket(response.Response.ticket, response.Response.cname, response.EncPart.key); Context.SelectedEType = (EncryptionType)Context.Ticket.Ticket.enc_part.etype.Value; } }
//Get the expected Kerberos PDU from byte array private KerberosPdu getExpectedPduFromBytes( byte[] receivedBytes, out int consumedLength, out int expectedLength) { // initialize lengths consumedLength = 0; expectedLength = 0; if (null == receivedBytes || 0 == receivedBytes.Length) { return null; } // TCP has a 4 bytes length header, while UDP has not byte[] pduBytes = receivedBytes; if ((this.Context.TransportType == TransportType.TCP)) { // insufficient data, needs to receive more if (receivedBytes.Length < sizeof(int)) { return null; } // get pdu data length byte[] lengthBytes = ArrayUtility.SubArray(receivedBytes, 0, sizeof(int)); Array.Reverse(lengthBytes); int pduLength = BitConverter.ToInt32(lengthBytes, 0); // insufficient data, needs to receive more expectedLength = sizeof(int) + pduLength; if (receivedBytes.Length < expectedLength) { return null; } // remove length header from pdu bytes pduBytes = ArrayUtility.SubArray<byte>(receivedBytes, sizeof(int), pduLength); } else { // UDP has no length header expectedLength = pduBytes.Length; } // decode according to message type consumedLength = expectedLength; // get message type // (the lower 5 bits indicates its kile message type) MsgType kileMessageType = (MsgType)(pduBytes[0] & 0x1f); KerberosPdu pdu = null; switch (kileMessageType) { case MsgType.KRB_AS_REQ: pdu = new KerberosAsRequest(); break; case MsgType.KRB_AS_RESP: pdu = new KerberosAsResponse(); break; case MsgType.KRB_TGS_REQ: pdu = new KerberosTgsRequest(); break; case MsgType.KRB_TGS_RESP: pdu = new KerberosTgsResponse(); break; case MsgType.KRB_ERROR: pdu = new KerberosKrbError(); break; default: throw new FormatException( "Unsupported Message Type: " + kileMessageType.ToString()); } pdu.FromBytes(pduBytes); // update context if (this.expectedPduType == null || this.expectedPduType == pdu.GetType()) this.UpdateContext(pdu); return pdu; }