QUIC APL: Add feature query implementation
authorHugo Landau <hlandau@openssl.org>
Mon, 22 Jan 2024 13:16:58 +0000 (13:16 +0000)
committerHugo Landau <hlandau@openssl.org>
Thu, 8 Feb 2024 16:50:00 +0000 (16:50 +0000)
Fixes https://github.com/openssl/project/issues/412
Fixes https://github.com/openssl/project/issues/415

Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/23360)

include/internal/quic_ssl.h
ssl/quic/quic_impl.c

index 47e856cd79f8be52dd015378eb3af823fdfc8539..38963d6bdca715c2933fd25fd7465358eb7ca900 100644 (file)
@@ -85,6 +85,10 @@ __owur int ossl_quic_set_incoming_stream_policy(SSL *s, int policy,
                                                 uint64_t aec);
 __owur SSL *ossl_quic_accept_stream(SSL *s, uint64_t flags);
 __owur size_t ossl_quic_get_accept_stream_queue_len(SSL *s);
+__owur int ossl_quic_get_value_uint(SSL *s, uint32_t class_, uint32_t id,
+                                    uint64_t *value);
+__owur int ossl_quic_set_value_uint(SSL *s, uint32_t class_, uint32_t id,
+                                    uint64_t value);
 
 __owur int ossl_quic_stream_reset(SSL *ssl,
                                   const SSL_STREAM_RESET_ARGS *args,
index 6261075b7691aff0b503c023d35e88ceed7934f7..f760f5f84d119fcaf2f5ec0b810098287be6ad1f 100644 (file)
@@ -3198,6 +3198,150 @@ int ossl_quic_set_incoming_stream_policy(SSL *s, int policy,
     return ret;
 }
 
+/*
+ * SSL_get_value, SSL_set_value
+ * ----------------------------
+ */
+QUIC_TAKES_LOCK
+static int qc_getset_idle_timeout(QCTX *ctx, uint32_t class_,
+                                  uint64_t *p_value_out, uint64_t *p_value_in)
+{
+    int ret = 0;
+    uint64_t value_out, value_in;
+
+    quic_lock(ctx->qc);
+
+    switch (class_) {
+    case SSL_VALUE_CLASS_FEATURE_REQUEST:
+        value_out = ossl_quic_channel_get_max_idle_timeout_request(ctx->qc->ch);
+
+        if (p_value_in != NULL) {
+            value_in = *p_value_in;
+            if (value_in > OSSL_QUIC_VLINT_MAX) {
+                QUIC_RAISE_NON_NORMAL_ERROR(ctx, ERR_R_PASSED_INVALID_ARGUMENT,
+                                            NULL);
+                goto err;
+            }
+
+            if (ossl_quic_channel_have_generated_transport_params(ctx->qc->ch)) {
+                QUIC_RAISE_NON_NORMAL_ERROR(ctx, SSL_R_FEATURE_NOT_RENEGOTIABLE,
+                                            NULL);
+                goto err;
+            }
+
+            ossl_quic_channel_set_max_idle_timeout_request(ctx->qc->ch, value_in);
+        }
+        break;
+
+    case SSL_VALUE_CLASS_FEATURE_PEER_REQUEST:
+    case SSL_VALUE_CLASS_FEATURE_NEGOTIATED:
+        if (p_value_in != NULL) {
+            QUIC_RAISE_NON_NORMAL_ERROR(ctx, SSL_R_UNSUPPORTED_CONFIG_VALUE_OP,
+                                        NULL);
+            goto err;
+        }
+
+        if (!ossl_quic_channel_is_handshake_complete(ctx->qc->ch)) {
+            QUIC_RAISE_NON_NORMAL_ERROR(ctx, SSL_R_FEATURE_NEGOTIATION_NOT_COMPLETE,
+                                        NULL);
+            goto err;
+        }
+
+        value_out = (class_ == SSL_VALUE_CLASS_FEATURE_NEGOTIATED)
+            ? ossl_quic_channel_get_max_idle_timeout_actual(ctx->qc->ch)
+            : ossl_quic_channel_get_max_idle_timeout_peer_request(ctx->qc->ch);
+        break;
+
+    default:
+        QUIC_RAISE_NON_NORMAL_ERROR(ctx, SSL_R_UNSUPPORTED_CONFIG_VALUE_CLASS,
+                                    NULL);
+        goto err;
+    }
+
+    ret = 1;
+err:
+    quic_unlock(ctx->qc);
+    if (ret && p_value_out != NULL)
+        *p_value_out = value_out;
+
+    return ret;
+}
+
+QUIC_TAKES_LOCK
+static int qc_get_stream_avail(QCTX *ctx, uint32_t class_,
+                               int is_uni, int is_remote,
+                               uint64_t *value)
+{
+    int ret = 0;
+
+    if (class_ != SSL_VALUE_CLASS_GENERIC) {
+        QUIC_RAISE_NON_NORMAL_ERROR(ctx, SSL_R_UNSUPPORTED_CONFIG_VALUE_CLASS,
+                                    NULL);
+        return 0;
+    }
+
+    quic_lock(ctx->qc);
+
+    *value = is_remote
+        ? ossl_quic_channel_get_remote_stream_count_avail(ctx->qc->ch, is_uni)
+        : ossl_quic_channel_get_local_stream_count_avail(ctx->qc->ch, is_uni);
+
+    ret = 1;
+    quic_unlock(ctx->qc);
+    return ret;
+}
+
+QUIC_TAKES_LOCK
+int ossl_quic_get_value_uint(SSL *s, uint32_t class_, uint32_t id,
+                             uint64_t *value)
+{
+    QCTX ctx;
+
+    if (!expect_quic_conn_only(s, &ctx))
+        return 0;
+
+    switch (id) {
+    case SSL_VALUE_QUIC_IDLE_TIMEOUT:
+        return qc_getset_idle_timeout(&ctx, class_, value, NULL);
+
+    case SSL_VALUE_QUIC_STREAM_BIDI_LOCAL_AVAIL:
+        return qc_get_stream_avail(&ctx, class_, /*uni=*/0, /*remote=*/0, value);
+    case SSL_VALUE_QUIC_STREAM_BIDI_REMOTE_AVAIL:
+        return qc_get_stream_avail(&ctx, class_, /*uni=*/0, /*remote=*/1, value);
+    case SSL_VALUE_QUIC_STREAM_UNI_LOCAL_AVAIL:
+        return qc_get_stream_avail(&ctx, class_, /*uni=*/1, /*remote=*/0, value);
+    case SSL_VALUE_QUIC_STREAM_UNI_REMOTE_AVAIL:
+        return qc_get_stream_avail(&ctx, class_, /*uni=*/1, /*remote=*/1, value);
+
+    default:
+        return QUIC_RAISE_NON_NORMAL_ERROR(&ctx,
+                                           SSL_R_UNSUPPORTED_CONFIG_VALUE, NULL);
+    }
+
+    return 1;
+}
+
+QUIC_TAKES_LOCK
+int ossl_quic_set_value_uint(SSL *s, uint32_t class_, uint32_t id,
+                             uint64_t value)
+{
+    QCTX ctx;
+
+    if (!expect_quic_conn_only(s, &ctx))
+        return 0;
+
+    switch (id) {
+    case SSL_VALUE_QUIC_IDLE_TIMEOUT:
+        return qc_getset_idle_timeout(&ctx, class_, NULL, &value);
+
+    default:
+        return QUIC_RAISE_NON_NORMAL_ERROR(&ctx,
+                                           SSL_R_UNSUPPORTED_CONFIG_VALUE, NULL);
+    }
+
+    return 1;
+}
+
 /*
  * SSL_accept_stream
  * -----------------