| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616 |
- /*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2019 Andy Green <[email protected]>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
- #include "private-lib-core.h"
- #include "private-lib-jose-jwe.h"
- /*
- * From RFC7518 JWA
- *
- * 4.6. Key Agreement with Elliptic Curve Diffie-Hellman Ephemeral Static
- * (ECDH-ES)
- *
- * This section defines the specifics of key agreement with Elliptic
- * Curve Diffie-Hellman Ephemeral Static [RFC6090], in combination with
- * the Concat KDF, as defined in Section 5.8.1 of [NIST.800-56A]. The
- * key agreement result can be used in one of two ways:
- *
- * 1. directly as the Content Encryption Key (CEK) for the "enc"
- * algorithm, in the Direct Key Agreement mode, or
- *
- * 2. as a symmetric key used to wrap the CEK with the "A128KW",
- * "A192KW", or "A256KW" algorithms, in the Key Agreement with Key
- * Wrapping mode.
- *
- * A new ephemeral public key value MUST be generated for each key
- * agreement operation.
- *
- * In Direct Key Agreement mode, the output of the Concat KDF MUST be a
- * key of the same length as that used by the "enc" algorithm. In this
- * case, the empty octet sequence is used as the JWE Encrypted Key
- * value. The "alg" (algorithm) Header Parameter value "ECDH-ES" is
- * used in the Direct Key Agreement mode.
- *
- * In Key Agreement with Key Wrapping mode, the output of the Concat KDF
- * MUST be a key of the length needed for the specified key wrapping
- * algorithm. In this case, the JWE Encrypted Key is the CEK wrapped
- * with the agreed-upon key.
- *
- * The following "alg" (algorithm) Header Parameter values are used to
- * indicate that the JWE Encrypted Key is the result of encrypting the
- * CEK using the result of the key agreement algorithm as the key
- * encryption key for the corresponding key wrapping algorithm:
- *
- * +-----------------+-------------------------------------------------+
- * | "alg" Param | Key Management Algorithm |
- * | Value | |
- * +-----------------+-------------------------------------------------+
- * | ECDH-ES+A128KW | ECDH-ES using Concat KDF and CEK wrapped with |
- * | | "A128KW" |
- * | ECDH-ES+A192KW | ECDH-ES using Concat KDF and CEK wrapped with |
- * | | "A192KW" |
- * | ECDH-ES+A256KW | ECDH-ES using Concat KDF and CEK wrapped with |
- * | | "A256KW" |
- * +-----------------+-------------------------------------------------+
- *
- * 4.6.1. Header Parameters Used for ECDH Key Agreement
- *
- * The following Header Parameter names are used for key agreement as
- * defined below.
- *
- * 4.6.1.1. "epk" (Ephemeral Public Key) Header Parameter
- *
- * The "epk" (ephemeral public key) value created by the originator for
- * the use in key agreement algorithms. This key is represented as a
- * JSON Web Key [JWK] public key value. It MUST contain only public key
- * parameters and SHOULD contain only the minimum JWK parameters
- * necessary to represent the key; other JWK parameters included can be
- * checked for consistency and honored, or they can be ignored. This
- * Header Parameter MUST be present and MUST be understood and processed
- * by implementations when these algorithms are used.
- *
- * 4.6.1.2. "apu" (Agreement PartyUInfo) Header Parameter
- *
- * The "apu" (agreement PartyUInfo) value for key agreement algorithms
- * using it (such as "ECDH-ES"), represented as a base64url-encoded
- * string. When used, the PartyUInfo value contains information about
- * the producer. Use of this Header Parameter is OPTIONAL. This Header
- * Parameter MUST be understood and processed by implementations when
- * these algorithms are used.
- *
- * 4.6.1.3. "apv" (Agreement PartyVInfo) Header Parameter
- *
- * The "apv" (agreement PartyVInfo) value for key agreement algorithms
- * using it (such as "ECDH-ES"), represented as a base64url encoded
- * string. When used, the PartyVInfo value contains information about
- * the recipient. Use of this Header Parameter is OPTIONAL. This
- * Header Parameter MUST be understood and processed by implementations
- * when these algorithms are used.
- *
- * 4.6.2. Key Derivation for ECDH Key Agreement
- *
- * The key derivation process derives the agreed-upon key from the
- * shared secret Z established through the ECDH algorithm, per
- * Section 6.2.2.2 of [NIST.800-56A].
- *
- * Key derivation is performed using the Concat KDF, as defined in
- * Section 5.8.1 of [NIST.800-56A], where the Digest Method is SHA-256.
- * The Concat KDF parameters are set as follows:
- *
- * Z
- * This is set to the representation of the shared secret Z as an
- * octet sequence.
- *
- * keydatalen
- * This is set to the number of bits in the desired output key. For
- * "ECDH-ES", this is length of the key used by the "enc" algorithm.
- * For "ECDH-ES+A128KW", "ECDH-ES+A192KW", and "ECDH-ES+A256KW", this
- * is 128, 192, and 256, respectively.
- *
- * AlgorithmID
- * The AlgorithmID value is of the form Datalen || Data, where Data
- * is a variable-length string of zero or more octets, and Datalen is
- * a fixed-length, big-endian 32-bit counter that indicates the
- * length (in octets) of Data. In the Direct Key Agreement case,
- * Data is set to the octets of the ASCII representation of the "enc"
- * Header Parameter value. In the Key Agreement with Key Wrapping
- * case, Data is set to the octets of the ASCII representation of the
- * "alg" (algorithm) Header Parameter value.
- *
- * PartyUInfo
- * The PartyUInfo value is of the form Datalen || Data, where Data is
- * a variable-length string of zero or more octets, and Datalen is a
- * fixed-length, big-endian 32-bit counter that indicates the length
- * (in octets) of Data. If an "apu" (agreement PartyUInfo) Header
- * Parameter is present, Data is set to the result of base64url
- * decoding the "apu" value and Datalen is set to the number of
- * octets in Data. Otherwise, Datalen is set to 0 and Data is set to
- * the empty octet sequence.
- *
- * PartyVInfo
- * The PartyVInfo value is of the form Datalen || Data, where Data is
- * a variable-length string of zero or more octets, and Datalen is a
- * fixed-length, big-endian 32-bit counter that indicates the length
- * (in octets) of Data. If an "apv" (agreement PartyVInfo) Header
- * Parameter is present, Data is set to the result of base64url
- * decoding the "apv" value and Datalen is set to the number of
- * octets in Data. Otherwise, Datalen is set to 0 and Data is set to
- * the empty octet sequence.
- *
- * SuppPubInfo
- * This is set to the keydatalen represented as a 32-bit big-endian
- * integer.
- *
- * SuppPrivInfo
- * This is set to the empty octet sequence.
- *
- * Applications need to specify how the "apu" and "apv" Header
- * Parameters are used for that application. The "apu" and "apv" values
- * MUST be distinct, when used. Applications wishing to conform to
- * [NIST.800-56A] need to provide values that meet the requirements of
- * that document, e.g., by using values that identify the producer and
- * consumer. Alternatively, applications MAY conduct key derivation in
- * a manner similar to "Diffie-Hellman Key Agreement Method" [RFC2631]:
- * in that case, the "apu" parameter MAY either be omitted or represent
- * a random 512-bit value (analogous to PartyAInfo in Ephemeral-Static
- * mode in RFC 2631) and the "apv" parameter SHOULD NOT be present.
- *
- */
- /*
- * - ECDH-ES[-variant] comes in the jose "alg" and just covers key agreement.
- * The "enc" action is completely separate and handled elsewhere. However
- * the key size throughout is determined by the needs of the "enc" action.
- *
- * - The jwe->jws.jwk is the PEER - the encryption consumer's - public key.
- *
- * - The public part of the ephemeral key comes out in jose.jwk_ephemeral
- *
- * - Return shared secret length or < 0 for error
- *
- * - Unwrapped CEK in EKEY. If any, wrapped CEK in "wrapped".
- *
- * - Caller responsibility to cleanse EKEY.
- */
- static int
- lws_jwe_encrypt_ecdh(struct lws_jwe *jwe, char *temp, int *temp_len,
- uint8_t *cek)
- {
- uint8_t shared_secret[LWS_JWE_LIMIT_KEY_ELEMENT_BYTES],
- derived[LWS_JWE_LIMIT_KEY_ELEMENT_BYTES];
- int m, n, ret = -1, ot = *temp_len, ss_len = sizeof(shared_secret),
- // kw_hlen = lws_genhash_size(jwe->jose.alg->hash_type),
- enc_hlen = (int)lws_genhmac_size(jwe->jose.enc_alg->hmac_type),
- ekbytes = 32; //jwe->jose.alg->keybits_fixed / 8;
- struct lws_genec_ctx ecctx;
- struct lws_jwk *ephem = &jwe->jose.recipient[jwe->recip].jwk_ephemeral;
- if (jwe->jws.jwk->kty != LWS_GENCRYPTO_KTY_EC) {
- lwsl_err("%s: unexpected kty %d\n", __func__, jwe->jws.jwk->kty);
- return -1;
- }
- ephem->kty = LWS_GENCRYPTO_KTY_EC;
- ephem->private_key = 1;
- /* Generate jose.jwk_ephemeral on the peer public key curve */
- if (lws_genecdh_create(&ecctx, jwe->jws.context, NULL))
- goto bail;
- /* ephemeral context gets random key on same curve as recip pubkey */
- if (lws_genecdh_new_keypair(&ecctx, LDHS_OURS, (const char *)
- jwe->jws.jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf,
- ephem->e))
- goto bail;
- /* peer context gets js->jwk key */
- if (lws_genecdh_set_key(&ecctx, jwe->jws.jwk->e, LDHS_THEIRS)) {
- lwsl_err("%s: setting peer pubkey failed\n", __func__);
- goto bail;
- }
- /* combine our ephemeral key and the peer pubkey to get the secret */
- if (lws_genecdh_compute_shared_secret(&ecctx, shared_secret, &ss_len)) {
- lwsl_notice("%s: lws_genecdh_compute_shared_secret failed\n",
- __func__);
- goto bail;
- }
- /*
- * The private part of the ephemeral key is finished with...
- * cleanse and free it. We need to keep the public part around so we
- * can publish it with the JWE as "epk".
- */
- lws_explicit_bzero(ephem->e[LWS_GENCRYPTO_EC_KEYEL_D].buf,
- ephem->e[LWS_GENCRYPTO_EC_KEYEL_D].len);
- lws_free_set_NULL(ephem->e[LWS_GENCRYPTO_EC_KEYEL_D].buf);
- ephem->e[LWS_GENCRYPTO_EC_KEYEL_D].len = 0;
- ephem->private_key = 0;
- /*
- * Derive the CEK from the shared secret... amount of bytes written to
- * derived matches bitcount in jwe->jose.enc_alg->keybits_fixed
- *
- * In Direct Key Agreement mode, the output of the Concat KDF MUST be a
- * key of the same length as that used by the "enc" algorithm.
- */
- if (lws_jwa_concat_kdf(jwe,
- jwe->jose.alg->algtype_crypto == LWS_JOSE_ENCTYPE_NONE,
- derived, shared_secret, ss_len)) {
- lwsl_notice("%s: lws_jwa_concat_kdf failed\n", __func__);
- goto bail;
- }
- /* in P-521 case, we get a 66-byte shared secret for a 64-byte key */
- if (ss_len < enc_hlen) {
- lwsl_err("%s: concat KDF bad derived key len %d\n", __func__,
- ss_len);
- goto bail;
- }
- /*
- * For "ECDH-ES", that was it, and we use what we just wrapped in
- * wrapped as the CEK without publishing it.
- *
- * For "ECDH-ES-AES[128,192,256]KW", we generate a new, random CEK and
- * then wrap it using the key we just wrapped, and make the wrapped
- * version available in EKEY.
- */
- if (jwe->jose.alg->algtype_crypto != LWS_JOSE_ENCTYPE_NONE) {
- struct lws_gencrypto_keyelem el;
- struct lws_genaes_ctx aesctx;
- /* generate the actual CEK in cek */
- if (lws_get_random(jwe->jws.context, cek, enc_hlen) !=
- (size_t)enc_hlen) {
- lwsl_err("Problem getting random\n");
- goto bail;
- }
- /* wrap with the derived key */
- el.buf = derived;
- el.len = enc_hlen / 2;
- if (lws_genaes_create(&aesctx, LWS_GAESO_ENC, LWS_GAESM_KW, &el,
- 1, NULL)) {
- lwsl_notice("%s: lws_genaes_create\n", __func__);
- goto bail;
- }
- /* wrap CEK into EKEY */
- n = lws_genaes_crypt(&aesctx, cek, enc_hlen,
- (void *)jwe->jws.map.buf[LJWE_EKEY],
- NULL, NULL, NULL, 0);
- m = lws_genaes_destroy(&aesctx, NULL, 0);
- if (n < 0) {
- lwsl_err("%s: encrypt cek fail\n", __func__);
- goto bail;
- }
- if (m < 0) {
- lwsl_err("%s: lws_genaes_destroy fail\n", __func__);
- goto bail;
- }
- jwe->jws.map.len[LJWE_EKEY] = enc_hlen + 8;
- /* Wrapped CEK is in EKEY. Random CEK is in cek. */
- } else /* direct derived CEK is in cek */
- memcpy(cek, derived, enc_hlen);
- /* rewrite the protected JOSE header to have the epk pieces */
- jwe->jws.map.buf[LJWE_JOSE] = temp;
- m = n = lws_snprintf(temp, *temp_len,
- "{\"alg\":\"%s\", \"enc\":\"%s\", \"epk\":",
- jwe->jose.alg->alg, jwe->jose.enc_alg->alg);
- *temp_len -= n;
- n = lws_jwk_export(ephem, 0, temp + (ot - *temp_len), temp_len);
- if (n < 0) {
- lwsl_err("%s: ephemeral export failed\n", __func__);
- goto bail;
- }
- m += n;
- n = lws_snprintf(temp + (ot - *temp_len), *temp_len, "}");
- *temp_len -= n + 1;
- m += n;
- jwe->jws.map.len[LJWE_JOSE] = m;
- /* create a b64 version of the JOSE header, needed later for AAD */
- if (lws_jws_encode_b64_element(&jwe->jws.map_b64, LJWE_JOSE,
- temp + (ot - *temp_len), temp_len,
- jwe->jws.map.buf[LJWE_JOSE],
- jwe->jws.map.len[LJWE_JOSE]))
- return -1;
- ret = enc_hlen;
- bail:
- lws_genec_destroy(&ecctx);
- /* cleanse the shared secret (watch out for cek at parent too) */
- lws_explicit_bzero(shared_secret, ekbytes);
- lws_explicit_bzero(derived, ekbytes);
- return ret;
- }
- int
- lws_jwe_encrypt_ecdh_cbc_hs(struct lws_jwe *jwe, char *temp, int *temp_len)
- {
- int ss_len, // kw_hlen = lws_genhash_size(jwe->jose.alg->hash_type),
- enc_hlen = (int)lws_genhmac_size(jwe->jose.enc_alg->hmac_type);
- uint8_t cek[LWS_JWE_LIMIT_KEY_ELEMENT_BYTES];
- int ekbytes = jwe->jose.alg->keybits_fixed / 8;
- int n, ot = *temp_len, ret = -1;
- /* if we will produce an EKEY, make space for it */
- if (jwe->jose.alg->algtype_crypto != LWS_JOSE_ENCTYPE_NONE) {
- if (lws_jws_alloc_element(&jwe->jws.map, LJWE_EKEY,
- temp + (ot - *temp_len), temp_len,
- enc_hlen + 8, 0))
- goto bail;
- }
- /* decrypt the CEK */
- ss_len = lws_jwe_encrypt_ecdh(jwe, temp + (ot - *temp_len), temp_len, cek);
- if (ss_len < 0) {
- lwsl_err("%s: lws_jwe_encrypt_ecdh failed\n", __func__);
- return -1;
- }
- /* cek contains the unwrapped CEK. EKEY may contain wrapped CEK */
- /* make space for the payload encryption pieces */
- if (lws_jws_alloc_element(&jwe->jws.map, LJWE_ATAG,
- temp + (ot - *temp_len),
- temp_len, enc_hlen / 2, 0))
- goto bail;
- if (lws_jws_alloc_element(&jwe->jws.map, LJWE_IV,
- temp + (ot - *temp_len),
- temp_len, LWS_JWE_AES_IV_BYTES, 0))
- goto bail;
- /* Perform the authenticated encryption on CTXT...
- * ...the AAD is b64u(protected JOSE header) */
- n = lws_jwe_encrypt_cbc_hs(jwe, cek,
- (uint8_t *)jwe->jws.map_b64.buf[LJWE_JOSE],
- jwe->jws.map_b64.len[LJWE_JOSE]);
- if (n < 0) {
- lwsl_notice("%s: lws_jwe_encrypt_cbc_hs failed\n", __func__);
- goto bail;
- }
- ret = 0;
- bail:
- /* if fail or direct CEK, cleanse and remove EKEY */
- if (ret || jwe->jose.enc_alg->algtype_crypto == LWS_JOSE_ENCTYPE_NONE) {
- if (jwe->jws.map.len[LJWE_EKEY])
- lws_explicit_bzero((void *)jwe->jws.map.buf[LJWE_EKEY],
- jwe->jws.map.len[LJWE_EKEY]);
- jwe->jws.map.len[LJWE_EKEY] = 0;
- }
- lws_explicit_bzero(cek, ekbytes);
- return ret;
- }
- /*
- * jwe->jws.jwk is recipient private key
- *
- * If kw mode, then EKEY is the wrapped CEK
- *
- *
- */
- static int
- lws_jwe_auth_and_decrypt_ecdh(struct lws_jwe *jwe)
- {
- uint8_t shared_secret[LWS_JWE_LIMIT_KEY_ELEMENT_BYTES],
- derived[LWS_JWE_LIMIT_KEY_ELEMENT_BYTES];
- int ekbytes = jwe->jose.enc_alg->keybits_fixed / 8,
- enc_hlen = (int)lws_genhmac_size(jwe->jose.enc_alg->hmac_type);
- struct lws_genec_ctx ecctx;
- int n, ret = -1, ss_len = sizeof(shared_secret);
- if (jwe->jws.jwk->kty != LWS_GENCRYPTO_KTY_EC) {
- lwsl_err("%s: unexpected kty %d\n", __func__, jwe->jws.jwk->kty);
- return -1;
- }
- if (jwe->jose.recipient[jwe->recip].jwk_ephemeral.kty !=
- LWS_GENCRYPTO_KTY_EC) {
- lwsl_err("%s: missing epk\n", __func__);
- return -1;
- }
- /*
- * Recompute the shared secret...
- *
- * - direct: it's the CEK
- *
- * - aeskw: apply it as AES keywrap to EKEY to get the CEK
- */
- /* Generate jose.jwk_ephemeral on the peer public key curve */
- if (lws_genecdh_create(&ecctx, jwe->jws.context, NULL))
- goto bail;
- /* Load our private key into our side of the ecdh context */
- if (lws_genecdh_set_key(&ecctx, jwe->jws.jwk->e, LDHS_OURS)) {
- lwsl_err("%s: setting our private key failed\n", __func__);
- goto bail;
- }
- /* Import the ephemeral public key into the peer side */
- if (lws_genecdh_set_key(&ecctx,
- jwe->jose.recipient[jwe->recip].jwk_ephemeral.e,
- LDHS_THEIRS)) {
- lwsl_err("%s: setting epk pubkey failed\n", __func__);
- goto bail;
- }
- /* combine their ephemeral key and our private key to get the secret */
- if (lws_genecdh_compute_shared_secret(&ecctx, shared_secret, &ss_len)) {
- lwsl_notice("%s: lws_genecdh_compute_shared_secret failed\n",
- __func__);
- goto bail;
- }
- lws_genec_destroy(&ecctx);
- if (ss_len < enc_hlen) {
- lwsl_err("%s: ss_len %d ekbytes %d\n", __func__, ss_len, enc_hlen);
- goto bail;
- }
- /*
- * Derive the CEK from the shared secret... amount of bytes written to
- * cek[] matches bitcount in jwe->jose.enc_alg->keybits_fixed
- */
- if (lws_jwa_concat_kdf(jwe,
- jwe->jose.alg->algtype_crypto == LWS_JOSE_ENCTYPE_NONE,
- derived, shared_secret, ss_len)) {
- lwsl_notice("%s: lws_jwa_concat_kdf failed\n", __func__);
- goto bail;
- }
- /*
- * "ECDH-ES": derived is the CEK
- * "ECDH-ES-AES[128,192,256]KW": wrapped key is in EKEY,
- * "derived" contains KEK
- */
- if (jwe->jose.alg->algtype_crypto != LWS_JOSE_ENCTYPE_NONE) {
- struct lws_gencrypto_keyelem el;
- struct lws_genaes_ctx aesctx;
- int m;
- /* Confirm space for EKEY */
- if (jwe->jws.map.len[LJWE_EKEY] < (unsigned int)enc_hlen) {
- lwsl_err("%s: missing EKEY\n", __func__);
- goto bail;
- }
- /* unwrap with the KEK we derived */
- el.buf = derived;
- el.len = enc_hlen / 2;
- if (lws_genaes_create(&aesctx, LWS_GAESO_DEC, LWS_GAESM_KW,
- &el, 1, NULL)) {
- lwsl_notice("%s: lws_genaes_create\n", __func__);
- goto bail;
- }
- /* decrypt the EKEY to end up with CEK in "shared_secret" */
- n = lws_genaes_crypt(&aesctx,
- (const uint8_t *)jwe->jws.map.buf[LJWE_EKEY],
- jwe->jws.map.len[LJWE_EKEY],
- (uint8_t *)shared_secret,
- NULL, NULL, NULL, 0);
- m = lws_genaes_destroy(&aesctx, NULL, 0);
- if (n < 0) {
- lwsl_err("%s: decrypt cek fail\n", __func__);
- goto bail;
- }
- if (m < 0) {
- lwsl_err("%s: lws_genaes_destroy fail\n", __func__);
- goto bail;
- }
- } else
- memcpy(shared_secret, derived, enc_hlen);
- /* either way, the recovered CEK is in shared_secret */
- if (lws_jwe_auth_and_decrypt_cbc_hs(jwe, shared_secret,
- (uint8_t *)jwe->jws.map_b64.buf[LJWE_JOSE],
- jwe->jws.map_b64.len[LJWE_JOSE]) < 0) {
- lwsl_err("%s: lws_jwe_auth_and_decrypt_cbc_hs fail\n", __func__);
- goto bail;
- }
- /* if all went well, then CTXT is now the plaintext */
- ret = 0;
- bail:
- /* cleanse wrapped on stack that contained the CEK / wrapped key */
- lws_explicit_bzero(derived, ekbytes);
- /* cleanse the shared secret */
- lws_explicit_bzero(shared_secret, ekbytes);
- return ret;
- }
- int
- lws_jwe_auth_and_decrypt_ecdh_cbc_hs(struct lws_jwe *jwe,
- char *temp, int *temp_len)
- {
- /* create a b64 version of the JOSE header, needed later for AAD */
- if (lws_jws_encode_b64_element(&jwe->jws.map_b64, LJWE_JOSE,
- temp, temp_len,
- jwe->jws.map.buf[LJWE_JOSE],
- jwe->jws.map.len[LJWE_JOSE]))
- return -1;
- return lws_jwe_auth_and_decrypt_ecdh(jwe);
- }
|