/// <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. } } }
/// <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 }); }
/// <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; } }
public KileTgsRequest CreateTgsRequest( Realm cRealm, PrincipalName cName, PrincipalName sName, KRBFlags kdcOptions, KerbUInt32 nonce, Realm realm, Asn1SequenceOf <PA_DATA> paData, ChecksumType checksumType, Ticket additionalTicket, AuthorizationData authorizationData) { if (cRealm == null) { throw new ArgumentNullException("cRealm"); } if (cName == null) { throw new ArgumentNullException("cName"); } if (sName == null) { throw new ArgumentNullException("sName"); } if (realm == null) { throw new ArgumentNullException("realm"); } KileTgsRequest request = new KileTgsRequest(context); request.Request.msg_type = new Asn1Integer((int)MsgType.KRB_TGS_REQ); request.Request.pvno = new Asn1Integer(ConstValue.KERBEROSV5); #region construct req_body request.Request.req_body = new KDC_REQ_BODY(); request.Request.req_body.kdc_options = new KDCOptions(KileUtility.ConvertInt2Flags((int)kdcOptions)); request.Request.req_body.nonce = nonce; request.Request.req_body.till = new KerberosTime(ConstValue.TGT_TILL_TIME); request.Request.req_body.etype = context.ClientEncryptionTypes; request.Request.req_body.realm = realm; if (additionalTicket != null) { request.Request.req_body.additional_tickets = new Asn1SequenceOf <Ticket>(new Ticket[] { additionalTicket }); } request.Request.req_body.sname = sName; request.EncAuthorizationData = authorizationData; if (authorizationData != null) { Asn1BerEncodingBuffer asnBuffer = new Asn1BerEncodingBuffer(); authorizationData.BerEncode(asnBuffer, true); request.Request.req_body.enc_authorization_data = new EncryptedData(); request.Request.req_body.enc_authorization_data.etype = new KerbInt32(0); byte[] encAsnEncoded = asnBuffer.Data; if (context.TgsSessionKey != null && context.TgsSessionKey.keytype != null && context.TgsSessionKey.keyvalue != null && context.TgsSessionKey.keyvalue.Value != null) { encAsnEncoded = KileUtility.Encrypt((EncryptionType)context.TgsSessionKey.keytype.Value, context.TgsSessionKey.keyvalue.ByteArrayValue, asnBuffer.Data, (int)KeyUsageNumber.TGS_REQ_KDC_REQ_BODY_AuthorizationData); request.Request.req_body.enc_authorization_data.etype = new KerbInt32(context.TgsSessionKey.keytype.Value); } request.Request.req_body.enc_authorization_data.cipher = new Asn1OctetString(encAsnEncoded); } #endregion construct req_body #region construct PA_DATA Asn1BerEncodingBuffer bodyBuffer = new Asn1BerEncodingBuffer(); request.Request.req_body.BerEncode(bodyBuffer); PA_DATA tgsPaData = ConstructTgsPaData(cRealm, cName, checksumType, bodyBuffer.Data); request.Request.padata = new Asn1SequenceOf <PA_DATA>(); if (paData == null || paData.Elements == null || paData.Elements.Length == 0) { request.Request.padata.Elements = new PA_DATA[] { tgsPaData }; } else { request.Request.padata.Elements = new PA_DATA[paData.Elements.Length + 1]; Array.Copy(paData.Elements, request.Request.padata.Elements, paData.Elements.Length); request.Request.padata.Elements[paData.Elements.Length] = tgsPaData; } #endregion construct PA_DATA return(request); }