I want to communicate between Server and Client using sockets using bouncy castle TLS library.
I went through many documentation(which was insufficient for me) but I did not get any idea how to do this,
I am using BouncyCastle v1.7.48(runtime version=v2.0.50727) binary,
and I have found these info,
I have to use, Org.BouncyCastle.Crypto.Tls namespace and TlsProtocolHandler class.
To achieve TLS communication,
what API I should use in server side?
what API I should use in client side?
System.IO.Stream inputStream, outputStream;
TlsProtocolHandler tls = new TlsProtocolHandler(inputStream, outputStream);
What are the parameters inputStream and outputStream?
public virtual void Connect(TlsClient tlsClient);
where, TlsClient is an interface, and that contains many interfaces inside.
4. How to use the above API? I have to declare new classes and implement methods inside that to all?
Please help me with this Bouncy Castle.
EDIT 1:
I created one class which inherits from an abstract class called DefaultTlsClient.
Then I could create an instance of my class and pass it for interface reference.
So I could send the parameter like this. tls.Connect(tlsClient);
I am not initializing any parameters except I mentioned above.
(Sockets are connected before these operation on 2055)
But I am not sure handshake is complete or not. My program will go to reading state.
There is no server-side TLS API in bouncy castle. You can read on main page that they support only client-side.
For client-side you have found right classes already. TlsProtocolHandler does the job, but it won't work without custom classes. Here is example code:
// Need class with TlsClient in inheritance chain
class MyTlsClient : DefaultTlsClient
{
public override TlsAuthentication GetAuthentication()
{
return new MyTlsAuthentication();
}
}
// Need class to handle certificate auth
class MyTlsAuthentication : TlsAuthentication
{
public TlsCredentials GetClientCredentials(CertificateRequest certificateRequest)
{
// return client certificate
return null;
}
public void NotifyServerCertificate(Certificate serverCertificate)
{
// validate server certificate
}
}
class Program
{
static void Main(string[] args)
{
TcpClient client = new TcpClient();
client.Connect(IPAddress.Loopback, 6000);
// input/output streams are deprecated, just pass client stream
TlsProtocolHandler handler = new TlsProtocolHandler(client.GetStream());
handler.Connect(new MyTlsClient());
// handshake completed
// use handler.Stream.Write/Read for sending app data
Console.ReadLine();
}
}
I have tested this with my tcp server and received client hello.
Keep in mind it is TLS in version 1.0 so if u need other version or server api then I recommend using other library (.NET framework supports TLS).
Related
I have been contemplating on a dilemma for hours. I have a Visual Studio Solution that contains a WCF, WebForms, UWP, Xamarin and a SharedLibrary Projects.
I intend to use the WCF project as the backend which talks to the database and process Email and SMS integration and feed the other apps.
OPTION A
Currently, The WCF is hosted on an Azure App Service which makes it accessible via POST, GET, etc from the url which is: https://mywcfprojectlink.azurewebsites.net/service1.svc/GetUsers
With such arrangements, I can perform a POST request to get data from the apps:
string response = string.Empty;
string url = "https://mywcfprojectlink.azurewebsites.net/service1.svc/GetUsers";
try
{
var values = new Dictionary<string, string>
{
{ "data", Encryption.EncryptString(dat.ToString()) } //dat is incoming method param
};
string jsonString = JsonConvert.SerializeObject(values);
var cli = new WebClient();
cli.Headers[HttpRequestHeader.ContentType] = "application/json";
response = cli.UploadString($"{url}", jsonString);
var result = JsonConvert.DeserializeObject<string>(response);
topic.InnerText = Encryption.DecryptString(result.ToString());
}
catch (Exception)
{
return string.Empty;
}
The method above is a simple one as I have other ones where I Deserialize with Models/Classes.
OPTION B
I equally have access to the methods defined in service1 by adding the project reference to my WebForms which surprisingly is also compatible with xamarin but not with UWP. Nevertheless, I am interested in the WebForms scenario. Below is an example method:
using BackEnd;
//Service1 service1 = new Service1();
//var send = service1.GetUsers(dat.ToString()); //dat is incoming method param
//topic.InnerText = send;
Obviously, using the Option B would eliminate the need to encrypt, decrypt, serialize or deserialize the data being sent. However, I have serious performance concerns.
I need to know the better option and if there is yet another alternative (probably an Azure Resource), you can share with me.
If you decide to use https endpoint of the Azure website, option A is secure because of SSL encryption. So you don't have to encrypt/decrypt it by yourself. The only tip is to create a proper authorization mechanism. For example use TransportWithMessageCredential. An example is provided in below article https://www.codeproject.com/Articles/1092557/WCF-Security-and-Authentication-in-Azure-WsHttpBin
I'm building a secure WebSockets client using C# and the WebSocket4Net library. I would like for all my connections to be proxied through a standard proxy.
This lib uses the SuperSocket.ClientEngine.Common.IProxyConnector to specify a websocket connection's proxy, but I'm not sure how I'm supposed to implement that.
Has anyone worked with this library and can offer some advice?
I had to do the same, to push all websocket connections through Fiddler, for easier debugging. Because the WebSocket4Net author chose to re-use his IProxyConnector interface, System.Net.WebProxy is not directly useable.
On this link the author suggests using the implementations from his parent library SuperSocket.ClientEngine which you can download from CodePlex and include both the SuperSocket.ClientEngine.Common.dll and SuperSocket.ClientEngine.Proxy.dll. I do not recommend this. This causes compiling issues because he (poorly) chose to use the same namespace with both ClientEngine and WebSocket4Net with IProxyConnector defined in both dll's.
What worked for me:
To get it working for debugging through Fiddler, I copied these two classes into my solution, and changed them to the local namespace:
HttpConnectProxy.cs
ProxyConnectionBase
HttpConnectProxy seemed to have a bug on the following line:
if (e.UserToken is DnsEndPoint)
change to:
if (e.UserToken is DnsEndPoint || targetEndPoint is DnsEndPoint)
After that, things worked fine. Sample code:
private WebSocket _socket;
public Initialize()
{
// initialize the client connection
_socket = new WebSocket("ws://echo.websocket.org", origin: "http://example.com");
// go through proxy for testing
var proxy = new HttpConnectProxy(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888));
_socket.Proxy = (SuperSocket.ClientEngine.IProxyConnector)proxy;
// hook in all the event handling
_socket.Opened += new EventHandler(OnSocketOpened);
//_socket.Error += new EventHandler<ErrorEventArgs>(OnSocketError);
//_socket.Closed += new EventHandler(OnSocketClosed);
//_socket.MessageReceived += new EventHandler<MessageReceivedEventArgs>(OnSocketMessageReceived);
// open the connection if the url is defined
if (!String.IsNullOrWhiteSpace(url))
_socket.Open();
}
private void OnSocketOpened(object sender, EventArgs e)
{
// send the message
_socket.Send("Hello World!");
}
My Android application is supposed to communicate with a ASP.net web api which is written in C#.Net. The data which is sent from the phone contains data that should not be exposed to the public. So I'm trying to use the https protocol. On my serverside I require all requests to be HTTPS, like this:
RequireRegisteredImei
public class RequireRegisteredImeiAttribute : AuthorizationFilterAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
var request = actionContext.ControllerContext.Request;
if (request.RequestUri.Scheme == Uri.UriSchemeHttps)
{
//OKAY
}
else
{
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden);
}
}
}
And in the Controller:
[RequireRegisteredImei]
public string Post()
{
}
I debugged this code by sending a simple http request from my phone, and this code works quite well, it will deny me.
So, I started looking at how I could send requests over https from my android phone. I came up with something like this:
public static DefaultHttpClient getSecureHttpClient() {
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
schemeRegistry.register(new Scheme("http", SSLSocketFactory.getSocketFactory(), 80));
BasicHttpParams params = new BasicHttpParams();
SingleClientConnManager mgr = new SingleClientConnManager(params, schemeRegistry);
return new DefaultHttpClient(mgr, params);
}
I'm using this method this way:
HttpClient httpClient = CustomHttpClient.getSecureHttpClient();
This will only result in an IOException: No peer certificate
I've read several threads regarding this:
Problems with https (No peer certificate) in android
Android SSL - No Peer Certificate
'No peer certificate' error in Android 2.3 but NOT in 4
But there has to be a simpler way to post data over HTTPS from android?
If you have a custom certificate or a certificate issued by a CA that is not included in all Android versions you can include the certificate into your app and use it directly.
To do so you have to import your server certificate (without the key of course) into a BKS key-store which then can be used as custom trust store.
A very good tutorial which describes how to do so is Using a Custom Certificate Trust Store on Android.
In difference to the standard solutions like EasyTrustManager or DummyTrustManager you find of Stackoverflow this solution doesn't disable the authentication of SSL and is therefore not insecure like the other solutions.
You can also configure the HttpClient to accept all certificates like this :
SSLSocketFactory sslSocketFactory=SSLSocketFactory.getSocketFactory();
HostnameVerifier hostnameVerifier=org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
sslSocketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(
new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(
new Scheme("https", sslSocketFactory, 443));
if you think that this may be a solution for you.
I've been trying to look in the wiki about doing this, I'm following it, but I seem to be missing something?
So here is where I am at:
I have a client side JS that works fine locally.
I now want to send something via an API to update the client side version.I should use SignalR Client right?
This is what i have:
var connection = new HubConnection("http://localhost/test/echo", useDefaultUrl: false);
Global.asax
RouteTable.Routes.MapConnection<MyConnection>("echo", "echo/{*operation}");
I'm getting an error along the lines of no cancellation token is declared....
Is it that I'm not hitting my HubConnection page?
If you need me to clarify let me know.
Thanks,
UPDATE:
Thanks for replying! I'm still uncertain on how a Hub can talk to a persistent connection?
This is what I have so far...
namespace ConnectionHubDemo{
public class ChatHub : Hub
{
public void SendMessage(string message)
{
Clients.NewMessage(message);
}
}
public class ConnectionHub
{
public string test(string data)
{
//Will this talk to my PersistentConnection?
var connection = new HubConnection("http://localhost/test", false);
var myHub = connection.CreateProxy("ConnectionHubDemo.ServiceHub");
//How would I send a message to my persisten connection?
//myHub...
//If succcessful bla bla bla
return data;
}
}
}
That's because you're not using Hubs. You're mixing Hubs and PersistentConnections. On the server Hubs are automatically routed so there's no need to map anything (see https://github.com/SignalR/SignalR/wiki/Hubs). From the wiki:
Unlike low level PersistentConnections, there's no need to specify a route for the hub as they are automatically accessible over a special url (/signalr). This url is configurable:
To make the client side work you just declare a HubConnection with the root url (see https://github.com/SignalR/SignalR/wiki/SignalR-Client-Hubs). Again from the documentation:
To connect to a hub using SignalR, create a HubConnection with the appropriate url.
NOTE: This url will not point to a specific connection. But will instead point to the root of your site.
Example
var connection = new HubConnection("http://mysite/");
So in your case, this would be:
var connection = new HubConnection("http://localhost/test");
Hope this helps.
UPDATE
Hubs DO NOT talk to persistent connections. All you have to do is follow the documentation. My answer above shows how to use Hubs on the server and on the client.
If you want to use Persistent connections then look at the documentation https://github.com/SignalR/SignalR/wiki/PersistentConnection (Server) and https://github.com/SignalR/SignalR/wiki/SignalR-Client (Client).
I have the following project:
server, client, remote object. client does something, then pass the proxy of remote object to the server. All the things work property until server and client are in different domains. Now, when I try to pass result to server I have an exception
"An unhandled exception of type 'System.Runtime.Remoting.RemotingException' occurred in mscorlib.dll
Additional information: This remoting proxy has no channel sink which means either the server has no registered server channels that are listening, or this application has no suitable client channel to talk to the server. "
some sources on Internet says that I need to create some additional channel but I don't know where and how should I do that because I have the channel registration on server and client yet.
Info:
server - domain 2
client - domain 1
remote object - domain 1
Thank you
Sounds like a permissions issue to me. How are you hosting your remoting objects? How are you authenticating across domains? Here's a decent article on some of the issues you might face with auth.
From this article ...
By default, a TCP client channel authenticates itself with the user identity under which the client process is running. You can specify an alternative identity by setting the domain, username, and password properties to specify an alternative identity
Have you specified correct credentials (including domain) on your channel properties?
then pass the proxy of remote object
to the server
Can you explain this? This doesn't sound like a good idea. Typically a proxy is used to invoke remote methods (RPC). Passing the proxy back to the server, doesn't make sense. Sure it may work in some scenarios, but it just adds unnecessary complication.
If you want to pass an object, create a separate data class and pass that as a parameter to the remote method.
Common.dll
[Serializable]
public class Data
{
int a;
int b;
}
[Serializable]
public class ResultData
{
int c;
}
public interface IServerInterface
{
ResultData DoSomething(Data data);
}
Server.dll
public class ServerObject : MarshalByRefObject, IServerInterface
{
public ResultData DoSomething(Data data)
{
// do some work on the server
return new ResultData();
}
}
Client.exe
class Program
{
static void Main(string[] args)
{
IServerInterface proxy = CreateProxy();
ResultData result = proxy.DoSomething(new Data());
}
}