public KileApRequest CreateApRequest( ApOptions apOptions, ChecksumType checksumType, int seqNumber, ChecksumFlags flag, EncryptionKey subkey, AuthorizationData authorizationData) { var request = new KileApRequest(context); request.Authenticator = CreateAuthenticator( checksumType, seqNumber, flag, subkey, authorizationData, context.ApSessionKey, null); request.Request.ap_options = new APOptions(KerberosUtility.ConvertInt2Flags((int)apOptions)); request.Request.msg_type = new Asn1Integer((int)MsgType.KRB_AP_REQ); request.Request.pvno = new Asn1Integer(ConstValue.KERBEROSV5); request.Request.ticket = context.ApTicket; return(request); }
/// <summary> /// Accept client token. /// </summary> /// <param name="inToken">The client's token.</param> /// <exception cref="System.ArgumentNullException">Thrown when the input parameter is null.</exception> /// <exception cref="System.FormatException">Thrown when the token format is invalid.</exception> public override void Accept(byte[] inToken) { if (inToken == null) { throw new ArgumentNullException("inToken"); } if (isInitialToken) { KileApRequest apRequest = new KileApRequest(server.Context); apRequest.FromBytes(inToken, ticketEncryptKey); bool isMutualAuth = (apRequest.Request.ap_options.ByteArrayValue[0] << 24 & (int)ApOptions.MutualRequired) == (int)ApOptions.MutualRequired; bool isDceStyle = inToken[0] != ConstValue.KERBEROS_TAG; if (isMutualAuth || isDceStyle) { EncryptionKey apSubKey = new EncryptionKey(new KerbInt32((int)EncryptionType.RC4_HMAC), new Asn1OctetString(Guid.NewGuid().ToByteArray())); KileApResponse apResponse = server.CreateApResponse(apSubKey); // Set a random sequence number Random randomNumber = new Random(); apResponse.ApEncPart.seq_number = new KerbUInt32(randomNumber.Next()); server.context.currentLocalSequenceNumber = (ulong)apResponse.ApEncPart.seq_number.Value; token = apResponse.ToBytes(); } isInitialToken = false; if (inToken[0] != ConstValue.KERBEROS_TAG) { // SEC_I_CONTINUE_NEEDED; continueProcess = true; } else { // SEC_E_OK; continueProcess = false; } } else { KileApResponse apResponse = new KileApResponse(server.Context); apResponse.FromBytes(inToken); if (server.Context.CurrentLocalSequenceNumber != (ulong)apResponse.ApEncPart.seq_number.Value) { throw new FormatException("Sequence number does not match."); } // SEC_E_OK; continueProcess = false; token = null; } }
/// <summary> /// AP exchange. /// Typically AP request and AP response start with /// GSSAPI token (asn.1 header + 1.2.840.113554.1.2.2), /// or a TokId (Krb5ApReq:0x100) /// </summary> /// <param name="apReq">AP request</param> /// <param name="apRep">AP response</param> /// <exception cref="ArgumentNullException"> /// Thrown when apReq or apRep is null. /// </exception> public void ApExchange(byte[] apReq, byte[] apRep) { if (apReq == null) { throw new ArgumentNullException(nameof(apReq)); } if (apRep == null) { throw new ArgumentNullException(nameof(apRep)); } var apReqPdu = new KileApRequest(kileDecoder.serverContext); apReqPdu.FromBytes(apReq); kileDecoder.clientContext.UpdateContext(apReqPdu); var apRepPdu = new KileApResponse(kileDecoder.clientContext); apRepPdu.FromBytes(apRep); kileDecoder.serverContext.UpdateContext(apRepPdu); }
public KileApRequest CreateApRequest( Realm cRealm, PrincipalName cName, ApOptions apOptions, ChecksumType checksumType, int seqNumber, ChecksumFlags flag, EncryptionKey subkey, AuthorizationData authorizationData) { if (cRealm == null) { throw new ArgumentNullException("cRealm"); } if (cName == null) { throw new ArgumentNullException("cName"); } KileApRequest request = new KileApRequest(context); request.Authenticator = CreateAuthenticator(cRealm, cName, checksumType, seqNumber, flag, subkey, authorizationData, context.ApSessionKey, null); request.Request.ap_options = new APOptions(KileUtility.ConvertInt2Flags((int)apOptions)); request.Request.msg_type = new Asn1Integer((int)MsgType.KRB_AP_REQ); request.Request.pvno = new Asn1Integer(ConstValue.KERBEROSV5); request.Request.ticket = context.ApTicket; return(request); }
/// <summary> /// Accept client token. /// </summary> /// <param name="inToken">The client's token.</param> /// <exception cref="System.ArgumentNullException">Thrown when the input parameter is null.</exception> /// <exception cref="System.FormatException">Thrown when the token format is invalid.</exception> public override void Accept(byte[] inToken) { if (inToken == null) { throw new ArgumentNullException("inToken"); } if (isInitialToken) { KileApRequest apRequest = new KileApRequest(server.Context); apRequest.FromBytes(inToken, ticketEncryptKey); bool isMutualAuth = (apRequest.Request.ap_options.mValue[0] << 24 & (int)ApOptions.MutualRequired) == (int)ApOptions.MutualRequired; bool isDceStyle = inToken[0] != ConstValue.KERBEROS_TAG; if (isMutualAuth || isDceStyle) { EncryptionKey apSubKey = new EncryptionKey((int)EncryptionType.RC4_HMAC, Guid.NewGuid().ToByteArray()); KileApResponse apResponse = server.CreateApResponse(apSubKey); // Set a random sequence number Random randomNumber = new Random(); apResponse.ApEncPart.seq_number = new UInt32(randomNumber.Next()); server.context.currentLocalSequenceNumber = (ulong)apResponse.ApEncPart.seq_number.mValue; token = apResponse.ToBytes(); } isInitialToken = false; if (inToken[0] != ConstValue.KERBEROS_TAG) { // SEC_I_CONTINUE_NEEDED; continueProcess = true; } else { // SEC_E_OK; continueProcess = false; } } else { KileApResponse apResponse = new KileApResponse(server.Context); apResponse.FromBytes(inToken); if (server.Context.CurrentLocalSequenceNumber != (ulong)apResponse.ApEncPart.seq_number.mValue) { throw new FormatException("Sequence number does not match."); } // SEC_E_OK; continueProcess = false; token = null; } }
/// <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 } }
/// <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> /// 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; } }