set to B<SSL_KEY_UPDATE_NONE>.
SSL_key_update() must only be called after the initial handshake has been
-completed and TLSv1.3 has been negotiated, at the same time, the application
-needs to ensure that the writing of data has been completed. The key update
-will not take place until the next time an IO operation such as SSL_read_ex()
-or SSL_write_ex() takes place on the connection. Alternatively SSL_do_handshake()
-can be called to force the update to take place immediately.
+completed and TLSv1.3 or QUIC has been negotiated, at the same time, the
+application needs to ensure that the writing of data has been completed. The key
+update will not take place until the next time an IO operation such as
+SSL_read_ex() or SSL_write_ex() takes place on the connection. Alternatively
+SSL_do_handshake() can be called to force the update to take place immediately.
SSL_get_key_update_type() can be used to determine whether a key update
operation has been scheduled but not yet performed. The type of the pending key
The SSL_renegotiate_pending() function returns 1 if a renegotiation or
renegotiation request has been scheduled but not yet acted on, or 0 otherwise.
+=head1 USAGE WITH QUIC
+
+SSL_key_update() can also be used to perform a key update when using QUIC. The
+function must be called on a QUIC connection SSL object. This is normally done
+automatically when needed. Since a locally initiated QUIC key update always
+causes a peer to also trigger a key update, passing
+B<SSL_KEY_UPDATE_NOT_REQUESTED> as B<updatetype> has the same effect as passing
+B<SSL_KEY_UPDATE_REQUESTED>.
+
+The QUIC connection must have been fully established before a key update can be
+performed, and other QUIC protocol rules govern how frequently QUIC key update
+can be performed. SSL_key_update() will fail if these requirements are not met.
+
+Because QUIC key updates are always handled immediately,
+SSL_get_key_update_type() always returns SSL_KEY_UPDATE_NONE when called on a
+QUIC connection SSL object.
+
=head1 RETURN VALUES
SSL_key_update(), SSL_renegotiate() and SSL_renegotiate_abbreviated() return 1
uint64_t ossl_quic_channel_get_tx_key_epoch(QUIC_CHANNEL *ch);
uint64_t ossl_quic_channel_get_rx_key_epoch(QUIC_CHANNEL *ch);
+/* Artificially trigger a spontaneous TXKU if possible. */
+int ossl_quic_channel_trigger_txku(QUIC_CHANNEL *ch);
+
# endif
#endif
__owur long ossl_quic_callback_ctrl(SSL *s, int cmd, void (*fp) (void));
__owur long ossl_quic_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp) (void));
__owur size_t ossl_quic_pending(const SSL *s);
+__owur int ossl_quic_key_update(SSL *s, int update_type);
+__owur int ossl_quic_get_key_update_type(const SSL *s);
__owur int ossl_quic_num_ciphers(void);
__owur const SSL_CIPHER *ossl_quic_get_cipher(unsigned int u);
int ossl_quic_renegotiate_check(SSL *ssl, int initok);
* (BIO/)SSL_write => ossl_quic_write
* SSL_pending => ossl_quic_pending
* SSL_stream_conclude => ossl_quic_conn_stream_conclude
+ * SSL_key_update => ossl_quic_key_update
*/
/* SSL_get_error */
return 1;
}
+/*
+ * SSL_key_update
+ * --------------
+ */
+int ossl_quic_key_update(SSL *ssl, int update_type)
+{
+ QCTX ctx;
+
+ if (!expect_quic_conn_only(ssl, &ctx))
+ return 0;
+
+ switch (update_type) {
+ case SSL_KEY_UPDATE_NOT_REQUESTED:
+ /*
+ * QUIC signals peer key update implicily by triggering a local
+ * spontaneous TXKU. Silently upgrade this to SSL_KEY_UPDATE_REQUESTED.
+ */
+ case SSL_KEY_UPDATE_REQUESTED:
+ break;
+
+ default:
+ /* Unknown type - error. */
+ return 0;
+ }
+
+ quic_lock(ctx.qc);
+
+ /* Attempt to perform a TXKU. */
+ if (!ossl_quic_channel_trigger_txku(ctx.qc->ch)) {
+ quic_unlock(ctx.qc);
+ return 0;
+ }
+
+ quic_unlock(ctx.qc);
+ return 1;
+}
+
+/*
+ * SSL_get_key_update_type
+ * -----------------------
+ */
+int ossl_quic_get_key_update_type(const SSL *s)
+{
+ /*
+ * We always handle key updates immediately so a key update is never
+ * pending.
+ */
+ return SSL_KEY_UPDATE_NONE;
+}
+
/*
* QUIC Front-End I/O API: SSL_CTX Management
* ==========================================
{
SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
+#ifndef OPENSSL_NO_QUIC
+ if (IS_QUIC(s))
+ return ossl_quic_key_update(s, updatetype);
+#endif
+
if (sc == NULL)
return 0;
{
const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
+#ifndef OPENSSL_NO_QUIC
+ if (IS_QUIC(s))
+ return ossl_quic_get_key_update_type(s);
+#endif
+
if (sc == NULL)
return 0;
return 1;
}
+static int trigger_key_update(struct helper *h, const struct script_op *op)
+{
+ if (!TEST_true(SSL_key_update(h->c_conn, SSL_KEY_UPDATE_REQUESTED)))
+ return 0;
+
+ return 1;
+}
+
static int check_key_update_ge(struct helper *h, const struct script_op *op)
{
QUIC_CHANNEL *ch = ossl_quic_conn_get_channel(h->c_conn);
if (!TEST_true(helper_local_init(&hl, h, thread_idx)))
goto out;
-#define SPIN_AGAIN() { no_advance = 1; continue; }
+#define SPIN_AGAIN() { OSSL_sleep(1); no_advance = 1; continue; }
for (;;) {
SSL *c_tgt = h->c_conn;
* 1 packet above, which is absurd; thus this ensures we only actually
* generate TXKUs when we are allowed to.
*/
- OP_CHECK (check_key_update_ge, 5)
+ OP_CHECK (check_key_update_ge, 4)
OP_CHECK (check_key_update_lt, 120)
/*
OP_END
};
+/* 19. Key update test - artificially triggered */
+static const struct script_op script_19[] = {
+ OP_C_SET_ALPN ("ossltest")
+ OP_C_CONNECT_WAIT ()
+
+ OP_C_WRITE (DEFAULT, "apple", 5)
+
+ OP_S_BIND_STREAM_ID (a, C_BIDI_ID(0))
+ OP_S_READ_EXPECT (a, "apple", 5)
+
+ OP_CHECK (check_key_update_lt, 1)
+ OP_CHECK (trigger_key_update, 0)
+
+ OP_C_WRITE (DEFAULT, "orange", 6)
+ OP_S_READ_EXPECT (a, "orange", 6)
+
+ OP_CHECK (check_key_update_ge, 1)
+
+ OP_END
+};
+
static const struct script_op *const scripts[] = {
script_1,
script_2,
script_16,
script_17,
script_18,
+ script_19,
};
static int test_script(int idx)