wolfSSL / wolfssl

The wolfSSL library is a small, fast, portable implementation of TLS/SSL for embedded devices to the cloud. wolfSSL supports up to TLS 1.3 and DTLS 1.3!
https://www.wolfssl.com
GNU General Public License v2.0
2.34k stars 830 forks source link

Issues with DTLS 1.3 Handshake over SCTP in WolfSSL #7898

Open lakshya-chopra opened 2 months ago

lakshya-chopra commented 2 months ago

I have a client-server model based on Linux's SCTP sockets, using WolfSSL's DTLS 1.3 server and client methods. However, I'm encountering an issue that prevents both peers from completing the DTLS/SSL handshake:

   error state on socket
   wrong client/server type

This error has been documented previously, but the suggested solution makes use of SSLv23_method(), which isn't fully compatible with SCTP or UDP sockets. Since there isn't a direct equivalent for DTLS 1.3, I tried using DTLS1_2_method(), but that didn't work either.

Is there an alternative solution to this problem?

rizlik commented 2 months ago

Hi, Thanks for reporting the issue. Is it possible to have a minimal reproducer example? This will make solving this issue a lot easier. Thanks

lakshya-chopra commented 1 month ago

Hello, Thank you for your response. Sorry, for not being able to provide an example, but I would like to provide a brief context regarding our usage of (PQ) DTLS 1.3. So, I am trying to integrate DTLS 1.3 & eventually Post Quantum version of it in 5G Radio Access Network (RAN). To explain a bit: Multiple threads are used in our architecture, with each thread being responsible for managing a specific Network Function. The challenge lies in the SCTP thread (Inter-Task Interface), which handles SCTP sockets. For each socket, we've added DTLS/SSL objects, meaning a single task is managing both client and server SSL objects.

The issue arises during the DTLS handshake, where this error occurs. Note that, on changing the SSL method to a generic one, that is, SSLv23_CTX, the handshake returns with no error. But this type of SSL object is not compatible with SCTP datagrams, and hence, not an option.

rizlik commented 1 month ago

Hello,

Thanks for the response and clarification! I'm going to investigate it and get back to you soon.

rizlik commented 1 month ago

Hi @lakshya-chopra ,

I'm sorry for the late response, I hope your project is going well. We lack a general DTLS method specific to v1.3, but you can use the version agnostic wolfDTLS_method(). If wolfSSL is compiled with DTLSv1.3 support, wolfDTLS_method() defaults to v1.3.

JYI we are adding the missing v1.3 specific method that can be used from both sides (#8012).

Please let me know if this is enough to fix your issue.

lakshya-chopra commented 1 month ago

Hello @rizlik , Thank you for your response! I will try out this method and will follow up soon with the results. Appreciate your help.

lakshya-chopra commented 1 month ago

Unfortunately, I couldn't get this method to work too.

image

Thanks for your time & efforts.

rizlik commented 1 month ago

Hi @lakshya-chopra ,

The root cause can be something else, but it's hard to guess without further information about your code. The segmentation fault is also not a good sign. If you can't provide an example (even a minimal reproducer would be okay), can you explain the life cycle of the wolfSSL objects inside your thread? Marco

lakshya-chopra commented 1 month ago

Hello @rizlik , To be precise that segmentation fault isn't really associated with the wolfSSL code, it was due to a logical bug where I tried to access the wolfSSL object (to get the cipher chosen), despite it getting freed due to the error. Now, I have resolved it, but the original error remains. As for the example, I'll discuss it with my team, but I can't confirm whether I'll be able to provide it or not.

However, I can provide the life cycle of wolfSSL objects as asked:

[The following are components of the O-RAN architecture, with CU being the control unit, and DU - Distributed Unit. They are essentially a split of the baseband unit which connects with the Remote Radio Heads and act as a backbone of the network.]

  1. Initialization of CU: At first, we start all the Inter-Task Interfaces i.e. POSIX threads, these include - TASK_CU, TASK_RRC, TASK_SCTP, TASK_DU, etc. The task we are concerned with is the TASK_CU, which sends a message to TASK_SCTP to set up a new SCTP listener and socket. Once the socket is created and bound to an IP address, we initialize the wolfSSL Server CTX with the required certificates, keys, and additional options.

  2. DU tries to form SCTP Association: The TASK_DU, connects to the CU and forms an SCTP association with TASK_CU using the socket set up earlier. During the initialization of this task, we create a new wolfSSL client CTX and provide it with the necessary information. The SCTP association request triggers the initialization of a wolfSSL DTLS object, which is used for the DTLS/SSL handshake. The DTLS object is only initialized once the SCTP state is established and the association is successfully formed. Note that TASK_DU doesn't handle the handshake or the SCTP association itself , instead TASK_SCTP does this on its behalf. The handshake is triggered when TASK_SCTP receives the SSL_DO_HANDSHAKE message from TASK_DU.

  3. CU-DU handshake When the DU tries to connect with the CU, TASK_SCTP accepts the SCTP association on behalf of the CU and sends an SCTP_STATE_ESTABLISHED message. Upon receiving this message, TASK_CU instructs the SCTP task to set up a wolfSSL DTLS object and initiate the handshake (just like in the case of TASK_DU).

  4. Errors: If the handshake fails due to SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, we retry the operation. In the case of a fatal error, we abort the handshake and free the wolfSSL objects.

Thus, from this it would be clear that a single thread is managing all the wolfSSL objects. Do note that we can run TASK_CU and TASK_DU separately.

I'd like to add that we have achieved this procedure with OpenSSL (along with the transfer of application datagrams) but due to the lacking DTLS 1.3 support over there, we are trying to make a switch to wolfSSL.

PS: Any improvements to this procedure will be appreciated.

rizlik commented 1 month ago

Thanks for the better explanation. Can you clarify in the DTLS connection who is the client and who is the server?

lakshya-chopra commented 1 month ago

In this case, CU (TASK_CU) is the server, and DU (TASK_DU) is the client.

rizlik commented 1 month ago

but, AFAIU, the connection ends are both managed by the SCTP task. Can you try to split the SCTP task context in two, one for server and one for client, and then use the specific client/server method?

lakshya-chopra commented 1 month ago

Well yes. I believe that this could be done, we'll consider your suggestion, and will try to implement it if feasible. Thanks!

lakshya-chopra commented 5 days ago

Update: Sorry for the late response, I have just resumed that project after a month. It seems that the SCTP Task is already split into 2 different contexts, one for the server & other for the client. Following your recommendation, I had used the agnostic wolfDTLS method too. It's still not working though.

rizlik commented 5 days ago

Hi @lakshya-chopra , I think that without a minimal example is hard to provide the right support. If it makes things easier, we can move the conversation privately on support@wolfssl.com .

lakshya-chopra commented 1 day ago

Sure, I can shift to a private mail conversation. However, I would like to provide some debug logs that I got after turning the debugging on:

wolfSSL Entering wolfSSL_SSL_do_handshake
wolfSSL Entering wolfSSL_SSL_do_handshake_internal
wolfSSL Entering wolfSSL_accept
wolfSSL Entering ReinitSSL
wolfSSL Entering RetrySendAlert
wolfSSL Entering RetrySendAlert
growing input buffer
wolfSSL Leaving wolfSSL_dtls_get_current_timeout, return 1
wolfSSL Entering EmbedReceiveFrom
wolfSSL Entering wolfSSL_dtls_get_using_nonblock
        Would block
Embed Receive From error
wolfSSL Entering wolfSSL_dtls_get_using_nonblock
wolfSSL Entering DtlsMsgPoolTimeout
wolfSSL Leaving DtlsMsgPoolTimeout(), return 0
wolfSSL Entering Dtls13RtxSendBuffered
wolfSSL Leaving wolfSSL_dtls_get_current_timeout, return 2
wolfSSL Entering EmbedReceiveFrom
wolfSSL Entering wolfSSL_dtls_get_using_nonblock
        Would block
Embed Receive From error
wolfSSL Entering wolfSSL_dtls_get_using_nonblock
wolfSSL Entering DtlsMsgPoolTimeout
wolfSSL Leaving DtlsMsgPoolTimeout(), return 0
wolfSSL Entering Dtls13RtxSendBuffered
wolfSSL Leaving wolfSSL_dtls_get_current_timeout, return 4
wolfSSL Entering EmbedReceiveFrom
wolfSSL Entering wolfSSL_dtls_get_using_nonblock
        Would block
Embed Receive From error
wolfSSL Entering wolfSSL_dtls_get_using_nonblock
wolfSSL Entering DtlsMsgPoolTimeout
wolfSSL Leaving DtlsMsgPoolTimeout(), return 0
wolfSSL Entering Dtls13RtxSendBuffered
wolfSSL Leaving wolfSSL_dtls_get_current_timeout, return 8
wolfSSL Entering EmbedReceiveFrom
wolfSSL Entering wolfSSL_dtls_get_using_nonblock
        Would block
Embed Receive From error
wolfSSL Entering wolfSSL_dtls_get_using_nonblock
wolfSSL Entering DtlsMsgPoolTimeout
wolfSSL Leaving DtlsMsgPoolTimeout(), return 0
wolfSSL Entering Dtls13RtxSendBuffered
wolfSSL Leaving wolfSSL_dtls_get_current_timeout, return 16
wolfSSL Entering EmbedReceiveFrom
wolfSSL Entering wolfSSL_dtls_get_using_nonblock
        Would block
Embed Receive From error
wolfSSL Entering wolfSSL_dtls_get_using_nonblock
wolfSSL Entering DtlsMsgPoolTimeout
wolfSSL Leaving DtlsMsgPoolTimeout(), return 0
wolfSSL Entering Dtls13RtxSendBuffered
wolfSSL Leaving wolfSSL_dtls_get_current_timeout, return 32
wolfSSL Entering EmbedReceiveFrom
wolfSSL Entering wolfSSL_dtls_get_using_nonblock
        Would block
Embed Receive From error
wolfSSL Entering wolfSSL_dtls_get_using_nonblock
wolfSSL Entering DtlsMsgPoolTimeout
wolfSSL Leaving DtlsMsgPoolTimeout(), return 0
wolfSSL Entering Dtls13RtxSendBuffered
wolfSSL Leaving wolfSSL_dtls_get_current_timeout, return 64
wolfSSL Entering EmbedReceiveFrom
wolfSSL Entering wolfSSL_dtls_get_using_nonblock
        Would block
Embed Receive From error
wolfSSL Entering wolfSSL_dtls_get_using_nonblock
wolfSSL Entering DtlsMsgPoolTimeout
wolfSSL Leaving DtlsMsgPoolTimeout(), return -1
Error trying to retransmit DTLS buffered message
wolfSSL error occurred, error = 308 line:9958 file:src/ssl.c
SSL handshake res: -1
wolfSSL Entering wolfSSL_get_error
wolfSSL Leaving wolfSSL_get_error, return -308
wolfSSL Entering wolfSSL_ERR_print_errors_fp
error state on socket
wolfSSL Entering wolfSSL_free
Free SSL: 0x7f8758004410
Free'ing server ssl
Unloading cert
wolfSSL Entering wolfSSL_FreeX509
wolfSSL Entering ExternalFreeX509
Unloading key
Shrinking input buffer
wolfSSL Entering DtlsMsgPoolReset
wolfSSL Entering Dtls13RtxFlushBuffered
wolfSSL Entering ClientSessionToSession
wolfSSL Entering wolfSSL_FreeSession
wolfSSL_FreeSession full free
wolfSSL Entering wolfSSL_sk_CIPHER_free
wolfSSL Entering wolfSSL_sk_free
wolfSSL Entering wolfSSL_sk_X509_pop_free
wolfSSL Entering wolfSSL_sk_pop_free
wolfSSL Entering wolfSSL_sk_X509_pop_free
wolfSSL Entering wolfSSL_sk_pop_free
wolfSSL Entering wolfSSL_sk_X509_NAME_pop_free
wolfSSL Entering wolfSSL_sk_pop_free
wolfSSL Entering Dtls13RtxFlushAcks
wolfSSL Entering DtlsMsgPoolReset
wolfSSL Entering Dtls13RtxFlushBuffered
wolfSSL Entering Dtls13RtxFlushBuffered
CTX ref count not 0 yet, no free
wolfSSL Leaving wolfSSL_free, return 0
wolfSSL Entering wolfSSL_SSL_do_handshake
wolfSSL Entering wolfSSL_SSL_do_handshake_internal
wolfSSL Entering wolfSSL_accept
wolfSSL Entering ReinitSSL
RNG_HEALTH_TEST_CHECK_SIZE = 128
sizeof(seedB_data)         = 128
opened /dev/urandom.
rnd read...
CertSetupCb set. server cert and key not checked
wolfSSL Entering RetrySendAlert
ProcessReply retry in error state, not allowed
wolfSSL error occurred, error = 308 line:9958 file:src/ssl.c
SSL handshake res: -1
wolfSSL Entering wolfSSL_get_error
wolfSSL Leaving wolfSSL_get_error, return -308
wolfSSL Entering wolfSSL_ERR_print_errors_fp
error state on socket
wolfSSL Entering wolfSSL_free
Free SSL: 0x7f8758004410
Free'ing server ssl
wolfSSL Entering wolfSSL_sk_SSL_CIPHER_free
wolfSSL Entering wolfSSL_sk_free

Could you help me spot where the handshake is going wrong? Thanks!

ETA:

Error trying to retransmit DTLS buffered message

Here's where it's going wrong, what could be the reason?

Edit 2: I came across this issue - Issue 7686 & following the steps, I started the make test process & got the same error: image

However, running the client & server example mentioned in that issue, completely worked. Here are the commands I used: Server:

./examples/server/server  -u -v 4 -l TLS13-AES256-GCM-SHA384 --pqc KYBER_LEVEL3

Client:

./examples/client/client -u -v 4 -l TLS13-AES256-GCM-SHA384 --pqc KYBER_LEVEL3 -H defCipherList