I am working on a TLS 1.3 client, and trying to support session resumption. I managed to do it in the following way:
When the server sends the NewSessionTicket, I have a callback function new_session_cb_func(SSL *ssl, SSL_SESSION *session)
that:
- Creates a file.
BIO *stmp = BIO_new_file(filepath, "w")
- Writes the session into it.
PEM_write_bio_SSL_SESSION(stmp, session)
.
When the client wants to resume the session, it uses the function PskSessionResume(SSL *ssl)
that:
- Opens the file where the session is stored.
BIO *stmp = BIO_new_file(filepath, "r")
- Reads the session from the
file.
SSL_SESSION *sess = PEM_read_bio_SSL_SESSION(stmp, NULL, 0, NULL)
- Resumes the session.
SSL_set_session(ssl, sess)
.
Currently, it works fine.
I tried to change the code so that the session will be kept in memory instead of a file.
new_session_cb_func(SSL *ssl, SSL_SESSION *session)
:
- Saves the session to a global variable.
SSL_SESSION *prev_sess = session
PskSessionResume(SSL *ssl)
:
- Ensure
prev_sess != NULL
. - Resumes the session.
SSL_set_session(ssl, prev_sess)
.
For some reason, the resumption doesn't work after the change. SSL_set_session
returns 1, but the client doesn't send the pre-shared key, and therefore a full handshake is conducted.
CodePudding user response:
It seems the pointer to the SESSION
passed to your callback is not expected to be kept as is. Actually, when storing the session, you want to copy the entire content of the structure, not just keep track of its address.
When you save your session in a file, the file is written with the structure content, not the address of the structure.
I strongly suspect that the pointer you keep track of gets freed and re-used somehow during the execution of your program (before you do the resumption). That is, when you want to resume the session and use the backed SESSION
pointer, it no longer points to valid/consistent memory data.
That is why the session cannot resume as expected and the process starts over from the very beginning.
A solution to this situation is to change the type of your global variable from SESSION *prev_sess;
to SESSION prev_sess
and save the session with prev_sess = *session;
in your callback. This way, you keep a copy of the structure content, not the pointer.
If everything is good, resuming the session will go nice and smooth!
EDIT:
The API provide a function for duplicating session context: SSL_SESSION_dup(SSL_SESSION *session)
. You may want to use it for duplicating the current session
passed to the callback.
Quoted from the documentation link:
SSL objects may be using the SSL_SESSION object; as a session may be reused, several SSL objects may be using one SSL_SESSION object at the same time. It is therefore crucial to keep the reference count (usage information) correct and not delete a SSL_SESSION object that is still used, as this may lead to program failures due to dangling pointers.
From there, it seems you can keep the original pointer as long as you also mark it with one more use with SSL_SESSION_up_ref
. This is supposed to guarantee that the structure never gets freed as long as you need it.