.NET SslStream: How to extract session key? - c#

I'm writing a desktop application and wish to give users ability to verify network traffic, so they know they are not being abused. My application establishes a TLS connection to servers using .NET's SslStream with the AuthenticateAsClient method. Wireshark users can decode TLS traffic using NSS key logs. I can see that both Firefox and Chrome have options to logging encryption keys. How can I do the same in my .NET application? i.e. How can I extract the session key from SslStream, programatically?

As of this writing, there is no way of doing that with dotnet's SslStream. Here's how to export the session keys using BouncyCastle:
internal static class BouncyCastleTls
{
public static Stream WrapWithTls(Stream stream)
{
var client = new MyTlsClient();
var tlsClientProtocol = new TlsClientProtocol(stream, new SecureRandom());
tlsClientProtocol.Connect(client);
return tlsClientProtocol.Stream;
}
}
internal sealed class MyTlsClient : DefaultTlsClient
{
public override TlsAuthentication GetAuthentication()
{
return new MyTlsAuthentication();
}
public override void NotifyHandshakeComplete()
{
var clientRandom = mContext.SecurityParameters.ClientRandom;
var masterSecret = mContext.SecurityParameters.MasterSecret;
Console.WriteLine("CLIENT_RANDOM {0} {1}", ToHex(clientRandom), ToHex(masterSecret));
}
private static string ToHex(byte[] bytes)
{
var sb = new StringBuilder(bytes.Length * 2);
for (var i = 0; i < bytes.Length; ++i)
sb.Append($"{bytes[i]:x2}");
return sb.ToString();
}
}
internal sealed class MyTlsAuthentication : TlsAuthentication
{
public void NotifyServerCertificate(Certificate serverCertificate)
{
}
public TlsCredentials GetClientCredentials(CertificateRequest certificateRequest)
{
return null;
}
}

Related

The smart card has been reset, so any shared state information is invalid

I am using PCSC Nuget library for accessing a smart card applets.
I created a load test with JMeter, where there are 20 threads hitting web api endpoint which calls a smart card for some data.
After a while and successful responses, I get this error:
PCSC.Exceptions.PCSCException: 'The smart card has been reset, so any shared state information is invalid.'
Exception is thrown on reader.Transmit call when I send APDU to select appropriate smart card applet.
I all my interface method implementations I am using a lock object and the SmartCard class object is created as a singleton.
public class SmartCard
{
private readonly object lockObj = new object();
public bool SmartCardMethod1(string data)
{
lock (lockObj)
{
using (var reader = GetReader())
{
var responseSCard = reader.Transmit(CreateAPDUCommand1(reader, data));
}
}
}
public bool SmartCardMethod2(string data)
{
lock (lockObj)
{
using (var reader = GetReader())
{
var responseSCard = reader.Transmit(CreateAPDUCommand2(reader, data));
}
}
}
private IsoReader GetReader()
{
if (!string.IsNullOrEmpty(_readerName))
{
SCardContext hContext = new SCardContext();
hContext.Establish(SCardScope.System);
var reader = new IsoReader(hContext);
reader.Connect(_readerName,
SCardShareMode.Shared,
SCardProtocol.T0 | SCardProtocol.T1);
var response = reader.Transmit(CreateSelectAppletAPDUCommand(reader));
if (response.SW1 == 0x90)
{
return reader;
}
}
}
}
I am getting this error on this line:
var response = reader.Transmit(CreateSelectAppletAPDUCommand(reader));

Need to access a serial port from different classes

I am using a serial port object that was generated by the designer in C# (non static).
I need to be able to access it from methods that are static in different classes (I know it is a bad practice but that is what I inherit)
The port access use the below code.
public bool Read_Board_Port()
{
byte[] bData = new byte[256];
string message;
bool sucess = false;
try
{
if (!(serialBoardPort.IsOpen == true))
Connect_To_Board(Globals.BoardportName, Globals.BoardbaudRate, Globals.Boardparity, Globals.BoardstopBits, Globals.BoarddataBits);
if(CMDDirect || Globals.HostCommandString)
{
serialBoardPort.ReadTimeout = 1000; // Timeout if no answer from the port.
message = serialBoardPort.ReadLine();
Globals.RXBoardBuff = Encoding.UTF8.GetBytes(message);
Write_To_Console_Dr(message);
sucess = true;
}
else
{
serialBoardPort.Read(Globals.RXBoardBuff, 0, Constants.RXBOARDBUFFSIZE);
if (Check_Command_Correct(Globals.RXBoardBuff, Globals.CommandOut))
sucess = true;
else
{
Write_Error_To_Console_Dr(Constants.ERRORDATAFROMBOARDPORT);
sucess = false;
}
}
}
catch
{
MessageBox.Show(Constants.ERRORNODATABOARPORT);
sucess = false;
}
return sucess;
}
If I declare new a different instance of the serial port will be used, I need to use the port that is already open.
Thanks
As stated by #Matthew Spencer you should pass the serial port as a parameter to the static methods that needs it. First create a method on your board class or whatever its name is that returns the instance of your serial port. Then use it to get the serial port for use to the static methods you mentioned.
Something like this should be what you need..
public bool Read_Board_Port()
{
byte[] bData = new byte[256];
string message;
bool sucess = false;
try
{
if (!(serialBoardPort.IsOpen == true))
Connect_To_Board(Globals.BoardportName, Globals.BoardbaudRate, Globals.Boardparity, Globals.BoardstopBits, Globals.BoarddataBits);
if(CMDDirect || Globals.HostCommandString)
{
serialBoardPort.ReadTimeout = 1000; // Timeout if no answer from the port.
message = serialBoardPort.ReadLine();
Globals.RXBoardBuff = Encoding.UTF8.GetBytes(message);
Write_To_Console_Dr(message);
sucess = true;
}
else
{
serialBoardPort.Read(Globals.RXBoardBuff, 0, Constants.RXBOARDBUFFSIZE);
if (Check_Command_Correct(Globals.RXBoardBuff, Globals.CommandOut))
sucess = true;
else
{
Write_Error_To_Console_Dr(Constants.ERRORDATAFROMBOARDPORT);
sucess = false;
}
}
}
catch
{
MessageBox.Show(Constants.ERRORNODATABOARPORT);
sucess = false;
}
return sucess;
}
// since serialBoardPort seems to be a globally declared variable
public SerialPort GetInstance()
{
return serialBoardPort;
}
// Let's name your class as board..
// on somewhere in your app code:
Board board = // GetValue
SerialPort boardSerialPort = board.GetInstance();
ClassXXX.StaticMethodNeedsPort(boardSerialPort); // pass your serial port to the static method
UPDATE: Since there was a bit of misunderstanding as the questioner said..
I suggest using an IoC container, read more here
Here is what I use. Normally this is already a part of frameworks such as MVVM Cross.
CODE:
public class Core
{
private static readonly Core instance = new Core();
private Dictionary<Type, object> container;
private Core()
{
container = new Dictionary<Type, object>();
}
public void RegisterSingleton<T>(T value) where T : class
{
Type type = typeof(T);
if (!container.ContainsKey(type))
container.Add(type, value);
}
public T GetSingleton<T>() where T : class
{
Type type = typeof(T);
if (container.ContainsKey(type))
return (T)container[type];
else
throw new Exception("Singleton instance not registered.");
}
public void RemoveSingleton<T>() where T : class
{
Type type = typeof(T);
if (container.ContainsKey(type))
container.Remove(type);
}
public void ClearSingletons()
{
container.Clear();
}
public static Core Instance
{
get { return instance; }
}
}
When your application loads add this line:
Core.Instance.ClearSingletons();
In case it already has a port upon loading since it is auto-generated by C# just register the instance too..
Core.Instance.RegisterSingleton(MySerialPortObject); // Or class. Can be object
On the part of the application when you need the port just get its instance like this...
SerialPort _myPort = Core.Instance.GetSingleton<X>(); // Where X value is the type of your registered object. If you are registering a SerialPort then replace X with SerialPort.
You can get the instance of your port anywhere you like. When I use this I normally register implementation of interfaces so that I can get it like
IFileHandler _fileHandler = Core.Instance.GetSingleton<IFileHandler>() // Where I registered the class that implements IFileHandler upon the startup of my application
Sorry for the long answer.

Extracting packet details in c#

I want to implement following functionality :
fetching one by one packets from pcap file. I need to separate packets depending on their protocol type. so basically i should be able to change packet objects like ip address
language i am using is c#
So is this possible to implement using Pcap.net ?
Is there standard code available with anybody ? please provide me that.
Thanks a lot
ftm
Yes, it is possible.
See "Reading packets from a dump file" in Pcap.Net's tutorial.
first, download PcapDotNet.Core.dll and PcapDotNet.Packets.dll and after create a class
public class Session
{
private IList<Packet> _PacketsSequence;
public IList<Packet> PacketsSequence
{
get
{
if (_PacketsSequence == null)
_PacketsSequence = new List<Packet>();
return _PacketsSequence;
}
set { _PacketsSequence = value; }
}
}
then create the class
public class PacketParser
{
private List<Session> _TermonatedSessions;
private IList<Session> _Sessions;
private IDictionary<int, List<Packet>> _Buffer;
public PacketParser()
{
_TermonatedSessions = new List<Session>();
_Sessions = new List<Session>();
_Buffer = new Dictionary<int, List<Packet>>();
}
public void ParsePacket(string filePath)
{
OfflinePacketDevice selectedDevice = new OfflinePacketDevice(filePath);
using (PacketCommunicator communicator = selectedDevice.Open(65536, PacketDeviceOpenAttributes.Promiscuous, 1000))
{
try
{
communicator.ReceivePackets(0, AnalyzeCurrentPacket);
}
catch { }
}
var AnalyzedSession = CombineOpenCloseSessions();
}
private IList<Session> CombineOpenCloseSessions()
{
_TermonatedSessions.AddRange(_Sessions);
_Sessions.Clear();
_Buffer.Clear();
return _TermonatedSessions;
}
}

Best way to implement a request response pattern that is extendable

OK,
I have to create a C# library that can send commands to a device and process the command specific responses and broadcasts over a serial port (or other communications method). The library must also be able to handle request and response extensions held in other libraries as certain devices implement an extended command set, but it must be possible to choose whether these extended commands are utilised (I guess using reflection in the client app). I have created a class of type Packet that is able to create the packet and add its payload, calculate its checksum and write the packet to the stream.
public class Packet
{
internal PacketHeaderType Header { get; private set; }
internal List<byte> Payload { get; private set; }
protected int PayloadLength { get { return Payload.Count; } }
protected byte HeaderByte { get { return (byte)((Convert.ToByte(Header) << 4) | PayloadLength); } } //we need to add the packet length to the lower nibble of the header before sending
public Packet(PacketHeaderType header, List<byte> payload)
{
this.Header = header;
this.Payload = new List<byte>(payload);
}
public Packet(PacketHeaderType headerByte)
{
this.Header = headerByte;
this.Payload = new List<byte>();
}
internal byte XorByte
{
get
{
Byte xorByte = Convert.ToByte(HeaderByte);
for (int i = 0; i < PayloadLength; i++)
xorByte ^= Payload.ToArray()[i];
return xorByte;
}
}
public async Task WriteAsync(Stream stream, bool flush = true, CancellationToken token = default(CancellationToken))
{
var buffer = new List<byte>();
buffer.Add(HeaderByte);
if (Payload != null && PayloadLength > 0)
{
buffer.AddRange(Payload);
}
buffer.Add(XorByte);
await stream.WriteAsync(buffer.ToArray(), 0, buffer.Count);
if (flush)
{
await stream.FlushAsync();
}
}
}
I have also created child classes that implement Type packet for each of the valid commands.
Finally I have also created a class of type PacketHandler that is able to read bytes from a stream and create it into a packet object.
The way I envisage using the library would be like this:
public async string GetCmdStnSoftwareVersion()
{
var msgReq = new CmdStnSoftwareVersionReqMessage();
await msgReq.WriteAsync(sPort.BaseStream);
await var response = msgReq.GetResponse(5); //5 = timeout in seconds!
return String.Format("{0}.{1}", response.Major, response.Minor);
}
What I am stuck on is a good pattern and/or example implementation for handling responses which is compatible with implementing the extension libraries. Can anyone provide input?

WMS authentication plugin

I'm trying to create a custom authentication plugin for WMS 2009 in C#.
I managed to implement something that for some reason blocks all requests...
[ComVisible(true)]
[Guid("C0A0B38C-C4FE-43B5-BE9E-C100A83BBCEE")]
public class AuthenticationPlugin : IWMSBasicPlugin, IWMSAuthenticationPlugin, IWMSAuthenticationContext
private const string SubKey = "SOFTWARE\\Microsoft\\Windows Media\\Server\\RegisteredPlugins\\Authentication\\{C0A0B38C-C4FE-43B5-BE9E-C100A83BBCEE}";
[ComRegisterFunction]
public static void RegisterFunction(Type t)
{
try
{
RegistryKey regHKLM = Registry.LocalMachine;
regHKLM = regHKLM.CreateSubKey(SubKey);
regHKLM.SetValue(null, "UC WMS Authentication plugin");
RegistryKey regHKCR = Registry.ClassesRoot;
regHKCR = regHKCR.CreateSubKey("CLSID\\{C0A0B38C-C4FE-43B5-BE9E-C100A83BBCEE}\\Properties");
regHKCR.SetValue("Name", CustomC WMS Authentication plugin");
regHKCR.SetValue("Author", "Me");
regHKCR.SetValue("CopyRight", "Copyright 2009. All rights reserved");
regHKCR.SetValue("Description", "Enables custom WMS authentication");
}
catch (Exception error)
{
Console.WriteLine(error.Message, "Inside RegisterFunction(). Cannot Register.");
}
}
[ComUnregisterFunction]
public static void UnRegisterFunction(Type t)
{
try
{
RegistryKey regHKLM = Registry.LocalMachine;
regHKLM.DeleteSubKey(SubKey);
RegistryKey regHKCR = Registry.ClassesRoot;
regHKCR.DeleteSubKeyTree("CLSID\\{C0A0B38C-C4FE-43B5-BE9E-C100A83BBCEE}");
regHKCR.DeleteSubKeyTree("CSEventTest.CSEventPlugin");
}
catch (Exception error)
{
Console.WriteLine(error.Message, "Cannot delete a subkey.");
}
}
#region IWMSBasicPlugin Members
public void InitializePlugin(IWMSContext serverContext, WMSNamedValues namedValues, IWMSClassObject classFactory)
{
}
public void ShutdownPlugin()
{
}
public void EnablePlugin(ref int flags, ref int heartbeatPeriod)
{
}
public void DisablePlugin()
{
}
public object GetCustomAdminInterface()
{
return null;
}
public void OnHeartbeat()
{
}
#endregion
#region IWMSAuthenticationPlugin Members
public IWMSAuthenticationContext CreateAuthenticationContext()
{
return (IWMSAuthenticationContext)this;
}
public int GetFlags()
{
return Convert.ToInt32(WMS_AUTHENTICATION_FLAGS.WMS_AUTHENTICATION_ANONYMOUS, CultureInfo.InvariantCulture);
}
public string GetPackageName()
{
return "Custom WMS Authentication";
}
public string GetProtocolName()
{
return "Basic";
}
#endregion
#region IWMSAuthenticationContext Members
public void Authenticate(object responseBlob, IWMSContext userContext, IWMSContext presentationContext, IWMSCommandContext commandContext, IWMSAuthenticationCallback callBack, object context)
{
callBack.OnAuthenticateComplete(WMS_AUTHENTICATION_RESULT.WMS_AUTHENTICATION_SUCCESS, null, context);
}
public IWMSAuthenticationPlugin GetAuthenticationPlugin()
{
return (IWMSAuthenticationPlugin)this;
}
public string GetImpersonationAccountName()
{
return String.Empty;
}
public int GetImpersonationToken()
{
return 0;
}
public string GetLogicalUserID()
{
return this.GetImpersonationAccountName();
}
#endregion
}
Can anyone spot why this is happening?
Also, is there any way I could have a look at the code for the standard Anonymous Authentication plugin already installed on the server? Is it in an assembly somewhere?
Thanks.
I ran into the same issue. It isn't enough to return success status from the Authenticate method.
Your implemented method must retrieve a handle to a valid Windows Login. Search the net for C# examples of how to call this method: http://msdn.microsoft.com/en-us/library/aa378184%28VS.85%29.aspx
bool result = LogonAPI.LogonUser("username", "domain", "password", LogonAPI.LOGON32_LOGON_NETWORK, LogonAPI.LOGON32_PROVIDER_DEFAULT, ref _userToken);
Store the IntPtr you get back from the LogonUser call and implement the GetImpersonationToken method like so:
public int GetImpersonationToken()
{
return _userToken.ToInt32();
}
Somehow the plug-in is able to tie that integer value back to a real windows account. I created a local account on the server that was in the Power Users group and used its username and password in the LogonUser method with the server being the domain. Once it is able to do so, the media should stream.
My whole IWMSAuthenticationPlugin is as follows (it uses basic authentication):
public class AuthenticationContext : IWMSAuthenticationContext
{
#region IWMSAuthenticationContext Members
private WMS_AUTHENTICATION_RESULT _result;
private readonly IWMSAuthenticationPlugin _plugin;
private Credentials _credentials;
private IntPtr _userToken;
public AuthenticationContext(IWMSAuthenticationPlugin plugin)
{
_plugin = plugin;
}
public void Authenticate(object responseBlob, IWMSContext pUserCtx, IWMSContext pPresentationCtx, IWMSCommandContext pCommandContext, IWMSAuthenticationCallback pCallback, object context)
{
// must be Unicode. If it isn't, the
// challenge isn't sent correctly
Encoding enc = Encoding.Unicode;
byte[] response;
byte[] challenge = enc.GetBytes("");
try
{
response = (byte[])responseBlob;
if (response.Length == 0)
{
// The client requested authentication; prepare the
// challenge response to send to the client. In order to
// do Basic authentication, be sure to return "Basic" from
// your implementation of IWMSAuthenticationPlugin.GetProtocolName()
string challengeTxt = "WWW-Authenticate: Basic realm=\"Domain\"";
challenge = enc.GetBytes(challengeTxt);
_result = WMS_AUTHENTICATION_RESULT.WMS_AUTHENTICATION_CONTINUE;
}
else
{
// parses Base64 encoded response and gets passed in credentials
SetCredentials(enc.GetString(response));
LdapConnection ldc = new LdapConnection("Domain");
NetworkCredential nc = new NetworkCredential(_credentials.Username, _credentials.Password, "Domain");
ldc.Credential = nc;
ldc.AuthType = AuthType.Negotiate;
ldc.Bind(nc); // user has authenticated at this point, as the credentials were used to login to the dc.
// must log in with a local windows account and get a handle for the account.
// even if success is returned, the plugin still needs a valid windows account
// to stream the file.
bool result = LogonAPI.LogonUser("local username", "local domain", "local password", LogonAPI.LOGON32_LOGON_NETWORK, LogonAPI.LOGON32_PROVIDER_DEFAULT, ref _userToken);
_result = WMS_AUTHENTICATION_RESULT.WMS_AUTHENTICATION_SUCCESS;
}
}
catch (LdapException e)
{
_result = WMS_AUTHENTICATION_RESULT.WMS_AUTHENTICATION_DENIED;
}
catch (Exception e)
{
_result = WMS_AUTHENTICATION_RESULT.WMS_AUTHENTICATION_ERROR;
}
finally
{
pCallback.OnAuthenticateComplete(_result, challenge, context);
}
}
public IWMSAuthenticationPlugin GetAuthenticationPlugin()
{
return _plugin;
}
public string GetImpersonationAccountName()
{
return "Domain\\" + _credentials.Username;
}
public int GetImpersonationToken()
{
// somehow the plugin knows how this integer ties to a windows account.
return _userToken.ToInt32();
}
public string GetLogicalUserID()
{
return GetImpersonationAccountName();
}
public void SetCredentials(string responseStr)
{
// for whatever reason, the responseStr has an extra character
// tacked on the end that blows up the conversion. When converting
// from the Base64 string, remove that last character.
string decoded = new UTF8Encoding().GetString(Convert.FromBase64String(responseStr.Substring(0, responseStr.Length - 1)));
// now that the string has been decoded and is now in the format
// username:password, parse it further into a Username and Password
// struct.
_credentials = new Credentials(decoded);
}
#endregion
}

Categories