From: William Lallemand Date: Thu, 6 Mar 2025 16:15:23 +0000 (+0100) Subject: TESTS: jws: implement a test for JWS signing X-Git-Tag: v3.2-dev8~118 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d014d7ee724555eb7744f2b93048529c292f9374;p=thirdparty%2Fhaproxy.git TESTS: jws: implement a test for JWS signing This test returns a JWS payload signed a specified private key in the PEM format, and uses the "jose" command tool to check if the signature is correct against the jwk public key. The test could be improved later by using the code from jwt.c allowing to check a signature. --- diff --git a/src/jws.c b/src/jws.c index ebf3d8451..72793e2eb 100644 --- a/src/jws.c +++ b/src/jws.c @@ -455,6 +455,94 @@ int jws_flattened(char *protected, char *payload, char *signature, char *dst, si return ret; } + +int jws_debug(int argc, char **argv) +{ + FILE *f = NULL; + EVP_PKEY *pkey = NULL; + char jwk[1024]; + + + char b64prot[4096]; + char b64payload[4096]; + char b64sign[4096]; + char output[16384]; + + int ret = 1; + const char *filename = NULL; + char *payload = NULL; + char *alg = NULL; + char *nonce = NULL; + char *url = NULL; + int nid; + + if (argc < 5) { + fprintf(stderr, "error: -U jws !\n"); + goto out; + } + + filename = argv[1]; + payload = argv[2]; + nonce = argv[3]; + url = argv[4]; + + if ((f = fopen(filename, "r")) == NULL) { + fprintf(stderr, "fopen!\n"); + goto out; + } + if ((pkey = PEM_read_PrivateKey(f, NULL, NULL, NULL)) == NULL) { + fprintf(stderr, "PEM_read_PrivateKey!\n"); + goto out; + } + + ret = !EVP_PKEY_to_pub_jwk(pkey, jwk, sizeof(jwk)); + + fprintf(stderr, "JWK: %s\n", jwk); + + if (EVP_PKEY_base_id(pkey) == EVP_PKEY_EC) { +#if HA_OPENSSL_VERSION_NUMBER > 0x30000000L + char curve[32] = {}; + size_t curvelen; + + if (EVP_PKEY_get_utf8_string_param(pkey, OSSL_PKEY_PARAM_GROUP_NAME, curve, sizeof(curve), &curvelen) == 0) + goto out; + + nid = curves2nid(curve); + +#else + const EC_KEY *ec = NULL; + const EC_GROUP *ec_group = NULL; + + if ((ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) + goto out; + if ((ec_group = EC_KEY_get0_group(ec)) == NULL) + goto out; + + nid = EC_GROUP_get_curve_name(ec_group); +#endif + switch (nid) { + case NID_X9_62_prime256v1: alg = "ES256"; break; + case NID_secp384r1: alg = "ES384"; break; + case NID_secp521r1: alg = "ES512"; break; + } + } else { + alg = "RS256"; + } + + jws_b64_protected(alg, NULL, jwk, nonce, url, b64prot, sizeof(b64prot)); + jws_b64_payload(payload, b64payload, sizeof(b64payload)); + jws_b64_signature(pkey, b64prot, b64payload, b64sign, sizeof(b64sign)); + jws_flattened(b64prot, b64payload, b64sign, output, sizeof(output)); + + fprintf(stdout, "%s", output); + + EVP_PKEY_free(pkey); +out: + + return ret; +} + + int jwk_debug(int argc, char **argv) { FILE *f = NULL; @@ -489,6 +577,7 @@ out: static void __jws_init(void) { hap_register_unittest("jwk", jwk_debug); + hap_register_unittest("jws", jws_debug); } diff --git a/tests/unit/jwk/jws.sh b/tests/unit/jwk/jws.sh new file mode 100755 index 000000000..8937d408b --- /dev/null +++ b/tests/unit/jwk/jws.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +check() { +# This test depends on the "jose" command tool, we can probably replace it later by the verifying code from jwt.c + + command -v jose + ${HAPROXY_PROGRAM} -vv | grep -E '^Unit tests list :' | grep -q "jws" +} + +run() { + + ${HAPROXY_PROGRAM} -U jws ${ROOTDIR}/tests/unit/jwk/ecdsa.key '{ "test": "yes" }' "KtFDYsfAgsiquFl9S921hd5K_QbdoqVyPSQ-8r8Ig7ZqOFg_WZQ" "https://haproxy.com" | jose jws ver -i- -k $ROOTDIR/tests/unit/jwk/ecdsa.pub.jwk -O- + ${HAPROXY_PROGRAM} -U jws ${ROOTDIR}/tests/unit/jwk/rsa.key '{ "test": "yes" }' "KtFDYsfAgsiquFl9S921hd5K_QbdoqVyPSQ-8r8Ig7ZqOFg_WZQ" "https://haproxy.com" | jose jws ver -i- -k $ROOTDIR/tests/unit/jwk/rsa.pub.jwk -O- +} + +case "$1" in + "check") + check + ;; + "run") + run + ;; +esac