]> git.kaiwu.me - haproxy.git/commitdiff
MEDIUM: ssl: add FIPS TLS 1.2 cipher check for AWS-LC
authorWilliam Lallemand <wlallemand@haproxy.com>
Tue, 30 Jun 2026 12:39:50 +0000 (12:39 +0000)
committerWilliam Lallemand <wlallemand@haproxy.com>
Tue, 30 Jun 2026 13:55:58 +0000 (13:55 +0000)
Add ssl_fips_check_ciphers() to check the cipher list already loaded
into an SSL_CTX against the FIPS-approved bulk cipher NID allowlist
(AES-128-GCM, AES-256-GCM).  The check is run unconditionally after
SSL_CTX_set_cipher_list() for both bind and server contexts.

The function reuses the fips_obj_info() helper introduced with the
version check to emit precise 'type proxy/name [file:line]' error
messages and returns ERR_ALERT|ERR_ABORT|ERR_FATAL on violation.

include/haproxy/fips.h
src/fips.c
src/ssl_sock.c

index 5b6dcee2b701bd5a836e0b99c288dedf1434d076..7cb70dcf68eea03f0708a38e481d1d2976205130 100644 (file)
@@ -8,6 +8,7 @@
 #include <haproxy/openssl-compat.h>
 
 #if defined(OPENSSL_IS_AWSLC)
+int ssl_fips_check_ciphers(SSL_CTX *ctx, const enum obj_type *obj);
 int ssl_fips_check_version(int min_ver, const enum obj_type *obj);
 #endif
 
index e24af8c425607df4af013520acdb34b2a9a9f9e7..4fafe972ace1fa6c12fd71629d0b9311d0a8ad42 100644 (file)
 #include <haproxy/ssl_sock-t.h>
 #include <haproxy/tools.h>
 
+/* FIPS-approved bulk cipher NIDs (TLS 1.2).  NID_undef terminates the list. */
+static const int fips_approved_cipher_nids[] = {
+       NID_aes_128_gcm,
+       NID_aes_256_gcm,
+       NID_undef
+};
+
 /* Fill display fields from <obj> for use in error messages. */
 static void fips_obj_info(const enum obj_type *obj,
                           const char **proxy_name, const char **type_str,
@@ -42,6 +49,49 @@ static void fips_obj_info(const enum obj_type *obj,
        }
 }
 
+/* Check that the TLS 1.2 cipher list configured on <ctx> is FIPS-compliant. */
+int ssl_fips_check_ciphers(SSL_CTX *ctx, const enum obj_type *obj)
+{
+       const char *proxy_name, *type_str, *obj_name, *file;
+       STACK_OF(SSL_CIPHER) *cipher_list;
+       const SSL_CIPHER *cipher;
+       int i, j, cipher_nid, line;
+       char *list = NULL;
+
+       if (!FIPS_mode())
+               return 0;
+
+       cipher_list = SSL_CTX_get_ciphers(ctx);
+       if (!cipher_list)
+               return 0;
+
+       for (i = 0; i < sk_SSL_CIPHER_num(cipher_list); i++) {
+               cipher     = sk_SSL_CIPHER_value(cipher_list, i);
+               cipher_nid = SSL_CIPHER_get_cipher_nid(cipher);
+
+               for (j = 0; fips_approved_cipher_nids[j] != NID_undef; j++) {
+                       if (cipher_nid == fips_approved_cipher_nids[j])
+                               goto next;
+               }
+               memprintf(&list, "%s%s'%s'", list ? list : "",
+                         list ? ", " : "", SSL_CIPHER_get_name(cipher));
+       next:;
+       }
+
+       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 cipher(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 cipher(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 minimum TLS version <min_ver> is FIPS-compliant. */
 int ssl_fips_check_version(int min_ver, const enum obj_type *obj)
 {
index 47583ffa9b0b1ede68b9680a9940ab95362ece38..77f88e2d033c4880f30a6f4cc93d7d9ac4b43793 100644 (file)
@@ -4732,6 +4732,11 @@ static int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, struct ssl_bind_con
        }
 #endif
 
+#if defined(OPENSSL_IS_AWSLC)
+       cfgerr |= ssl_fips_check_ciphers(ctx,
+                                        &LIST_ELEM(bind_conf->listeners.n, struct listener *, by_bind)->obj_type);
+#endif
+
 #ifndef OPENSSL_NO_DH
        if (!local_dh_1024)
                local_dh_1024 = ssl_get_dh_1024();
@@ -5275,6 +5280,10 @@ static int ssl_sock_prepare_srv_ssl_ctx(const struct server *srv, SSL_CTX *ctx)
                cfgerr++;
        }
 #endif
+
+#if defined(OPENSSL_IS_AWSLC)
+       cfgerr += !!ssl_fips_check_ciphers(ctx, &srv->obj_type);
+#endif
 #if defined(OPENSSL_NPN_NEGOTIATED) && !defined(OPENSSL_NO_NEXTPROTONEG)
        if (srv->ssl_ctx.npn_str)
                SSL_CTX_set_next_proto_select_cb(ctx, ssl_sock_srv_select_protos, (struct server*)srv);