/// <summary>
        /// Create KRB_ERROR response
        /// </summary>
        /// <param name="kileConnection">Maintain a connection with a target client. This argument cannot be null.</param>
        /// <param name="errorCode">Error code returned by Kerberos or the server when a request fails</param>
        /// <param name="errorText">Additional text to help explain the error code. This argument could be null.</param>
        /// <param name="errorData">Additional data about the error. This argument could be null.</param>
        /// <returns>The created Krb Error response</returns>
        /// <exception cref="System.ArgumentNullException">Thrown when the input parameter is null.</exception>
        public KileKrbError CreateKrbErrorResponse(
            KileConnection kileConnection,
            KRB_ERROR_CODE errorCode,
            string errorText,
            byte[] errorData)
        {
            KileServerContext serverContext = GetServerContextByKileConnection(kileConnection);
            KileKrbError      response      = new KileKrbError(serverContext);

            // Set KRB_ERROR
            response.KerberosError.pvno       = new Asn1Integer(ConstValue.KERBEROSV5);
            response.KerberosError.msg_type   = new Asn1Integer((int)MsgType.KRB_ERROR);
            response.KerberosError.stime      = KileUtility.CurrentKerberosTime;
            response.KerberosError.susec      = new Microseconds(0);
            response.KerberosError.sname      = serverContext.SName;
            response.KerberosError.realm      = new Realm(domain);
            response.KerberosError.error_code = new Int32((int)errorCode);

            if (errorText != null)
            {
                response.KerberosError.e_text = new KerberosString(errorText);
            }
            if (errorData != null)
            {
                response.KerberosError.e_data = new Asn1OctetString(errorData);
            }

            return(response);
        }
        /// <summary>
        /// Decode the KRB_ERROR token got from application.
        /// </summary>
        /// <param name="errorToken">The token got from an application message. This argument cannot be null.</param>
        /// <returns>The decoded AP response.</returns>
        /// <exception cref="System.ArgumentNullException">Thrown when the input parameter is null.</exception>
        /// <exception cref="System.FormatException">Thrown when the errorToken is not valid.</exception>
        public KileKrbError ParseKrbError(byte[] errorToken)
        {
            if (errorToken == null)
            {
                throw new ArgumentNullException("errorToken");
            }

            byte[] errorBody = KileUtility.VerifyGssApiTokenHeader(errorToken);

            // Check if it has a two-byte tok_id
            if (errorBody == null || errorBody.Length <= sizeof(TOK_ID))
            {
                throw new FormatException("Not a valid KRB_ERROR token!");
            }

            TOK_ID id = (TOK_ID)KileUtility.ConvertEndian(BitConverter.ToUInt16(errorBody, 0));

            if (id != TOK_ID.KRB_ERROR)
            {
                throw new FormatException("Not a valid KRB_ERROR token!");
            }

            errorBody = ArrayUtility.SubArray(errorBody, sizeof(TOK_ID));
            KileKrbError error = new KileKrbError();

            error.FromBytes(errorBody);
            return(error);
        }
        /// <summary>
        /// Create KRB_ERROR response
        /// </summary>
        /// <param name="kileConnection">Maintain a connection with a target client. This argument cannot be null.</param>
        /// <param name="errorCode">Error code returned by Kerberos or the server when a request fails</param>
        /// <param name="errorText">Additional text to help explain the error code. This argument could be null.</param>
        /// <param name="errorData">Additional data about the error. This argument could be null.</param>
        /// <returns>The created Krb Error response</returns>
        /// <exception cref="System.ArgumentNullException">Thrown when the input parameter is null.</exception>
        public KileKrbError CreateKrbErrorResponse(
            KileConnection kileConnection,
            KRB_ERROR_CODE errorCode,
            string errorText,
            byte[] errorData)
        {
            KileServerContext serverContext = GetServerContextByKileConnection(kileConnection);
            KileKrbError response = new KileKrbError(serverContext);

            // Set KRB_ERROR
            response.KerberosError.pvno = new Asn1Integer(ConstValue.KERBEROSV5);
            response.KerberosError.msg_type = new Asn1Integer((int)MsgType.KRB_ERROR);
            response.KerberosError.stime = KileUtility.CurrentKerberosTime;
            response.KerberosError.susec = new Microseconds(0);
            response.KerberosError.sname = serverContext.SName;
            response.KerberosError.realm = new Realm(domain);
            response.KerberosError.error_code = new Int32((int)errorCode);

            if (errorText != null)
            {
                response.KerberosError.e_text = new KerberosString(errorText);
            }
            if (errorData != null)
            {
                response.KerberosError.e_data = new Asn1OctetString(errorData);
            }

            return response;
        }
Exemple #4
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;
            }
        }
Exemple #5
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 });
        }