Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

application: serial_lte_modem: Support DTLS connection ID #11244

Closed
wants to merge 1 commit into from

Conversation

junqingzou
Copy link
Contributor

Support RFC9146 DTLS v1.2 Connection Identifier.

  • Requires lib_modem from NCS v2.4.0 and beyond.
  • Requires mfw-1.3.5 and beyond.

Supported in DTLS client proxy #XUDPCLI only.

@junqingzou junqingzou added the DNM label May 19, 2023
@github-actions github-actions bot added the changelog-entry-required Update changelog before merge. Remove label if entry is not needed or already added. label May 19, 2023
@junqingzou
Copy link
Contributor Author

Under testing with mfw_1.3.5 pre-release

@NordicBuilder
Copy link
Contributor

NordicBuilder commented May 19, 2023

Test specification

CI/Jenkins/NRF

  • Integration Platforms

CI/Jenkins/integration

Test Module File based changes Manually selected West overwrite
test-fw-nrfconnect-nrf-iot_serial_lte_modem X

Detailed information of selected test modules

Note: This message is automatically posted and updated by the CI

Support RFC9146 DTLS v1.2 Connection Identifier.
- Requires lib_modem from NCS v2.4.0 and beyond.
- Requires mfw-1.3.5 and beyond.

Supported in DTLS client proxy #XUDPCLI only.

Signed-off-by: Jun Qing Zou <jun.qing.zou@nordicsemi.no>
Copy link
Contributor

@SeppoTakalo SeppoTakalo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left my review remarks and proposals.

@@ -481,7 +529,7 @@ int handle_at_udp_server(enum at_cmd_type cmd_type)
}

/**@brief handle AT#XUDPCLI commands
* AT#XUDPCLI=<op>[,<url>,<port>[,<sec_tag>]
* AT#XUDPCLI=<op>[,<url>,<port>[,<sec_tag>,<connection_id>]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* AT#XUDPCLI=<op>[,<url>,<port>[,<sec_tag>,<connection_id>]
* AT#XUDPCLI=<op>[,<url>,<port>[,<sec_tag>[,<connection_id>]

Connection ID parameter seem optional.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, it's optional.

Comment on lines +251 to +256
ret = nrf_setsockopt(proxy.sock, NRF_SOL_SECURE,
NRF_SO_SEC_DTLS_CONN_SAVE,
NULL, 0);
if (ret) {
LOG_WRN("Save DTLS connection failed: %d", ret);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we blindly save the session if connection ID is enabled?
I would propose that we don't use that feature as it might run out of memory.

Copy link
Contributor Author

@junqingzou junqingzou Jun 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there will be only ONE session saved on modem side, as only SAVE/LOAD defined and no DELETE, so there should be no incremental memeory usage. SAVE after confirmation of CID active would only update the session data as I assumed. Finally if APP dones not SAVE then it could not LOAD, either.

Copy link
Contributor

@MarkusLassila MarkusLassila Jun 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that this SAVE/LOAD works as you expect. According to the documentation, SAVEd socket cannot be used, before it is LOADed. To me it seems like this should be used after we have transmitted the wanted data and are waiting for more data. Not sure how suitable this is for SLM.

https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrfxlib/nrf_modem/doc/sockets.html:
...
Once the DTLS context is saved, the socket can’t be used before the DTLS context is loaded with [NRF_SO_SEC_DTLS_CONN_LOAD]
...
The option will fail with nrf_errno NRF_ENOMEM if the amount of saved connections exceeds four.
....

edit: Noticed that @SeppoTakalo addressed this as well, leaving this up.

Comment on lines +197 to +201
uint32_t dtls_cid = (proxy.conn_id != 0) ?
NRF_SO_SEC_DTLS_CID_ENABLED : NRF_SO_SEC_DTLS_CID_DISABLED;

ret = nrf_setsockopt(proxy.sock, NRF_SOL_SECURE, NRF_SO_SEC_DTLS_CID,
&dtls_cid, sizeof(dtls_cid));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
uint32_t dtls_cid = (proxy.conn_id != 0) ?
NRF_SO_SEC_DTLS_CID_ENABLED : NRF_SO_SEC_DTLS_CID_DISABLED;
ret = nrf_setsockopt(proxy.sock, NRF_SOL_SECURE, NRF_SO_SEC_DTLS_CID,
&dtls_cid, sizeof(dtls_cid));
if (proxy.conn_id) {
ret = nrf_setsockopt(proxy.sock, NRF_SOL_SECURE, NRF_SO_SEC_DTLS_CID,
&proxy.conn_id, sizeof(proxy.conn_id));
}

I propose that we only set the socket option if it is other than zero.
Also require that AT parameter is 0, 1 or 2, so it is already same as what our socket API can take.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a bit awkward to set TLS_DTLS_CID_SUPPORTED, but will be allowed.
Then we'll need to differentiate TLS_DTLS_CID_SUPPORTED and TLS_DTLS_CID_ENABLED.

Comment on lines +204 to +213
} else if (proxy.conn_id != 0) {
ret = nrf_setsockopt(proxy.sock, NRF_SOL_SECURE,
NRF_SO_SEC_DTLS_CONN_LOAD,
NULL, 0);
if (ret) {
LOG_WRN("Load DTLS connection failed: %d", ret);
} else {
LOG_INF("DTLS connection resumed");
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My proposal would be not to use to storing/loading, at least not in the first phase.

Either drop it, or have it as a separate option / AT command.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think modem will automatically SAVE/LOAD CID so if APP does not do that, CID might not take effect for DTLS re-handshake.

Copy link
Contributor

@MarkusLassila MarkusLassila Jun 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same CID should not be re-used in DTLS re-handshake.

https://datatracker.ietf.org/doc/html/rfc9146:

In DTLS 1.2, CIDs are exchanged at the beginning of the DTLS session only. There is no dedicated "CID update" message that allows new CIDs to be established mid-session, because DTLS 1.2 in general does not allow TLS 1.3-style post-handshake messages that do not themselves begin other handshakes. When a DTLS session is resumed or renegotiated, the "connection_id" extension is negotiated afresh.

Also:
https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrfxlib/nrf_modem/doc/sockets.html

NRF_SO_SEC_DTLS_CONN_SAVE
Save DTLS connection. This option is write-only. This option require a DTLS v1.2 connection with renegotiation disabled.

edit: Noticed that @SeppoTakalo addressed this as well, leaving this up.

@@ -516,6 +564,9 @@ int handle_at_udp_client(enum at_cmd_type cmd_type)
proxy.sec_tag = INVALID_SEC_TAG;
if (at_params_valid_count_get(&at_param_list) > 4) {
at_params_unsigned_int_get(&at_param_list, 4, &proxy.sec_tag);
if (at_params_valid_count_get(&at_param_list) > 5) {
at_params_int_get(&at_param_list, 5, &proxy.conn_id);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should verify here that conn_id is either 0, 1 or 2, so we can feed it directly to Socket API.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes we can do that

@junqingzou
Copy link
Contributor Author

junqingzou commented Jun 12, 2023

Left my review remarks and proposals.

Sorry to be late in replying due to local expo and tech tour.
This PR remains DNM as I cannot verify against a DTLS server that supports CID.
Openssl no, mbedTLS v3.3.0~ yes.

@SeppoTakalo
Copy link
Contributor

Can you verify that there is no misunderstanding of connection ID SAVE/LOAD functionality, because I believe it works differently than what this code is using.
https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrfxlib/nrf_modem/doc/sockets.html

My understanding of the documentation is that:

  • When you have a socket created, you can enable the CID functionality.
  • It might be enabled after you have connected. Depends on the server.
  • If you call CONN_SAVE, the existing DTLS session will be serialized into RAM and active connection is dropped to save some RAM from modem.
  • Socket is now unusable, until CONN_LOAD is called.
  • If you call close() on the socket, the saved CID will be removed. Nothing is permanently stored.

@junqingzou
Copy link
Contributor Author

Can you verify that there is no misunderstanding of connection ID SAVE/LOAD functionality, because I believe it works differently than what this code is using. https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrfxlib/nrf_modem/doc/sockets.html

My understanding of the documentation is that:

  • When you have a socket created, you can enable the CID functionality.
  • It might be enabled after you have connected. Depends on the server.
    // It's enabled in Client Hello so during connect() for DTLS handshake I think (as seen in Wireshark)
  • If you call CONN_SAVE, the existing DTLS session will be serialized into RAM and active connection is dropped to save some RAM from modem.
  • Socket is now unusable, until CONN_LOAD is called.
    // This was misunderstood by me. In my test, server does not responded with STATUS_ENABLED so I was not able to test out the socket unusable.
  • If you call close() on the socket, the saved CID will be removed. Nothing is permanently stored.

I get your point. I referred to lib_modem socket test code, but it does not really reflect the correct sequence of LOAD and SAVE.

Comment on lines +251 to +256
ret = nrf_setsockopt(proxy.sock, NRF_SOL_SECURE,
NRF_SO_SEC_DTLS_CONN_SAVE,
NULL, 0);
if (ret) {
LOG_WRN("Save DTLS connection failed: %d", ret);
}
Copy link
Contributor

@MarkusLassila MarkusLassila Jun 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that this SAVE/LOAD works as you expect. According to the documentation, SAVEd socket cannot be used, before it is LOADed. To me it seems like this should be used after we have transmitted the wanted data and are waiting for more data. Not sure how suitable this is for SLM.

https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrfxlib/nrf_modem/doc/sockets.html:
...
Once the DTLS context is saved, the socket can’t be used before the DTLS context is loaded with [NRF_SO_SEC_DTLS_CONN_LOAD]
...
The option will fail with nrf_errno NRF_ENOMEM if the amount of saved connections exceeds four.
....

edit: Noticed that @SeppoTakalo addressed this as well, leaving this up.

Comment on lines +204 to +213
} else if (proxy.conn_id != 0) {
ret = nrf_setsockopt(proxy.sock, NRF_SOL_SECURE,
NRF_SO_SEC_DTLS_CONN_LOAD,
NULL, 0);
if (ret) {
LOG_WRN("Load DTLS connection failed: %d", ret);
} else {
LOG_INF("DTLS connection resumed");
}
}
Copy link
Contributor

@MarkusLassila MarkusLassila Jun 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same CID should not be re-used in DTLS re-handshake.

https://datatracker.ietf.org/doc/html/rfc9146:

In DTLS 1.2, CIDs are exchanged at the beginning of the DTLS session only. There is no dedicated "CID update" message that allows new CIDs to be established mid-session, because DTLS 1.2 in general does not allow TLS 1.3-style post-handshake messages that do not themselves begin other handshakes. When a DTLS session is resumed or renegotiated, the "connection_id" extension is negotiated afresh.

Also:
https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrfxlib/nrf_modem/doc/sockets.html

NRF_SO_SEC_DTLS_CONN_SAVE
Save DTLS connection. This option is write-only. This option require a DTLS v1.2 connection with renegotiation disabled.

edit: Noticed that @SeppoTakalo addressed this as well, leaving this up.

@junqingzou
Copy link
Contributor Author

Thanks for the comments.
LOAD/SAVE has NOT been testable yet (even libmodem team) as mbedTLS v3.3.0 based DTLS server required.
Plan to move SAVE to do_udp_client_disconnect(), but unless testable the LOAD/SAVE scenario cannot be decided.

@SeppoTakalo
Copy link
Contributor

@junqingzou Can you drop the SAVE/LOAD functionality.

Connection Identifier itself does not require it, it should be considered as a separate thing.
To enable CID, you only need to set one socket option. For example #11493

@junqingzou
Copy link
Contributor Author

I can actually close this PR and keep the code as local test object.
If someone knows how to test with a known good DTLS server please teach me.
With openssl X.509-based DTLS is OK but server ignores extension 54 in Client_Hello.

@junqingzou junqingzou closed this Jun 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
changelog-entry-required Update changelog before merge. Remove label if entry is not needed or already added. DNM
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants