Merge pull request #5522 from mpg/fixup-psa-migration
Fixup psa migration documentation
diff --git a/ChangeLog.d/mbedtls_ssl_ticket_rotate.txt b/ChangeLog.d/mbedtls_ssl_ticket_rotate.txt
new file mode 100644
index 0000000..b843bfd
--- /dev/null
+++ b/ChangeLog.d/mbedtls_ssl_ticket_rotate.txt
@@ -0,0 +1,2 @@
+Features
+ * Add mbedtls_ssl_ticket_rotate() for external ticket rotation.
diff --git a/include/mbedtls/ssl_ticket.h b/include/mbedtls/ssl_ticket.h
index 0f4117d..8559309 100644
--- a/include/mbedtls/ssl_ticket.h
+++ b/include/mbedtls/ssl_ticket.h
@@ -42,12 +42,16 @@
extern "C" {
#endif
+#define MBEDTLS_SSL_TICKET_MAX_KEY_BYTES 32 /*!< Max supported key length in bytes */
+#define MBEDTLS_SSL_TICKET_KEY_NAME_BYTES 4 /*!< key name length in bytes */
+
/**
* \brief Information for session ticket protection
*/
typedef struct mbedtls_ssl_ticket_key
{
- unsigned char MBEDTLS_PRIVATE(name)[4]; /*!< random key identifier */
+ unsigned char MBEDTLS_PRIVATE(name)[MBEDTLS_SSL_TICKET_KEY_NAME_BYTES];
+ /*!< random key identifier */
uint32_t MBEDTLS_PRIVATE(generation_time); /*!< key generation timestamp (seconds) */
mbedtls_cipher_context_t MBEDTLS_PRIVATE(ctx); /*!< context for auth enc/decryption */
}
@@ -98,7 +102,7 @@
* supported. Usually that means a 256-bit key.
*
* \note The lifetime of the keys is twice the lifetime of tickets.
- * It is recommended to pick a reasonnable lifetime so as not
+ * It is recommended to pick a reasonable lifetime so as not
* to negate the benefits of forward secrecy.
*
* \return 0 if successful,
@@ -110,6 +114,43 @@
uint32_t lifetime );
/**
+ * \brief Rotate session ticket encryption key to new specified key.
+ * Provides for external control of session ticket encryption
+ * key rotation, e.g. for synchronization between different
+ * machines. If this function is not used, or if not called
+ * before ticket lifetime expires, then a new session ticket
+ * encryption key is generated internally in order to avoid
+ * unbounded session ticket encryption key lifetimes.
+ *
+ * \param ctx Context to be set up
+ * \param name Session ticket encryption key name
+ * \param nlength Session ticket encryption key name length in bytes
+ * \param k Session ticket encryption key
+ * \param klength Session ticket encryption key length in bytes
+ * \param lifetime Tickets lifetime in seconds
+ * Recommended value: 86400 (one day).
+ *
+ * \note \c name and \c k are recommended to be cryptographically
+ * random data.
+ *
+ * \note \c nlength must match sizeof( ctx->name )
+ *
+ * \note \c klength must be sufficient for use by cipher specified
+ * to \c mbedtls_ssl_ticket_setup
+ *
+ * \note The lifetime of the keys is twice the lifetime of tickets.
+ * It is recommended to pick a reasonable lifetime so as not
+ * to negate the benefits of forward secrecy.
+ *
+ * \return 0 if successful,
+ * or a specific MBEDTLS_ERR_XXX error code
+ */
+int mbedtls_ssl_ticket_rotate( mbedtls_ssl_ticket_context *ctx,
+ const unsigned char *name, size_t nlength,
+ const unsigned char *k, size_t klength,
+ uint32_t lifetime );
+
+/**
* \brief Implementation of the ticket write callback
*
* \note See \c mbedtls_ssl_ticket_write_t for description
diff --git a/library/ssl_ticket.c b/library/ssl_ticket.c
index e998111..b04e184 100644
--- a/library/ssl_ticket.c
+++ b/library/ssl_ticket.c
@@ -48,9 +48,9 @@
#endif
}
-#define MAX_KEY_BYTES 32 /* 256 bits */
+#define MAX_KEY_BYTES MBEDTLS_SSL_TICKET_MAX_KEY_BYTES
-#define TICKET_KEY_NAME_BYTES 4
+#define TICKET_KEY_NAME_BYTES MBEDTLS_SSL_TICKET_KEY_NAME_BYTES
#define TICKET_IV_BYTES 12
#define TICKET_CRYPT_LEN_BYTES 2
#define TICKET_AUTH_TAG_BYTES 16
@@ -122,6 +122,35 @@
}
/*
+ * Rotate active session ticket encryption key
+ */
+int mbedtls_ssl_ticket_rotate( mbedtls_ssl_ticket_context *ctx,
+ const unsigned char *name, size_t nlength,
+ const unsigned char *k, size_t klength,
+ uint32_t lifetime )
+{
+ const unsigned char idx = 1 - ctx->active;
+ mbedtls_ssl_ticket_key * const key = ctx->keys + idx;
+ const int bitlen = mbedtls_cipher_get_key_bitlen( &key->ctx );
+ int ret;
+ if( nlength < TICKET_KEY_NAME_BYTES || klength * 8 < (size_t)bitlen )
+ return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+
+ /* With GCM and CCM, same context can encrypt & decrypt */
+ ret = mbedtls_cipher_setkey( &key->ctx, k, bitlen, MBEDTLS_ENCRYPT );
+ if( ret != 0 )
+ return( ret );
+
+ ctx->active = idx;
+ ctx->ticket_lifetime = lifetime;
+ memcpy( key->name, name, TICKET_KEY_NAME_BYTES );
+#if defined(MBEDTLS_HAVE_TIME)
+ key->generation_time = (uint32_t) mbedtls_time( NULL );
+#endif
+ return 0;
+}
+
+/*
* Setup context for actual use
*/
int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx,
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index c77119b..595300e 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -119,6 +119,7 @@
#define DFL_MFL_CODE MBEDTLS_SSL_MAX_FRAG_LEN_NONE
#define DFL_TRUNC_HMAC -1
#define DFL_TICKETS MBEDTLS_SSL_SESSION_TICKETS_ENABLED
+#define DFL_TICKET_ROTATE 0
#define DFL_TICKET_TIMEOUT 86400
#define DFL_TICKET_AEAD MBEDTLS_CIPHER_AES_256_GCM
#define DFL_CACHE_MAX -1
@@ -286,6 +287,7 @@
#if defined(MBEDTLS_SSL_SESSION_TICKETS)
#define USAGE_TICKETS \
" tickets=%%d default: 1 (enabled)\n" \
+ " ticket_rotate=%%d default: 0 (disabled)\n" \
" ticket_timeout=%%d default: 86400 (one day)\n" \
" ticket_aead=%%s default: \"AES-256-GCM\"\n"
#else
@@ -613,6 +615,7 @@
unsigned char mfl_code; /* code for maximum fragment length */
int trunc_hmac; /* accept truncated hmac? */
int tickets; /* enable / disable session tickets */
+ int ticket_rotate; /* session ticket rotate (code coverage) */
int ticket_timeout; /* session ticket lifetime */
int ticket_aead; /* session ticket protection */
int cache_max; /* max number of session cache entries */
@@ -1542,6 +1545,7 @@
opt.mfl_code = DFL_MFL_CODE;
opt.trunc_hmac = DFL_TRUNC_HMAC;
opt.tickets = DFL_TICKETS;
+ opt.ticket_rotate = DFL_TICKET_ROTATE;
opt.ticket_timeout = DFL_TICKET_TIMEOUT;
opt.ticket_aead = DFL_TICKET_AEAD;
opt.cache_max = DFL_CACHE_MAX;
@@ -1915,6 +1919,12 @@
if( opt.tickets < 0 || opt.tickets > 1 )
goto usage;
}
+ else if( strcmp( p, "ticket_rotate" ) == 0 )
+ {
+ opt.ticket_rotate = atoi( q );
+ if( opt.ticket_rotate < 0 || opt.ticket_rotate > 1 )
+ goto usage;
+ }
else if( strcmp( p, "ticket_timeout" ) == 0 )
{
opt.ticket_timeout = atoi( q );
@@ -2737,6 +2747,23 @@
mbedtls_ssl_ticket_write,
mbedtls_ssl_ticket_parse,
&ticket_ctx );
+
+ /* exercise manual ticket rotation (not required for typical use)
+ * (used for external synchronization of session ticket encryption keys)
+ */
+ if( opt.ticket_rotate ) {
+ unsigned char kbuf[MBEDTLS_SSL_TICKET_MAX_KEY_BYTES];
+ unsigned char name[MBEDTLS_SSL_TICKET_KEY_NAME_BYTES];
+ if( ( ret = rng_get( &rng, name, sizeof( name ) ) ) != 0 ||
+ ( ret = rng_get( &rng, kbuf, sizeof( kbuf ) ) ) != 0 ||
+ ( ret = mbedtls_ssl_ticket_rotate( &ticket_ctx,
+ name, sizeof(name), kbuf, sizeof(kbuf),
+ opt.ticket_timeout ) ) != 0 )
+ {
+ mbedtls_printf( " failed\n ! mbedtls_ssl_ticket_rotate returned %d\n\n", ret );
+ goto exit;
+ }
+ }
}
#endif
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 4ec62ae..2480713 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -2707,6 +2707,21 @@
-s "a session has been resumed" \
-c "a session has been resumed"
+requires_config_disabled MBEDTLS_USE_PSA_CRYPTO
+run_test "Session resume using tickets: manual rotation" \
+ "$P_SRV debug_level=3 tickets=1 ticket_rotate=1" \
+ "$P_CLI debug_level=3 tickets=1 reconnect=1" \
+ 0 \
+ -c "client hello, adding session ticket extension" \
+ -s "found session ticket extension" \
+ -s "server hello, adding session ticket extension" \
+ -c "found session_ticket extension" \
+ -c "parse new session ticket" \
+ -S "session successfully restored from cache" \
+ -s "session successfully restored from ticket" \
+ -s "a session has been resumed" \
+ -c "a session has been resumed"
+
run_test "Session resume using tickets: cache disabled" \
"$P_SRV debug_level=3 tickets=1 cache_max=0" \
"$P_CLI debug_level=3 tickets=1 reconnect=1" \