/// <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);
        }
Ejemplo n.º 9
0
        /// <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);
        }
Ejemplo n.º 10
0
        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);
        }
Ejemplo n.º 15
0
 /// <summary>
 /// Updated context based on Kerberos pdu
 /// </summary>
 /// <param name="pdu">Kerberos pdu</param>
 public virtual void UpdateContext(KerberosPdu 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);
            }
        }
        /// <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;
        }
        //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);
        }