[tls] Allow session to be saved multiple times

TLS version 1.3 defers the NewSessionTicket until after the handshake
has completed, and allows the server to send multiple NewSessionTicket
messages (e.g. to refresh short-lived tickets).

The default session ID generated in tls_save() will currently end up
with the same value on each invocation.  While session IDs are unused
in TLS version 1.3, this could lead to confusing debug messages and
packet captures.

Add a function tls_random() to generate random nonces using the
channel ephemeral secret, a label, and a 64-bit counter, and this
function to generate unique session IDs.

Non-sequential record IVs are also generated using channel ephemeral
secrets.  Simplify this code by using tls_random() instead of a direct
call to channel_ephemeral().

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2026-09-21 23:02:04 +01:00
parent 194306d457
commit 1037cf358f
+29 -12
View File
@@ -456,6 +456,30 @@ static void tls_nonce ( struct tls_connection *tls,
sizeof ( *nonce ) );
}
/**
* Generate random nonce
*
* @v tls TLS connection
* @v nonce Nonce to fill in
* @v len Length of nonce
*/
static void tls_random ( struct tls_connection *tls, void *nonce,
size_t len ) {
static struct {
char label[16];
uint64_t counter;
} salt = {
.label = "tls random nonce",
};
/* Ensure uniqueness */
salt.counter++;
/* Generate nonce as an ephemeral secret */
channel_ephemeral ( &tls->channel, &salt, sizeof ( salt ),
nonce, len );
}
/**
* Clear key schedule digest algorithm
*
@@ -1557,19 +1581,16 @@ static struct secure_channel_operations tls_channel_ops = {
* Set a random session ID
*
* @v tls TLS connection
* @v label Label for ephemeral secret
*
* The session ID will be generated deterministically using the
* per-connection ephemeral secret and will therefore be guaranteed to
* differ between connections (including restarted connections).
*/
static void tls_set_session_id ( struct tls_connection *tls,
const char *label ) {
static void tls_set_session_id ( struct tls_connection *tls ) {
struct tls_session *session = tls->session;
/* Generate session ID */
channel_ephemeral_label ( &tls->channel, label, session->id.data,
sizeof ( session->id.data ) );
tls_random ( tls, session->id.data, sizeof ( session->id.data ) );
session->id.len = sizeof ( session->id.data );
}
@@ -1581,7 +1602,6 @@ static void tls_set_session_id ( struct tls_connection *tls,
* @ret rc Return status code
*/
static int tls_session ( struct tls_connection *tls, const char *name ) {
static const char label[] = "tls initial session id";
struct tls_session *session;
char *name_copy;
int rc;
@@ -1619,7 +1639,7 @@ static int tls_session ( struct tls_connection *tls, const char *name ) {
/* Generate random initial session ID */
tls->session = session;
tls_set_session_id ( tls, label );
tls_set_session_id ( tls );
DBGC ( tls, "TLS %p created session %s:\n", tls, name );
DBGC_HDA ( tls, 0, session->id.data, session->id.len );
@@ -1637,7 +1657,6 @@ static int tls_session ( struct tls_connection *tls, const char *name ) {
* @ret rc Return status code
*/
static int tls_save ( struct tls_connection *tls ) {
static const char label[] = "tls reset session id";
struct tls_session *session = tls->session;
const char *name = session->name;
int rc;
@@ -1646,7 +1665,7 @@ static int tls_save ( struct tls_connection *tls ) {
assert ( tls->new_id.len || tls->new_ticket.len );
/* Clear any existing session state */
tls_set_session_id ( tls, label );
tls_set_session_id ( tls );
zfree ( session->ticket.data );
session->ticket.data = NULL;
session->ticket.len = 0;
@@ -3584,9 +3603,7 @@ static int tls_send_record ( struct tls_connection *tls, unsigned int type,
- sizeof ( authhdr.seq ) ),
&authhdr.seq, sizeof ( authhdr.seq ) );
} else {
channel_ephemeral ( &tls->channel, &authhdr,
sizeof ( authhdr ), iv.record,
sizeof ( iv.record ) );
tls_random ( tls, iv.record, sizeof ( iv.record ) );
}
if ( ( rc = cipher_setiv ( cipher, pipe->ctx, &iv,
sizeof ( iv ) ) ) != 0 ) {