Add mbedtls_ssl_ticket_rotate for ticket rotation.

Signed-off-by: Glenn Strauss <gstrauss@gluelogic.com>
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..4d48806 100644
--- a/include/mbedtls/ssl_ticket.h
+++ b/include/mbedtls/ssl_ticket.h
@@ -98,7 +98,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 +110,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..e410b6b 100644
--- a/library/ssl_ticket.c
+++ b/library/ssl_ticket.c
@@ -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,