From 32edb7993ff1758ab71cf97cecda24f3c4e0ba8f Mon Sep 17 00:00:00 2001 From: Tal Aloni Date: Thu, 4 Jan 2018 20:30:22 +0200 Subject: [PATCH] Added NegTokenInit2 implementation --- .../GSSAPI/SPNEGO/DerEncodingHelper.cs | 16 +- .../SimpleProtectedNegotiationTokenInit2.cs | 251 ++++++++++++++++++ SMBLibrary/SMBLibrary.csproj | 1 + 3 files changed, 267 insertions(+), 1 deletion(-) create mode 100644 SMBLibrary/Authentication/GSSAPI/SPNEGO/SimpleProtectedNegotiationTokenInit2.cs diff --git a/SMBLibrary/Authentication/GSSAPI/SPNEGO/DerEncodingHelper.cs b/SMBLibrary/Authentication/GSSAPI/SPNEGO/DerEncodingHelper.cs index b6c94bd..c5c1e7b 100644 --- a/SMBLibrary/Authentication/GSSAPI/SPNEGO/DerEncodingHelper.cs +++ b/SMBLibrary/Authentication/GSSAPI/SPNEGO/DerEncodingHelper.cs @@ -6,15 +6,17 @@ */ using System; using System.Collections.Generic; +using System.Text; using Utilities; namespace SMBLibrary.Authentication.GSSAPI { public enum DerEncodingTag : byte { - ByteArray = 0x04, + ByteArray = 0x04, // Octet String ObjectIdentifier = 0x06, Enum = 0x0A, + GeneralString = 0x1B, Sequence = 0x30, } @@ -78,5 +80,17 @@ namespace SMBLibrary.Authentication.GSSAPI return 1; } } + + public static byte[] EncodeGeneralString(string value) + { + // We do not support character-set designation escape sequences + return ASCIIEncoding.ASCII.GetBytes(value); + } + + public static string DecodeGeneralString(byte[] bytes) + { + // We do not support character-set designation escape sequences + return ASCIIEncoding.ASCII.GetString(bytes); + } } } diff --git a/SMBLibrary/Authentication/GSSAPI/SPNEGO/SimpleProtectedNegotiationTokenInit2.cs b/SMBLibrary/Authentication/GSSAPI/SPNEGO/SimpleProtectedNegotiationTokenInit2.cs new file mode 100644 index 0000000..4c12bc1 --- /dev/null +++ b/SMBLibrary/Authentication/GSSAPI/SPNEGO/SimpleProtectedNegotiationTokenInit2.cs @@ -0,0 +1,251 @@ +/* Copyright (C) 2018 Tal Aloni . All rights reserved. + * + * You can redistribute this program and/or modify it under the terms of + * the GNU Lesser Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + */ +using System; +using System.Collections.Generic; +using System.IO; +using Utilities; + +namespace SMBLibrary.Authentication.GSSAPI +{ + /// + /// [MS-SPNG] - NegTokenInit2 + /// + public class SimpleProtectedNegotiationTokenInit2 : SimpleProtectedNegotiationTokenInit + { + public const byte NegHintsTag = 0xA3; + new public const byte MechanismListMICTag = 0xA4; + + public const byte HintNameTag = 0xA0; + public const byte HintAddressTag = 0xA1; + + public string HintName; + public byte[] HintAddress; + + public SimpleProtectedNegotiationTokenInit2() + { + HintName = "not_defined_in_RFC4178@please_ignore"; + } + + /// The offset following the NegTokenInit2 tag + /// + public SimpleProtectedNegotiationTokenInit2(byte[] buffer, int offset) + { + int constructionLength = DerEncodingHelper.ReadLength(buffer, ref offset); + byte tag = ByteReader.ReadByte(buffer, ref offset); + if (tag != (byte)DerEncodingTag.Sequence) + { + throw new InvalidDataException(); + } + int sequenceLength = DerEncodingHelper.ReadLength(buffer, ref offset); + int sequenceEndOffset = offset + sequenceLength; + while (offset < sequenceEndOffset) + { + tag = ByteReader.ReadByte(buffer, ref offset); + if (tag == MechanismTypeListTag) + { + MechanismTypeList = ReadMechanismTypeList(buffer, ref offset); + } + else if (tag == RequiredFlagsTag) + { + throw new NotImplementedException("negTokenInit.ReqFlags is not implemented"); + } + else if (tag == MechanismTokenTag) + { + MechanismToken = ReadMechanismToken(buffer, ref offset); + } + else if (tag == NegHintsTag) + { + HintName = ReadHints(buffer, ref offset, out HintAddress); + } + else if (tag == MechanismListMICTag) + { + MechanismListMIC = ReadMechanismListMIC(buffer, ref offset); + } + else + { + throw new InvalidDataException("Invalid negTokenInit structure"); + } + } + } + + public override byte[] GetBytes() + { + int sequenceLength = GetTokenFieldsLength(); + int sequenceLengthFieldSize = DerEncodingHelper.GetLengthFieldSize(sequenceLength); + int constructionLength = 1 + sequenceLengthFieldSize + sequenceLength; + int constructionLengthFieldSize = DerEncodingHelper.GetLengthFieldSize(constructionLength); + int bufferSize = 1 + constructionLengthFieldSize + 1 + sequenceLengthFieldSize + sequenceLength; + byte[] buffer = new byte[bufferSize]; + int offset = 0; + ByteWriter.WriteByte(buffer, ref offset, NegTokenInitTag); + DerEncodingHelper.WriteLength(buffer, ref offset, constructionLength); + ByteWriter.WriteByte(buffer, ref offset, (byte)DerEncodingTag.Sequence); + DerEncodingHelper.WriteLength(buffer, ref offset, sequenceLength); + if (MechanismTypeList != null) + { + WriteMechanismTypeList(buffer, ref offset, MechanismTypeList); + } + if (MechanismToken != null) + { + WriteMechanismToken(buffer, ref offset, MechanismToken); + } + if (HintName != null || HintAddress != null) + { + WriteHints(buffer, ref offset, HintName, HintAddress); + } + if (MechanismListMIC != null) + { + WriteMechanismListMIC(buffer, ref offset, MechanismListMIC); + } + return buffer; + } + + protected override int GetTokenFieldsLength() + { + int result = base.GetTokenFieldsLength();; + if (HintName != null || HintAddress != null) + { + int hintsSequenceLength = GetHintsSequenceLength(HintName, HintAddress); + int hintsSequenceLengthFieldSize = DerEncodingHelper.GetLengthFieldSize(hintsSequenceLength); + int hintsSequenceConstructionLength = 1 + hintsSequenceLengthFieldSize + hintsSequenceLength; + int hintsSequenceConstructionLengthFieldSize = DerEncodingHelper.GetLengthFieldSize(hintsSequenceConstructionLength); + int entryLength = 1 + hintsSequenceConstructionLengthFieldSize + 1 + hintsSequenceLengthFieldSize + hintsSequenceLength; + result += entryLength; + } + return result; + } + + protected static string ReadHints(byte[] buffer, ref int offset, out byte[] hintAddress) + { + string hintName = null; + hintAddress = null; + int constructionLength = DerEncodingHelper.ReadLength(buffer, ref offset); + byte tag = ByteReader.ReadByte(buffer, ref offset); + if (tag != (byte)DerEncodingTag.Sequence) + { + throw new InvalidDataException(); + } + int sequenceLength = DerEncodingHelper.ReadLength(buffer, ref offset); + int sequenceEndOffset = offset + sequenceLength; + while (offset < sequenceEndOffset) + { + tag = ByteReader.ReadByte(buffer, ref offset); + if (tag == HintNameTag) + { + hintName = ReadHintName(buffer, ref offset); + } + else if (tag == HintAddressTag) + { + hintAddress = ReadHintAddress(buffer, ref offset); + } + else + { + throw new InvalidDataException(); + } + } + return hintName; + } + + protected static string ReadHintName(byte[] buffer, ref int offset) + { + int constructionLength = DerEncodingHelper.ReadLength(buffer, ref offset); + byte tag = ByteReader.ReadByte(buffer, ref offset); + if (tag != (byte)DerEncodingTag.GeneralString) + { + throw new InvalidDataException(); + } + int hintLength = DerEncodingHelper.ReadLength(buffer, ref offset); + byte[] hintNameBytes = ByteReader.ReadBytes(buffer, ref offset, hintLength); + return DerEncodingHelper.DecodeGeneralString(hintNameBytes); + } + + protected static byte[] ReadHintAddress(byte[] buffer, ref int offset) + { + int constructionLength = DerEncodingHelper.ReadLength(buffer, ref offset); + byte tag = ByteReader.ReadByte(buffer, ref offset); + if (tag != (byte)DerEncodingTag.ByteArray) + { + throw new InvalidDataException(); + } + int hintLength = DerEncodingHelper.ReadLength(buffer, ref offset); + return ByteReader.ReadBytes(buffer, ref offset, hintLength); + } + + protected static int GetHintsSequenceLength(string hintName, byte[] hintAddress) + { + int sequenceLength = 0; + if (hintName != null) + { + byte[] hintNameBytes = DerEncodingHelper.EncodeGeneralString(hintName); + int lengthFieldSize = DerEncodingHelper.GetLengthFieldSize(hintNameBytes.Length); + int constructionLength = 1 + lengthFieldSize + hintNameBytes.Length; + int constructionLengthFieldSize = DerEncodingHelper.GetLengthFieldSize(constructionLength); + int entryLength = 1 + constructionLengthFieldSize + 1 + lengthFieldSize + hintNameBytes.Length; + sequenceLength += entryLength; + } + if (hintAddress != null) + { + int lengthFieldSize = DerEncodingHelper.GetLengthFieldSize(hintAddress.Length); + int constructionLength = 1 + lengthFieldSize + hintAddress.Length; + int constructionLengthFieldSize = DerEncodingHelper.GetLengthFieldSize(constructionLength); + int entryLength = 1 + constructionLengthFieldSize + 1 + lengthFieldSize + hintAddress.Length; + sequenceLength += entryLength; + } + return sequenceLength; + } + + private static void WriteHints(byte[] buffer, ref int offset, string hintName, byte[] hintAddress) + { + int sequenceLength = GetHintsSequenceLength(hintName, hintAddress); + int sequenceLengthFieldSize = DerEncodingHelper.GetLengthFieldSize(sequenceLength); + int constructionLength = 1 + sequenceLengthFieldSize + sequenceLength; + ByteWriter.WriteByte(buffer, ref offset, NegHintsTag); + DerEncodingHelper.WriteLength(buffer, ref offset, constructionLength); + ByteWriter.WriteByte(buffer, ref offset, (byte)DerEncodingTag.Sequence); + DerEncodingHelper.WriteLength(buffer, ref offset, sequenceLength); + if (hintName != null) + { + WriteHintName(buffer, ref offset, hintName); + } + if (hintAddress != null) + { + WriteHintAddress(buffer, ref offset, hintAddress); + } + } + + private static void WriteHintName(byte[] buffer, ref int offset, string hintName) + { + byte[] hintNameBytes = DerEncodingHelper.EncodeGeneralString(hintName); + int constructionLength = 1 + DerEncodingHelper.GetLengthFieldSize(hintNameBytes.Length) + hintNameBytes.Length; + ByteWriter.WriteByte(buffer, ref offset, HintNameTag); + DerEncodingHelper.WriteLength(buffer, ref offset, constructionLength); + ByteWriter.WriteByte(buffer, ref offset, (byte)DerEncodingTag.GeneralString); + DerEncodingHelper.WriteLength(buffer, ref offset, hintNameBytes.Length); + ByteWriter.WriteBytes(buffer, ref offset, hintNameBytes); + } + + private static void WriteHintAddress(byte[] buffer, ref int offset, byte[] hintAddress) + { + int constructionLength = 1 + DerEncodingHelper.GetLengthFieldSize(hintAddress.Length) + hintAddress.Length; + ByteWriter.WriteByte(buffer, ref offset, HintAddressTag); + DerEncodingHelper.WriteLength(buffer, ref offset, constructionLength); + ByteWriter.WriteByte(buffer, ref offset, (byte)DerEncodingTag.ByteArray); + DerEncodingHelper.WriteLength(buffer, ref offset, hintAddress.Length); + ByteWriter.WriteBytes(buffer, ref offset, hintAddress); + } + + new protected static void WriteMechanismListMIC(byte[] buffer, ref int offset, byte[] mechanismListMIC) + { + int mechanismListMICLengthFieldSize = DerEncodingHelper.GetLengthFieldSize(mechanismListMIC.Length); + ByteWriter.WriteByte(buffer, ref offset, MechanismListMICTag); + DerEncodingHelper.WriteLength(buffer, ref offset, 1 + mechanismListMICLengthFieldSize + mechanismListMIC.Length); + ByteWriter.WriteByte(buffer, ref offset, (byte)DerEncodingTag.ByteArray); + DerEncodingHelper.WriteLength(buffer, ref offset, mechanismListMIC.Length); + ByteWriter.WriteBytes(buffer, ref offset, mechanismListMIC); + } + } +} diff --git a/SMBLibrary/SMBLibrary.csproj b/SMBLibrary/SMBLibrary.csproj index 44ee14e..31f6dd7 100644 --- a/SMBLibrary/SMBLibrary.csproj +++ b/SMBLibrary/SMBLibrary.csproj @@ -37,6 +37,7 @@ +