int sctl_ex_index = -1;
+/* Returns 1 with the selected context's SCT list in <out>/<outlen>, or 0
+ * to omit the extension when that context has no list.
+ */
static __maybe_unused int ssl_sock_sctl_add_cbk(SSL *ssl, unsigned ext_type, const unsigned char **out, size_t *outlen, int *al, void *add_arg)
{
- struct buffer *sctl = add_arg;
+ struct buffer *sctl;
+
+ /* All frontend contexts register the extension; only some have a list. */
+ sctl = SSL_CTX_get_ex_data(SSL_get_SSL_CTX(ssl), sctl_ex_index);
+ if (!sctl)
+ return 0;
*out = (unsigned char *) sctl->area;
*outlen = sctl->data;
return 1;
}
+/* Accepts the client's SCT request without inspecting its payload. Returns 1. */
static __maybe_unused int ssl_sock_sctl_parse_cbk(SSL *s, unsigned int ext_type, const unsigned char *in, size_t inlen, int *al, void *parse_arg)
{
return 1;
}
+/* Attaches <sctl> to <ctx>. Returns 0 on success or -1 on failure. */
static int ssl_sock_load_sctl(SSL_CTX *ctx, struct buffer *sctl)
{
- int ret = -1;
-
- if (!SSL_CTX_add_server_custom_ext(ctx, CT_EXTENSION_TYPE, ssl_sock_sctl_add_cbk, NULL, sctl, ssl_sock_sctl_parse_cbk, NULL))
- goto out;
-
- SSL_CTX_set_ex_data(ctx, sctl_ex_index, sctl);
+ if (!SSL_CTX_set_ex_data(ctx, sctl_ex_index, sctl))
+ return -1;
+ return 0;
+}
- ret = 0;
+#endif
-out:
- return ret;
-}
+/* Registers SCTL on frontend <ctx> of <bind_conf>. Call after creating each
+ * context so extension arrays match across SSL_set_SSL_CTX() switches,
+ * avoiding out-of-bounds accesses in OpenSSL. Skip QUIC: native OpenSSL
+ * reads freed memory when merging its transport parameters extension.
+ * Returns 1 on success (including skipped contexts), 0 on failure.
+ */
+int ssl_sock_ctx_add_sctl_ext(struct bind_conf *bind_conf, SSL_CTX *ctx)
+{
+#ifdef HAVE_SSL_CTX_ADD_SERVER_CUSTOM_EXT
+ /* xprt is not yet set to QUIC when certificates are loaded */
+ if (bind_conf->options & BC_O_USE_SOCK_DGRAM)
+ return 1;
+ if (!SSL_CTX_add_server_custom_ext(ctx, CT_EXTENSION_TYPE, ssl_sock_sctl_add_cbk, NULL, NULL, ssl_sock_sctl_parse_cbk, NULL))
+ return 0;
#endif
+ return 1;
+}
static void ssl_sock_infocbk(const SSL *ssl, int where, int ret)
{
SSL_CTX_set_ex_data(ctx, ssl_crtname_index, crtname);
+ if (!ssl_sock_ctx_add_sctl_ext(bind_conf, ctx)) {
+ memprintf(err, "%sunable to register the SCTL extension for cert '%s'.\n",
+ err && *err ? *err : "", path);
+ errcode |= ERR_ALERT | ERR_FATAL;
+ goto error;
+ }
+
if (global_ssl.security_level > -1)
SSL_CTX_set_security_level(ctx, global_ssl.security_level);
bind_conf->initial_ctx = ctx;
+ if (!ssl_sock_ctx_add_sctl_ext(bind_conf, ctx)) {
+ cfgerr += 1;
+ ha_alert("Proxy '%s': failed to register the SCTL extension for bind '%s' at [%s:%d].\n",
+ bind_conf->frontend->id, bind_conf->arg, bind_conf->file, bind_conf->line);
+ }
+
if (global_ssl.security_level > -1)
SSL_CTX_set_security_level(ctx, global_ssl.security_level);