/// <summary> /// Construct a Kerberos test client for FAST /// </summary> /// <param name="domain">The realm part of the client's principal identifier. /// This argument cannot be null.</param> /// <param name="cName">The account to logon the remote machine. Either user account or computer account /// This argument cannot be null.</param> /// <param name="password">The password of the user. This argument cannot be null.</param> /// <param name="accountType">The type of the logon account. User or Computer</param> public KerberosFunctionalClient(string domain, string cName, string password, KerberosAccountType accountType, KerberosTicket armorTicket, EncryptionKey armorSessionKey, string kdcAddress, int kdcPort, TransportType transportType, KerberosConstValue.OidPkt omiPkt, ITestSite baseTestSite) : base(domain, cName, password, accountType, armorTicket, armorSessionKey, kdcAddress, kdcPort, transportType, omiPkt) { testSite = baseTestSite; if (accountType == KerberosAccountType.Device) { testSite.Log.Add(LogEntryKind.Debug, "Construct Kerberos client using computer account: {0}@{1}.", cName, domain); } else { testSite.Log.Add(LogEntryKind.Debug, "Construct Kerberos client using user account: {0}@{1}.", cName, domain); } EncryptionType[] encryptionTypes = new EncryptionType[] { EncryptionType.AES256_CTS_HMAC_SHA1_96, EncryptionType.AES128_CTS_HMAC_SHA1_96, EncryptionType.RC4_HMAC, EncryptionType.RC4_HMAC_EXP, EncryptionType.DES_CBC_CRC, EncryptionType.DES_CBC_MD5 }; KerbInt32[] etypes = new KerbInt32[encryptionTypes.Length]; for (int i = 0; i < encryptionTypes.Length; i++) { etypes[i] = new KerbInt32((int)encryptionTypes[i]); } Asn1SequenceOf<KerbInt32> etype = new Asn1SequenceOf<KerbInt32>(etypes); Context.SupportedEType = etype; Context.Pvno = KerberosConstValue.KERBEROSV5; }
/// <summary> /// Add a token header for AP request/response, wrap token or getmic token to make them a complete token. /// </summary> /// <param name="tokenBody">The AP request/response, wrap token or getmic token. /// This argument can be null.</param> /// <returns>The completed token.</returns> public static byte[] AddGssApiTokenHeader(byte[] tokenBody, KerberosConstValue.OidPkt oidPkt = KerberosConstValue.OidPkt.KerberosToken, KerberosConstValue.GSSToken gssToken = KerberosConstValue.GSSToken.GSSSPNG) { List <byte> gssDataList = new List <byte>(); gssDataList.Add(KerberosConstValue.KERBEROS_TAG); // kerberos oid (1.2.840.113554.1.2.2) byte[] oid; oid = KerberosConstValue.GetKerberosOid(); if (tokenBody == null) { tokenBody = new byte[0]; } int length = tokenBody.Length + oid.Length; if (length > 127) { // If the indicated value is 128 or more, it shall be represented in two or more octets, // with bit 8 of the first octet set to "1" and the remaining bits of the first octet // specifying the number of additional octets. The subsequent octets carry the value, // 8 bits per octet, most significant digit first. [rfc 2743] int temp = length; int index = 1; List <byte> lengthList = new List <byte>(); lengthList.Add((byte)(temp & 0xFF)); while ((temp >>= 8) != 0) { index++; lengthList.Add((byte)(temp & 0xFF)); } gssDataList.Add((byte)(0x80 | index)); lengthList.Reverse(); gssDataList.AddRange(lengthList.ToArray()); } else { // If the indicated value is less than 128, it shall be represented in a single octet with bit 8 // (high order) set to "0" and the remaining bits representing the value. [rfc 2743] gssDataList.Add((byte)length); } gssDataList.AddRange(oid); gssDataList.AddRange(tokenBody); if (gssToken == KerberosConstValue.GSSToken.GSSAPI) { return(gssDataList.ToArray()); } else { return(KerberosUtility.EncodeInitialNegToken(gssDataList.ToArray(), oidPkt)); } }
/// <summary> /// Create a KileClient instance. /// </summary> /// <param name="domain">The realm part of the client's principal identifier. /// This argument cannot be null.</param> /// <param name="cName">The account to logon the remote machine. Either user account or computer account /// This argument cannot be null.</param> /// <param name="password">The password of the user. This argument cannot be null.</param> /// <param name="accountType">The type of the logon account. User or Computer</param> /// <param name="kdcAddress">The IP address of the KDC.</param> /// <param name="kdcPort">The port of the KDC.</param> /// <param name="transportType">Whether the transport is TCP or UDP transport.</param> /// <exception cref="System.ArgumentNullException">Thrown when the input parameter is null.</exception> public KerberosClient(string domain, string cName, string password, KerberosAccountType accountType, KerberosTicket armorTicket, EncryptionKey armorSessionKey, string kdcAddress, int kdcPort, TransportType transportType, KerberosConstValue.OidPkt oidPkt = KerberosConstValue.OidPkt.KerberosToken, string salt = null) { TransportBufferSize = KerberosConstValue.TRANSPORT_BUFFER_SIZE; this.Context = new KerberosContext(domain, cName, password, accountType, salt, armorTicket, armorSessionKey); this.kdcAddress = kdcAddress; this.kdcPort = kdcPort; this.transportType = transportType; this.oidPkt = oidPkt; this.Context.TransportType = transportType; }
/// <summary> /// Verify and remove a token header from AP request/response, /// wrap token or getmic token. /// </summary> /// <param name="completeToken">The complete token got from application message. /// This argument can be null. If it is null, null will be returned.</param> /// <returns>The token body without the header.</returns> /// <exception cref="System.FormatException">Throw FormatException if the token header is incorrect.</exception> public static byte[] VerifyGssApiTokenHeader(byte[] completeToken, KerberosConstValue.OidPkt oidPkt = KerberosConstValue.OidPkt.KerberosToken) { byte[] oid; oid = KerberosConstValue.GetKerberosOid(); if (completeToken == null || completeToken.Length < KerberosConstValue.GetKerberosOid().Length) { throw new FormatException("The GSS-API token header is incomplete!"); } if (completeToken[0] != KerberosConstValue.KERBEROS_TAG) { throw new FormatException("The GSS-API token header is incorrect!"); } int length = 0; int index = 2; // the tag and length fields // If the length value is 128 or more. if ((completeToken[1] & 0x80) == 0x80) { // If the indicated value is 128 or more, it shall be represented in two or more octets, // with bit 8 of the first octet set to "1" and the remaining bits of the first octet // specifying the number of additional octets. The subsequent octets carry the value, // 8 bits per octet, most significant digit first. int num = completeToken[1] & 0x7F; index += num; if (num < 1 || num > 4) { throw new FormatException("The GSS-API token length is incorrect!"); } for (int i = 0; i < num; ++i) { length = (length << 8) | completeToken[2 + i]; } } else { // If the indicated value is less than 128, it shall be represented in a single octet with bit 8 // (high order) set to "0" and the remaining bits representing the value. [rfc 2743] length = completeToken[1]; } if (!ArrayUtility.CompareArrays(oid, ArrayUtility.SubArray(completeToken, index, oid.Length))) { throw new FormatException("The GSS-API token oid is incorrect!"); } byte[] tokenBody = ArrayUtility.SubArray(completeToken, index + oid.Length); return(tokenBody); }
public static byte[] EncodeInitialNegToken(byte[] token, KerberosConstValue.OidPkt oidPkt) { int[] oidInt; if (oidPkt == KerberosConstValue.OidPkt.KerberosToken) { oidInt = KerberosConstValue.GetKerberosOidInt(); } else if (oidPkt == KerberosConstValue.OidPkt.MSKerberosToken) { oidInt = KerberosConstValue.GetMsKerberosOidInt(); } else { throw new NotSupportedException("oid not support"); } MechTypeList mechTypeList = new MechTypeList( new MechType[] { new MechType(oidInt) } ); Asn1OctetString octetString = new Asn1OctetString(token); NegTokenInit init = new NegTokenInit(mechTypeList, null, new Asn1OctetString(octetString.ByteArrayValue), new Asn1OctetString((byte[])null)); NegotiationToken negToken = new NegotiationToken(NegotiationToken.negTokenInit, init); MechType spnegoMech = new MechType(KerberosConstValue.GetSpngOidInt()); InitialNegToken initToken = new InitialNegToken(spnegoMech, negToken); Asn1BerEncodingBuffer buffer = new Asn1BerEncodingBuffer(); initToken.BerEncode(buffer); return(buffer.Data); }
/// <summary> /// Construct a Kerberos test client /// </summary> /// <param name="domain">The realm part of the client's principal identifier. /// This argument cannot be null.</param> /// <param name="cName">The account to logon the remote machine. Either user account or computer account /// This argument cannot be null.</param> /// <param name="password">The password of the user. This argument cannot be null.</param> /// <param name="accountType">The type of the logged on account. User or Computer</param> public KerberosTestClient(string domain, string cName, string password, KerberosAccountType accountType, string kdcAddress, int kdcPort, TransportType transportType, KerberosConstValue.OidPkt oidPkt, string salt = null) : base(domain, cName, password, accountType, kdcAddress, kdcPort, transportType, oidPkt, salt) { testSite = TestClassBase.BaseTestSite; if (accountType == KerberosAccountType.Device) { testSite.Log.Add(LogEntryKind.Debug, "Construct Kerberos client using computer account: {0}@{1}.", cName, domain); } else { testSite.Log.Add(LogEntryKind.Debug, "Construct Kerberos client using user account: {0}@{1}.", cName, domain); } EncryptionType[] encryptionTypes = new EncryptionType[] { EncryptionType.AES256_CTS_HMAC_SHA1_96, EncryptionType.AES128_CTS_HMAC_SHA1_96, EncryptionType.RC4_HMAC, EncryptionType.RC4_HMAC_EXP, EncryptionType.DES_CBC_CRC, EncryptionType.DES_CBC_MD5 }; Microsoft.Protocols.TestTools.StackSdk.Security.KerberosLib.KerbInt32[] etypes = new Microsoft.Protocols.TestTools.StackSdk.Security.KerberosLib.KerbInt32[encryptionTypes.Length]; for (int i = 0; i < encryptionTypes.Length; i++) { etypes[i] = new Microsoft.Protocols.TestTools.StackSdk.Security.KerberosLib.KerbInt32((int)encryptionTypes[i]); } Asn1SequenceOf<KerbInt32> etype = new Asn1SequenceOf<KerbInt32>(etypes); Context.SupportedEType = etype; Context.Pvno = KerberosConstValue.KERBEROSV5; }
/// <summary> /// Decode GSSAPI token to AP-REP /// </summary> /// <param name="token">GSSAPI token</param> /// <returns></returns> public KerberosApResponse GetApResponseFromToken(byte[] token, KerberosConstValue.GSSToken gssToken = KerberosConstValue.GSSToken.GSSSPNG) { if (gssToken == KerberosConstValue.GSSToken.GSSSPNG) token = KerberosUtility.DecodeNegotiationToken(token); if (token[0] == KerberosConstValue.KERBEROS_TAG) { byte[] apData = KerberosUtility.VerifyGssApiTokenHeader(token, this.oidPkt); // Check if it has a two-byte tok_id if (null == apData || apData.Length <= sizeof(TOK_ID)) { throw new FormatException( "Data length is shorter than a valid AP Response data length."); } // verify TOK_ID byte[] tokenID = ArrayUtility.SubArray<byte>(apData, 0, sizeof(TOK_ID)); Array.Reverse(tokenID); TOK_ID id = (TOK_ID)BitConverter.ToUInt16(tokenID, 0); this.testSite.Assert.AreEqual(TOK_ID.KRB_AP_REP, id, "The Token ID should be KRB_AP_REP"); // Get apBody token = ArrayUtility.SubArray(apData, sizeof(TOK_ID)); } KerberosApResponse response = new KerberosApResponse(); response.FromBytes(token); return response; }