QUIC CHANNEL: Allow time source to be overridden
authorHugo Landau <hlandau@openssl.org>
Tue, 21 Feb 2023 10:18:59 +0000 (10:18 +0000)
committerHugo Landau <hlandau@openssl.org>
Thu, 30 Mar 2023 10:14:09 +0000 (11:14 +0100)
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/20348)

include/internal/quic_channel.h
include/internal/quic_ssl.h
include/internal/quic_tserver.h
ssl/quic/quic_channel.c
ssl/quic/quic_channel_local.h
ssl/quic/quic_impl.c
ssl/quic/quic_local.h
ssl/quic/quic_tserver.c

index 1f7ef71ed48ce9aa171cf16160f97ce482bc5479..bba7256d037b5d43f41b66d964142f108d62014b 100644 (file)
@@ -111,6 +111,13 @@ typedef struct quic_channel_args_st {
      * mutex primitive or using its RW mutex primitive.
      */
     CRYPTO_MUTEX    *mutex;
+
+    /*
+     * Optional function pointer to use to retrieve the current time. If NULL,
+     * ossl_time_now() is used.
+     */
+    OSSL_TIME       (*now_cb)(void *arg);
+    void            *now_cb_arg;
 } QUIC_CHANNEL_ARGS;
 
 typedef struct quic_channel_st QUIC_CHANNEL;
index 3cf32e0944c8d2cf2d5396cacdaf7e6574ec3cc5..e4af2c57bec861cc60f3303ac95b9238adbaf463 100644 (file)
@@ -65,6 +65,14 @@ BIO *ossl_quic_conn_get_net_wbio(const QUIC_CONNECTION *qc);
 __owur int ossl_quic_conn_set_initial_peer_addr(QUIC_CONNECTION *qc,
                                                 const BIO_ADDR *peer_addr);
 
+/*
+ * Used to override ossl_time_now() for debug purposes. Must be called before
+ * connecting.
+ */
+void ossl_quic_conn_set_override_now_cb(SSL *s,
+                                        OSSL_TIME (*now_cb)(void *arg),
+                                        void *now_cb_arg);
+
 # endif
 
 #endif
index a7fbb393f2651dd69b81d7c1af2b6a62f9c0b092..4545630a90aacc0a66036053a7e296ecbebe074a 100644 (file)
@@ -37,6 +37,8 @@ typedef struct quic_tserver_args_st {
     OSSL_LIB_CTX *libctx;
     const char *propq;
     BIO *net_rbio, *net_wbio;
+    OSSL_TIME (*now_cb)(void *arg);
+    void *now_cb_arg;
 } QUIC_TSERVER_ARGS;
 
 QUIC_TSERVER *ossl_quic_tserver_new(const QUIC_TSERVER_ARGS *args,
index 16b158d8a9312730b9fc352492e94172c434314a..2774329e5c615dc0c7551137754f8889f6db6463 100644 (file)
@@ -133,7 +133,7 @@ static int ch_init(QUIC_CHANNEL *ch)
     if (!ossl_quic_rxfc_init(&ch->conn_rxfc, NULL,
                              2  * 1024 * 1024,
                              10 * 1024 * 1024,
-                             get_time, NULL))
+                             get_time, ch))
         goto err;
 
     if (!ossl_statm_init(&ch->statm))
@@ -144,7 +144,7 @@ static int ch_init(QUIC_CHANNEL *ch)
     if ((ch->cc_data = ch->cc_method->new(NULL, NULL, NULL)) == NULL)
         goto err;
 
-    if ((ch->ackm = ossl_ackm_new(get_time, NULL, &ch->statm,
+    if ((ch->ackm = ossl_ackm_new(get_time, ch, &ch->statm,
                                   ch->cc_method, ch->cc_data)) == NULL)
         goto err;
 
@@ -166,6 +166,7 @@ static int ch_init(QUIC_CHANNEL *ch)
     txp_args.cc_method          = ch->cc_method;
     txp_args.cc_data            = ch->cc_data;
     txp_args.now                = get_time;
+    txp_args.now_arg            = ch;
     for (pn_space = QUIC_PN_SPACE_INITIAL; pn_space < QUIC_PN_SPACE_NUM; ++pn_space) {
         ch->crypto_send[pn_space] = ossl_quic_sstream_new(INIT_CRYPTO_BUF_LEN);
         if (ch->crypto_send[pn_space] == NULL)
@@ -180,7 +181,7 @@ static int ch_init(QUIC_CHANNEL *ch)
 
     if ((ch->demux = ossl_quic_demux_new(/*BIO=*/NULL,
                                          /*Short CID Len=*/rx_short_cid_len,
-                                         get_time, NULL)) == NULL)
+                                         get_time, ch)) == NULL)
         goto err;
 
     /*
@@ -232,7 +233,7 @@ static int ch_init(QUIC_CHANNEL *ch)
     if (!ossl_quic_rxfc_init(&ch->stream0->rxfc, &ch->conn_rxfc,
                              1 * 1024 * 1024,
                              5 * 1024 * 1024,
-                             get_time, NULL))
+                             get_time, ch))
         goto err;
 
     /* Plug in the TLS handshake layer. */
@@ -332,6 +333,8 @@ QUIC_CHANNEL *ossl_quic_channel_new(const QUIC_CHANNEL_ARGS *args)
     ch->is_server   = args->is_server;
     ch->tls         = args->tls;
     ch->mutex       = args->mutex;
+    ch->now_cb      = args->now_cb;
+    ch->now_cb_arg  = args->now_cb_arg;
 
     if (!ch_init(ch)) {
         OPENSSL_free(ch);
@@ -457,7 +460,12 @@ CRYPTO_MUTEX *ossl_quic_channel_get_mutex(QUIC_CHANNEL *ch)
 /* Used by various components. */
 static OSSL_TIME get_time(void *arg)
 {
-    return ossl_time_now();
+    QUIC_CHANNEL *ch = arg;
+
+    if (ch->now_cb == NULL)
+        return ossl_time_now();
+
+    return ch->now_cb(ch->now_cb_arg);
 }
 
 /* Used by QSM. */
@@ -1237,7 +1245,7 @@ static void ch_tick(QUIC_TICK_RESULT *res, void *arg, uint32_t flags)
      * expired.
      */
     if (ossl_quic_channel_is_terminating(ch)) {
-        now = ossl_time_now();
+        now = get_time(ch);
 
         if (ossl_time_compare(now, ch->terminate_deadline) >= 0) {
             ch_on_terminating_timeout(ch);
@@ -1279,7 +1287,7 @@ static void ch_tick(QUIC_TICK_RESULT *res, void *arg, uint32_t flags)
      * ACKM ACK generation deadline is polled by TXP, so we don't need to handle
      * it here.
      */
-    now = ossl_time_now();
+    now = get_time(ch);
     if (ossl_time_compare(now, ch->idle_deadline) >= 0) {
         /*
          * Idle timeout differs from normal protocol violation because we do not
@@ -1934,7 +1942,7 @@ static void ch_start_terminating(QUIC_CHANNEL *ch,
             ch->state = tcause->remote ? QUIC_CHANNEL_STATE_TERMINATING_DRAINING
                                        : QUIC_CHANNEL_STATE_TERMINATING_CLOSING;
             ch->terminate_deadline
-                = ossl_time_add(ossl_time_now(),
+                = ossl_time_add(get_time(ch),
                                 ossl_time_multiply(ossl_ackm_get_pto_duration(ch->ackm),
                                                    3));
 
@@ -2038,7 +2046,7 @@ static void ch_update_idle(QUIC_CHANNEL *ch)
     if (ch->max_idle_timeout == 0)
         ch->idle_deadline = ossl_time_infinite();
     else
-        ch->idle_deadline = ossl_time_add(ossl_time_now(),
+        ch->idle_deadline = ossl_time_add(get_time(ch),
             ossl_ms2time(ch->max_idle_timeout));
 }
 
index e1e60bf2b426d7d7ec123aa276c50fc9125b137b..57db9792a988a1bf086874689ffee837d1d5687b 100644 (file)
@@ -33,6 +33,12 @@ struct quic_channel_st {
      */
     CRYPTO_RWLOCK                   *mutex;
 
+    /*
+     * Callback used to get the current time.
+     */
+    OSSL_TIME                       (*now_cb)(void *arg);
+    void                            *now_cb_arg;
+
     /*
      * The associated TLS 1.3 connection data. Used to provide the handshake
      * layer; its 'network' side is plugged into the crypto stream for each EL
index b478e7c4f27d61aac7626e1936d8ecb3804ebc5f..766a88633aa21e78cbe4e28b3204253d5ebc960d 100644 (file)
@@ -246,6 +246,16 @@ int ossl_quic_clear(SSL *s)
     return 1;
 }
 
+void ossl_quic_conn_set_override_now_cb(SSL *s,
+                                        OSSL_TIME (*now_cb)(void *arg),
+                                        void *now_cb_arg)
+{
+    QUIC_CONNECTION *qc = QUIC_CONNECTION_FROM_SSL(s);
+
+    qc->override_now_cb     = now_cb;
+    qc->override_now_cb_arg = now_cb_arg;
+}
+
 /*
  * QUIC Front-End I/O API: Network BIO Configuration
  * =================================================
@@ -683,6 +693,8 @@ static int ensure_channel(QUIC_CONNECTION *qc)
     args.is_server  = 0;
     args.tls        = qc->tls;
     args.mutex      = qc->mutex;
+    args.now_cb     = qc->override_now_cb;
+    args.now_cb_arg = qc->override_now_cb_arg;
 
     qc->ch = ossl_quic_channel_new(&args);
     if (qc->ch == NULL)
index d40505267459ebb2e8ff8203560c0b9c8ee18578..a20e92df2ada38b2bd01b4f9a1187a15a9877ea5 100644 (file)
@@ -71,6 +71,10 @@ struct quic_conn_st {
     QUIC_THREAD_ASSIST              thread_assist;
 #endif
 
+    /* If non-NULL, used instead of ossl_time_now(). Used for testing. */
+    OSSL_TIME                       (*override_now_cb)(void *arg);
+    void                            *override_now_cb_arg;
+
     /* Have we started? */
     unsigned int                    started                 : 1;
 
index 4278f13f09616936cfc7bee439f6f80bb08aa924..110e34a83751a18b1c1209d834841a7185413756 100644 (file)
@@ -94,6 +94,8 @@ QUIC_TSERVER *ossl_quic_tserver_new(const QUIC_TSERVER_ARGS *args,
     ch_args.tls         = srv->tls;
     ch_args.mutex       = srv->mutex;
     ch_args.is_server   = 1;
+    ch_args.now_cb      = srv->args.now_cb;
+    ch_args.now_cb_arg  = srv->args.now_cb_arg;
 
     if ((srv->ch = ossl_quic_channel_new(&ch_args)) == NULL)
         goto err;