obgm / libcoap

A CoAP (RFC 7252) implementation in C
Other
790 stars 422 forks source link

Does libcoap support coap+DTLS1.3? #1285

Open yangyangliuli opened 10 months ago

yangyangliuli commented 10 months ago

There are two problems: 1)Does coap-server-openssl support coap+DTLS1.2+session resumption? If supported, what CMD is needed to start the server? 2)Does libcoap support coap+DTLS1.3? If supported, which ciphersuites should be used?

mrdeep1 commented 10 months ago

@yangyangliuli Good questions

Does coap-server-openssl support coap+DTLS1.2+session resumption? If supported, what CMD is needed to start the server?

Support is not currently there for session resumption. This could be a project that someone takes on

Does libcoap support coap+DTLS1.3? If supported, which ciphersuites should be used?

As far as I can tell, none of the (D)TLS libraries that libcoap supports (OpenSSL, GnuTLS, Mbed TLS, TinyDTLS) have yet implemented DTLS1.3 support. When they do, it should be very easy to enable DTLS1.3 support.

WolfSSL does support DTLS1.3, and is a possible addition to the libcoap supported (D)TLS libraries, but again needs someone to work on it.

yangyangliuli commented 10 months ago

Hi, Thank you for your answer. Does libcoap have plans to integrate wolfssl? According to your experience, how long will it take if wolfssl is integrated? I'm newer to libcoap, if I go to integrate, how long do you think it will take me to complete?

mrdeep1 commented 10 months ago

Yes, there are plans to integrate wolfSSL, but no specific time frames.

I have set up a skeleton src/coap_wolfssl.c and updated some of the other environment to support wolfSSL. These changes can be found in my fork at https://github.com/mrdeep1/libcoap.git with the wolfssl_skeletonbranch.

In simple terms, coap_wolfssl.c is the interface between libcoap functionality and the underlying wolfSSL library. I would initially work on the dtls functions that need to be coded following how one of the other TLS library interface file is coded. Start with the Client functionality with PSK and test against a known working coap-server that uses a different TLS library.

WolfSSL needs to be set up to use the libcoap provided socket i/o functions to to the actual read / write across the network.

How long? No real idea, but I would expect at least a week.

yangyangliuli commented 10 months ago

wow, thank you very much, looking forward to your results , hope I am your first tester.

mrdeep1 commented 10 months ago

The skeleton is there for you to work on to get things going. I don't have the time at present to do the work on this.

yangyangliuli commented 10 months ago

OK, thanks.

fj-blanco commented 10 months ago

I have a wolfSSL integration here https://github.com/qursa-uc3m/libcoap-wolfssl using OpenSSL compatibility layer.

There are still some TODOs to address (you can see them in the coap_wolfssl.c) but I've made significant progress. Take a look at the wolfssl_dev README.md for some info on the tests done so far. Any help or feedback is welcome.

yangyangliuli commented 10 months ago

What a surprise, I will build according to README.md. I need your help with two questions: 1)Does this branch support DTLS1.3 connections with session resumption? 2)1)Does this branch support DTLS1.3 connections with session resumption + 0-RTT?

fj-blanco commented 10 months ago

What a surprise, I will build according to README.md. I need your help with two questions: 1)Does this branch support DTLS1.3 connections with session resumption? 2)1)Does this branch support DTLS1.3 connections with session resumption + 0-RTT?

I haven't tried that yet, but I'll give it a try soon. I think you may need to compile wolfSSL with WOLFSSL_DTLS13_NO_HRR_ON_RESUME.

 WOLFSSL_DTLS13_NO_HRR_ON_RESUME
 *     If defined, a DTLS server will not do a cookie exchange on successful
 *     client resumption: the resumption will be faster (one RTT less) and
 *     will consume less bandwidth (one ClientHello and one
 *     HelloVerifyRequest/HelloRetryRequest less). On the other hand, if a valid
 *     SessionID/ticket/psk is collected, forged clientHello messages will
 *     consume resources on the server. For DTLS 1.3, using this option also
 *     allows for the server to process Early Data/0-RTT Data. Without this, the
 *     Early Data would be dropped since the server doesn't enter stateful
 *     processing until receiving a verified ClientHello with the cookie.
 *
 *     To allow DTLS 1.3 resumption without the cookie exchange:
 *     - Compile wolfSSL with WOLFSSL_DTLS13_NO_HRR_ON_RESUME defined
 *     - Call wolfSSL_dtls13_no_hrr_on_resume(ssl, 1) on the WOLFSSL object to
 *       disable the cookie exchange on resumption
 *     - Continue like with a normal connection

Also set the hardcoded HRR_COOKIE to 0 in the coap_wolfssl.c file.

If you can contribute with any test for this feature, it will be greatly appreciated.

yangyangliuli commented 10 months ago

Hi, Thank you for your quick response, I just tried, log is as follows:

root@M2M:/home/xx/libcoap_wolf/libcoap-wolfssl/examples# ./coap-server -A ::1 -c ./certs/server-cert.pem -j ./certs/server-key.pem HERE SHOULD BE THE CALL TO wolfSSL_dtls13_allow_ch_frag() HERE SHOULD BE THE CALL TO wolfSSL_dtls13_allow_ch_frag()

xx@M2M:~/libcoap_wolf/libcoap-wolfssl/examples$ ./coap-client-wolfssl -m get coaps://[::1]/ This is a test server made with libcoap (see https://libcoap.net) Copyright (C) 2010--2023 Olaf Bergmann bergmann@tzi.org and others

1)Is it rght? 2) Does the client support put and post?( I can see help info supported, but I don't know how to enable) 3) As far as I know, wolfssl has supported dtls1.3 session resumption and 0-RTT, and I have tested successfully using the wolfssl example. But I don’t know how to use libcoap-wolfssl.

fj-blanco commented 10 months ago

Hi, Thank you for your quick response, I just tried, log is as follows:

root@M2M:/home/xx/libcoap_wolf/libcoap-wolfssl/examples# ./coap-server -A ::1 -c ./certs/server-cert.pem -j ./certs/server-key.pem HERE SHOULD BE THE CALL TO wolfSSL_dtls13_allow_ch_frag() HERE SHOULD BE THE CALL TO wolfSSL_dtls13_allow_ch_frag()

xx@M2M:~/libcoap_wolf/libcoap-wolfssl/examples$ ./coap-client-wolfssl -m get coaps://[::1]/ This is a test server made with libcoap (see https://libcoap.net) Copyright (C) 2010--2023 Olaf Bergmann bergmann@tzi.org and others

1)Is it rght? 2) Does the client support put and post?( I can see help info supported, but I don't know how to enable) 3) As far as I know, wolfssl has supported dtls1.3 session resumption and 0-RTT, and I have tested successfully using the wolfssl example. But I don’t know how to use libcoap-wolfssl.

The log with the wolfSSL_dtls13_allow_ch_frag() thing on the server-side is no longer necessary, it's legacy from when I was making the handshake work with client hello fragmentation (a recent addition to wolfSSL), required por some PQ KEMs. I should remove that. The output on the client-side indicates that the message has been received succesfully. You may want to check with Wireshark that everything is working as expected (have into account that Wireshark doesn't have DTLS 1.3 support yet and everything is interpreted in the light of DTLS 1.2, but you can still get an idea). I'm not sure if you can get the session ressumption tested just with the sample server/client or if we need a to build a minimal app for this. Does anyone have any idea about this?

Regarding PUT/POST support, yes it has. That is independent of the wolfSSL integration.

I will be busy the next two days on a trip but after that I will also try to get a session resumption with 0-RTT after that. You have my email on my GitHub profile if you want more direct communication on this.

Also, as this issue is not wolfSSL specific, perhaps we should move this discussion to https://github.com/obgm/libcoap/issues/1021 .

yangyangliuli commented 10 months ago

Ok, thank you for your help, we are developing coap+dtls1.3 client. I tried to connect wlfssl DTLS1.3 server, and response some fake data, and test. If libcoap supports coap_wolfssl_server, I will try connect to coap_wolfssl_server. Mainly testing 1) coap+dtls1.3+session resumption. 2)coap+dtls1.3+session resumption+early data. If I test some problem, I will connect you by email.

fj-blanco commented 10 months ago

Ok, thank you for your help, we are developing coap+dtls1.3 client. I tried to connect wlfssl DTLS1.3 server, and response some fake data, and test. If libcoap supports coap_wolfssl_server, I will try connect to coap_wolfssl_server. Mainly testing

  1. coap+dtls1.3+session resumption. 2)coap+dtls1.3+session resumption+early data. If I test some problem, I will connect you by email.

Thank you. I've been investigating this and it appears that the client side requires some modifications for session resumption to function properly. The server side should operate correctly by simply disabling HRR cookies. I'll give it a try over the next few days and keep you informed.

mrdeep1 commented 5 months ago

PR #1358 to add in wolfSSL support has been created and is ready for testing.

fj-blanco commented 4 months ago

Not sure if I should create a dedicated issue for this.

The following scenario, with

coap-server -A ::1 -c server_cert.pem -j server_key.pem

on server side, and

coap-client -m get coaps://[::1]/

is not working when the flag HAVE_RPK is not set.

The Client Hello is sent correctly, but this error is being thrown by wolfSSL debugging on server side

Setting WOLFSSL_SSL to be server side
wolfSSL Entering wolfSSL_DTLS_SetCookieSecret
wolfSSL Leaving wolfSSL_DTLS_SetCookieSecret, return 0
Server missing certificate
wolfSSL error occurred, error = 317 line:9666 file:../src/ssl.c

It seems setup_pki_ssl() is never called so the certificates are never being set. I'm not sure if the tls_server_name_call_back() is expected to be called after receiving the first Client Hello, which should then trigger setup_pki_ssl(), but this is not happening. Any idea?

mrdeep1 commented 4 months ago

It should really have been raised as a separate issue as this has nothing specifically to do with DTLS1.3.

I need to dig further into what is happening here.

mrdeep1 commented 4 months ago

This works as expected for me with HAVE_RPK both set and not set using the latest master for wolfSSL and develop for libcoap. It may be an issue with your server_cert.pem or server_cert.key files.

I assume all works for you if HAVE_RPK is enabled?

It would be best to raise this as a separate issue detailing both the libcoap and wolfSSL ./configure output and invocation lines along with the cert details if it cannot immediately be resolved.

Prashaanth06 commented 2 months ago

@mrdeep1 I am trying to figure out if the libcoap library uses DTLS 1.2 or what exactly it uses. I verified from the libcoap code that the minimum version required is set to DTLS1_2_VERSION but what is it exactly.

I have a client code which is almost similar to libcoap_minimal client with DTLS enabled and I have set these based on my requirements, dtls.version = COAP_DTLS_PKI_SETUP_VERSION; dtls.verify_peer_cert = 0; // Verify peer certificate dtls.check_common_ca = 0; // Require a server certificate dtls.allow_self_signed = 1; // Allow self signed certificate dtls.allow_expired_certs = 1; // No expired certificates dtls.cert_chain_validation = 1; // Validate the chain dtls.check_cert_revocation = 0; // Check the revocation list dtls.cert_chain_verify_depth = 2; // Depth of validation. dtls.pki_key.key_type = COAP_PKI_KEY_DEFINE

when I run my client my can see these logs in wireshark

image

It says SSLv3/TLS what is it exactly, how do I get to know the exact version here that is being used? Also is there an api to set the libcoap version when doing a request from client?

mrdeep1 commented 2 months ago

I'm not sure that your question is relevant to whether DTLS.13 is supported or not and perhaps should have been raised as a separate issue.

It says SSLv3/TLS what is it exactly, how do I get to know the exact version here that is being used?

It appears that you are using OpenSSL for the DTLS support. SSLv3/TLS is a part of the message string that is generated by OpenSSL, not libcoap. This generically refers to the SSLv3 protocol and TLS protocol (which updated and obsoleted SSLv3), but does not report the specific (D)TLS protocol that has been negotiated between the 2 end points. The fact that DTLS1_2_VERSIONhas been set means that the minimum version of DTLS that can be negotiated is DTLS1.2 (i.e. DTLS1.1 will get rejected, but DTLS1.2 or DTLS1.3 are acceptable) between the 2 endpoints.

DTLS1.3 is not (yet) supported by OpenSSL. Note that DTLS1.3 and TLS1.3 are not the same, but do have a lot of common features and are different in some areas.

The logs you have provided are generated by libcoap, not Wireshark. Wireshark will tell what has been negotiated 'on the wire' when analyzing the packet caopture.

Also is there an api to set the libcoap version when doing a request from client?

Do you mean the (D)TLS version? To set the libcoap version, you need to link against the correct library version of libcoap.

No, there is not currently a libcoap API to set the min/max version of (D)TLS that can be negotiated.

Prashaanth06 commented 2 months ago

Thanks for your reply @mrdeep1, I understand that these logs are generated by libcoap but is there any log in libcoap where I can get the DTLS version used because I see in an issue you had mentioned, image likewise will I be able to get the DTLS version printed in logs?

It appears that you are using OpenSSL for the DTLS support. SSLv3/TLS is a part of the message string that is generated by OpenSSL, not libcoap. This generically refers to the SSLv3 protocol and TLS protocol (which updated and obsoleted SSLv3), but does not report the specific (D)TLS protocol that has been negotiated between the 2 end points. The fact that DTLS1_2_VERSIONhas been set means that the minimum version of DTLS that can be negotiated is DTLS1.2 (i.e. DTLS1.1 will get rejected, but DTLS1.2 or DTLS1.3 are acceptable) between the 2 endpoints.

I want to achieve this "does not report the specific (D)TLS protocol that has been negotiated between the 2 end points"

I am aiming to address these 2 points,

  1. I need to check and confirm the version of dtls being using.
  2. Any DTLS connections with a version less than 1.2 should be rejected by the coap dtls server (Here I understand that we have already set the DTLS version to 1.2 using the SSL_CTX_set_min_proto_version API but using a dtls client will I be able to set some specific version so that my server will reject the connection throwing these log that DTLS version is unsupported. Do you see any possibility here).
mrdeep1 commented 2 months ago

I don't see why someone cannot come up with a libcoap public API which gives the ability to define min/max (D)TLS versions (stored in coap_context_t). These values are then used when initiating (D)TLS. Whatever is done needs to be generic enough to support the different ways that all the libcoap supported TLS libraries implement the max/min protos.

In your case, it may be easier to hard code test changes to src/coap_openssl.c for your testing.

boaks commented 2 weeks ago
There are two problems:
1)Does coap-server-openssl support coap+DTLS1.2+session resumption? If supported, what CMD is needed to start the server?
2)Does libcoap support coap+DTLS1.3? If supported, which ciphersuites should be used?

3) coap+DTLS 1.2 CID (RFC 9146). AFAIK currently C implementation are mbedtls and a feature branch of tinydtls.

DTLS 1.2 CID or DTLS 1.3 are the basic parts of such solutions, the other part will then be, how the DTLS sessions are managed. If the session are close after 10 minutes without traffic, the result may get disappointing.

mrdeep1 commented 2 weeks ago

coap+DTLS 1.2 CID (RFC 9146). AFAIK currently C implementation are mbedtls and a feature branch of tinydtls.

libcoap supports CID for MbedTLS (DTLS1.2), TinyDTLS (DTLS1.2 Client only) and wolfSSL (DTLS1.3, not DTLS1.2). The appropriate functionality needs to be enabled in the respective (D)TLS libraries.

Server side checks for an incoming Tuple match, if no match then checks if there is a CID and whether that CID matches another tuple - if so the other tuple is updated to the new tuple so that the DTLS session is able to continue.

However, if session associated with a tuple and CID enabled DTLS is not used for some time (libcoap default 300 secs), then the session will expire which will destroy any DTLS session information and so the (re-)use of the CID from any client IP will get dropped. It is worth considering doing some sort of keep-alive here.

boaks commented 2 weeks ago

Thanks a lot for the explanation.

Just as information: It's pretty common to use DTLS 1.2 CID for "long term - low power" communication. A timeout of 300s will then be very disappointing. The use of (much) longer timeouts may then case other issues.

I guess, the session management applies also for DTLS 1.3? And also doesn't allow, to resume the DTLS 1.2 session?

mrdeep1 commented 2 weeks ago

The libcoap session timeout can be set to (within reason) however long you want it to be - coap_context_set_session_timeout(3. However, there does need to be some sort of reasonable inactive timeout to manage server session garbage collection. libcoap also support limiting the number of idle/inactive sessions - coap_context_set_max_idle_sessions(3).

Resume session is not currently supported by libcoap (session tickets etc. are not stored anywhere). I can't see any reason as to why this could not be added in by someone at some point.

I guess, the session management applies also for DTLS 1.3?

Apart from the CID being transmitted differently between DTLS1.2 and DTLS1.3, there is no difference as to what happens to the tuple.

boaks commented 2 weeks ago

I read the documentation for both functions. If the timeout is used to "remove idle server sessions" and the other to limit "maximum number of idle server sessions", I'm not sure, how "idle" is defined? Could you explain that?

mrdeep1 commented 2 weeks ago

For "remove idle server sessions", "Idle" is when no packet sent / received (including (D)TLS packets) for the specified (session timeout) period of time, as well as there is no current reference count to the session.

For "maximum number of idle server sessions", "Idle" is any session that is not transmit pending something and has a reference count of 0. The longest "Idle" session since the last transmit / receive is then removed if the number of "Idle" sessions exceeds the maximum number defined - this logic occurs when a new session/tuple needs to be created.

boaks commented 2 weeks ago

And "reference count" means?

mrdeep1 commented 2 weeks ago

For a client, the reference count is bumped so that its session does not go away until the client has finished.

For the server, the reference count is bumped to make sure it does not unexpectedly go away. An example would be that an Observe relationship has been set up - and the reference count decremented when the Observe is cancelled/dropped.

Other server examples would be when protecting critical code - for example bumping the reference count before sending a packet over a TCP socket so that if a socket closure needs to take place, the socket and session can be 'freed' off, but the caller can still reference the session on function return to do whatever, and then when the session reference count is decremented by the caller, the session can 'go away'.