/// <summary>
        /// Exchange AS or TGS token with KDC.
        /// </summary>
        /// <param name="token">A token</param>
        /// <param name="sentFromClient">True if the token is a request, false is a response</param>
        /// <returns>Kerberos PDU</returns>
        private KilePdu ExchangeLegWithKdc(byte[] token, bool sentFromClient)
        {
            kileDecoder.isClientRole = !sentFromClient;

            int consumedLength;
            int expectedLength;

            KilePdu[] pduList = kileDecoder.DecodePacketCallback(
                FAKE_ENDPOINT,
                token,
                out consumedLength,
                out expectedLength);

            if (pduList == null || pduList.Length != 1 || consumedLength == 0)
            {
                throw new InvalidOperationException("Unable to decode data buffer");
            }

            KilePdu pdu = pduList[0];

            if (sentFromClient)
            {
                kileDecoder.clientContext.UpdateContext(pdu);
            }
            else
            {
                kileDecoder.serverContext.UpdateContext(pdu);
            }

            return(pdu);
        }
        /// <summary>
        /// Encrypts Message. User decides what SecBuffers are used.
        /// </summary>
        /// <param name="kileRole">Represents client or server</param>
        /// <param name="securityBuffers">The security buffers to encrypt.</param>
        /// <exception cref="System.ArgumentException">Thrown when the data or token is not valid.</exception>
        internal static void Encrypt(KileRole kileRole, params SecurityBuffer[] securityBuffers)
        {
            byte[] message = SspiUtility.ConcatenateReadWriteSecurityBuffers(securityBuffers, SecurityBufferType.Data);
            byte[] token   = SspiUtility.ConcatenateSecurityBuffers(securityBuffers, SecurityBufferType.Token);

            if (token.Length == 0)
            {
                throw new ArgumentException("Token buffer is not valid.");
            }

            SGN_ALG sgnAlg = GetSgnAlg(kileRole);
            KilePdu pdu    = kileRole.GssWrap(true, sgnAlg, message);

            byte[] cipherData = null;

            if (pdu.GetType() == typeof(Token4121))
            {
                cipherData = pdu.ToBytes();
            }
            else
            {
                byte[] allData     = pdu.ToBytes();
                byte[] paddingData = ((Token1964_4757)pdu).paddingData;
                cipherData = ArrayUtility.SubArray(allData, 0, allData.Length - paddingData.Length);
                SspiUtility.UpdateSecurityBuffers(securityBuffers, SecurityBufferType.Padding, paddingData);
            }
            SspiUtility.UpdateSecurityBuffers(securityBuffers, SecurityBufferType.Data,
                                              ArrayUtility.SubArray(cipherData, cipherData.Length - message.Length));
            SspiUtility.UpdateSecurityBuffers(securityBuffers, SecurityBufferType.Token,
                                              ArrayUtility.SubArray(cipherData, 0, cipherData.Length - message.Length));
        }
        /// <summary>
        /// Expect to receive a PDU of any type from the remote host.
        /// </summary>
        /// <param name="timeout">Timeout of receiving PDU.</param>
        /// <param name="kileConnection">The connection with a client.</param>
        /// <returns>The expected PDU.</returns>
        public KilePdu ExpectPdu(TimeSpan timeout, out KileConnection kileConnection)
        {
            TransportEvent eventPacket = transport.ExpectTransportEvent(timeout);
            KilePdu        packet      = (KilePdu)eventPacket.EventObject;

            kileConnection = new KileConnection((IPEndPoint)eventPacket.EndPoint);

            return(packet);
        }
        /// <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(KilePdu pdu)
        {
            if (pdu == null)
            {
                throw new ArgumentNullException("pdu");
            }

            context.UpdateContext(pdu);
            kdcTransport.SendPacket(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 KilePdu ExpectPdu(TimeSpan timeout)
        {
            if (timeout.TotalMilliseconds < 0)
            {
                throw new TimeoutException(ConstValue.TIMEOUT_EXCEPTION);
            }

            TransportEvent eventPacket = kdcTransport.ExpectTransportEvent(timeout);
            KilePdu        packet      = (KilePdu)eventPacket.EventObject;

            return(packet);
        }
        /// <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.</param>
        /// <param name="kileConnection">Maintain a connection with a target client</param>
        /// <exception cref="System.ArgumentNullException">Thrown when the input parameter is null.</exception>
        public void SendPdu(KilePdu pdu, KileConnection kileConnection)
        {
            if (kileConnection == null)
            {
                throw new ArgumentNullException("kileConnection");
            }
            if (pdu == null)
            {
                throw new ArgumentNullException("pdu");
            }

            KileServerContext serverContext = GetServerContextByKileConnection(kileConnection);

            transport.SendPacket(kileConnection.TargetEndPoint, pdu);
            serverContext.UpdateContext(pdu);
        }
        /// <summary>
        /// This takes the given SecurityBuffer array, signs data part, and updates signature into token part
        /// </summary>
        /// <param name="kileRole">Represents client or server</param>
        /// <param name="securityBuffers">Data to sign and token to update.</param>
        /// <exception cref="System.ArgumentException">Thrown when the data or token is not valid.</exception>
        internal static void Sign(KileRole kileRole, params SecurityBuffer[] securityBuffers)
        {
            byte[] token = SspiUtility.ConcatenateReadWriteSecurityBuffers(securityBuffers, SecurityBufferType.Token);

            if (token.Length == 0)
            {
                throw new ArgumentException("No token can be updated for signature.");
            }
            byte[]  message = GetToBeSignedDataFromSecurityBuffers(securityBuffers);
            SGN_ALG sgnAlg  = GetSgnAlg(kileRole);
            KilePdu pdu     = kileRole.GssGetMic(sgnAlg, message);

            byte[] signature = pdu.ToBytes();

            SspiUtility.UpdateSecurityBuffers(securityBuffers, SecurityBufferType.Token, signature);
        }
        /// <summary>
        /// This takes the given byte array, decrypts it, and returns
        /// the original, unencrypted byte array.
        /// </summary>
        /// <param name="kileRole">Represents client or server</param>
        /// <param name="securityBuffers">The security buffers to decrypt.</param>
        /// <exception cref="System.ArgumentException">Thrown when the data or token is not valid.</exception>
        internal static bool Decrypt(KileRole kileRole, params SecurityBuffer[] securityBuffers)
        {
            KilePdu pdu = kileRole.GssUnWrapEx(securityBuffers);

            byte[] decryptedMessage = null;

            if (pdu.GetType() == typeof(Token4121))
            {
                decryptedMessage = ((Token4121)pdu).Data;
            }
            else if (pdu.GetType() == typeof(Token1964_4757))
            {
                Token1964_4757 tokenData = (Token1964_4757)pdu;
                decryptedMessage = tokenData.Data;
                SspiUtility.UpdateSecurityBuffers(securityBuffers, SecurityBufferType.Padding, tokenData.paddingData);
            }
            // else do nothing

            return(true);
        }
        /// <summary>
        /// Decrypt a request or response
        /// </summary>
        /// <param name="token">A token containing encrypted data.</param>
        /// <param name="sentFromClient">True if the token is a request, false is a response</param>
        /// <returns>Plain-text data.</returns>
        private byte[] Decrypt(byte[] token, bool sentFromClient)
        {
            KileContext context = sentFromClient ? (KileContext)kileDecoder.serverContext : (KileContext)kileDecoder.clientContext;
            KilePdu     pdu     = KileRole.GssUnWrap(context, token);

            Token4121 token4121Pdu = pdu as Token4121;

            if (token4121Pdu != null)
            {
                return(token4121Pdu.Data);
            }

            Token1964_4757 token1964or4757Pdu = pdu as Token1964_4757;

            if (token1964or4757Pdu != null)
            {
                return(token1964or4757Pdu.Data);
            }

            throw new InvalidOperationException("Token type is not supported.");
        }
 /// <summary>
 /// Decode and verify a Gss_GetMic token.
 /// </summary>
 /// <param name="kileConnection">Maintain a connection with a target client</param>
 /// <param name="token">The token got from an application message.
 /// If this argument is null, null will be returned.</param>
 /// <param name="message">The message to be computed signature.
 /// If this argument is null, null will be returned.</param>
 /// <param name="pdu">The decoded Gss_GetMic token.</param>
 /// <returns>If verifying mic token is successful.</returns>
 /// <exception cref="System.NotSupportedException">Thrown when the encryption is not supported.</exception>
 public bool GssVerifyMic(KileConnection kileConnection, byte[] token, byte[] message, out KilePdu pdu)
 {
     context = GetServerContextByKileConnection(kileConnection);
     return(GssVerifyMic(token, message, out pdu));
 }
Пример #11
0
        /// <summary>
        /// Update the context.
        /// </summary>
        /// <param name="pdu">The PDU to update the context.</param>
        internal override void UpdateContext(KilePdu pdu)
        {
            if (pdu == null)
            {
                return;
            }

            lock (contextLock)
            {
                Type pduType = pdu.GetType();

                if (pduType == typeof(KileAsRequest))
                {
                    KileAsRequest request = (KileAsRequest)pdu;
                    if (request.Request != null && request.Request.req_body != null)
                    {
                        cName  = request.Request.req_body.cname;
                        cRealm = request.Request.req_body.realm;
                        eType  = request.Request.req_body.etype;
                    }
                }
                else if (pduType == typeof(KileAsResponse))
                {
                    KileAsResponse response = (KileAsResponse)pdu;
                    if (response.EncPart != null)
                    {
                        tgsSessionKey = response.EncPart.key;
                    }

                    if (response.Response != null)
                    {
                        tgsTicket = response.Response.ticket;
                        if (tgsTicket != null && tgsTicket.sname != null &&
                            tgsTicket.sname.name_string != null && tgsTicket.sname.name_string.Elements != null &&
                            tgsTicket.sname.name_string.Elements.Length > 1)
                        {
                            int count = tgsTicket.sname.name_string.Elements.Length;
                            cRealm = new Realm(tgsTicket.sname.name_string.Elements[count - 1].Value);
                        }

                        if (response.Response.padata != null && response.Response.padata.Elements != null)
                        {
                            foreach (PA_DATA paData in response.Response.padata.Elements)
                            {
                                if (paData.padata_type != null &&
                                    paData.padata_type.Value == (long)PaDataType.PA_ETYPE_INFO2)
                                {
                                    Asn1DecodingBuffer buffer     = new Asn1DecodingBuffer(paData.padata_value.ByteArrayValue);
                                    ETYPE_INFO2        eTypeInfo2 = new ETYPE_INFO2();
                                    eTypeInfo2.BerDecode(buffer);
                                    if (eTypeInfo2.Elements != null && eTypeInfo2.Elements.Length > 0)
                                    {
                                        // the salt is received from KDC
                                        salt = eTypeInfo2.Elements[0].salt.Value;
                                        return;
                                    }
                                }
                            }
                        }
                    }
                }
                else if (pduType == typeof(KileTgsResponse))
                {
                    KileTgsResponse response = (KileTgsResponse)pdu;
                    if (response.Response != null)
                    {
                        apTicket = response.Response.ticket;
                        if (apTicket != null && apTicket.sname != null &&
                            apTicket.sname.name_string != null && apTicket.sname.name_string.Elements != null &&
                            apTicket.sname.name_string.Elements.Length > 1)
                        {
                            int count = apTicket.sname.name_string.Elements.Length;
                            cRealm = new Realm(apTicket.sname.name_string.Elements[count - 1].Value);
                        }
                    }

                    if (response.EncPart != null)
                    {
                        apSessionKey = response.EncPart.key;
                    }
                }
                else if (pduType == typeof(KileApRequest))
                {
                    KileApRequest request = (KileApRequest)pdu;
                    if (request.Authenticator != null)
                    {
                        apSubKey       = request.Authenticator.subkey;
                        apRequestCtime = request.Authenticator.ctime;
                        apRequestCusec = request.Authenticator.cusec;

                        if (request.Authenticator.cksum != null &&
                            request.Authenticator.cksum.cksumtype.Value == (int)ChecksumType.ap_authenticator_8003 &&
                            request.Authenticator.cksum.checksum != null &&
                            request.Authenticator.cksum.checksum.Value != null &&
                            request.Authenticator.cksum.checksum.Value.Length == ConstValue.AUTH_CHECKSUM_SIZE)
                        {
                            int flag = BitConverter.ToInt32(request.Authenticator.cksum.checksum.ByteArrayValue,
                                                            ConstValue.AUTHENTICATOR_CHECKSUM_LENGTH + sizeof(int));
                            checksumFlag = (ChecksumFlags)flag;
                        }

                        if (request.Authenticator.seq_number != null)
                        {
                            currentLocalSequenceNumber  = (ulong)request.Authenticator.seq_number.Value;
                            currentRemoteSequenceNumber = currentLocalSequenceNumber;
                        }
                    }
                }
                else if (pduType == typeof(KileApResponse))
                {
                    KileApResponse response = (KileApResponse)pdu;
                    if (response.ApEncPart != null)
                    {
                        if (response.ApEncPart.seq_number != null)
                        {
                            currentRemoteSequenceNumber = (ulong)response.ApEncPart.seq_number.Value;
                        }

                        if (response.ApEncPart.subkey != null)
                        {
                            acceptorSubKey = response.ApEncPart.subkey;
                        }
                    }
                }
                // else do nothing
            }
        }
Пример #12
0
        /// <summary>
        /// Update the context.
        /// </summary>
        /// <param name="pdu">The Pdu to update the context.</param>
        internal override void UpdateContext(KilePdu pdu)
        {
            if (pdu != null)
            {
                Type pduType = pdu.GetType();

                if (pduType == typeof(KileAsRequest))
                {
                    KileAsRequest request = (KileAsRequest)pdu;

                    if (request.Request != null && request.Request.req_body != null)
                    {
                        cName       = request.Request.req_body.cname;
                        cRealm      = request.Request.req_body.realm;
                        sName       = request.Request.req_body.sname;
                        encryptType = request.Request.req_body.etype;
                        addresses   = request.Request.req_body.addresses;
                        nonce       = request.Request.req_body.nonce;
                        endTime     = request.Request.req_body.till;
                        rtime       = request.Request.req_body.rtime;
                    }
                }
                else if (pduType == typeof(KileAsResponse))
                {
                    KileAsResponse response = (KileAsResponse)pdu;
                    tgsSessionKey = response.EncPart.key;
                }
                else if (pduType == typeof(KileTgsRequest))
                {
                    KileTgsRequest request = (KileTgsRequest)pdu;
                    encryptType = request.Request.req_body.etype;
                    nonce       = request.Request.req_body.nonce;
                    tgsTicket   = request.tgtTicket;
                    sName       = request.Request.req_body.sname;

                    if (request.authenticator != null)
                    {
                        tgsSubSessionKey = request.authenticator.subkey;
                    }
                }
                else if (pduType == typeof(KileTgsResponse))
                {
                    KileTgsResponse response = (KileTgsResponse)pdu;
                    apSessionKey = response.EncPart.key;
                }
                else if (pduType == typeof(KileApRequest))
                {
                    KileApRequest request = (KileApRequest)pdu;
                    apRequestCtime = request.Authenticator.ctime;
                    apRequestCusec = request.Authenticator.cusec;

                    if (request.Authenticator.cksum != null)
                    {
                        int flag = BitConverter.ToInt32(request.Authenticator.cksum.checksum.mValue,
                                                        ConstValue.AUTHENTICATOR_CHECKSUM_LENGTH + sizeof(ChecksumFlags));
                        checksumFlag = (ChecksumFlags)flag;
                    }
                    apSubKey = request.Authenticator.subkey;

                    if (request.Authenticator.seq_number != null)
                    {
                        currentRemoteSequenceNumber = (ulong)request.Authenticator.seq_number.mValue;
                        currentLocalSequenceNumber  = currentRemoteSequenceNumber;
                    }
                }
                else if (pduType == typeof(KileApResponse))
                {
                    KileApResponse response = (KileApResponse)pdu;

                    if (response.ApEncPart.subkey != null)
                    {
                        acceptorSubKey = response.ApEncPart.subkey;
                    }
                }
                else
                {
                    // Do nothing.
                }
            }
        }
Пример #13
0
        /// <summary>
        /// Initialize the context from a token.
        /// </summary>
        /// <param name="inToken">The token used to initialize.</param>
        /// <exception cref="System.NotSupportedException">Thrown when the ContextAttribute contains a flag that not be
        /// supported.</exception>
        /// <exception cref="System.InvalidOperationException">Thrown when an error is returned.</exception>
        public override void Initialize(byte[] inToken)
        {
            if (inToken == null || inToken.Length == 0)
            {
                KilePdu       response = null;
                string        sname    = ConstValue.KERBEROS_SNAME;
                KileAsRequest asRequest;
                EncryptionKey subkey = null;

                // Create and send AS request for pre-authentication
                KdcOptions options = KdcOptions.FORWARDABLE | KdcOptions.RENEWABLE
                                     | KdcOptions.CANONICALIZE | KdcOptions.RENEWABLEOK;
                KDCOptions flags = new KDCOptions(KerberosUtility.ConvertInt2Flags((int)options));

                // Create and send AS request for pre-authentication
                asRequest = client.CreateAsRequest(sname, flags, null, this.GetClientSupportedEtype());
                client.SendPdu(asRequest);
                response = client.ExpectPdu(ConstValue.TIMEOUT_DEFAULT);
                KileKrbError preAuthError = response as KileKrbError;
                if ((preAuthError == null) || (!preAuthError.ErrorCode.Equals(KRB_ERROR_CODE.KDC_ERR_PREAUTH_REQUIRED)))
                {
                    throw new InvalidOperationException("The Error code should be KDC_ERR_PREAUTH_REQUIRED");
                }

                // Create and send AS request for TGT
                var                      defualtEncryptType = (client.ClientContext.TgsSessionKey == null) ? EncryptionType.RC4_HMAC : (EncryptionType)client.ClientContext.TgsSessionKey.keytype.Value;
                PaEncTimeStamp           timestamp          = client.ConstructPaEncTimeStamp(defualtEncryptType);
                PaPacRequest             pacRequest         = client.ConstructPaPacRequest(true);
                Asn1SequenceOf <PA_DATA> paData             = client.ConstructPaData(timestamp, pacRequest);

                if ((contextAttribute & ClientSecurityContextAttribute.DceStyle) == ClientSecurityContextAttribute.DceStyle)
                {
                    asRequest = client.CreateAsRequest(sname, flags, paData, this.GetClientSupportedEtype());
                    //subkey = new EncryptionKey((int)EncryptionType.AES256_CTS_HMAC_SHA1_96,
                    //    KileUtility.GenerateRandomBytes(ConstValue.AES_KEY_LENGTH));

                    var key = KeyGenerator.MakeKey(EncryptionType.AES256_CTS_HMAC_SHA1_96, client.ClientContext.Password, client.ClientContext.Salt);
                    subkey = new EncryptionKey(new KerbInt32((long)EncryptionType.AES256_CTS_HMAC_SHA1_96), new Asn1OctetString(key));
                }
                else
                {
                    asRequest = client.CreateAsRequest(sname, flags, paData, this.GetClientSupportedEtype());
                }
                client.SendPdu(asRequest);
                response = client.ExpectPdu(ConstValue.TIMEOUT_DEFAULT);

                if (response.GetType() == typeof(KileKrbError))
                {
                    throw new InvalidOperationException("Received Kerberos Error response: " + ((KileKrbError)response).ErrorCode);
                }
                KileAsResponse asResponse = (KileAsResponse)response;

                // Create and send TGS request

                // for example: "KERB.COMldapsut02.kerb.com"
                client.ClientContext.Salt = domain.ToUpper();
                string[] nameList = userLogonName.Split('/');
                foreach (string name in nameList)
                {
                    client.ClientContext.Salt += name;
                }
                KileTgsRequest tgsRequest = client.CreateTgsRequest(this.serverName,
                                                                    flags,
                                                                    null,
                                                                    ChecksumType.hmac_md5_string,
                                                                    null,
                                                                    null);
                client.SendPdu(tgsRequest);
                response = client.ExpectPdu(ConstValue.TIMEOUT_DEFAULT);

                if (response.GetType() == typeof(KileKrbError))
                {
                    throw new InvalidOperationException("Received Kerberos Error response: " + ((KileKrbError)response).ErrorCode);
                }

                KileTgsResponse tgsResponse = (KileTgsResponse)response;

                ApOptions     apOption;
                ChecksumFlags checksumFlag;
                GetFlagsByContextAttribute(out apOption, out checksumFlag);

                KerbAuthDataTokenRestrictions adRestriction =
                    client.ConstructKerbAuthDataTokenRestrictions(0,
                                                                  (uint)LSAP_TOKEN_INFO_INTEGRITY_Flags.FULL_TOKEN,
                                                                  (uint)LSAP_TOKEN_INFO_INTEGRITY_TokenIL.Medium,
                                                                  new Guid().ToString());
                AdAuthDataApOptions adApOptions = client.ConstructAdAuthDataApOptions(ConstValue.KERB_AP_OPTIONS_CBT);
                AuthorizationData   authData    = client.ConstructAuthorizationData(adRestriction, adApOptions);
                KileApRequest       apRequest   = client.CreateApRequest(apOption,
                                                                         ChecksumType.ap_authenticator_8003,
                                                                         ConstValue.SEQUENCE_NUMBER_DEFAULT,
                                                                         checksumFlag,
                                                                         subkey,
                                                                         authData);
                token = apRequest.ToBytes();

                bool isMutualAuth = (contextAttribute & ClientSecurityContextAttribute.MutualAuth)
                                    == ClientSecurityContextAttribute.MutualAuth;
                bool isDceStyle = (contextAttribute & ClientSecurityContextAttribute.DceStyle)
                                  == ClientSecurityContextAttribute.DceStyle;

                if (isMutualAuth || isDceStyle)
                {
                    continueProcess = true;   // SEC_I_CONTINUE_NEEDED;
                }
                else
                {
                    continueProcess = false;  // SEC_E_OK;
                }
            }
            else  // mutual authentication
            {
                KileApResponse apResponse = client.ParseApResponse(inToken);
                token = null;

                if ((contextAttribute & ClientSecurityContextAttribute.DceStyle)
                    == ClientSecurityContextAttribute.DceStyle)
                {
                    KileApResponse apResponseSend = client.CreateApResponse(null);
                    token = apResponseSend.ToBytes();
                }

                this.continueProcess = false;      // SEC_E_OK;
            }
        }
Пример #14
0
 /// <summary>
 /// Update the context.
 /// </summary>
 /// <param name="pdu">The PDU to update the context.</param>
 internal abstract void UpdateContext(KilePdu pdu);
 /// <summary>
 /// Decode and verify a Gss_GetMic token.
 /// </summary>
 /// <param name="kileConnection">Maintain a connection with a target client</param>
 /// <param name="token">The token got from an application message. 
 /// If this argument is null, null will be returned.</param>
 /// <param name="message">The message to be computed signature. 
 /// If this argument is null, null will be returned.</param>
 /// <param name="pdu">The decoded Gss_GetMic token.</param>
 /// <returns>If verifying mic token is successful.</returns>
 /// <exception cref="System.NotSupportedException">Thrown when the encryption is not supported.</exception>
 public bool GssVerifyMic(KileConnection kileConnection, byte[] token, byte[] message, out KilePdu pdu)
 {
     context = GetServerContextByKileConnection(kileConnection);
     return GssVerifyMic(token, message, out pdu);
 }
        /// <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.</param>
        /// <param name="kileConnection">Maintain a connection with a target client</param>
        /// <exception cref="System.ArgumentNullException">Thrown when the input parameter is null.</exception>
        public void SendPdu(KilePdu pdu, KileConnection kileConnection)
        {
            if (kileConnection == null)
            {
                throw new ArgumentNullException("kileConnection");
            }
            if (pdu == null)
            {
                throw new ArgumentNullException("pdu");
            }

            KileServerContext serverContext = GetServerContextByKileConnection(kileConnection);
            transport.SendPacket(kileConnection.TargetEndPoint, pdu);
            serverContext.UpdateContext(pdu);
        }
Пример #17
0
        /// <summary>
        /// Decode KILE 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 KILE PDUs</returns>
        /// <exception cref="System.FormatException">thrown when a kile message type is unsupported</exception>
        internal KilePdu[] DecodePacketCallback(object endPoint,
                                                byte[] receivedBytes,
                                                out int consumedLength,
                                                out int expectedLength)
        {
            // initialize lengths
            consumedLength = 0;
            expectedLength = 0;

            if (null == receivedBytes || 0 == receivedBytes.Length)
            {
                return(null);
            }
            if (!isClientRole)
            {
                serverContext = null;

                if (serverContextList != null)
                {
                    KileConnection kileConnection = new KileConnection((IPEndPoint)endPoint);

                    if (!serverContextList.ContainsKey(kileConnection))
                    {
                        serverContext = new KileServerContext();
                        serverContext.TransportType = connectionType;
                        serverContextList.Add(kileConnection, serverContext);
                    }
                    else
                    {
                        serverContext = serverContextList[kileConnection];
                    }
                }
                if (serverContext == null)
                {
                    throw new InvalidOperationException("The kileConnection related context does not exist.");
                }
            }

            // TCP has a 4 bytes length header, while UDP has not
            byte[] pduBytes = receivedBytes;

            if ((isClientRole && clientContext.TransportType == KileConnectionType.TCP) ||
                (!isClientRole && serverContext.TransportType == KileConnectionType.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);
                }

                // check if it is a krb zero message
                if (pduLength == 0 && receivedBytes.Length == sizeof(int))
                {
                    consumedLength = sizeof(int);
                    KrbZero krbZeroPdu = new KrbZero(clientContext);
                    return(new KilePdu[] { krbZeroPdu });
                }

                // remove length header from pdu bytes
                pduBytes = ArrayUtility.SubArray <byte>(receivedBytes, sizeof(int), pduLength);
            }
            else
            {
                // UDP has no length header
                expectedLength = pduBytes.Length;
            }

            // get message type
            // (the lower 5 bits indicates its kile message type)
            MsgType kileMessageType = (MsgType)(pduBytes[0] & 0x1f);

            // decode according to message type
            consumedLength = expectedLength;
            KilePdu pdu = null;

            switch (kileMessageType)
            {
            case MsgType.KRB_AS_REQ:
                pdu = new KileAsRequest(serverContext);
                break;

            case MsgType.KRB_AS_RESP:
                pdu = new KileAsResponse(clientContext);
                break;

            case MsgType.KRB_TGS_REQ:
                pdu = new KileTgsRequest(serverContext);
                break;

            case MsgType.KRB_TGS_RESP:
                pdu = new KileTgsResponse(clientContext);
                break;

            case MsgType.KRB_ERROR:
                pdu = new KileKrbError();
                break;

            default:
                throw new FormatException(
                          "Unsupported Message Type: " + kileMessageType.ToString());
            }
            pdu.FromBytes(pduBytes);

            // update context
            if (isClientRole)
            {
                clientContext.UpdateContext(pdu);
            }
            else
            {
                serverContext.UpdateContext(pdu);
            }

            return(new KilePdu[] { pdu });
        }