MEDIUM: ssl: add FIPS elliptic curve check for AWS-LC

Add ssl_fips_check_curves() which validates the configured curve list
against the FIPS-approved NIST P-curves (P-256, P-384, P-521).  Each
colon-separated name is resolved to a NID via OBJ_txt2nid() so all
standard aliases (P-256, prime256v1, secp256r1) are handled uniformly.
A NULL list is silently accepted since the global defaults were already
overwritten with FIPS values at init time.

The check is called right after SSL_CTX_set1_curves_list() in both the
bind (ssl_sock_prepare_ctx) and server (ssl_sock_prepare_srv_ssl_ctx)
configuration paths.
This commit is contained in:
William Lallemand 2026-06-30 13:28:03 +00:00
parent 8f7351fb02
commit 035e4000c8
3 changed files with 67 additions and 0 deletions

View file

@ -10,6 +10,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_curves(const char *curves, const enum obj_type *obj);
int ssl_fips_check_version(int min_ver, const enum obj_type *obj);
#endif

View file

@ -4,6 +4,8 @@
#include <stdlib.h>
#include <openssl/ec.h>
#include <haproxy/errors.h>
#include <haproxy/obj_type.h>
#include <haproxy/openssl-compat.h>
@ -20,6 +22,14 @@ static const int fips_approved_cipher_nids[] = {
NID_undef
};
/* FIPS-approved elliptic curve NIDs (NIST P-curves). NID_undef terminates the list. */
static const int fips_approved_curve_nids[] = {
NID_X9_62_prime256v1, /* P-256 */
NID_secp384r1, /* P-384 */
NID_secp521r1, /* P-521 */
NID_undef
};
/* FIPS-approved TLS 1.3 ciphersuite names. NULL terminates the list.
* TLS_AES_128_CCM_SHA256 is FIPS-approved but not implemented by AWS-LC. */
static const char *fips_approved_ciphersuites[] = {
@ -103,6 +113,55 @@ int ssl_fips_check_ciphersuites(const char *ciphersuites, const enum obj_type *o
return 0;
}
/* Check that the elliptic curve list <curves> is FIPS-compliant. */
int ssl_fips_check_curves(const char *curves, const enum obj_type *obj)
{
const char *proxy_name, *type_str, *obj_name, *file;
const char *p, *end;
char *list = NULL;
char name[64];
int i, nid, line;
size_t len;
if (!FIPS_mode() || !curves)
return 0;
p = curves;
while (p && *p) {
end = strchr(p, ':');
len = end ? (size_t)(end - p) : strlen(p);
if (len < sizeof(name)) {
memcpy(name, p, len);
name[len] = '\0';
nid = OBJ_txt2nid(name);
if (nid == NID_undef)
nid = EC_curve_nist2nid(name);
for (i = 0; fips_approved_curve_nids[i] != NID_undef; i++) {
if (nid == fips_approved_curve_nids[i])
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 curve(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 curve(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 <ctx> is FIPS-compliant. */
int ssl_fips_check_ciphers(SSL_CTX *ctx, const enum obj_type *obj)
{

View file

@ -4788,6 +4788,10 @@ static int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, struct ssl_bind_con
}
(void)SSL_CTX_set_ecdh_auto(ctx, 1);
}
#if defined(OPENSSL_IS_AWSLC)
cfgerr |= ssl_fips_check_curves(conf_curves,
&LIST_ELEM(bind_conf->listeners.n, struct listener *, by_bind)->obj_type);
#endif
#endif /* defined(SSL_CTX_set1_curves_list) */
if (!conf_curves) {
@ -5330,6 +5334,9 @@ static int ssl_sock_prepare_srv_ssl_ctx(const struct server *srv, SSL_CTX *ctx)
cfgerr++;
}
}
#if defined(OPENSSL_IS_AWSLC)
cfgerr += !!ssl_fips_check_curves(conf_curves, &srv->obj_type);
#endif
#endif /* defined(SSL_CTX_set1_curves_list) */
return cfgerr;