Native SSL Support for WINAPI - c++

I'm trying to make a simple IRC client, using the Winsock API, to which I want to add SSL support. Currently I just use overlapped socket I/O like this:
SOCKET sock = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0x02, 0x01);
if (!sock)
return;
struct sockaddr_in ircClient;
memcpy(&ircClient.sin_addr, he->h_addr_list[0], he->h_length);
ircClient.sin_family = AF_INET;
ircClient.sin_port = wPort;
WSAEVENT hDataEvent = WSA_INVALID_EVENT;
if (WSAConnect(sock, (sockaddr*)&ircClient, sizeof(ircClient), 0, 0, 0, 0) > 0) {
closesocket(sock);
return;
}
if (wsWSAGetLastError() != 0) {
closesocket(sock);
return;
}
Now, as I understand, for SSL support, I need to do SSL handshake after WSAConnect(). I found old Internet posts saying there are no SSL support in Winsock. It is now is year 2017, and 95% of websites work with SSL. Is there still no way to do this? I have found Using Secure Socket Extensions, but it is not SSL.

I've done years ago some SSL/TLS stuff over standard TCP connections using native windows API, but I'm not familiar with this specific "secure socket extension".
I can recommend using SSPI. It doesn't automatically transform your socket to SSL, but can be used pretty easy for generating SSL request/response/data packets on request.
Look for InitializeSecurityContext for more info.

Related

Problem connecting websocket from c++ compiled with emscripten

Trying to connect to websocket (poco-1.9.0 samples\WebSocketServer) using c++ code compiled with emscripten. Using compiled boost 1.69 and one of common examples to connect to socket.
boost::asio::ssl::context ctxt(context::sslv23_client);
ctxt.set_verify_mode(boost::asio::ssl::verify_none);
boost::asio::io_service svc;
tcp::resolver resolver(svc);
tcp::resolver::query query("127.0.0.1", "9980",
boost::asio::ip::resolver_query_base::numeric_service);
tcp::resolver::iterator i = resolver.resolve(query, ec);
boost::asio::ssl::stream<tcp::socket> s(svc, ctxt);
s.lowest_layer().connect(*i, ec);
s.handshake(boost::asio::ssl::stream<tcp::socket>::client, ec);
Server output is as following
Request from 127.0.0.1:58152: GET / HTTP/1.1
Host: 127.0.0.1:9980
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Origin: http://127.0.0.1:8887
Sec-WebSocket-Version: 13
Sec-WebSocket-Protocol: binary
WebSocket connection established.
Frame received (length=0, flags=0x0).
WebSocket connection closed.
However, this code hangs after handshake. Can it be used this way or it's necessary to use async calls from asio?
Also, if there is any similar example that you know of, please share.
I always tell people who try WebAssembly that...
WebAssembly (in a browser context) is JavaScript.
Even though you code in C/C++ using Emscripten, compiled WebAssembly bytecode is run in a browser's JavaScript engine such as V8. This means that WASM code does not have any special low-level APIs beyond JavaScript APIs. Every system-level functions are emulated using JavaScript.
What does it mean? Low-level socket control such as setting SSL versions and SSL handshaking does not make sense because your WASM code can only make use of JavaScript WebSocket API for networking, thus sockets are handled by the browser, not your WASM code.
Instead, you can use plain BSD sockets. Emscripten will convert the BSD sockets into JavaScript WebSocket. In other words, you can't use Poco library at all.
Like this:
struct sockaddr_in addr;
ing res;
int fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
unsigned long nonblocking = 1;
fcntl(fd, F_SETFL, O_NONBLOCK);
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(9980);
if (inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) != 1) {
perror("inet_pton failed");
finish(EXIT_FAILURE);
}
res = connect(server.fd, (struct sockaddr *)&addr, sizeof(addr));
BTW you are forced to use asynchronous (nonblocking) socket operations only, since it is JS websockets.
Related references:
Introduction to Emscripten Sockets by Jonathan Hale
Emscripten socket test code

C++ Should Any Socket Options Be Set Via setsockopt()? (Simple socket POST request)

Currently in my C++ application I authenticate a client by creating a simple POST request then sending it to my webserver (all data is encrypted during transfer) through the C++ socket then receiving and processing the response. The flow of how I make connection and send/receive response to/from my server is like so:
(error handling and other code has been removed, this is all important code relevant to question)
createSocket = socket(AF_INET, SOCK_STREAM, 0);
connect(createSocket, (struct sockaddr *)&sock_t, sizeof(sock_t));
send(createSocket, POSTRequestSend, strlen(POSTRequestSend), 0);
recv(createSocket, responseBuffer, 6000, 0);
So this works just fine, but my question is should I apply any socket options via setsockopt() to my socket? Being that I am only receiving and sending small pieces of data I was wondering if there are any socket options that could help improve performance or if there are any socket options I in general should be using?
I.e. I've seen some examples of people creating/sending similar requests to mine apply these socket options:
int on = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&on, sizeof(int));
So if I were to add this to my socket code it would look like:
int on = 1;
createSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
setsockopt(createSocket, IPPROTO_TCP, TCP_NODELAY, (const char *)&on, sizeof(int));
connect(createSocket, (struct sockaddr *)&sock_t, sizeof(sock_t));
send(createSocket, POSTRequestSend, strlen(POSTRequestSend), 0);
recv(createSocket, responseBuffer, 6000, 0);
Would there be any benifit to setting these socket options? Or are there any other socket options that I should be using based on me only sending POST request with small amounts of data sent/received.

socket() and sendto() dont return error codes when theres no internet connection

Why does socket() not return INVALID_SOCKET when I have no internet connection? I thought it would fail and then I could exit my function. My function's error checking continues till recvfrom() and then just hangs when I have no internet connection. I thought that socket() or sendto() would return an error code when I have no internet connection but they are not. I am trying to rely on their failure as a sign the user has no internet connection and exit my function but thats just not working for some weird reason.
void myFunc()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("myipaddress");
server_addr.sin_port = htons(123);
// Doesn't fail when there's no internet connection
protoent *proto = getprotobyname("udp");
int s = socket(PF_INET, SOCK_DGRAM, proto->p_proto);
if (s == INVALID_SOCKET) {
goto Cleanup;
}
// Doesn't fail when there's no internet connection
char msg[48] = { 0x08, 0, 0, 0, 0, 0, 0, 0, 0 };
int iResult = sendto(s, msg, sizeof(msg), 0, (struct sockaddr *) &server_addr, sizeof(server_addr));
if (iResult == SOCKET_ERROR) {
goto Cleanup;
}
// Hangs when there's no internet connection
memset(msg, 0, sizeof(msg));
struct sockaddr saddr;
socklen_t saddr_l = sizeof(saddr);
iResult = recvfrom(s, msg, 48, 0, &saddr, &saddr_l);
if (iResult == SOCKET_ERROR) {
goto Cleanup;
}
Cleanup:
closesocket(s);
WSACleanup();
}
Because there is no requirement for sockets to be connected to the internet. Many applications use sockets for inter-process communication on a single machine. Such applications can still run fine when there is no internet connection.
sendto() could arguably return an error code; it can (under certain situations, as demonstrated by the desktop notification about network connection status) know that the packet can never be delivered. However, UDP communication and sendto() make no guarantees about delivery whatsoever, and apparently the implementation you are using does not consider the lack of connection worthy of an error code. Arguably this is a quality of implementation issue.
recvfrom() simply waits as long as you have specified (possibly indefinitely) for a message, but never receives one. Again, this is within spec, and again it could be considered a quality of implementation issue whether or not this particular situation is flagged or not.
I looked into the linux man page for sendto (assuming that all relevant the implementations are sufficiently similar to the berkley sockets baseline) here:
http://linux.die.net/man/2/sendto
The documentation does not mention reporting and error if the network stack 'knows' that the message is undeliverable. This is reasonable, since the socket's transport may well not be IP4 or IP6. It could be any transport we chose to write a driver for: packet radio, serial cables or carrier-pigeons (if we could figure out the hardware for loading the printed messages into their satchels).
The only reference to possible errors from the transport is here:
These are some standard errors generated by the socket layer. Additional errors may be generated and returned from the underlying protocol modules; see their respective manual pages.
As mentioned by others, UDP is an unreliable datagram protocol. Unreliability is expected. Non-delivery of a message is expected. Therefore not really an error. There would be little incentive for a protocol-layer author to code for handling transport errors - since they too are expected and not an error in the context of this protocol.
When a socket is opened over TCP, then lack of socket continuity is an error. If the transport reports that packet delivery is not possible (for a sufficiently long time) then this is an error condition in the protocol.

UDP Broadcasting using winsock on a win 10 machine not working

I'm making a LAN multiplayer game using c++ and winsock, were I've created my own protocol for connecting two machines to eachother. The protocol involves broadcasting a message over the local LAN, which strangely isn't working on one of the two machines I'm using to test my code. The strange part is that it's as mentioned working on one machine, whereas not on the other. I've used wireshark to monitor outgoing packets, and the packets isn't being sent on the failing machine, even though that sendto() is returning the correct amount of bytes. The only difference between the machines is that one (the failing one) is using win10 and the other win8.
Is there any difference in the winsock library/networking layer between windows 10 and windows 8 that could cause this? Else, do you have any other ideas of what could cause the failure?
The code for sending a broadcast looks like this:
sockaddr_in send_addr;
send_addr.sin_family = AF_INET;
send_addr.sin_port = htons(PORT);
send_addr.sin_addr.s_addr = inet_addr("255.255.255.255");
int iResult = sendto(sock,
reinterpret_cast<char*>(&packet),
sizeof(Packet),
0,
(SOCKADDR *)&send_addr,
sizeof(send_addr));
if (iResult == SOCKET_ERROR)
{
printf("Failed to send broadcastmsg");
}
And the code to recieve it looks like this:
sockaddr_in sender_addr;
int sender_addrLen = sizeof(sender_addr);
Packet recvdPacket = {};
int iResult = recvfrom(sock,
reinterpret_cast<char*>(&recvdPacket),
sizeof(recvdPacket),
0,
(SOCKADDR*)&sender_addr,
&sender_addrLen);
if (iResult > 0)
{
return recvdPacket;
}
return Packet{};
You need to enable broadcast setting SO_BROADCAST before sending a broadcast message: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740476(v=vs.85).aspx ,
Why do we need SocketOptions.SO_BROADCAST to enable broadcast?
char broadcast = 1;
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast))
Also you should use directed broadcast (for example, 192.168.0.255) instead of Internet broadcast (255.255.255.255). I believe you don't need Internet broadcast.
Also, can you print the value returned by sendto? is iResult == sizeof(Packet)?
Last, which is the size of Packet? Is it a class? you are reinterpreting &packet as a char *. You must be sure there is no error there.
Could broadcast be blocked in the Win10 PC? I don't know if it's possible.
Consider using multicast.

If a winsock2 socket is non-blocking, would an SSL object associated with it also exhibit non-blocking behavior?

I'm asking this question because I am unsure whether an SSL object treats a socket as a sink/source for messages like it does with a BIO object. My gut is telling me yes, but I'm not certain.
Goal:
I am integrating a SSL authentication into already existing TCP code. Rather than calling the conventional send()/receive(), I would like to direct the messages through OpenSSL's SSL_read()/SSL_write() instead. My other requirement is that communication is non-blocking and data can be partially sent.
Here's how I've associated the SSL object with the socket (Server code).
SSL_Init(std::wstring &peer_hostname, SOCKET sock){
//...
//Initialize SSL structure
ssl = SSL_new(context);
if (ssl == NULL){
mr = APPZRETURN(E_FAIL, L"%ls (%d) : SSL_new failed. Unable to create SSL structure", __FUNCTIONW__, __LINE__);
}
//Agent uses winsock class, but OpenSSL uses unix socket. Surpressed warning added here for 4244. It works
if (SSL_set_fd(ssl, sock) == 0){ //set file descriptor for ssl
//Operation failed
return -1;
}
//...
int status = SSL_accept(ssl);
SSL_set_mode(ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER|SSL_MODE_ENABLE_PARTIAL_WRITE);
//...
}
According to the documentation for SSL_read() [https://www.openssl.org/docs/ssl/SSL_read.html], the SSL is non-blocking if the underlying BIO is non-blocking. If my assumption is correct, does that mean if the socket is non-blocking, the SSL is as well?
Extension of my Question: Is a winsock tcp socket non-blocking by default (assuming I have created a TCP socket, but have not called ioctlsocket and set non-blocking mode)
Thank you for taking the time to read this. It's much appreciated.
If my assumption is correct, does that mean if the socket is non-blocking, the SSL is as well?
Yes.
Is a winsock tcp socket non-blocking by default (assuming I have created a TCP socket, but have not called ioctlsocket and set non-blocking mode)
Unix sockets are by default blocking. Haven't used Winsock. But am sure Winsock should be by default blocking.
try following code:
SSL_set_fd(ss, sock);
retry:
int ret = SSL_accept(ssl);
if (ret != 1) {
int err = SSL_get_error(ssl, ret);
if (err == SSL_ERROR_WANT_READ || SSL_ERROR_WANT_WRITE) {
// maybe need some sleep or select
goto retry;
}
}