Added NegTokenInit2 implementation

This commit is contained in:
Tal Aloni 2018-01-04 20:30:22 +02:00
parent 0494fd758f
commit 32edb7993f
3 changed files with 267 additions and 1 deletions

View file

@ -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);
}
}
}

View file

@ -0,0 +1,251 @@
/* Copyright (C) 2018 Tal Aloni <tal.aloni.il@gmail.com>. 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
{
/// <summary>
/// [MS-SPNG] - NegTokenInit2
/// </summary>
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";
}
/// <param name="offset">The offset following the NegTokenInit2 tag</param>
/// <exception cref="System.IO.InvalidDataException"></exception>
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);
}
}
}

View file

@ -37,6 +37,7 @@
<Compile Include="Authentication\GSSAPI\SPNEGO\DerEncodingHelper.cs" />
<Compile Include="Authentication\GSSAPI\SPNEGO\SimpleProtectedNegotiationToken.cs" />
<Compile Include="Authentication\GSSAPI\SPNEGO\SimpleProtectedNegotiationTokenInit.cs" />
<Compile Include="Authentication\GSSAPI\SPNEGO\SimpleProtectedNegotiationTokenInit2.cs" />
<Compile Include="Authentication\GSSAPI\SPNEGO\SimpleProtectedNegotiationTokenResponse.cs" />
<Compile Include="Authentication\LoginCounter.cs" />
<Compile Include="Authentication\NTLM\Helpers\AuthenticationMessageUtils.cs" />