cpl integer integer
crc32([avalanche]) binary integer
crc32c([avalanche]) binary integer
+curve2name(format) string string
cut_crlf string string
da-csv-conv(prop[,prop*]) string string
date string integer
not be used for security purposes as a 32-bit hash is trivial to break. See
also "djb2", "sdbm", "wt6", "crc32" and the "hash-type" directive.
+curve2name(<format>)
+ Converts a curve name to the naming convention selected by <format>. The
+ following formats are supported:
+
+ - iana: registered TLS group name, such as "secp256r1" or "x25519".
+ Names are listed in the IANA TLS Supported Groups registry:
+ https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8
+ - ansi: ANSI X9.62 curve name, such as "prime256v1".
+ - nist: NIST curve name, such as "P-256".
+
+ The format is mandatory and case-insensitive. Input names are matched
+ case-insensitively against the known names and compatibility aliases. This
+ converter requires SSL support.
+
+ The original input is returned unchanged if it is unknown or the curve has
+ no name in the requested convention. For example,
+ "prime256v1,curve2name(iana)" produces "secp256r1", and
+ "secp256r1,curve2name(nist)" produces "P-256".
+
+ Example:
+ http-response set-header X-Curve %[ssl_fc_curve,curve2name(iana)]
+
cut_crlf
Cuts the string representation of the input sample on the first carriage
return ('\r') or newline ('\n') character found. Only the string length is
--- /dev/null
+#REGTEST_TYPE=devel
+
+varnishtest "Convert curve names between naming conventions"
+feature ignore_unknown_macro
+feature cmd "$HAPROXY_PROGRAM -cc 'feature(OPENSSL)'"
+
+haproxy h1 -conf {
+ defaults
+ mode http
+ timeout connect 5s
+ timeout client 5s
+ timeout server 5s
+
+ frontend fe
+ bind "fd@${fe}"
+ http-request return status 200 hdr x-iana %[req.hdr(curve),curve2name(IANA)] hdr x-ansi %[req.hdr(curve),curve2name(ANSI)] hdr x-nist %[req.hdr(curve),curve2name(NiSt)]
+} -start
+
+client c1 -connect ${h1_fe_sock} {
+ txreq -hdr "curve: prime256v1"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.x-iana == "secp256r1"
+ expect resp.http.x-ansi == "prime256v1"
+ expect resp.http.x-nist == "P-256"
+
+ txreq -hdr "curve: p-192"
+ rxresp
+ expect resp.http.x-iana == "secp192r1"
+ expect resp.http.x-ansi == "prime192v1"
+ expect resp.http.x-nist == "P-192"
+
+ txreq -hdr "curve: secp384r1"
+ rxresp
+ expect resp.http.x-iana == "secp384r1"
+ expect resp.http.x-ansi == "secp384r1"
+ expect resp.http.x-nist == "P-384"
+
+ txreq -hdr "curve: X25519"
+ rxresp
+ expect resp.http.x-iana == "x25519"
+ expect resp.http.x-ansi == "X25519"
+ expect resp.http.x-nist == "X25519"
+
+ txreq -hdr "curve: ecdh_x448"
+ rxresp
+ expect resp.http.x-iana == "x448"
+
+ txreq -hdr "curve: MLKEM768"
+ rxresp
+ expect resp.http.x-iana == "MLKEM768"
+
+ txreq -hdr "curve: secp256r1-extra"
+ rxresp
+ expect resp.http.x-iana == "secp256r1-extra"
+ expect resp.http.x-ansi == "secp256r1-extra"
+ expect resp.http.x-nist == "secp256r1-extra"
+} -run
#include <haproxy/api.h>
+#include <haproxy/arg.h>
#include <haproxy/buf-t.h>
#include <haproxy/chunk.h>
#include <haproxy/openssl-compat.h>
+#include <haproxy/sample.h>
+#include <haproxy/tools.h>
#include <haproxy/ssl_sock.h>
#include <haproxy/ssl_utils.h>
return -1;
}
+
+/* Validate the requested curve naming convention. */
+static int check_curve2name(struct arg *args, struct sample_conv *conv,
+ const char *file, int line, char **err)
+{
+ const char *format = args[0].data.str.area;
+
+ if (!strcasecmp(format, "iana") ||
+ !strcasecmp(format, "ansi") || !strcasecmp(format, "nist"))
+ return 1;
+
+ memprintf(err, "expected 'iana', 'ansi' or 'nist'");
+ return 0;
+}
+
+/* Compare a sample string without requiring a terminating NUL. */
+static int curve_name_matches(const struct buffer *input, const char *name)
+{
+ return name && input->data == strlen(name) &&
+ !strncasecmp(input->area, name, input->data);
+}
+
+static int sample_conv_curve2name(const struct arg *args, struct sample *smp,
+ void *private)
+{
+ struct curve *item, *canonical;
+ const char *format = args[0].data.str.area;
+ const char *name = NULL;
+
+ for (item = curves_list; item->curve_id; item++) {
+ if (curve_name_matches(&smp->data.u.str, item->ansi) ||
+ curve_name_matches(&smp->data.u.str, item->iana) ||
+ curve_name_matches(&smp->data.u.str, item->nist))
+ break;
+ }
+ if (!item->curve_id)
+ return 1;
+
+ /* Resolve compatibility aliases to the first entry for the group. */
+ for (canonical = curves_list; canonical->curve_id != item->curve_id; canonical++)
+ ;
+
+ if (!strcasecmp(format, "iana"))
+ name = canonical->iana;
+ else if (!strcasecmp(format, "ansi"))
+ name = canonical->ansi;
+ else if (!strcasecmp(format, "nist"))
+ name = canonical->nist;
+
+ if (!name)
+ return 1;
+
+ smp->data.u.str.area = (char *)name;
+ smp->data.u.str.data = strlen(name);
+ smp->data.u.str.size = 0;
+ smp->flags |= SMP_F_CONST;
+ return 1;
+}
+
+static struct sample_conv_kw_list curve_conv_kws = { ILH, {
+ { "curve2name", sample_conv_curve2name, ARG1(1,STR), check_curve2name, SMP_T_STR, SMP_T_STR },
+ { NULL, NULL, 0, 0, 0 },
+}};
+
+INITCALL1(STG_REGISTER, sample_register_convs, &curve_conv_kws);