OpenSSL C++ DTLS client - c++

I'm trying to establish DTLS connection using openssl (c++).
However whereas there is DTLSv1_listen() function for server side I can't find any client side equivalent to actually establish UDP connection to server from client. Or send something to DTLS server. Could someone help me understand how to establish "connection" to DTLS server (I know the point of UDP and datagram communication is to be connectionless but by connection I mean scheme like DNS request+response)?
I need to send single message to server and then receive 1 response message. Encrypted. With certificate verification. How such communication scheme would work in DTLS world?

What are you using for signalling. You actually don't have to use openssl for your signalling layer you could use a Memory Bio and read and write from it.
With DTLS You will have 2 sides here, a Client and a Server. The Client will initiate things with a Client Hello. The server hopefully receives it, writes it into the bio, reads back a Server Hello and responds via the signalling layer.
There is a lot of stuff required to really finish up your app into the real world so I wont cover everything.
If you have a SSL Context, and you have your BIO's created. To Initiate the Server:
SSL_set_accept_state(*sslContext)
and to initiate the client:
SSL_set_connect_state(*sslContext);
You then want to start a handshake on the client. There is so many factors here on how your application is going to work its hard to give advice but the client should call:
SSL_do_handshake(*sslContext);
Depending on how you have wired everything up, your program may automatically send the client hello at this point. You can use Wireshark, grab only UDP and at the top filter DTLS to see it. If not you may be required to signal manually.
I wrote the following program myself to test OpenSSL dll's to see if there were any issues after compiling them. I can't share all the code with you but it shows how in memory you can use a single console app to do the handshake (no transmission via the internet just to see how it works).
Notes:
The BIO is a Memory BIO in this case.
Handshake is a SSL_do_handshake
WriteCipherText is a call to BIO_write
ReadCipherText is a call to BIO_read
You have to open it and do the other basic setup states first. At the end both of the handshakes will return 1 for succcess. This just kind of shows you how to do a basic memory DTLS handshake using openssl.
Console.WriteLine("[Client] Open: " + Client.Open("ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:AES128-SHA:AES128-GCM-SHA256:AES128-SHA256", "SRTP_AES128_CM_SHA1_80"));
Console.WriteLine("[Server] Open: " + Server.Open("ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:AES128-SHA:AES128-GCM-SHA256:AES128-SHA256", "SRTP_AES128_CM_SHA1_80"));
Console.WriteLine("[Client] Handshake" + Client.Handshake());
Console.WriteLine("Client: [Read] Client Hello");
var clientHello = Client.ReadCipherText();
Console.WriteLine("[Server] Write Hello: " + Server.WriteCipherText(clientHello));
Console.WriteLine("[Server] Handshake" + Server.Handshake());
clientHello.Free();
Console.WriteLine("[Server] Read Server Hello");
var serverHello = Server.ReadCipherText();
Console.WriteLine("[Client] Write Server Hello: " + Client.WriteCipherText(serverHello));
Console.WriteLine("[Client] Handshake" + Client.Handshake());
serverHello.Free();
Console.WriteLine("[Client] Read Certificate");
var clientCertificate = Client.ReadCipherText();
Console.WriteLine("[Server] Write Certificate: " + Server.WriteCipherText(clientCertificate));
Console.WriteLine("[Server] Handshake: " + Server.Handshake());
clientCertificate.Free();
Console.WriteLine("[Server] Read Change Cipher Spec");
var serverChangeCipherSpec = Server.ReadCipherText();
Console.WriteLine("[Client] Write Change Cipher Spec: " + Client.WriteCipherText(serverChangeCipherSpec));
serverChangeCipherSpec.Free();
Console.WriteLine("[Client] Handshake" + Client.Handshake());
Console.WriteLine("[Server] Handshake" + Server.Handshake());
Console.ReadLine();
Lots of helpful resources too to take a look at:
https://web.archive.org/web/20150814081716/http://sctp.fh-muenster.de/dtls-samples.html This ones really good
http://chris-wood.github.io/2016/05/06/OpenSSL-DTLS.html
https://wiki.openssl.org/index.php/SSL/TLS_Client

On the client side you create the UDP-socket, pass it with BIO_new_dgram to the SSL context and connect it with connect() or BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, &server_sockaddr). The connect just forces the file descriptors write to always be sent to server_sockaddr.
Now just do a regular SSL_connect and it should work.
For server side it's a little more complicated. I made a post and an example implementation

Related

Clarification needed about a SSL client using Boost asio

I have a C++ application that uses Boost_asio to do TCP/IP connection who read a .php document in a Web server that in turn uses the php script to update certain statistics.
The whole thing work as planned, but recently the server changed to use SSL (Google mandatory) and naturally, the previous connection stopped to work.
After a lot of theoretical reading about SSL, I'm still in the dark about certain practical details.
Using the example in the Boost asio documentation and a file “cacert.pem”, downloaded form somewhere following indications in this site, I'm able to run correctly the example using:
<host> = “www.google.com” and <port> = “https”.
Using the example “as is”, the Google server response is:
Verifying /OU=GlobalSign Root CA - R2/O=GlobalSign/CN=GlobalSign
Verifying /C=US/O=Google Trust Services/CN=Google Internet Authority G3
Verifying /C=US/ST=California/L=Mountain View/O=Google LLC/CN=www.google.com
Enter message: Reply:
But when using
<host> = “www.zator.com” and <port> = “https”
my domain, hosted in 1&1 IONOS, the reply is:
Handshake failed: tlsv1 alert internal error
At this point I have several questions:
What in the hell mean the sentence: ctx.load_verify_file("cacert.pem"); ?
The content of that file, can be the culprit of the fail when connecting with my domain?
Is that sentence essential to complete the connection?
In the case of google server (absence of error), is it supposed that after the sentence io_context.run(); the connection has been correctly established?
Assuming I make public the client's member socket_ (private in the example), can I continue with some as (I can't test that in google :-)
std::string request("GET /mystatistics.php HTTP/1.1\r\n\r\n");
boost::asio::write(c.socket_, boost::asio::buffer(request));
boost::system::error_code ec;
std::string response;
do { // read response
char buf[1024];
size_t bytes_transferred = c.socket_.read_some(boost::asio::buffer(buf), ec);
if (!ec) response.append(buf, buf + bytes_transferred);
} while (!ec);
std::cout << "Response received: '" << response << "'\n";
Thanks in advance.
I've found some useful information here. A good, albeit partial info, and a good start point to further search

After Successfull TLS handshake the server closes with error SSL routines:SSL3_GET_RECORD:wrong version number

We are using openssl 1.0.2k for our TLS related functionalities.
In one of our deployment the client is able to complete the TLS handshakes using TLSv1.2 and was able to send application data towards server.After some requests the TLS connections closed from the server side with the below error
"error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number"
TLS handshake steps:
1. Client hello
2. Server Hello
3. Certificate,Certificate Request, Server hello done
4. Certificate,Client Key Exchange,Change Cipher spec,Encrypted handshake message
5. Change Cipher spec,Encrypted handshake message
6. Application data exchanges between client and server
7. Encrypted Alert(server to client)
8. Encrypted Alert( client to server
The error logs from server side says "error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number"
Can you please let us know the cause for this issue. If the ssl version is mismatching then the handshake phase should not succeed right?
But in our case handshake is successful and after some application data transfer our server is failing with this error.
If the ssl version is mismatching then the handshake phase should not succeed right?
No. Any TLS packet have header, and header has TLS version inside:
(
byte - record_type
byte[2] - version
byte[2] - length
) header
byte[length] - encrypted or raw data
Header is always in raw, it is never encrypted. Even if during handshake client sent TLS 1.2 version in all TLS packets, he can send another version after handshake is finished. Or someone in between can modify network traffic. In this case OpenSSL throws described error.
In my case, I was using OpenSSL for client functionality.
I was calling SSL_set_connect_state after SSL_connect. It should be called before.
SSL_set_connect_state (for client only) cleans up all the state!
snippet:
void SSL_set_connect_state(SSL *s)
{
s->server = 0;
s->shutdown = 0;
ossl_statem_clear(s);
s->handshake_func = s->method->ssl_connect;
clear_ciphers(s);
}
In my case:
1) Client <-> Server handshake succeeded.
2) SSL_write from client side (client sending message to server) lead to exact same error as mentioned in question (on server side)
I looked at pkt dump on server side.
read from 0x2651570 [0x2656c63] (5 bytes => 5 (0x5)) .
0000 - 16 03 01 01 e2 .....
ERROR
139688140752544:error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong >version number:s3_pkt.c:337:
1) 5 Bytes read in the above snipped is the size of SSL record. Server received data, and it attempted reading SSL record.
2) 1'st byte of the record is the SSL record type In this case ===> x16 => '22'
This itself is wrong, as far as server is concerned, handshake was successful and it was expecting application data. Instead it received data with SSL record for handshake, hence it was throwing the error.
A correct snippet of application data is as follows: 'x17' ==> 23
read from 0x2664f80 [0x2656c63] (5 bytes => 5 (0x5)) .
0000 - 17 03 03 00 1c
Since SSL_set_connect_state was called after connecting, client state was lost and SSL_write will attempt handshake if handshake wasnt performed before (client thought so as its state was lost!)
More data on these SSL records can be found here:
https://www.ibm.com/support/knowledgecenter/SSB23S_1.1.0.12/gtps7/s5rcd.html

Python socket.recv Closing Socket Prematurely

I have a web proxy that starts a TCP listener socket that accepts connections from clients. The listener accepts connections via:
clientConnection, clientAddress = listenerSocket.accept()
and then a new thread handles the client connection from there.
To mock a client connection, I am using telnet to connect to the proxy and issue commands. The proxy needs to receive data from telnet and I need to make sure that I receive all of it. To achieve this, I am doing the following:
while True:
requestBytes = clientConnection.recv(1024)
if not requestBytes:
break
requestBuffer += requestBytes
The proxy then decodes the bytes and does some things with them that takes a little bit of time, and then has to send a response back to the same client. However, when using the above code the connection with clientConnection gets closed long before I can process the bytes and respond.
Here's what I don't understand, when I use the following instead:
while True:
requestBytes = clientConnection.recv(1024)
requestBuffer += requestBytes
break
It works just fine and the clientConnection remains intact. This obviously has a problem if I receive more than 1024 bytes, but the clientConnection does not get closed.
More specifically, the error occurs after I have a response to send to the client and call:
clientConnection.sendall(response)
clientConnection.shutdown(1)
clientConnection.close()
The line clientConnection.shutdown(1) throws the error:
[Errno 107] Transport endpoint is not connected
which is confusing because somehow it was able to still call sendall on the previous line. Note that I did not actually receive anything on the client side.
I am sure that the connection is not getting closed elsewhere in the code. What exactly is happening here and what is the best way to do something like recvall and keep the clientConnection open?

Detect if re-connection has taken place in redis websocket on client side

I am quite new to django-websocket-redis and as normal I am facing some problems.
I have established a communication from the client to the server and vice versa using Websockets for Redis.
I would like to detect when a client is reconnected or disconnected from the server (meaning when the connection is closed and/or opened again), so that I implement a mechanism where clients are responsible for asking "what did I miss" when they reconnect, and then query the data that they missed.
Currently my client code is like this (fiddle here).
I can detect when the connections is established for the first time, but not when websocket connection is broken and reconnected.
Any ideas on how can i do that ?
The problem is with the function name which you have set it should not be on_connecting() instead it should be only the name of the function on_connecting.
Below is the code, replace your code with below one and check if that works.
var ws4redis = WS4Redis({
uri: '{{ WEBSOCKET_URI }}foobar?subscribe-broadcast&publish-broadcast&echo',
receive_message: receiveMessage,
connecting: on_connecting,
connected: on_connected,
error: on_error,
disconnected: on_disconnected,
close: on_close,
open: on_open,
});
When you write on_connecting() the functions are getting called when the WS4redis is been initialized that's why you see the console log for all the events

OpenSSL client not sending client certificate

I am struggling with a client certificate problem and hope somebody here can help me. I'm developing a client/server pair using boost asio but I'll try to be unspecific. I'm on windows and using openssl 1.0.1e
Basically, I want to have client authentication by using client certificates. The server shall only accept clients that have a certificate signed by my own CA. So I have setup a self signed CA. This has issued two more certificates. One for the client and one for the server. Both signed by the CA.
I have done that quite a few times now and I am confident that I got it.
My server side also works fine. It requests client certificates and if I'm using s_client and give those certs everything works. Also if I'm using a browser and have my root CA installed as trusted and then import the client certs.
The only thing that I can't get to work is the libssl client. It always fails during the handshake and as far as I can see it will not send the client certficate:
$ openssl.exe s_server -servername localhost -bugs -CAfile myca.crt -cert server.crt
-cert2 server.crt -key private/server.key -key2 private/server.key -accept 8887 -www
-state -Verify 5
verify depth is 5, must return a certificate
Setting secondary ctx parameters
Using default temp DH parameters
Using default temp ECDH parameters
ACCEPT
SSL_accept:before/accept initialization
SSL_accept:SSLv3 read client hello A
SSL_accept:SSLv3 write server hello A
SSL_accept:SSLv3 write certificate A
SSL_accept:SSLv3 write key exchange A
SSL_accept:SSLv3 write certificate request A
SSL_accept:SSLv3 flush data
SSL3 alert read:warning:no certificate
SSL3 alert write:fatal:handshake failure
SSL_accept:error in SSLv3 read client certificate B
SSL_accept:error in SSLv3 read client certificate B
2675716:error:140890C7:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:peer did not return a
certificate:s3_srvr.c:3193:
ACCEPT
I'm using this s_server as debugging tool but against my real server the same thing occurs.
s_client will work fine with the same certificates. Also, if I disable "-Verify" in the server the connection works. So it really seems just the client refusing to send it's certficate. What can be the reason for that?
Since I'm using boost asio as an SSL wrapper the code looks like this:
m_ssl_context.set_verify_mode( asio::ssl::context::verify_peer );
m_ssl_context.load_verify_file( "myca.crt" );
m_ssl_context.use_certificate_file( "testclient.crt", asio::ssl::context::pem );
m_ssl_context.use_private_key_file( "testclient.key", asio::ssl::context::pem );
I have also tried to bypass asio and access the SSL context directly by saying:
SSL_CTX *ctx = m_ssl_context.impl();
SSL *ssl = m_ssl_socket.impl()->ssl;
int res = 0;
res = SSL_CTX_use_certificate_chain_file(ctx, "myca.crt");
if (res <= 0) {
// handle error
}
res = SSL_CTX_use_certificate_file(ctx, "testclient.crt", SSL_FILETYPE_PEM);
if (res <= 0) {
// handle error
}
res = SSL_CTX_use_PrivateKey_file(ctx, "testclient.key", SSL_FILETYPE_PEM);
if (res <= 0) {
// handle error
}
I can't see any difference in behavior. It should be mentioned that I am using a very old boost 1.43 asio which I cannot update but I suppose all relevant calls go more or less directly to OpenSSL anyway and the server works fine with that version so I think I can rule that out.
If I start forcing client and server to specific versions, the error messages change but it never works and still always works with the s_client test. Currently it is set to TLSv1
If I switch it to TLSv1 for example there is more chatter between client and server and eventually I get the error:
...
SSL_accept:SSLv3 read client key exchange A
<<< TLS 1.0 ChangeCipherSpec [length 0001]
01
<<< TLS 1.0 Handshake [length 0010], Finished
14 00 00 0c f4 71 28 4d ab e3 dd f2 46 e8 8b ed
>>> TLS 1.0 Alert [length 0002], fatal unexpected_message
02 0a
SSL3 alert write:fatal:unexpected_message
SSL_accept:failed in SSLv3 read certificate verify B
2675716:error:140880AE:SSL routines:SSL3_GET_CERT_VERIFY:missing verify
message:s3_srvr.c:2951:
2675716:error:140940E5:SSL routines:SSL3_READ_BYTES:ssl handshake failure:s3_pkt.c:989:
ACCEPT
I have found an older bug entry posted on the openssl mailing list that refereed to this. Apparently a wrong CRLF in the handshake that has been fixed two yrs ago. Or has it?
I have been debugging this for almost a week now and I'm really stuck. Does anyone have a suggestion on what to try? I'm out of ideas...
Cheers,
Stephan
PS: Here is what the above s_server debug out would be with s_client and the same certficate:
$ openssl s_client -CAfile ca.crt -cert testclient.crt -key private/testclient.key -verify 2 -connect myhost:8887
ACCEPT
SSL_accept:before/accept initialization
SSL_accept:SSLv3 read client hello A
SSL_accept:SSLv3 write server hello A
SSL_accept:SSLv3 write certificate A
SSL_accept:SSLv3 write key exchange A
SSL_accept:SSLv3 write certificate request A
SSL_accept:SSLv3 flush data
depth=1 C = DE, // further info
verify return:1
depth=0 C = DE, // further info
verify return:1
SSL_accept:SSLv3 read client certificate A
SSL_accept:SSLv3 read client key exchange A
SSL_accept:SSLv3 read certificate verify A
SSL_accept:SSLv3 read finished A
SSL_accept:SSLv3 write session ticket A
SSL_accept:SSLv3 write change cipher spec A
SSL_accept:SSLv3 write finished A
SSL_accept:SSLv3 flush data
ACCEPT
... handshake completes and data is transferred.
All right, after much suffering, the answer has been found by Dave Thompson of OpenSSL.
The reason was that my ssl code called all those functions on the OpenSSL context after the socket object (SSL*) was created from it. Which means all those functions did practically nothing or the wrong thing.
All I had to do was either:
1. Call SSL_use_certificate_file
res = SSL_use_certificate_file(ssl, "testclient.crt", SSL_FILETYPE_PEM);
if (res <= 0) {
// handle error
}
res = SSL_use_PrivateKey_file(ssl, "testclient.key", SSL_FILETYPE_PEM);
if (res <= 0) {
// handle error
}
(notice the missing CTX)
2. Call the CTX functions
Call the CTX functions upon the context before the socket was created. As asio seemingly encourages to create the context and socket right afterwards (as I did in the initializer list) the calls were all but useless.
The SSL context (in lib OpenSSL or asio alike) encapsulates the SSL usage and each socket created from it will share it's properties.
Thank you guys for your suggestions.
You should not use both SSL_CTX_use_certificate_chain_file() and SSL_CTX_use_certificate_file(), as SSL_CTX_use_certificate_chain_file() tries to load a chain including the client certificate, not just the CA chain. From SSL_CTX_use_certificate(3):
SSL_CTX_use_certificate_chain_file() loads a certificate chain from file into ctx. The certificates must be in PEM format and must be sorted starting with the subject's certificate (actual client or server certificate), followed by intermediate CA certificates if applicable, and ending at the highest level (root) CA.
I think you should be fine using only SSL_CTX_use_certificate_file() and SSL_CTX_use_PrivateKey_file(), as the client does not care much for the CA chain anyway.
I think you need to call SSL_CTX_set_client_CA_list on the server side. This sets a list of certificate authorities to be sent together with the client certificate request.
The client will not send its certificate, even if one was requested, if the certificate does not match that CA list sent by the server.