/// <summary> /// Encode a PDU to a binary stream. Then send the stream. /// </summary> /// <param name="pdu">A specified type of a PDU. This argument cannot be null. /// If it is null, ArgumentNullException will be thrown.</param> /// <exception cref="System.ArgumentNullException">Thrown when the input parameter is null.</exception> public void SendPdu(KerberosPdu pdu) { if (pdu == null) { throw new ArgumentNullException("pdu"); } if (UseProxy) { Debug.Assert(ProxyClient != null, "Proxy Client should be set when using proxy."); //temporarily change the tranpsort type to TCP, since all proxy messages are TCP format. var oriTransportType = Context.TransportType; Context.TransportType = TransportType.TCP; KDCProxyMessage message = ProxyClient.MakeProxyMessage(pdu); //send proxy message ProxyClient.SendProxyRequest(message); //restore the original transport type Context.TransportType = oriTransportType; } else { this.Connect(); kdcTransport.SendPacket(pdu); } }
/// <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; }
/// <summary> /// Create a Gss_Wrap token. Then use KilePdu.ToBytes() to get the byte array. /// </summary> /// <param name="isEncrypted">If encrypt the message.</param> /// <param name="signAlgorithm">Specify the checksum type. /// This is only used for encryption types DES and RC4.</param> /// <param name="message">The message to be wrapped. This argument can be null.</param> /// <returns>The created Gss_Wrap token.</returns> /// <exception cref="System.NotSupportedException">Thrown when the encryption type is not supported.</exception> public KerberosPdu GssWrap(bool isEncrypted, SGN_ALG signAlgorithm, byte[] message) { KerberosPdu pdu = null; EncryptionKey key = Context.ContextKey; switch ((EncryptionType)key.keytype.Value) { case EncryptionType.AES128_CTS_HMAC_SHA1_96: case EncryptionType.AES256_CTS_HMAC_SHA1_96: pdu = GssWrap4121(isEncrypted, message, Context.IsInitiator); break; case EncryptionType.DES_CBC_CRC: case EncryptionType.DES_CBC_MD5: pdu = GssWrap1964(isEncrypted, signAlgorithm, message); break; case EncryptionType.RC4_HMAC: case EncryptionType.RC4_HMAC_EXP: pdu = GssWrap4757(isEncrypted, signAlgorithm, message); break; default: throw new NotSupportedException("The Encryption Type can only be AES128_CTS_HMAC_SHA1_96, " + "AES256_CTS_HMAC_SHA1_96, DES_CBC_CRC, DES_CBC_MD5, RC4_HMAC or RC4_HMAC_EXP."); } return(pdu); }
/// <summary> /// Decode a Gss_Wrap token from security buffers /// </summary> /// <param name="context">The context of decoding</param> /// <param name="securityBuffers">Security buffers</param> /// <returns>The decoded Gss_Wrap token.</returns> internal static KerberosPdu GssUnWrapEx(KerberosContext context, SecurityBuffer[] securityBuffers) { KerberosPdu pdu = null; EncryptionKey key = context.ContextKey; switch ((EncryptionType)key.keytype.Value) { case EncryptionType.AES128_CTS_HMAC_SHA1_96: case EncryptionType.AES256_CTS_HMAC_SHA1_96: var token4121Pdu = new Token4121(context); token4121Pdu.FromSecurityBuffers(securityBuffers); pdu = token4121Pdu; break; case EncryptionType.DES_CBC_CRC: case EncryptionType.DES_CBC_MD5: case EncryptionType.RC4_HMAC: case EncryptionType.RC4_HMAC_EXP: var token1964or4757Pdu = new Token1964_4757(context); token1964or4757Pdu.FromSecurityBuffers(securityBuffers); pdu = token1964or4757Pdu; break; default: throw new NotSupportedException("The Encryption Type can only be AES128_CTS_HMAC_SHA1_96, " + "AES256_CTS_HMAC_SHA1_96, DES_CBC_CRC, DES_CBC_MD5, RC4_HMAC or RC4_HMAC_EXP."); } return(pdu); }
/// <summary> /// Expect to receive a PDU of any type from the remote host. /// </summary> /// <param name="timeout">Timeout of receiving PDU.</param> /// <returns>The expected PDU.</returns> /// <exception cref="System.TimeoutException">Thrown when the timeout parameter is negative.</exception> public KerberosPdu ExpectPdu(TimeSpan timeout, Type pduType = null) { this.expectedPduType = pduType; KerberosPdu pdu = null; if (UseProxy) { Debug.Assert(ProxyClient != null, "Proxy Client should be set when using proxy."); int consumedLength = 0; int expectedLength = 0; if (ProxyClient.Error == KKDCPError.STATUS_SUCCESS) { KDCProxyMessage message = ProxyClient.GetProxyResponse(); //temporarily change the tranpsort type to TCP, since all proxy messages are TCP format. var oriTransportType = Context.TransportType; Context.TransportType = TransportType.TCP; //get proxy message pdu = getExpectedPduFromBytes(message.Message.kerb_message.ByteArrayValue, out consumedLength, out expectedLength); //restore the original transport type Context.TransportType = oriTransportType; } } else { if (timeout.TotalMilliseconds < 0) { throw new TimeoutException(KerberosConstValue.TIMEOUT_EXCEPTION); } TransportEvent eventPacket = kdcTransport.ExpectTransportEvent(timeout); pdu = (KerberosPdu)eventPacket.EventObject; this.DisConnect(); } return(pdu); }
/// <summary> /// Decode Kpassword PDUs from received message bytes /// </summary> /// <param name="endPoint">An endpoint from which the message bytes are received</param> /// <param name="receivedBytes">The received bytes to be decoded</param> /// <param name="consumedLength">Length of message bytes consumed by decoder</param> /// <param name="expectedLength">Length of message bytes the decoder expects to receive</param> /// <returns>The decoded Kpassword PDUs</returns> /// <exception cref="System.FormatException">thrown when a kpassword message type is unsupported</exception> public override KerberosPdu[] DecodePacketCallback(object endPoint, byte[] receivedBytes, out int consumedLength, out int expectedLength) { KerberosPdu pdu = getExpectedPduFromBytes(receivedBytes, out consumedLength, out expectedLength); // insufficient data, need to receive more if (pdu == null) { return(null); } return(new KerberosPdu[] { pdu }); }
/// <summary> /// Wrap the KerberosPdu provided into proxy message. /// </summary> /// <param name="pdu">the specified KerberosPdu to be wrapped</param> public KDCProxyMessage MakeProxyMessage(KerberosPdu pdu) { //prepare proxy message KDCProxyMessage message = new KDCProxyMessage(pdu); if (!string.IsNullOrEmpty(TargetDomain)) { message.TargetDomain = TargetDomain; } if (DCLocatorHint.HasValue) { message.DCLocatorHint = DCLocatorHint.Value; } return message; }
/// <summary> /// Wrap the KerberosPdu provided into proxy message. /// </summary> /// <param name="pdu">the specified KerberosPdu to be wrapped</param> public KDCProxyMessage MakeProxyMessage(KerberosPdu pdu) { //prepare proxy message KDCProxyMessage message = new KDCProxyMessage(pdu); if (!string.IsNullOrEmpty(TargetDomain)) { message.TargetDomain = TargetDomain; } if (DCLocatorHint.HasValue) { message.DCLocatorHint = DCLocatorHint.Value; } return(message); }
/// <summary> /// Expected a KDC_ERR_PREAUTH_REQUIRED error /// </summary> /// <param name="eData">Error data of this error</param> /// <returns></returns> private KerberosKrbError ExpectPreauthRequiredError(out METHOD_DATA eData) { KerberosPdu responsePdu = this.client.ExpectPdu(KerberosConstValue.TIMEOUT_DEFAULT, typeof(KerberosKrbError)); if ((responsePdu == null) || (!(responsePdu is KerberosKrbError))) { throw new InvalidOperationException("Response type should be KerberosKrbError"); } KerberosKrbError krbError = responsePdu as KerberosKrbError; if (!krbError.ErrorCode.Equals(KRB_ERROR_CODE.KDC_ERR_PREAUTH_REQUIRED)) { throw new InvalidOperationException("The Error code should be KDC_ERR_PREAUTH_REQUIRED"); } eData = new METHOD_DATA(); Asn1DecodingBuffer buffer = new Asn1DecodingBuffer(krbError.KrbError.e_data.ByteArrayValue); eData.BerDecode(buffer); return(krbError); }
private KerberosAsResponse ExpectAsResponse() { KerberosPdu responsePdu = this.client.ExpectPdu(KerberosConstValue.TIMEOUT_DEFAULT, typeof(KerberosAsResponse)); if (responsePdu == null) { throw new Exception("Expected KerberosAsResponse data is null"); } if (responsePdu is KerberosKrbError) { KerberosKrbError errorResponse = responsePdu as KerberosKrbError; throw new Exception($"Expected KerberosAsResponse failed, Error Code:{errorResponse.ErrorCode}"); } else if (!(responsePdu is KerberosAsResponse)) { throw new Exception($"Expected KerberosAsResponse failed, reponse type is not a valid KerberosAsResponse, Response Type:{responsePdu.GetType().ToString()}"); } KerberosAsResponse response = responsePdu as KerberosAsResponse; response.Decrypt(this.Context.ReplyKey.keyvalue.ByteArrayValue); return(response); }
/// <summary> /// Updated context based on Kerberos pdu /// </summary> /// <param name="pdu">Kerberos pdu</param> public virtual void UpdateContext(KerberosPdu pdu) { }
internal static bool GssVerifyMicEx(KerberosContext context, SecurityBuffer[] securityBuffers, out KerberosPdu pdu) { pdu = null; bool isVerified = true; EncryptionKey key = context.ContextKey; switch ((EncryptionType)key.keytype.Value) { case EncryptionType.AES128_CTS_HMAC_SHA1_96: case EncryptionType.AES256_CTS_HMAC_SHA1_96: var micPdu4121 = new Token4121(context); try { micPdu4121.FromSecurityBuffers(securityBuffers); } catch (FormatException) { isVerified = false; } pdu = micPdu4121; break; case EncryptionType.DES_CBC_CRC: case EncryptionType.DES_CBC_MD5: case EncryptionType.RC4_HMAC: case EncryptionType.RC4_HMAC_EXP: var micPdu1964_4757 = new Token1964_4757(context); try { micPdu1964_4757.FromSecurityBuffers(securityBuffers); } catch (FormatException) { isVerified = false; } pdu = micPdu1964_4757; break; default: throw new NotSupportedException("The Encryption Type can only be AES128_CTS_HMAC_SHA1_96, " + "AES256_CTS_HMAC_SHA1_96, DES_CBC_CRC, DES_CBC_MD5, RC4_HMAC or RC4_HMAC_EXP."); } return(isVerified); }
public bool GssVerifyMicEx(SecurityBuffer[] securityBuffers, out KerberosPdu pdu) { return(GssVerifyMicEx(Context, securityBuffers, out pdu)); }
//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; } consumedLength = expectedLength; KerberosPdu pdu = null; //Get AP data in message to judge the kpassword type byte[] apLengthBytes = ArrayUtility.SubArray <byte>(pduBytes, 2 * sizeof(ushort), sizeof(ushort)); Array.Reverse(apLengthBytes); ushort apLength = BitConverter.ToUInt16(apLengthBytes, 0); //If the length is zero, then the last field contains a KRB-ERROR message instead of a KRB-PRIV message. if (apLength == 0) { pdu = new KerberosKrbError(); pdu.FromBytes(ArrayUtility.SubArray <byte>(pduBytes, 3 * sizeof(ushort))); return(pdu); } // get message type // (the lower 5 bits indicates its message type) byte[] apBytes = ArrayUtility.SubArray <byte>(pduBytes, 3 * sizeof(ushort), apLength); MsgType kpassMsgType = (MsgType)(apBytes[0] & 0x1f); if (kpassMsgType == MsgType.KRB_AP_REQ) { pdu = new KpasswordRequest(); } else { pdu = new KpasswordResponse(); pdu.FromBytes(pduBytes); } return(pdu); }
/// <summary> /// Encode a PDU to a binary stream. Then send the stream. /// The pdu could be got by calling method Create***Request or Create***Token. /// </summary> /// <param name="pdu">A specified type of a PDU. This argument cannot be null. /// If it is null, ArgumentNullException will be thrown.</param> /// <exception cref="System.ArgumentNullException">Thrown when the input parameter is null.</exception> public void SendPdu(KerberosPdu pdu) { if (pdu == null) { throw new ArgumentNullException("pdu"); } this.UpdateContext(pdu); if (UseProxy) { Debug.Assert(ProxyClient != null, "Proxy Client should be set when using proxy."); //temporarily change the tranpsort type to TCP, since all proxy messages are TCP format. var oriTransportType = Context.TransportType; Context.TransportType = TransportType.TCP; KDCProxyMessage message = ProxyClient.MakeProxyMessage(pdu); //send proxy message ProxyClient.SendProxyRequest(message); //restore the original transport type Context.TransportType = oriTransportType; } else { this.Connect(); kdcTransport.SendPacket(pdu); } }
//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); }