mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2026-03-14 03:22:06 +01:00
MINOR: jwt: Manage ec certificates in jwt_decrypt_cert
This patch adds the support of algorithms in the ECDH family in the jwt_decrypt_cert converter.
This commit is contained in:
parent
3925bb8efc
commit
31bbc1f0f1
13
reg-tests/jwt/ec_decrypt.crt
Normal file
13
reg-tests/jwt/ec_decrypt.crt
Normal file
@ -0,0 +1,13 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICBTCCAaugAwIBAgIUN+Ne3W00v5RwrlIBqhub+WHgq3kwCgYIKoZIzj0EAwIw
|
||||
VzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
|
||||
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEQMA4GA1UEAwwHZm9vLmJhcjAgFw0yNjAy
|
||||
MjYxMDM5MjhaGA8yMDUzMDcxNDEwMzkyOFowVzELMAkGA1UEBhMCQVUxEzARBgNV
|
||||
BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
|
||||
ZDEQMA4GA1UEAwwHZm9vLmJhcjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGwE
|
||||
ope2KbYUXi5bSLGiQmkaxO17SwkVbTqRrXTztIx99xj9qfSrVKFqN3lnaNDXAclG
|
||||
GnfmU/j7xsEocZdYmPujUzBRMB0GA1UdDgQWBBQZSL9UUhRofXo5X9BoS0XBug4i
|
||||
DzAfBgNVHSMEGDAWgBQZSL9UUhRofXo5X9BoS0XBug4iDzAPBgNVHRMBAf8EBTAD
|
||||
AQH/MAoGCCqGSM49BAMCA0gAMEUCIQDFDrvj5p9R7wmMRoJGUuEJu7I2xYtXDcOP
|
||||
lLE0quJtvwIgWW7vuM3B+ruCslhIrMMqD+DYeguxAxi+aHRVMnBig/c=
|
||||
-----END CERTIFICATE-----
|
||||
5
reg-tests/jwt/ec_decrypt.key
Normal file
5
reg-tests/jwt/ec_decrypt.key
Normal file
@ -0,0 +1,5 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg6qbbYYII1zqqmlDH
|
||||
hTwJt+JYBe+ELI02yAecAx+nD4yhRANCAARsBKKXtim2FF4uW0ixokJpGsTte0sJ
|
||||
FW06ka1087SMffcY/an0q1Shajd5Z2jQ1wHJRhp35lP4+8bBKHGXWJj7
|
||||
-----END PRIVATE KEY-----
|
||||
@ -53,6 +53,10 @@ haproxy h1 -conf {
|
||||
# { "kty": "RSA", "e": "AQAB", "n": "wsqJbopx18NQFYLYOq4ZeMSE89yGiEankUpf25yV8QqroKUGrASj_OeqTWUjwPGKTN1vGFFuHYxiJeAUQH2qQPmg9Oqk6-ATBEKn9COKYniQ5459UxCwmZA2RL6ufhrNyq0JF3GfXkjLDBfhU9zJJEOhknsA0L_c-X4AI3d_NbFdMqxNe1V_UWAlLcbKdwO6iC9fAvwUmDQxgy6R0DC1CMouQpenMRcALaSHar1cm4K-syoNobv3HEuqgZ3s6-hOOSqauqAO0GUozPpaIA7OeruyRl5sTWT0r-iz39bchID2bIKtcqLiFcSYPLBcxmsaQCqRlGhmv6stjTCLV1yT9w", "kid": "ff3c5c96-392e-46ef-a839-6ff16027af78", "d": "b9hXfQ8lOtw8mX1dpqPcoElGhbczz_-xq2znCXQpbBPSZBUddZvchRSH5pSSKPEHlgb3CSGIdpLqsBCv0C_XmCM9ViN8uqsYgDO9uCLIDK5plWttbkqA_EufvW03R9UgIKWmOL3W4g4t-C2mBb8aByaGGVNjLnlb6i186uBsPGkvaeLHbQcRQKAvhOUTeNiyiiCbUGJwCm4avMiZrsz1r81Y1Z5izo0ERxdZymxM3FRZ9vjTB-6DtitvTXXnaAm1JTu6TIpj38u2mnNLkGMbflOpgelMNKBZVxSmfobIbFN8CHVc1UqLK2ElsZ9RCQANgkMHlMkOMj-XT0wHa3VBUQ", "p": "8mgriveKJAp1S7SHqirQAfZafxVuAK_A2QBYPsAUhikfBOvN0HtZjgurPXSJSdgR8KbWV7ZjdJM_eOivIb_XiuAaUdIOXbLRet7t9a_NJtmX9iybhoa9VOJFMBq_rbnbbte2kq0-FnXmv3cukbC2LaEw3aEcDgyURLCgWFqt7M0", "q": "zbbTv5421GowOfKVEuVoA35CEWgl8mdasnEZac2LWxMwKExikKU5LLacLQlcOt7A6n1ZGUC2wyH8mstO5tV34Eug3fnNrbnxFUEE_ZB_njs_rtZnwz57AoUXOXVnd194seIZF9PjdzZcuwXwXbrZ2RSVW8if_ZH5OVYEM1EsA9M", "dp": "1BaIYmIKn1X3InGlcSFcNRtSOnaJdFhRpotCqkRssKUx2qBlxs7ln_5dqLtZkx5VM_UE_GE7yzc6BZOwBxtOftdsr8HVh-14ksSR9rAGEsO2zVBiEuW4qZf_aQM-ScWfU--wcczZ0dT-Ou8P87Bk9K9fjcn0PeaLoz3WTPepzNE", "dq": "kYw2u4_UmWvcXVOeV_VKJ5aQZkJ6_sxTpodRBMPyQmkMHKcW4eKU1mcJju_deqWadw5jGPPpm5yTXm5UkAwfOeookoWpGa7CvVf4kPNI6Aphn3GBjunJHNpPuU6w-wvomGsxd-NqQDGNYKHuFFMcyXO_zWXglQdP_1o1tJ1M-BM", "qi": "j94Ens784M8zsfwWoJhYq9prcSZOGgNbtFWQZO8HP8pcNM9ls7YA4snTtAS_B4peWWFAFZ0LSKPCxAvJnrq69ocmEKEk7ss1Jo062f9pLTQ6cnhMjev3IqLocIFt5Vbsg_PWYpFSR7re6FRbF9EYOM7F2-HRv1idxKCWoyQfBqk" }
|
||||
load crt rsa_oeap.pem key rsa_oeap.key jwt on
|
||||
|
||||
# Private key built out of the following JWK:
|
||||
# {"crv":"P-256","d":"6qbbYYII1zqqmlDHhTwJt-JYBe-ELI02yAecAx-nD4w","kty":"EC","x":"bASil7YpthReLltIsaJCaRrE7XtLCRVtOpGtdPO0jH0","y":"9xj9qfSrVKFqN3lnaNDXAclGGnfmU_j7xsEocZdYmPs"}
|
||||
load crt ec_decrypt.crt key ec_decrypt.key jwt on
|
||||
|
||||
listen main-fe
|
||||
bind "fd@${mainfe}"
|
||||
|
||||
@ -84,6 +88,11 @@ haproxy h1 -conf {
|
||||
|
||||
http-request set-var(txn.decrypted) var(txn.jwe),jwt_decrypt_cert(txn.pem)
|
||||
|
||||
.if ssllib_name_startswith(AWS-LC)
|
||||
acl aws_unmanaged var(txn.jwe),jwt_header_query('$.alg') -m end "A128KW" -m end "A192KW"
|
||||
http-request set-var(txn.decrypted) str("AWS-LC UNMANAGED") if aws_unmanaged
|
||||
.endif
|
||||
|
||||
http-after-response set-header X-Decrypted %[var(txn.decrypted)]
|
||||
server s1 ${s1_addr}:${s1_port}
|
||||
|
||||
@ -276,6 +285,11 @@ client c9 -connect ${h1_mainfe_sock} {
|
||||
rxresp
|
||||
expect resp.http.x-decrypted == "Random test message for ECDH-ES encrypted tokens"
|
||||
|
||||
txreq -url "/pem" -hdr "Authorization: Bearer eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTEyOENCQy1IUzI1NiIsImVwayI6eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6InhEcUZveF9oR3Q5VjZWSWZjRUpaU1VVTm1uT0V5Qk1BYzZybHlOV09lcjgiLCJ5IjoiUVZmdkstcVJ0V0J1Uk9XVzRnMmlVampqMFN3U1BzYjB6ZE10R0c2czBFUSJ9fQ..0ykoqdP2WMKra2VugMQMzg.dyCI6QGNIf-x4n0DIaXgVnGtoSCOD3sOX7I01djrFdNRRSmPnITcQiJn1lw1LbiZyqZxOLf_mJHw7BRrcgPxBG6gsP3oFBnLeXllcD6kuLtllVofaPDEKdr66W9dp6Cr.002j4NUlGTYz8d_0mTM38A" \
|
||||
-hdr "X-PEM: ${testdir}/ec_decrypt.crt"
|
||||
rxresp
|
||||
expect resp.http.x-decrypted == "Random test message for ECDH-ES encrypted token (with some extra padding for good measure)"
|
||||
|
||||
} -run
|
||||
|
||||
# ECDH-ES+A___KW
|
||||
@ -287,6 +301,11 @@ client c10 -connect ${h1_mainfe_sock} {
|
||||
rxresp
|
||||
expect resp.http.x-decrypted ~ "(Random test message for ECDH-ES encrypted tokens|AWS-LC UNMANAGED)"
|
||||
|
||||
txreq -url "/pem" -hdr "Authorization: Bearer eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImVuYyI6IkExMjhDQkMtSFMyNTYiLCJlcGsiOnsiY3J2IjoiUC0yNTYiLCJrdHkiOiJFQyIsIngiOiJKeUJzcDZtZjVCMWROYUk0ZGppX2pnMm9NdFRRQUd4akxTekdGbGJ0dXZZIiwieSI6IlFfZnlBUmZiMGpjWXFtSTZUNEdXTXA1U2dGYXZiQ3lGUGF3OHhab1BIYzAifX0.JKrKKRF9QdxUyv0KX-MV11eHpP2Vz8Amdh8j3ipd_QP57jkN-OWRCQ.CjpnSVRVV51C10cUwCTaXA.bliaBk7mGYIOGdvgiMg481iC8GiOarRrjIkUgEBuqiSJENmOi90IXgnoVp4qQdi70bJVBNuCYP7Q9sLzZc4X2g.C_TCuAfAH5020v-NdR91BA" \
|
||||
-hdr "X-PEM: ${testdir}/ec_decrypt.crt"
|
||||
rxresp
|
||||
expect resp.http.x-decrypted ~ "(Random test message for ECDH-ES\\+A128KW encrypted token|AWS-LC UNMANAGED)"
|
||||
|
||||
|
||||
# ECDH-ES+A192KW
|
||||
txreq -url "/jwk" -hdr "Authorization: Bearer eyJhbGciOiJFQ0RILUVTK0ExOTJLVyIsImVuYyI6IkExOTJDQkMtSFMzODQiLCJlcGsiOnsiY3J2IjoiUC0zODQiLCJrdHkiOiJFQyIsIngiOiJDcTd3Y0MzUm92VFRZSTMzLU9DcXBocjFlN1NzeEZWY0dOQXhEOEpWZHBRQmROaGg3Z2dLNTJKVkJ1RF9uZXVHIiwieSI6IjlaLU1MV09TQ3VZd0JZVTEtcTd2YUREWUZ1WFhqc1EwSmxpWllLVmdOU0dqVHVLY3VXQnJHemV2RzZEeGgyRHQifX0.75lt6Ixq6UhlN8uiaEphy8SiqEVsuD4Rc3QbFcmP7MJUTyt15LcZ3y-M7TJeNBh3Ajy_6K2WooU.cO9tUaQ2eVo0tIuOqb5_Bw.HQ6DqnLhW2Ad0c78WFGgwCStefYdL37xmh2Fa2mCsVNW5q0K3-xeDHYuIP9Q5xBYEY70U6wV5a0iVN87ii_iMA.feLteQh1ickYVJ2ZZ2whoVzNGRHgUpjp" \
|
||||
|
||||
65
src/jwe.c
65
src/jwe.c
@ -1110,12 +1110,14 @@ static int sample_conv_jwt_decrypt_cert(const struct arg *args, struct sample *s
|
||||
jwe_alg alg = JWE_ALG_UNMANAGED;
|
||||
jwe_enc enc = JWE_ENC_UNMANAGED;
|
||||
int rsa = 0;
|
||||
int ec = 0;
|
||||
int size = 0;
|
||||
struct buffer *cert = NULL;
|
||||
struct buffer **cek = NULL;
|
||||
struct buffer *decrypted_cek = NULL;
|
||||
struct buffer *out = NULL;
|
||||
struct jose_fields fields = {};
|
||||
EVP_PKEY *privkey = NULL;
|
||||
|
||||
input = alloc_trash_chunk();
|
||||
if (!input)
|
||||
@ -1147,6 +1149,12 @@ static int sample_conv_jwt_decrypt_cert(const struct arg *args, struct sample *s
|
||||
case JWE_ALG_RSA_OAEP_256:
|
||||
rsa = 1;
|
||||
break;
|
||||
case JWE_ALG_ECDH_ES:
|
||||
case JWE_ALG_ECDH_ES_A128KW:
|
||||
case JWE_ALG_ECDH_ES_A192KW:
|
||||
case JWE_ALG_ECDH_ES_A256KW:
|
||||
ec = 1;
|
||||
break;
|
||||
default:
|
||||
/* Not managed yet */
|
||||
goto end;
|
||||
@ -1162,30 +1170,58 @@ static int sample_conv_jwt_decrypt_cert(const struct arg *args, struct sample *s
|
||||
if (chunk_printf(cert, "%.*s", (int)b_data(&cert_smp.data.u.str), b_orig(&cert_smp.data.u.str)) <= 0)
|
||||
goto end;
|
||||
|
||||
/* With asymetric crypto algorithms we should always have a CEK */
|
||||
if (!items[JWE_ELT_CEK].length)
|
||||
goto end;
|
||||
/* With ECDH-ES no CEK will be provided. */
|
||||
if (!ec || alg != JWE_ALG_ECDH_ES) {
|
||||
|
||||
cek = &decoded_items[JWE_ELT_CEK];
|
||||
/* With asymetric crypto algorithms we should always have a CEK */
|
||||
if (!items[JWE_ELT_CEK].length)
|
||||
goto end;
|
||||
|
||||
*cek = alloc_trash_chunk();
|
||||
if (!*cek)
|
||||
goto end;
|
||||
cek = &decoded_items[JWE_ELT_CEK];
|
||||
|
||||
*cek = alloc_trash_chunk();
|
||||
if (!*cek)
|
||||
goto end;
|
||||
|
||||
|
||||
size = base64urldec(items[JWE_ELT_CEK].start, items[JWE_ELT_CEK].length,
|
||||
(*cek)->area, (*cek)->size);
|
||||
if (size < 0) {
|
||||
goto end;
|
||||
}
|
||||
(*cek)->data = size;
|
||||
}
|
||||
|
||||
decrypted_cek = alloc_trash_chunk();
|
||||
if (!decrypted_cek) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
size = base64urldec(items[JWE_ELT_CEK].start, items[JWE_ELT_CEK].length,
|
||||
(*cek)->area, (*cek)->size);
|
||||
if (size < 0) {
|
||||
goto end;
|
||||
}
|
||||
(*cek)->data = size;
|
||||
|
||||
if (rsa && decrypt_cek_rsa(*cek, decrypted_cek, cert, alg))
|
||||
goto end;
|
||||
else if (ec) {
|
||||
struct ckch_store *store = NULL;
|
||||
|
||||
if (HA_SPIN_TRYLOCK(CKCH_LOCK, &ckch_lock))
|
||||
goto end;
|
||||
|
||||
store = ckchs_lookup(b_orig(cert));
|
||||
if (!store || !store->data->key || !store->conf.jwt) {
|
||||
HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
|
||||
goto end;
|
||||
}
|
||||
|
||||
privkey = store->data->key;
|
||||
|
||||
EVP_PKEY_up_ref(privkey);
|
||||
|
||||
HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
|
||||
|
||||
if (do_decrypt_cek_ec((cek != NULL) ? *cek : NULL, decrypted_cek,
|
||||
privkey, fields.pubkey,
|
||||
alg, enc, fields.apu, fields.apv))
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (decrypt_ciphertext(enc, items, decoded_items, decrypted_cek, &out))
|
||||
goto end;
|
||||
@ -1204,6 +1240,7 @@ end:
|
||||
free_trash_chunk(out);
|
||||
clear_decoded_items(decoded_items);
|
||||
clear_jose_fields(&fields);
|
||||
EVP_PKEY_free(privkey);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user