From: William Lallemand Date: Tue, 30 Jun 2026 13:14:53 +0000 (+0000) Subject: MEDIUM: ssl: add FIPS TLS 1.3 ciphersuite check for AWS-LC X-Git-Url: http://git.kaiwu.me/sitemap.xml?a=commitdiff_plain;h=8bed24905fb44bcb77d568a16102af8cfe172901;p=haproxy.git MEDIUM: ssl: add FIPS TLS 1.3 ciphersuite check for AWS-LC AWS-LC does not expose TLS 1.3 ciphersuites set via SSL_CTX_set_ciphersuites() through SSL_CTX_get_ciphers(), so the existing NID-based cipher check in ssl_fips_check_ciphers() cannot catch non-FIPS TLS 1.3 suites. This is further compounded by a defect in the AWS-LC-FIPS 3.x branch where TLS 1.3 ciphers are missing from SSL_get_ciphers() entirely (fixed in https://github.com/aws/aws-lc/pull/2092), making any SSL_CTX-based inspection unreliable across versions. Add ssl_fips_check_ciphersuites() which validates the ciphersuite string directly against a FIPS-approved allowlist (TLS_AES_128_GCM_SHA256 and TLS_AES_256_GCM_SHA384). A NULL string is silently accepted since the global defaults were already overwritten with FIPS values at init time. The new check is called right after SSL_CTX_set_ciphersuites() in both the bind (ssl_sock_prepare_ctx) and server (ssl_sock_prepare_srv_ssl_ctx) configuration paths. --- diff --git a/include/haproxy/fips.h b/include/haproxy/fips.h index 7cb70dcf6..d4c39a99f 100644 --- a/include/haproxy/fips.h +++ b/include/haproxy/fips.h @@ -9,6 +9,7 @@ #if defined(OPENSSL_IS_AWSLC) int ssl_fips_check_ciphers(SSL_CTX *ctx, const enum obj_type *obj); +int ssl_fips_check_ciphersuites(const char *ciphersuites, const enum obj_type *obj); int ssl_fips_check_version(int min_ver, const enum obj_type *obj); #endif diff --git a/src/fips.c b/src/fips.c index 4fafe972a..731abd4f8 100644 --- a/src/fips.c +++ b/src/fips.c @@ -17,6 +17,13 @@ static const int fips_approved_cipher_nids[] = { NID_undef }; +/* FIPS-approved TLS 1.3 ciphersuite names. NULL terminates the list. */ +static const char *fips_approved_ciphersuites[] = { + "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", + NULL +}; + /* Fill display fields from for use in error messages. */ static void fips_obj_info(const enum obj_type *obj, const char **proxy_name, const char **type_str, @@ -49,6 +56,48 @@ static void fips_obj_info(const enum obj_type *obj, } } +/* Check that the TLS 1.3 ciphersuite list is FIPS-compliant. */ +int ssl_fips_check_ciphersuites(const char *ciphersuites, const enum obj_type *obj) +{ + const char *proxy_name, *type_str, *obj_name, *file; + const char *p, *end; + char *list = NULL; + int i, line; + size_t len; + + if (!FIPS_mode() || !ciphersuites) + return 0; + + p = ciphersuites; + while (p && *p) { + end = strchr(p, ':'); + len = end ? (size_t)(end - p) : strlen(p); + + for (i = 0; fips_approved_ciphersuites[i]; i++) { + if (strlen(fips_approved_ciphersuites[i]) == len && + strncmp(p, fips_approved_ciphersuites[i], len) == 0) + goto next; + } + memprintf(&list, "%s%s'%.*s'", list ? list : "", + list ? ", " : "", (int)len, p); + next: + p = end ? end + 1 : NULL; + } + + if (list) { + fips_obj_info(obj, &proxy_name, &type_str, &obj_name, &file, &line); + if (file) + ha_alert("[%s:%d] %s '%s/%s': FIPS mode active but non-FIPS ciphersuite(s) configured: %s.\n", + file, line, type_str, proxy_name, obj_name, list); + else + ha_alert("%s '%s/%s': FIPS mode active but non-FIPS ciphersuite(s) configured: %s.\n", + type_str, proxy_name, obj_name, list); + free(list); + return ERR_ALERT | ERR_ABORT | ERR_FATAL; + } + return 0; +} + /* Check that the TLS 1.2 cipher list configured on is FIPS-compliant. */ int ssl_fips_check_ciphers(SSL_CTX *ctx, const enum obj_type *obj) { diff --git a/src/ssl_sock.c b/src/ssl_sock.c index b3907cc6f..f77eb0162 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -4730,6 +4730,10 @@ static int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, struct ssl_bind_con err && *err ? *err : "", curproxy->id, conf_ciphersuites, bind_conf->arg, bind_conf->file, bind_conf->line); cfgerr |= ERR_ALERT | ERR_FATAL; } +#if defined(OPENSSL_IS_AWSLC) + cfgerr |= ssl_fips_check_ciphersuites(conf_ciphersuites, + &LIST_ELEM(bind_conf->listeners.n, struct listener *, by_bind)->obj_type); +#endif #endif #if defined(OPENSSL_IS_AWSLC) @@ -5279,6 +5283,9 @@ static int ssl_sock_prepare_srv_ssl_ctx(const struct server *srv, SSL_CTX *ctx) srv->ssl_ctx.ciphersuites); cfgerr++; } +#if defined(OPENSSL_IS_AWSLC) + cfgerr += !!ssl_fips_check_ciphersuites(srv->ssl_ctx.ciphersuites, &srv->obj_type); +#endif #endif #if defined(OPENSSL_IS_AWSLC)