using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.Runtime.InteropServices;
using System.Net;
using System.IO;
using System.Net.Sockets;
using System.Diagnostics;
using System.Security;
namespace Intel.Management.Wsman
{
///
/// Implements an SChannel Client
///
public class SchannelClient : IDisposable
{
SECURITY_HANDLE _hCredHandle;//handle to acquired Credential (FreeCredentialsHandle)
SECURITY_HANDLE _hContext; //handle to the context (DeleteSecurityContext)
UserCredentials _creds; // user credentials
static List _credCache; // credential Cache
static object _credLock = new object(); //thread lock for cached credentials
//package info
uint _cbMaxToken = 0;
string _packageName;
string _target; //name of server or SPN to verify
TcpClient _tcpClient;
static TraceSource _trace = new TraceSource("Intel.Management.Wsman.Schannel");
public SchannelClient(string packageName)
{
_trace.TraceInformation("Request Schannel package for {0}",packageName);
// store package info in a structure (static)
IntPtr pkgPtr;
int status = QuerySecurityPackageInfo(packageName, out pkgPtr);
if (status == 0)
{
SecPkgInfo pkgInfo = SecPkgInfo.FromIntPtr(pkgPtr);
_cbMaxToken = pkgInfo.cbMaxToken;
_packageName = pkgInfo.Name;
status = FreeContextBuffer(pkgPtr);
}
// create a credential cache
lock (_credLock)
{
if (_credCache == null)
_credCache = new List();
}
}
public string Target
{
get { return _target; }
set { _target = value; }
}
public X509Certificate2 GetSessionCerticate()
{
return null;
}
public bool GetSessionInfo(out string SessionId)
{
SessionId = string.Empty;
return false;
}
// acquire credentials for a user
public int AcquireCredentials(string user, string domain, SecureString password)
{
WindowsCredentials winCreds = new WindowsCredentials();
winCreds.UserName = user;
winCreds.DomainName = domain;
winCreds.Password = password;
_creds = winCreds;
int status = 0;
lock (_credLock)
{
long expirers;
status = AcquireCredentials(out expirers);
}
return status;
}
///
/// Acquire credentials for MTLS handshake
///
/// Certificate Credentials
public void AcquireCredentials(X509Certificate2 certificate)
{
AcquireCredentials(certificate, true, true, false);
}
///
/// Acquire credentials for TLS handshake
///
public void AcquireCredentials(X509Certificate2 certificate, bool verifyCa, bool verifyHost, bool sentRoot)
{
_creds = new CertificateCredentials();
if (certificate != null)
{
//_trace.TraceInformation("Acquire Credentials for certificate {0}", certificate.Subject);
((CertificateCredentials)_creds).Certificate = certificate;
((CertificateCredentials)_creds).SkipDefaultCreds();
if (sentRoot)
((CertificateCredentials)_creds).SendRoot();
if (!verifyCa)
((CertificateCredentials)_creds).SkipCACheck();
if (!verifyHost)
((CertificateCredentials)_creds).SkipCNCheck();
}
else
{
_trace.TraceInformation("Acquire Credentials (no certificates specified)");
}
lock (_credLock)
{
long expirers;
int status = AcquireCredentials(out expirers);
}
}
private int AcquireCredentials(out long expiers)
{
// assume the creds are locked when this is called
//CacheItem removeItem = null;
// find exising item in cache existing cred
foreach (CacheItem cacheItem in _credCache)
{
if (cacheItem.Credentials.CompareTo(_creds))
{
_hCredHandle.HighPart=cacheItem.HighPart;
_hCredHandle.LowPart=cacheItem.LowPart;
//get a copy of the connection flags
expiers = cacheItem.Expiers;
_trace.TraceInformation("Found cached credential");
return 0;
} // end cached handle not freed
}//end for
expiers = 0;
int status = AcquireCredentialsHandle(null,
_packageName,
2, //2=SECPKG_CRED_OUTBOUND
IntPtr.Zero, //
_creds, //handle to schannel creds (client certificates)
IntPtr.Zero,
IntPtr.Zero,
ref _hCredHandle, //acquired cred Handle
ref expiers);
if (status == 0)
{
_trace.TraceInformation("Credential Handle {0}", this.GetHandleMessage(ref _hCredHandle));
_trace.TraceInformation("Acquired Credentials added to cache");
_credCache.Add(new CacheItem(_hCredHandle.HighPart, _hCredHandle.LowPart, _creds, expiers));
}
else
{
_trace.TraceInformation("Acquire Credentials returned {0}", GetSchannelMessage(status));
throw new WsmanConnectionException(GetSchannelMessage(status));
}
return status;
}
#region IDisposableMembers
private bool _disposed = false;
public void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
_creds?.Dispose();
_creds = null;
}
_disposed = true;
}
public void Dispose()
{
CloseContext();
Dispose(true);
GC.SuppressFinalize(this);
}
~SchannelClient()
{
Dispose(false);
}
#endregion
public string GetToken(string prevToken)
{
string result = null;
//inFlags = Delegate=1, MutualAuth=2, ReplayDetect=4, SequenceDetect=8, Confidentiality=16, Connection=2048
//allocate memory=256
uint flags = 1 | 2 | 4 | 8 | 16 | 2048 | 256;
long expiers = 0;
uint contextAttr = 0;
int status = 0;
ChannelOutputBuffer outBuff = new ChannelOutputBuffer();
InputBuffer inputBuff = new InputBuffer();
byte[] token = null;
if (prevToken != null)
{
int pos = prevToken.LastIndexOf(" ");
string tokenString = prevToken.Substring(pos + 1);
if (string.Compare(tokenString,"Negotiate",true)!=0)
{
token = Convert.FromBase64String(tokenString);
}
}
if (token==null)
{
CloseContext();
status = InitializeSecurityContextInit(
ref _hCredHandle,
IntPtr.Zero,
_target,
flags, //Delegate=1, MutualAuth=2, ReplayDetect=4, SequenceDetect=8, Confidentiality=16, Connection=2048,
0,
16, //SECURITY_NATIVE_DREP=16
IntPtr.Zero,
0,
ref _hContext,
outBuff,
ref contextAttr,
ref expiers);
}
else
{
inputBuff = new InputBuffer(1);
inputBuff[0].BufferType=BufferType.Token;
inputBuff[0].SetBuffer(token, 0, token.Length);
status = InitializeSecurityContextExchange(
ref _hCredHandle,
IntPtr.Zero,
_target,
flags, //Delegate=1, MutualAuth=2, ReplayDetect=4, SequenceDetect=8, Confidentiality=16, Connection=2048,
0,
16, //SECURITY_NATIVE_DREP=16
inputBuff,
0,
ref _hContext,
outBuff,
ref contextAttr,
ref expiers);
}
_trace.TraceInformation("InitializeSecurityContext({0}) returned {1}", _target, GetSchannelMessage(status));
_trace.TraceInformation("New Context is {0}", _hContext.ToString());
if (status >= 0)
{
result = _packageName + " " + Convert.ToBase64String(outBuff[0].Data, 0, outBuff[0].Data.Length);
}
return result;
}
public void CloseContext()
{
if (!_hContext.LowPart.Equals(IntPtr.Zero) ||
!_hContext.HighPart.Equals(IntPtr.Zero))
{
int status = DeleteSecurityContext(ref _hContext);
if (status == 0)
{
_hContext.HighPart = IntPtr.Zero;
_hContext.LowPart = IntPtr.Zero;
}
}
}
public void CloseNotify()
{
long expiers = 0;
uint contextAttrs = 0;
InputBuffer buffer = new InputBuffer(1);
buffer[0].BufferType=BufferType.Token;
byte[] data = BitConverter.GetBytes((int)1);
buffer[0].SetBuffer(data, 0, data.Length);
int status=ApplyControlToken(ref _hContext,buffer);
_trace.TraceInformation("ApplyControlToken for Shutdown retured {0}", GetSchannelMessage(status));
ChannelOutputBuffer outBuff = new ChannelOutputBuffer();
InputBuffer inBuff = new InputBuffer();
status = InitializeSecurityContext(
ref _hCredHandle,
ref _hContext,
_target,
49436, //ISC_REQ_SEQUENCE_DETECT|ISC_REQ_REPLAY_DETECT|ISC_REQ_CONFIDENTIALITY|ISC_RET_EXTENDED_ERROR |ISC_REQ_ALLOCATE_MEMORY |ISC_REQ_STREAM;
0,
16, //SECURITY_NATIVE_DREP
inBuff,
0,
IntPtr.Zero,
outBuff,
ref contextAttrs,
ref expiers);
_trace.TraceInformation("InitializeSecurityContext for shutdown retured {0}", GetSchannelMessage(status));
if (status == 0)
SendBuffer(outBuff[0]);
_tcpClient = null;
CloseContext();
}
public void WriteMessage(string message)
{
//SECPKG_ATTR_STREAM_SIZES=4
StreamSizeAttribute sizes = new StreamSizeAttribute();
int status = QueryContextAttributes(ref _hContext, 4, sizes);
_trace.TraceInformation("QueryContextAttributes for SECPKG_ATTR_STREAM_SIZES returned {0}", GetSchannelMessage(status));
if (status!=0)
throw new IOException(GetSchannelMessage(status));
byte[] dataString = Encoding.ASCII.GetBytes(message);
byte[] data = new byte[sizes.Header + dataString.Length + sizes.Trailer];
//copy the data into the buffer
Array.Copy(dataString,0,data,sizes.Header,dataString.Length);
InputBuffer input = new InputBuffer(4);
input[0].BufferType = BufferType.StreamHeader;
input[0].SetBuffer(data, 0, sizes.Header);
input[1].BufferType = BufferType.Data;
input[1].SetBuffer(data, sizes.Header, dataString.Length);
input[2].BufferType = BufferType.StreamTrailer;
input[2].SetBuffer(data, sizes.Header + dataString.Length,sizes.Trailer);
input[3].BufferType = BufferType.Empty;
status = EncryptMessage(ref _hContext, 0,input, 0);
_trace.TraceInformation("EncryptMessage returned {0}", GetSchannelMessage(status));
//send the data buffer
int total = input[0].Length + input[1].Length + input[2].Length;
if (status == 0)
_tcpClient.GetStream().Write(data, 0, total);
else
throw new IOException(GetSchannelMessage(status));
_trace.TraceInformation("Encrypted message sent {0} bytes", total);
}
private int ExpectingData(byte[] data)
{
//we have 5 bytes
if (data.Length >= 5)
{
int messageType = (int)data[0];
int majorVersion = (int)data[1];
int minorVersion = (int)data[2];
byte[] sizeArray = { data[4], data[3],0 ,0 };
int len= BitConverter.ToInt32(sizeArray, 0);
}
return 5;
}
public int ReadMessage(byte[] data,int offset,int buffLen)
{
const int SEC_E_OK = 0;
//const int SEC_E_INCOMPLETE_MESSAGE = -2146893032;
const int SEC_I_RENEGOTIATE = 590625;
int status;
InputBuffer input = new InputBuffer(4);
_trace.TraceInformation("Reading data from server");
byte[] tlsData = ReadRecord();
int copyLen = 0;
_trace.TraceInformation("Recieved {0} encrypted bytes from server", tlsData.Length);
input[0].BufferType = BufferType.Data;
input[0].SetBuffer(tlsData, 0, tlsData.Length);
input[1].BufferType = BufferType.Empty;
input[1].SetBuffer(null, 0, 0);
input[2].BufferType = BufferType.Empty;
input[2].SetBuffer(null, 0, 0);
input[3].BufferType = BufferType.Empty;
input[3].SetBuffer(null, 0, 0);
status = DecryptMessage(ref _hContext, input, 0, IntPtr.Zero);
_trace.TraceInformation("DecryptMessage returned {0}", GetSchannelMessage(status));
if (status >= 0)
{
if (status == SEC_I_RENEGOTIATE)
{
throw new IOException();
}
for (int i = 0; i < input.Count; i++)
{
if (input[i].BufferType == BufferType.Data)
{
copyLen = input[i].Length;
if (copyLen > buffLen)
{
copyLen = buffLen;
//store left over for next read
}
//result = new byte[input[i].Length];
Array.Copy(input[i].Data, input[i].Offset, data, 0, copyLen);
}
} //for input[i]
}// if status>0
return copyLen;
}
protected void SendBuffer(SecurityBuffer buffer)
{
if (buffer.Data != null && buffer.Length > 0)
{
_tcpClient.GetStream().Write(buffer.Data, buffer.Offset, buffer.Length);
}
}
public byte[] ReadRecord()
{
// for SSL Record layer potocol verying header is at least 5 bytes
byte[] data = new byte[5];
int offset=0;
int br=0;
do
{
br = _tcpClient.GetStream().Read(data, offset, data.Length-offset);
offset += br;
if (br == 0 && offset > 0)
throw new IOException("Server Unexpecity closed connection");
if (br==0 && offset==0)
return new byte[0];
} while (offset < data.Length);
//we have 5 byte
int messageType = (int)data[0];
int majorVersion = (int)data[1];
int minorVersion = (int)data[2];
byte[] sizeArray = { data[4], data[3], 0, 0 };
int len = BitConverter.ToInt32(sizeArray, 0);
byte[] temp = data;
data = new byte[len + data.Length];
Array.Copy(temp, 0, data, 0, temp.Length);
offset = 5;
br = 0;
do
{
br = _tcpClient.GetStream().Read(data, offset, data.Length - offset);
if (br == 0)
throw new IOException("Server Unexpetily disconnected");
offset += br;
}
while (offset < data.Length);
return data;
}
private void PerformClientLoop(bool doInitialRead)
{
bool doRead = doInitialRead;
int offset = 0;
long exp = 0;
uint contextAttrs;
byte[] data = new byte[_cbMaxToken]; //read from the server
SecurityHandle nullHandle = new NullSecuirtyHandle();
const int SEC_E_OK = 0;
const int SEC_I_CONTINUE_NEEDED = 590610;
const int SEC_E_INCOMPLETE_MESSAGE = -2146893032;
const int SEC_I_INCOMPLETE_CREDENTIALS = 590624;
const int ISC_RET_EXTENDED_ERROR = 16384;
int status = SEC_I_CONTINUE_NEEDED;
while (status == SEC_I_CONTINUE_NEEDED || status == SEC_I_INCOMPLETE_CREDENTIALS ||
status == SEC_E_INCOMPLETE_MESSAGE)
{
if (doRead)
{
offset += _tcpClient.GetStream().Read(data, offset, data.Length - offset);
if (offset == 0)
{
status = SEC_E_INCOMPLETE_MESSAGE;
break;
}
//ExpectingData(data);
}
doRead = true;
//
// Set up the input buffers. Buffer 0 is used to pass in data
// received from the server. Schannel will consume some or all
// of this. Leftover data (if any) will be placed in buffer 1 and
// given a buffer type of SECBUFFER_EXTRA.
//
contextAttrs = 0;
exp = 0;
ChannelOutputBuffer outBuff = new ChannelOutputBuffer();
InputBuffer inBuff = new InputBuffer(2);
inBuff[0].BufferType = BufferType.Token;
inBuff[0].SetBuffer(data, 0, offset);
inBuff[1].BufferType = BufferType.Empty;
status = InitializeSecurityContext(
ref _hCredHandle,
ref _hContext,
_target,
49436, //ISC_REQ_SEQUENCE_DETECT|ISC_REQ_REPLAY_DETECT|ISC_REQ_CONFIDENTIALITY|ISC_RET_EXTENDED_ERROR |ISC_REQ_ALLOCATE_MEMORY |ISC_REQ_STREAM;
0,
16, //SECURITY_NATIVE_DREP
inBuff,
0,
IntPtr.Zero,
outBuff,
ref contextAttrs,
ref exp);
_trace.TraceInformation("InitializeSecurityContext returned {0}", GetSchannelMessage(status));
// If InitializeSecurityContext was successful (or if the error was
// one of the special extended ones), send the contends of the output
// buffer to the server.
//
if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED ||
(status < 0 && (contextAttrs & ISC_RET_EXTENDED_ERROR) > 0))
{
//if (outBuff[0].Length>0) ExpectingData(outBuff[0].Data);
SendBuffer(outBuff[0]);
}
//
// If InitializeSecurityContext returned SEC_E_INCOMPLETE_MESSAGE,
// then we need to read more data from the server and try again.
//
if (status == SEC_E_INCOMPLETE_MESSAGE)
{
continue;
}
if (status == SEC_I_INCOMPLETE_CREDENTIALS)
{
//we have a problem with the credentials
}
//copy extra to offset data
int extraIndex = -1;
for (int i = 0; i < inBuff.Count; i++)
{
if (inBuff[i].BufferType == BufferType.Extra)
{
extraIndex = i;
break;
}
}
if (extraIndex>=0)
{
offset = 0;
Array.Copy(inBuff[extraIndex].Data, 0, data, offset, inBuff[extraIndex].Length);
offset = inBuff[extraIndex].Length;
}
else
{
offset = 0;
}
if (status == SEC_E_OK)
{
// If the "extra" buffer contains data, this is encrypted application
// protocol layer stuff. It needs to be saved. The application layer
// will later decrypt it with DecryptMessage.
//
//value extra buffer
if (offset > 0)
throw new InvalidDataException();
break;
}
}//End while
if (status != SEC_E_OK)
{
//ToDO Fix
//_hContext.Close();
throw new Exception(GetSchannelMessage(status));
}
}
public void PerformHandshake(TcpClient tcpClient)
{
long expiers = 0;
uint contextAttr = 0;
int status = 0;
_tcpClient = tcpClient;
SecurityHandle nullHandle = new NullSecuirtyHandle();
//TODO: release previous context
if (_target == null)
_target = _tcpClient.Client.RemoteEndPoint.ToString();
ChannelOutputBuffer outBuff = new ChannelOutputBuffer();
InputBuffer inputBuff = new InputBuffer();
status = InitializeSecurityContextInit(
ref _hCredHandle,
IntPtr.Zero,
_target,
49436, //ISC_REQ_SEQUENCE_DETECT|ISC_REQ_REPLAY_DETECT|ISC_REQ_CONFIDENTIALITY|ISC_RET_EXTENDED_ERROR |ISC_REQ_ALLOCATE_MEMORY |ISC_REQ_STREAM;
0,
16, //SECURITY_NATIVE_DREP=16
IntPtr.Zero,
0,
ref _hContext,
outBuff,
ref contextAttr,
ref expiers);
_trace.TraceInformation("InitializeSecurityContext({0}) returned {1}", _target, GetSchannelMessage(status));
_trace.TraceInformation("New Context is {0}", this.GetHandleMessage(ref _hCredHandle));
// check the buffer
if (status >= 0)
SendBuffer(outBuff[0]);//send the buffer
if (status > 0)
PerformClientLoop(true);
}
public uint SChannelRequestFlags
{
get
{
//ISC_REQ_SEQUENCE_DETECT |
//ISC_REQ_REPLAY_DETECT |
//ISC_REQ_CONFIDENTIALITY |
//ISC_RET_EXTENDED_ERROR |
//ISC_REQ_ALLOCATE_MEMORY |
//ISC_REQ_STREAM;
return 49436;
}
}
private string GetHandleMessage(ref SECURITY_HANDLE handle)
{
return handle.HighPart + "," + handle.LowPart;
}
public string GetSchannelMessage(int status)
{
string result=string.Empty;
switch ((uint)status)
{
case 0x00000000:
result = "Completed successfully.";
break;
case 0x80090300:
result="Not enough memory is available to complete this request";
break;
case 0x80090301:
result="The handle specified is invalid";
break;
case 0x80090302:
result="The function requested is not supported";
break;
case 0x80090303:
result="The specified target is unknown or unreachable";
break;
case 0x80090304:
result="The Local Security Authority cannot be contacted";
break;
case 0x80090305:
result="The requested security package does not exist";
break;
case 0x80090306:
result="The caller is not the owner of the desired credentials";
break;
case 0x80090307:
result="The security package failed to initialize, and cannot be installed";
break;
case 0x80090308:
result="The token supplied to the function is invalid";
break;
case 0x80090309:
result="The security package is not able to marshall the logon buffer, so the logon attempt has failed";
break;
case 0x8009030A:
result="The per-message Quality of Protection is not supported by the security package";
break;
case 0x8009030B:
result="The security context does not allow impersonation of the client";
break;
case 0x8009030C:
result="The logon attempt failed";
break;
case 0x8009030D:
result="The credentials supplied to the package were not recognized";
break;
case 0x8009030E:
result="No credentials are available in the security package";
break;
case 0x8009030F:
result="The message supplied for verification has been altered";
break;
case 0x80090310:
result="The message supplied for verification is out of sequence";
break;
case 0x80090311:
result="No authority could be contacted for authentication.";
break;
case 0x00090312:
result="The function completed successfully, but must be called again to complete the context";
break;
case 0x00090313:
result="The function completed successfully, but CompleteToken must be called";
break;
case 0x00090314:
result="The function completed successfully, but both CompleteToken and this function must be called to complete the context";
break;
case 0x00090315:
result="The logon was completed, but no network authority was available. The logon was made using locally known information";
break;
case 0x80090316:
result="The requested security package does not exist";
break;
case 0x80090317:
result="The context has expired and can no longer be used.";
break;
case 0x80090318:
result="The supplied message is incomplete. The signature was not verified.";
break;
case 0x00090320:
result="The credentials supplied were not complete, and could not be verified. Additional information can be returned from the context.";
break;
case 0x80090321:
result="The buffers supplied to a function was too small.";
break;
case 0x00090321:
result = "The context data must be renegotiated with the peer.";
break;
case 0x80090322:
result = "The target principal name is incorrect";
break;
case 0x80090325:
result = "The certificate chain was issued by an authority that is not trusted.";
break;
case 0x80090326:
result = "The message recieved was unexpected or badly formatted.";
break;
case 0x80090327:
result = "The certificate recieved from the remote server has not validated correctly";
break;
case 0x80090329:
result = "The specified data could not be encrypted";
break;
case 0x80090330:
result = "The specified data could not be decrypted.";
break;
default:
result = "SChannel Error " + status.ToString("X8");
break;
}
return result;
}
///
/// Security provider for TLS handshake
///
public static string SchannelPackageName
{
get { return "Microsoft Unified Security Protocol Provider"; }
}
///
/// TraceSource for Schannel Tracing
///
public static TraceSource TraceSource
{
get
{
return _trace;
}
}
///
/// Schannel Buffer type
///
protected enum BufferType : int
{
Empty=0,
Data=1,
Token=2,
Params=3,
Missing=4,
Extra=5,
StreamTrailer=6,
StreamHeader=7,
Negotiate=8,
Padding=9,
Stream=10,
}
///
/// An Schannel Security buffer
///
///
protected class SecurityBuffer
{
//Schannal data
int _bufferSize;
BufferType _bufferType;
byte[] _data;
// internal data
int _offset;
public SecurityBuffer()
{
}
public BufferType BufferType
{
get { return _bufferType;}
set { _bufferType=value;}
}
public byte[] Data
{
get { return _data; }
}
public int Length
{
get {return _bufferSize; }
}
public int Offset
{
get { return _offset; }
}
public void SetBuffer(byte[] data,int offset, int len)
{
_data=data;
_offset=offset;
_bufferSize=len;
}
}
///
/// A description of schannel SecurityBuffers
///
/// InputBuffer,ChannelOutputBuffer inherit this
protected class SecurityBufferDescription
{
SecurityBuffer[] _buffers;
protected SecurityBufferDescription()
{
_buffers = new SecurityBuffer[0];
}
protected SecurityBufferDescription(int size)
{
_buffers = new SecurityBuffer[size];
for (int i = 0; i < size; i++)
_buffers[i] = new SecurityBuffer();
}
public SecurityBuffer this[int index]
{
get { return _buffers[index]; }
}
public int Count
{
get { return _buffers.Length; }
}
}
///
/// An Schannel Input buffer
///
/// A buffer size of 0 will result in a null value being marshaled
protected class InputBuffer : SecurityBufferDescription
{
public InputBuffer()
: base(0)
{
}
public InputBuffer(int size)
: base(size)
{
}
}
///
/// An Schannel Allocated output buffer
///
protected class ChannelOutputBuffer : SecurityBufferDescription
{
public ChannelOutputBuffer() : base(1)
{
}
}
///
/// Base definition of a Security Handle
///
protected class SecurityHandle
{
protected SecurityHandle()
{
}
}
///
/// Represents a Null Security Handle
///
protected class NullSecuirtyHandle : SecurityHandle
{
public NullSecuirtyHandle()
: base()
{
}
}
///
/// Base Security Handle with a HI/Low pointers
///
protected class HiLoHandle : SecurityHandle
{
SECURITY_HANDLE _handle;
protected HiLoHandle()
{
_handle.HighPart = IntPtr.Zero;
_handle.LowPart = IntPtr.Zero;
}
public IntPtr HighPart
{
get { return _handle.HighPart; }
set { _handle.HighPart = value; }
}
public IntPtr LowPart
{
get { return _handle.LowPart; }
set { _handle.LowPart = value; }
}
}
///
/// A Security Credential Passed to AcquireCredentialsHandle()
///
protected class UserCredentials : IDisposable
{
public virtual IntPtr MarshalToPtr() { return IntPtr.Zero; }
public virtual bool CompareTo(UserCredentials creds)
{
return false;
}
#region IDisposableMembers
private bool _disposed = false;
protected virtual void Dispose(bool disposing)
{
_disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~UserCredentials()
{
Dispose(false);
}
#endregion
}//End UserCredentials
///
/// A Null Credential Passed to AcquireCredentialsHandle()
///
protected class NullCredential : UserCredentials
{
}// End NullCredential
///
/// A Windows User Credential to
///
protected class WindowsCredentials : UserCredentials
{
string _user;
string _domain;
SecureString _password;
public WindowsCredentials()
: base()
{
}
public string UserName
{
get { return _user; }
set { _user = value; }
}
public string DomainName
{
get { return _domain; }
set { _domain = value; }
}
public SecureString Password
{
get { return _password; }
set
{
_password?.Dispose();
_password = value ?? new SecureString();
}
}
public override IntPtr MarshalToPtr()
{
IntPtr ptr;
SEC_WINNT_AUTH_IDENTITY identity = new SEC_WINNT_AUTH_IDENTITY();
identity.Flags = 2;//Unicode
identity.User = _user;
if (_user == null)
identity.UserLength = 0;
else
identity.UserLength = _user.Length;
identity.Domain = _domain;
if (_domain == null)
identity.DomainLength = 0;
else
identity.DomainLength = _domain.Length;
identity.Password = _password?.Copy();
if (_password == null)
identity.PasswordLength = 0;
else
identity.PasswordLength = _password.Length;
ptr = Marshal.AllocHGlobal(Marshal.SizeOf(identity));
//old struct has nothing to dispose so (true) means nothing
Marshal.StructureToPtr(identity, ptr, false);
return ptr;
}
public override bool CompareTo(UserCredentials creds)
{
if (creds is WindowsCredentials)
{
WindowsCredentials winCreds = (WindowsCredentials)creds;
if (winCreds.DomainName == null || winCreds.UserName == null)
{
return UserName == null && DomainName == null;
}
if (winCreds.UserName.Equals(UserName) &&
winCreds.DomainName.Equals(DomainName))
{
return true;
}
}
return base.CompareTo(creds);
}
#region IDisposableMembers
private bool _disposed = false;
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
base.Dispose(disposing);
if (disposing)
{
_password?.Dispose();
}
_disposed = true;
}
#endregion
}
protected class CertificateCredentials : UserCredentials
{
X509Certificate2 _cert;
uint _flags;
public CertificateCredentials()
: base()
{
}
public override IntPtr MarshalToPtr()
{
IntPtr ptr = IntPtr.Zero;
if (_cert != null || _flags != 0)
{
SCHANNEL_CRED cred = new SCHANNEL_CRED();
cred.dwVersion = 4;//SCHANNEL_CRED_VERSION=4
cred.dwFlags = _flags; //manual verification
//cred.dwFlags = 262168;
cred.cCreds = 0;
if (_cert != null) cred.cCreds = 1;
ptr = Marshal.AllocHGlobal(Marshal.SizeOf(cred) + (IntPtr.Size * (int)cred.cCreds));
if (cred.cCreds > 0)
{
cred.paCred = new IntPtr(ptr.ToInt64() + Marshal.SizeOf(cred));
}
Marshal.StructureToPtr(cred, ptr, false);
if (cred.cCreds > 0)
{
Marshal.WriteIntPtr(cred.paCred, _cert.Handle);
IntPtr tt = Marshal.ReadIntPtr(cred.paCred);
}
}
return ptr;
}
public X509Certificate2 Certificate
{
get { return _cert; }
set { _cert = value; }
}
public void SendRoot()
{
//SCH_CRED_NO_DEFAULT_CREDS=0x00000010;
//SCH_SEND_ROOT_CERT=0x00040000
_flags = _flags |0x00040000 | 0x00000010;
}
public void SkipCNCheck()
{
//SCH_CRED_NO_DEFAULT_CREDS=0x00000010;
//SCH_CRED_NO_SERVERNAME_CHECK = 0x00000004;
_flags = _flags |0x00000004 | 0x00000010;
}
public void SkipCACheck()
{
//SCH_CRED_NO_DEFAULT_CREDS=0x00000010;
//SCH_CRED_MANUAL_CRED_VALIDATION=0x00000008
_flags = _flags |0x00000008 | 0x00000010;
}
public void SkipDefaultCreds()
{
//SCH_CRED_NO_DEFAULT_CREDS=0x00000010;
//SCH_CRED_MANUAL_CRED_VALIDATION=0x00000008
_flags = 0x00000010;
}
public override bool CompareTo(UserCredentials creds)
{
bool certMatch = false;
bool flagMatch = false;
if (creds is CertificateCredentials)
{
CertificateCredentials certCreds = (CertificateCredentials)creds;
if (certCreds.Certificate != null && _cert != null)
{
certMatch = certCreds.Certificate.Thumbprint.Equals(_cert.Thumbprint);
}
else
{
certMatch = certCreds.Certificate == null && _cert == null;
}
flagMatch = certCreds._flags ==_flags;
}
return certMatch && flagMatch;
}
}
///
/// A Cached Credential Item
///
protected class CacheItem
{
IntPtr _highPtr;
IntPtr _lowPtr;
UserCredentials _credentials;
long _expires;
public CacheItem(IntPtr hiPtr,IntPtr lowPtr, UserCredentials auth, long expires)
{
_highPtr = hiPtr;
_lowPtr = lowPtr;
_credentials = auth;
_expires = expires;
}
public UserCredentials Credentials
{
get { return _credentials; }
}
public IntPtr HighPart
{
get { return _highPtr; }
}
public IntPtr LowPart
{
get { return _lowPtr; }
}
public long Expiers
{
get { return _expires; }
}
}
///
/// A Security Context Attribute
///
protected class SecurityAttribute
{
protected SecurityAttribute()
: base()
{
}
public virtual void FreeNavtive(IntPtr ptr)
{
Marshal.FreeHGlobal(ptr);
}
public virtual IntPtr MarshalToNavtive()
{
return IntPtr.Zero;
}
public virtual void MarshalFromNavtive(IntPtr ptr)
{
}
}
///
/// A Security Context Attribute
///
protected class StreamSizeAttribute : SecurityAttribute
{
SecPkgContext_StreamSizes _attribute;
public StreamSizeAttribute()
: base()
{
}
public override IntPtr MarshalToNavtive()
{
IntPtr result = Marshal.AllocHGlobal(Marshal.SizeOf(_attribute));
return result;
}
public override void MarshalFromNavtive(IntPtr ptr)
{
_attribute = (SecPkgContext_StreamSizes)Marshal.PtrToStructure(ptr, typeof(SecPkgContext_StreamSizes));
}
public int Header
{
get { return (int)_attribute.cbHeader; }
}
public int Trailer
{
get { return (int)_attribute.cbTrailer; }
}
public int MaximumMessage
{
get { return (int)_attribute.cbMaximumMessage; }
}
}
///
/// Custom Marshaler for Schannel API Structures
///
/// MashalCookie is used to select Marshaler for the specific type
protected class ChannelMarshaler : ICustomMarshaler
{
object _objectToMashal; // the managed object being marshaled
public ChannelMarshaler()
{
}
public int GetNativeDataSize()
{
return -1;//never gets called?
}
public void CleanUpManagedData(object managedObject)
{
// nothing to clean up
}
public void CleanUpNativeData(IntPtr ptr)
{
if (!ptr.Equals(IntPtr.Zero)) Marshal.FreeCoTaskMem(ptr);
}
public IntPtr MarshalManagedToNative(object managedObject)
{
IntPtr result=IntPtr.Zero;
if (managedObject is NullSecuirtyHandle)
{
_objectToMashal = managedObject;
}
else if (managedObject is HiLoHandle)
{
_objectToMashal = managedObject;
int x = Marshal.SizeOf(typeof(SECURITY_HANDLE));
x.ToString();
result = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(SECURITY_HANDLE)));
Marshal.WriteIntPtr(result, 0, ((HiLoHandle)managedObject).LowPart);
Marshal.WriteIntPtr(result, IntPtr.Size, ((HiLoHandle)managedObject).HighPart);
}
return result;
}
public object MarshalNativeToManaged(IntPtr ptr)
{
if (_objectToMashal is NullSecuirtyHandle)
{
}
else if (_objectToMashal is HiLoHandle)
{
((HiLoHandle)_objectToMashal).LowPart = Marshal.ReadIntPtr(ptr, 0 );
((HiLoHandle)_objectToMashal).HighPart = Marshal.ReadIntPtr(ptr, IntPtr.Size );
}
return _objectToMashal;
}
public static ICustomMarshaler GetInstance(string cookie)
{
ICustomMarshaler result=null;
switch (cookie)
{
case "Input":
result = new InputBufferMarshaler();
break;
case "Output":
result = new OutputBufferMarshaler();
break;
case "Handle":
result = new ChannelMarshaler();
break;
case "Attribute":
result = new AttributeMarshaler();
break;
case "Credential":
result = new CredentialMarshaler();
break;
default:
throw new ArgumentException("Unknown Schannel Marshal Cookie");
}
return result;
}
}
///
/// Attribute Marshaler for Schannel API Structures
///
/// MashalCookie is used to select Marshaler for the specific type
protected class AttributeMarshaler : ICustomMarshaler
{
SecurityAttribute _objectToMarshal;
public AttributeMarshaler()
{
}
public int GetNativeDataSize()
{
return -1;//never gets called?
}
public void CleanUpManagedData(object managedObject)
{
_objectToMarshal = null;
}
public void CleanUpNativeData(IntPtr ptr)
{
_objectToMarshal.FreeNavtive(ptr);
}
public IntPtr MarshalManagedToNative(object managedObject)
{
_objectToMarshal = (SecurityAttribute)managedObject;
return _objectToMarshal.MarshalToNavtive();
}
public object MarshalNativeToManaged(IntPtr ptr)
{
_objectToMarshal.MarshalFromNavtive(ptr);
return _objectToMarshal;
}
}
///
/// Credential Marshaler for Schannel API Structures
///
/// MashalCookie is used to select Marshaler for the specific type
protected class CredentialMarshaler : ICustomMarshaler
{
public CredentialMarshaler()
{
}
public int GetNativeDataSize()
{
return -1;//never gets called?
}
public void CleanUpManagedData(object managedObject)
{
}
public void CleanUpNativeData(IntPtr ptr)
{
//_objectToMarshal.FreeNavtive(ptr);
if (!ptr.Equals(IntPtr.Zero))
Marshal.FreeHGlobal(ptr);
}
public IntPtr MarshalManagedToNative(object managedObject)
{
UserCredentials userCreds = (UserCredentials)managedObject;
return userCreds.MarshalToPtr();
}
public object MarshalNativeToManaged(IntPtr ptr)
{
//_objectToMarshal.MarshalFromNavtive(ptr);
//return _objectToMarshal;
return null;
}
}
///
/// Mashaler for Schannel Allocated OuputBuffers
///
internal class OutputBufferMarshaler : ICustomMarshaler
{
ChannelOutputBuffer _objectToMarshal;
public OutputBufferMarshaler()
{
}
public int GetNativeDataSize()
{
return -1;//never gets called?
}
public void CleanUpManagedData(object managedObject)
{
// nothing to clean up
}
public void CleanUpNativeData(IntPtr ptr)
{
Marshal.FreeHGlobal(ptr);
}
public IntPtr MarshalManagedToNative(object managedObject)
{
IntPtr result = IntPtr.Zero;
_objectToMarshal = (ChannelOutputBuffer)managedObject;
// alocate enough memory
result = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SecBufferDesc)) + Marshal.SizeOf(typeof(SecBuffer)));
//write the description
Marshal.WriteInt32(result, 0, 0); //write SECBUFFER_VERSION
Marshal.WriteInt32(result, sizeof(uint), 1); //write buffer count
//create an array pointer to a buffer
IntPtr pBuffer = new IntPtr(result.ToInt64() + Marshal.SizeOf(typeof(SecBufferDesc)));
Marshal.WriteInt32(pBuffer, 0, 0); //write buffer size
Marshal.WriteInt32(pBuffer, sizeof(uint), (int)BufferType.Token); //write buffer type
Marshal.WriteIntPtr(pBuffer, sizeof(uint) + sizeof(uint), IntPtr.Zero); //write pointer
//write the array pointer
Marshal.WriteIntPtr(result, sizeof(uint) + sizeof(uint), pBuffer); //write buffer count
return result;
}
public object MarshalNativeToManaged(IntPtr ptr)
{
//read the description
int buffSize = Marshal.ReadInt32(ptr, sizeof(uint)); //read buffer count
IntPtr pBuffers = Marshal.ReadIntPtr(ptr, sizeof(uint) + sizeof(uint)); //read buffer
int cb = Marshal.ReadInt32(pBuffers, 0); //read buffer size
IntPtr pCtxData = Marshal.ReadIntPtr(pBuffers, sizeof(uint) + sizeof(uint)); //read buffer
ChannelOutputBuffer result = _objectToMarshal;
if (result==null)
result = new ChannelOutputBuffer();
if (!pCtxData.Equals(IntPtr.Zero) && cb > 0)
{
byte[] data = new byte[cb];
Marshal.Copy(pCtxData, data, 0, data.Length);
int status=FreeContextBuffer(pCtxData);
result[0].SetBuffer(data,0,cb);
}
return result;
}
}
///
/// Mashaler for Schannel InputBuffers
///
internal class InputBufferMarshaler : ICustomMarshaler
{
InputBuffer _objectToMarshal;
public InputBufferMarshaler()
{
}
public int GetNativeDataSize()
{
return -1; //never gets called?
}
public void CleanUpManagedData(object managedObject)
{
}
public void CleanUpNativeData(IntPtr ptr)
{
if (!ptr.Equals(IntPtr.Zero)) Marshal.FreeHGlobal(ptr);
}
public IntPtr MarshalManagedToNative(object managedObject)
{
IntPtr result = IntPtr.Zero;
_objectToMarshal = (InputBuffer)managedObject;
if (_objectToMarshal.Count>0)
{
//calc total size
int total = Marshal.SizeOf(typeof(SecBufferDesc));
total += Marshal.SizeOf(typeof(SecBuffer))*_objectToMarshal.Count;
int dataLen = 0;
//get size of all buffers
for (int i=0;i<_objectToMarshal.Count;i++)
dataLen+=_objectToMarshal[i].Length;
total += dataLen;
result = Marshal.AllocHGlobal(total);
for (int i = 0; i < total; i++)
Marshal.WriteByte(result, i, (byte)0);
//write the description
Marshal.WriteInt32(result, 0, 0); //write SECBUFFER_VERSION
Marshal.WriteInt32(result, sizeof(uint), _objectToMarshal.Count); //write buffer count
//create an array pointer to a buffer
IntPtr pBuffer = new IntPtr(result.ToInt64() + Marshal.SizeOf(typeof(SecBufferDesc)));
Marshal.WriteIntPtr(result, sizeof(uint)+sizeof(uint), pBuffer); //write buffer
int arrayOffset =0;
int dataOffet = Marshal.SizeOf(typeof(SecBufferDesc))+(Marshal.SizeOf(typeof(SecBuffer))*_objectToMarshal.Count);
byte[] baseData = null;
for (int i=0;i<_objectToMarshal.Count;i++)
{
//write buffer size
Marshal.WriteInt32(pBuffer, arrayOffset,_objectToMarshal[i].Length);
//write buffer type
Marshal.WriteInt32(pBuffer, arrayOffset +sizeof(uint),(int)_objectToMarshal[i].BufferType);
if (i == 0)
baseData = _objectToMarshal[i].Data;
//write buffer Pointer
if (_objectToMarshal[i].Length>0)
{
IntPtr dataPtr = new IntPtr(result.ToInt64()+dataOffet);
//only copy the data if its not null (otherwise its uninitalized data)
Marshal.Copy(
baseData,
_objectToMarshal[i].Offset,
dataPtr,
_objectToMarshal[i].Length);
//write pointer
Marshal.WriteIntPtr(pBuffer, arrayOffset+ sizeof(uint) + sizeof(uint), dataPtr);
}
else
Marshal.WriteIntPtr(pBuffer,arrayOffset+ sizeof(uint) + sizeof(uint), IntPtr.Zero);
arrayOffset+=Marshal.SizeOf(typeof(SecBuffer));
dataOffet+=_objectToMarshal[i].Length;
}
}
return result;
}
public object MarshalNativeToManaged(IntPtr ptr)
{
//read the description
int buffNums = Marshal.ReadInt32(ptr, sizeof(uint)); //read buffer count
IntPtr pBuffers = Marshal.ReadIntPtr(ptr, sizeof(uint) + sizeof(uint)); //read buffer
InputBuffer result = _objectToMarshal;
int arrayOffset =0;
long baseLong=0;
byte[] baseData = null;
int prevLen=0;
IntPtr prevBuffer=IntPtr.Zero;
for (int i = 0; i < buffNums; i++)
{
//read buffer size
int buffSize = Marshal.ReadInt32(pBuffers, arrayOffset);
BufferType buffType = (BufferType)Marshal.ReadInt32(pBuffers, arrayOffset +sizeof(uint));
IntPtr buffPtr = Marshal.ReadIntPtr(pBuffers, arrayOffset+ sizeof(uint) + sizeof(uint));
_objectToMarshal[i].BufferType = buffType;
// the buffer is the managed data and Navtive data
if (buffType == BufferType.Extra)
{
int of = prevLen - buffSize;
baseLong = prevBuffer.ToInt64()+of;
buffPtr = new IntPtr( baseLong);
}
if (i == 0)
{
baseLong = buffPtr.ToInt64();
baseData = _objectToMarshal[i].Data;
prevLen = buffSize;
prevBuffer = buffPtr;
}
try
{
_objectToMarshal[i].SetBuffer(baseData, (int)(buffPtr.ToInt64() - baseLong), buffSize);//Conversion from long to int
}
catch (System.OverflowException e)
{
throw new System.OverflowException(e.ToString());
}
if (buffSize > 0 && !buffPtr.Equals(IntPtr.Zero))
{
Marshal.Copy(buffPtr,
baseData,
_objectToMarshal[i].Offset,
buffSize);
}
_objectToMarshal[i].BufferType = buffType; // update the buffer type (should be token ot Extra)
arrayOffset += Marshal.SizeOf(typeof(SecBuffer));
}
return result;
}
}
[DllImport("secur32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int AcquireCredentialsHandle(
string pszPrincipal,
string pszPackage,
int fCredentialUse,
IntPtr PAuthenticationID,
[In, MarshalAs(UnmanagedType.CustomMarshaler,
MarshalTypeRef = typeof(ChannelMarshaler), MarshalCookie = "Credential")]
UserCredentials pAuthData,
IntPtr pGetKeyFn,
IntPtr pvGetKeyArgument,
ref SECURITY_HANDLE phCredential,
ref long ptsExpiry);
[DllImport("secur32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int InitializeSecurityContext(
ref SECURITY_HANDLE phCredential,
ref SECURITY_HANDLE phContext,
string pszTargetName,
uint fContextReq,
uint Reserved1,
uint TargetDataRep,
[In, Out, MarshalAs(UnmanagedType.CustomMarshaler,
MarshalTypeRef = typeof(ChannelMarshaler), MarshalCookie = "Input")]
SecurityBufferDescription pInput,
uint Reserved2,
IntPtr hNewContext,
[In,Out,MarshalAs(UnmanagedType.CustomMarshaler,
MarshalTypeRef = typeof(ChannelMarshaler), MarshalCookie = "Output")]
SecurityBufferDescription pOutput,
ref uint pfContextAttr,
ref long ptsExpiry);
[DllImport("secur32.dll", EntryPoint = "InitializeSecurityContext", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int InitializeSecurityContextInit(
ref SECURITY_HANDLE phCredential,
IntPtr phContext, //this is null on input
string pszTargetName,
uint fContextReq,
uint Reserved1,
uint TargetDataRep,
IntPtr pInput, //this is null on init call
uint Reserved2,
ref SECURITY_HANDLE hNewContext, // this is output
[In, Out, MarshalAs(UnmanagedType.CustomMarshaler,
MarshalTypeRef = typeof(ChannelMarshaler), MarshalCookie = "Output")]
SecurityBufferDescription pOutput,
ref uint pfContextAttr,
ref long ptsExpiry);
[DllImport("secur32.dll", EntryPoint = "InitializeSecurityContext", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int InitializeSecurityContextExchange(
ref SECURITY_HANDLE phCredential,
IntPtr pContext, //this is null on exhange
string pszTargetName,
uint fContextReq,
uint Reserved1,
uint TargetDataRep,
[In, Out, MarshalAs(UnmanagedType.CustomMarshaler,
MarshalTypeRef = typeof(ChannelMarshaler), MarshalCookie = "Input")]
SecurityBufferDescription pInput,
uint Reserved2,
ref SECURITY_HANDLE hNewContext, // this is output
[In, Out, MarshalAs(UnmanagedType.CustomMarshaler,
MarshalTypeRef = typeof(ChannelMarshaler), MarshalCookie = "Output")]
SecurityBufferDescription pOutput,
ref uint pfContextAttr,
ref long ptsExpiry);
[DllImport("secur32.dll", SetLastError = true)]
private static extern int EncryptMessage(
ref SECURITY_HANDLE hContext,
uint fQoP,
[In,Out, MarshalAs(UnmanagedType.CustomMarshaler,
MarshalTypeRef = typeof(ChannelMarshaler), MarshalCookie = "Input")]
SecurityBufferDescription buffer,
ulong seqNum);
[DllImport("secur32.dll", SetLastError = true)]
private static extern int DecryptMessage(
ref SECURITY_HANDLE hContext,
[In, Out, MarshalAs(UnmanagedType.CustomMarshaler,
MarshalTypeRef = typeof(ChannelMarshaler), MarshalCookie = "Input")]
SecurityBufferDescription buffer,
ulong seqNum,
IntPtr fQoP
);
[DllImport("secur32.dll", SetLastError = true)]
private static extern int ApplyControlToken(
ref SECURITY_HANDLE hContext,
[In, Out, MarshalAs(UnmanagedType.CustomMarshaler,
MarshalTypeRef = typeof(ChannelMarshaler), MarshalCookie = "Input")]
SecurityBufferDescription buffer);
[DllImport("secur32.dll", SetLastError = true)]
private static extern int FreeContextBuffer(IntPtr ptrToBuffer);
[DllImport("secur32.dll", SetLastError = true)]
private static extern int DeleteSecurityContext(
ref SECURITY_HANDLE hContext);
[DllImport("secur32.dll", SetLastError = true)]
private static extern int FreeCredentialsHandle(
ref SECURITY_HANDLE phCredHandle);
[DllImport("secur32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int QuerySecurityPackageInfo(
string packageName,
out IntPtr packageInfo);
[DllImport("secur32.dll", SetLastError = true)]
private static extern int QueryContextAttributes(
ref SECURITY_HANDLE hContext,
uint ulAttribute,
[In,Out, MarshalAs(UnmanagedType.CustomMarshaler,
MarshalTypeRef = typeof(ChannelMarshaler), MarshalCookie = "Attribute")]
SecurityAttribute buffer);
[StructLayout(LayoutKind.Sequential)]
private struct SecPkgContext_StreamSizes
{
public uint cbHeader;
public uint cbTrailer;
public uint cbMaximumMessage;
public uint cBuffers;
public uint cbBlockSize;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct SEC_WINNT_AUTH_IDENTITY
{
public string User;
public int UserLength;
public string Domain;
public int DomainLength;
public SecureString Password;
public int PasswordLength;
public int Flags;//UNICODE=2,ASNI=1
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct SecPkgInfo
{
public uint fCapabilities;
public ushort wVersion;
public ushort wRPCID;
public uint cbMaxToken;
public string Name;
public string Comment;
public static SecPkgInfo FromIntPtr(IntPtr ptr)
{
return (SecPkgInfo)Marshal.PtrToStructure(ptr, typeof(SecPkgInfo));
}
}
[StructLayout(LayoutKind.Sequential)]
private struct SCHANNEL_CRED
{
public uint dwVersion;
public uint cCreds;
public IntPtr paCred;
public IntPtr hRootStore;
public uint cMappers;
public IntPtr aphMappers;
public uint cSupportedAlgs;
public IntPtr palgSupportedAlgs;
public uint grbitEnabledProtocols;
public uint dwMinimumCipherStrength;
public uint dwMaximumCipherStrength;
public uint dwSessionLifespan;
public uint dwFlags;
public uint dwCredFormat;
}
[StructLayout(LayoutKind.Sequential)]
private struct SECURITY_HANDLE
{
public IntPtr LowPart;
public IntPtr HighPart;
}
[StructLayout(LayoutKind.Sequential)]
private struct SecBufferDesc
{
public uint ulVersion;// Version number SECBUFFER_VERSION=0
public uint cBuffers;// Number of buffers
public IntPtr pBuffers;
}
[StructLayout(LayoutKind.Sequential)]
private struct SecBuffer
{
public uint cbBuffer;
public uint BufferType;
public IntPtr pvBuffer;
public static IntPtr Create(int size)
{
SecBuffer outBuffer = new SecBuffer();
IntPtr result = Marshal.AllocHGlobal(Marshal.SizeOf(outBuffer)*size);
//zero fill
for (int i = 0; i < (Marshal.SizeOf(outBuffer) * size); i++)
Marshal.WriteByte(result, i, 0);
return result;
}
}
} //end class
}//end namespace