private.h: rename to contain dir
[platform/upstream/libwebsockets.git] / lib / jose / jwe / jwe-ecdh-es-aeskw.c
1 /*
2  * libwebsockets - JSON Web Encryption support
3  *
4  * Copyright (C) 2018 Andy Green <andy@warmcat.com>
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation:
9  *  version 2.1 of the License.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  *  MA  02110-1301  USA
20  *
21  *
22  * JWE code related to ecdh-es + Concat KDF and aes kw
23  *
24  */
25
26 #include "private-lib-core.h"
27 #include "private-lib-jose-jwe.h"
28
29 /*
30  * From RFC7518 JWA
31  *
32  * 4.6.  Key Agreement with Elliptic Curve Diffie-Hellman Ephemeral Static
33  *    (ECDH-ES)
34  *
35  * This section defines the specifics of key agreement with Elliptic
36  * Curve Diffie-Hellman Ephemeral Static [RFC6090], in combination with
37  * the Concat KDF, as defined in Section 5.8.1 of [NIST.800-56A].  The
38  * key agreement result can be used in one of two ways:
39  *
40  * 1.  directly as the Content Encryption Key (CEK) for the "enc"
41  *     algorithm, in the Direct Key Agreement mode, or
42  *
43  * 2.  as a symmetric key used to wrap the CEK with the "A128KW",
44  *     "A192KW", or "A256KW" algorithms, in the Key Agreement with Key
45  *     Wrapping mode.
46  *
47  * A new ephemeral public key value MUST be generated for each key
48  * agreement operation.
49  *
50  * In Direct Key Agreement mode, the output of the Concat KDF MUST be a
51  * key of the same length as that used by the "enc" algorithm.  In this
52  * case, the empty octet sequence is used as the JWE Encrypted Key
53  * value.  The "alg" (algorithm) Header Parameter value "ECDH-ES" is
54  * used in the Direct Key Agreement mode.
55  *
56  * In Key Agreement with Key Wrapping mode, the output of the Concat KDF
57  * MUST be a key of the length needed for the specified key wrapping
58  * algorithm.  In this case, the JWE Encrypted Key is the CEK wrapped
59  * with the agreed-upon key.
60  *
61  * The following "alg" (algorithm) Header Parameter values are used to
62  * indicate that the JWE Encrypted Key is the result of encrypting the
63  * CEK using the result of the key agreement algorithm as the key
64  * encryption key for the corresponding key wrapping algorithm:
65  *
66  * +-----------------+-------------------------------------------------+
67  * | "alg" Param     | Key Management Algorithm                        |
68  * | Value           |                                                 |
69  * +-----------------+-------------------------------------------------+
70  * | ECDH-ES+A128KW  | ECDH-ES using Concat KDF and CEK wrapped with   |
71  * |                 | "A128KW"                                        |
72  * | ECDH-ES+A192KW  | ECDH-ES using Concat KDF and CEK wrapped with   |
73  * |                 | "A192KW"                                        |
74  * | ECDH-ES+A256KW  | ECDH-ES using Concat KDF and CEK wrapped with   |
75  * |                 | "A256KW"                                        |
76  * +-----------------+-------------------------------------------------+
77  *
78  * 4.6.1.  Header Parameters Used for ECDH Key Agreement
79  *
80  * The following Header Parameter names are used for key agreement as
81  * defined below.
82  *
83  * 4.6.1.1.  "epk" (Ephemeral Public Key) Header Parameter
84  *
85  * The "epk" (ephemeral public key) value created by the originator for
86  * the use in key agreement algorithms.  This key is represented as a
87  * JSON Web Key [JWK] public key value.  It MUST contain only public key
88  * parameters and SHOULD contain only the minimum JWK parameters
89  * necessary to represent the key; other JWK parameters included can be
90  * checked for consistency and honored, or they can be ignored.  This
91  * Header Parameter MUST be present and MUST be understood and processed
92  * by implementations when these algorithms are used.
93  *
94  * 4.6.1.2.  "apu" (Agreement PartyUInfo) Header Parameter
95  *
96  * The "apu" (agreement PartyUInfo) value for key agreement algorithms
97  * using it (such as "ECDH-ES"), represented as a base64url-encoded
98  * string.  When used, the PartyUInfo value contains information about
99  * the producer.  Use of this Header Parameter is OPTIONAL.  This Header
100  * Parameter MUST be understood and processed by implementations when
101  * these algorithms are used.
102  *
103  * 4.6.1.3.  "apv" (Agreement PartyVInfo) Header Parameter
104  *
105  * The "apv" (agreement PartyVInfo) value for key agreement algorithms
106  * using it (such as "ECDH-ES"), represented as a base64url encoded
107  * string.  When used, the PartyVInfo value contains information about
108  * the recipient.  Use of this Header Parameter is OPTIONAL.  This
109  * Header Parameter MUST be understood and processed by implementations
110  * when these algorithms are used.
111  *
112  * 4.6.2.  Key Derivation for ECDH Key Agreement
113  *
114  * The key derivation process derives the agreed-upon key from the
115  * shared secret Z established through the ECDH algorithm, per
116  * Section 6.2.2.2 of [NIST.800-56A].
117  *
118  * Key derivation is performed using the Concat KDF, as defined in
119  * Section 5.8.1 of [NIST.800-56A], where the Digest Method is SHA-256.
120  * The Concat KDF parameters are set as follows:
121  *
122  * Z
123  *    This is set to the representation of the shared secret Z as an
124  *    octet sequence.
125  *
126  * keydatalen
127  *    This is set to the number of bits in the desired output key.  For
128  *    "ECDH-ES", this is length of the key used by the "enc" algorithm.
129  *    For "ECDH-ES+A128KW", "ECDH-ES+A192KW", and "ECDH-ES+A256KW", this
130  *    is 128, 192, and 256, respectively.
131  *
132  * AlgorithmID
133  *    The AlgorithmID value is of the form Datalen || Data, where Data
134  *    is a variable-length string of zero or more octets, and Datalen is
135  *    a fixed-length, big-endian 32-bit counter that indicates the
136  *    length (in octets) of Data.  In the Direct Key Agreement case,
137  *    Data is set to the octets of the ASCII representation of the "enc"
138  *    Header Parameter value.  In the Key Agreement with Key Wrapping
139  *    case, Data is set to the octets of the ASCII representation of the
140  *    "alg" (algorithm) Header Parameter value.
141  *
142  * PartyUInfo
143  *    The PartyUInfo value is of the form Datalen || Data, where Data is
144  *    a variable-length string of zero or more octets, and Datalen is a
145  *    fixed-length, big-endian 32-bit counter that indicates the length
146  *    (in octets) of Data.  If an "apu" (agreement PartyUInfo) Header
147  *    Parameter is present, Data is set to the result of base64url
148  *    decoding the "apu" value and Datalen is set to the number of
149  *    octets in Data.  Otherwise, Datalen is set to 0 and Data is set to
150  *    the empty octet sequence.
151  *
152  * PartyVInfo
153  *    The PartyVInfo value is of the form Datalen || Data, where Data is
154  *    a variable-length string of zero or more octets, and Datalen is a
155  *    fixed-length, big-endian 32-bit counter that indicates the length
156  *    (in octets) of Data.  If an "apv" (agreement PartyVInfo) Header
157  *    Parameter is present, Data is set to the result of base64url
158  *    decoding the "apv" value and Datalen is set to the number of
159  *    octets in Data.  Otherwise, Datalen is set to 0 and Data is set to
160  *    the empty octet sequence.
161  *
162  * SuppPubInfo
163  *    This is set to the keydatalen represented as a 32-bit big-endian
164  *    integer.
165  *
166  * SuppPrivInfo
167  *    This is set to the empty octet sequence.
168  *
169  * Applications need to specify how the "apu" and "apv" Header
170  * Parameters are used for that application.  The "apu" and "apv" values
171  * MUST be distinct, when used.  Applications wishing to conform to
172  * [NIST.800-56A] need to provide values that meet the requirements of
173  * that document, e.g., by using values that identify the producer and
174  * consumer.  Alternatively, applications MAY conduct key derivation in
175  * a manner similar to "Diffie-Hellman Key Agreement Method" [RFC2631]:
176  * in that case, the "apu" parameter MAY either be omitted or represent
177  * a random 512-bit value (analogous to PartyAInfo in Ephemeral-Static
178  * mode in RFC 2631) and the "apv" parameter SHOULD NOT be present.
179  *
180  */
181
182
183 /*
184  * - ECDH-ES[-variant] comes in the jose "alg" and just covers key agreement.
185  *   The "enc" action is completely separate and handled elsewhere.  However
186  *   the key size throughout is determined by the needs of the "enc" action.
187  *
188  * - The jwe->jws.jwk is the PEER - the encryption consumer's - public key.
189  *
190  * - The public part of the ephemeral key comes out in jose.jwk_ephemeral
191  *
192  * - Return shared secret length or < 0 for error
193  *
194  * - Unwrapped CEK in EKEY.  If any, wrapped CEK in "wrapped".
195  *
196  * - Caller responsibility to cleanse EKEY.
197  */
198
199 static int
200 lws_jwe_encrypt_ecdh(struct lws_jwe *jwe, char *temp, int *temp_len,
201                      uint8_t *cek)
202 {
203         uint8_t shared_secret[LWS_JWE_LIMIT_KEY_ELEMENT_BYTES],
204                 derived[LWS_JWE_LIMIT_KEY_ELEMENT_BYTES];
205         int m, n, ret = -1, ot = *temp_len, ss_len = sizeof(shared_secret),
206           //  kw_hlen = lws_genhash_size(jwe->jose.alg->hash_type),
207             enc_hlen = lws_genhmac_size(jwe->jose.enc_alg->hmac_type),
208             ekbytes = 32; //jwe->jose.alg->keybits_fixed / 8;
209         struct lws_genec_ctx ecctx;
210         struct lws_jwk *ephem = &jwe->jose.recipient[jwe->recip].jwk_ephemeral;
211
212         if (jwe->jws.jwk->kty != LWS_GENCRYPTO_KTY_EC) {
213                 lwsl_err("%s: unexpected kty %d\n", __func__, jwe->jws.jwk->kty);
214
215                 return -1;
216         }
217
218         ephem->kty = LWS_GENCRYPTO_KTY_EC;
219         ephem->private_key = 1;
220
221         /* Generate jose.jwk_ephemeral on the peer public key curve */
222
223         if (lws_genecdh_create(&ecctx, jwe->jws.context, NULL))
224                 goto bail;
225
226         /* ephemeral context gets random key on same curve as recip pubkey */
227         if (lws_genecdh_new_keypair(&ecctx, LDHS_OURS, (const char *)
228                                 jwe->jws.jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf,
229                                 ephem->e))
230                 goto bail;
231
232         /* peer context gets js->jwk key */
233         if (lws_genecdh_set_key(&ecctx, jwe->jws.jwk->e, LDHS_THEIRS)) {
234                 lwsl_err("%s: setting peer pubkey failed\n", __func__);
235                 goto bail;
236         }
237
238         /* combine our ephemeral key and the peer pubkey to get the secret */
239
240         if (lws_genecdh_compute_shared_secret(&ecctx, shared_secret, &ss_len)) {
241                 lwsl_notice("%s: lws_genecdh_compute_shared_secret failed\n",
242                                 __func__);
243
244                 goto bail;
245         }
246
247         /*
248          * The private part of the ephemeral key is finished with...
249          * cleanse and free it.  We need to keep the public part around so we
250          * can publish it with the JWE as "epk".
251          */
252
253         lws_explicit_bzero(ephem->e[LWS_GENCRYPTO_EC_KEYEL_D].buf,
254                            ephem->e[LWS_GENCRYPTO_EC_KEYEL_D].len);
255         lws_free_set_NULL(ephem->e[LWS_GENCRYPTO_EC_KEYEL_D].buf);
256         ephem->e[LWS_GENCRYPTO_EC_KEYEL_D].len = 0;
257         ephem->private_key = 0;
258
259         /*
260          * Derive the CEK from the shared secret... amount of bytes written to
261          * derived matches bitcount in jwe->jose.enc_alg->keybits_fixed
262          *
263          * In Direct Key Agreement mode, the output of the Concat KDF MUST be a
264          * key of the same length as that used by the "enc" algorithm.
265          */
266
267         if (lws_jwa_concat_kdf(jwe,
268                         jwe->jose.alg->algtype_crypto == LWS_JOSE_ENCTYPE_NONE,
269                         derived, shared_secret, ss_len)) {
270                 lwsl_notice("%s: lws_jwa_concat_kdf failed\n", __func__);
271
272                 goto bail;
273         }
274
275         /* in P-521 case, we get a 66-byte shared secret for a 64-byte key */
276         if (ss_len < enc_hlen) {
277                 lwsl_err("%s: concat KDF bad derived key len %d\n", __func__,
278                          ss_len);
279                 goto bail;
280         }
281
282         /*
283          * For "ECDH-ES", that was it, and we use what we just wrapped in
284          * wrapped as the CEK without publishing it.
285          *
286          * For "ECDH-ES-AES[128,192,256]KW", we generate a new, random CEK and
287          * then wrap it using the key we just wrapped, and make the wrapped
288          * version available in EKEY.
289          */
290
291         if (jwe->jose.alg->algtype_crypto != LWS_JOSE_ENCTYPE_NONE) {
292                 struct lws_gencrypto_keyelem el;
293                 struct lws_genaes_ctx aesctx;
294
295                 /* generate the actual CEK in cek */
296
297                 if (lws_get_random(jwe->jws.context, cek, enc_hlen) != enc_hlen) {
298                         lwsl_err("Problem getting random\n");
299                         goto bail;
300                 }
301
302                 /* wrap with the derived key */
303
304                 el.buf = derived;
305                 el.len = enc_hlen / 2;
306
307                 if (lws_genaes_create(&aesctx, LWS_GAESO_ENC, LWS_GAESM_KW, &el,
308                                         1, NULL)) {
309
310                         lwsl_notice("%s: lws_genaes_create\n", __func__);
311                         goto bail;
312                 }
313
314                 /* wrap CEK into EKEY */
315
316                 n = lws_genaes_crypt(&aesctx, cek, enc_hlen,
317                                      (void *)jwe->jws.map.buf[LJWE_EKEY],
318                                      NULL, NULL, NULL, 0);
319                 m = lws_genaes_destroy(&aesctx, NULL, 0);
320                 if (n < 0) {
321                         lwsl_err("%s: encrypt cek fail\n", __func__);
322                         goto bail;
323                 }
324                 if (m < 0) {
325                         lwsl_err("%s: lws_genaes_destroy fail\n", __func__);
326                         goto bail;
327                 }
328
329                 jwe->jws.map.len[LJWE_EKEY] = enc_hlen + 8;
330
331                 /* Wrapped CEK is in EKEY. Random CEK is in cek. */
332
333         } else /* direct derived CEK is in cek */
334                 memcpy(cek, derived, enc_hlen);
335
336         /* rewrite the protected JOSE header to have the epk pieces */
337
338         jwe->jws.map.buf[LJWE_JOSE] = temp + (ot - *temp_len);
339
340         m = n = lws_snprintf(temp + (ot - *temp_len), *temp_len,
341                              "{\"alg\":\"%s\", \"enc\":\"%s\", \"epk\":",
342                              jwe->jose.alg->alg, jwe->jose.enc_alg->alg);
343         *temp_len -= n;
344
345         n = lws_jwk_export(ephem, 0, temp + (ot - *temp_len), temp_len);
346         if (n < 0) {
347                 lwsl_err("%s: ephemeral export failed\n", __func__);
348                 goto bail;
349         }
350         m += n;
351
352         n = lws_snprintf(temp + (ot - *temp_len), *temp_len, "}");
353         *temp_len -= n + 1;
354         m += n;
355         jwe->jws.map.len[LJWE_JOSE] = m;
356
357         /* create a b64 version of the JOSE header, needed later for AAD */
358
359         if (lws_jws_encode_b64_element(&jwe->jws.map_b64, LJWE_JOSE,
360                                        temp + (ot - *temp_len), temp_len,
361                                        jwe->jws.map.buf[LJWE_JOSE],
362                                        jwe->jws.map.len[LJWE_JOSE]))
363                 return -1;
364
365         ret = enc_hlen;
366
367 bail:
368         lws_genec_destroy(&ecctx);
369
370         /* cleanse the shared secret (watch out for cek at parent too) */
371         lws_explicit_bzero(shared_secret, ekbytes);
372         lws_explicit_bzero(derived, ekbytes);
373
374         return ret;
375 }
376
377 int
378 lws_jwe_encrypt_ecdh_cbc_hs(struct lws_jwe *jwe, char *temp, int *temp_len)
379 {
380         int ss_len, // kw_hlen = lws_genhash_size(jwe->jose.alg->hash_type),
381             enc_hlen = lws_genhmac_size(jwe->jose.enc_alg->hmac_type);
382         uint8_t cek[LWS_JWE_LIMIT_KEY_ELEMENT_BYTES];
383         int ekbytes = jwe->jose.alg->keybits_fixed / 8;
384         int n, ot = *temp_len, ret = -1;
385
386         /* if we will produce an EKEY, make space for it */
387
388         if (jwe->jose.alg->algtype_crypto != LWS_JOSE_ENCTYPE_NONE) {
389                 if (lws_jws_alloc_element(&jwe->jws.map, LJWE_EKEY,
390                                           temp + (ot - *temp_len), temp_len,
391                                           enc_hlen + 8, 0))
392                         goto bail;
393         }
394
395         /* decrypt the CEK */
396
397         ss_len = lws_jwe_encrypt_ecdh(jwe, temp + (ot - *temp_len), temp_len, cek);
398         if (ss_len < 0) {
399                 lwsl_err("%s: lws_jwe_encrypt_ecdh failed\n", __func__);
400                 return -1;
401         }
402
403         /* cek contains the unwrapped CEK.  EKEY may contain wrapped CEK */
404
405         /* make space for the payload encryption pieces */
406
407         if (lws_jws_alloc_element(&jwe->jws.map, LJWE_ATAG,
408                                   temp + (ot - *temp_len),
409                                   temp_len, enc_hlen / 2, 0))
410                 goto bail;
411
412         if (lws_jws_alloc_element(&jwe->jws.map, LJWE_IV,
413                                   temp + (ot - *temp_len),
414                                   temp_len, LWS_JWE_AES_IV_BYTES, 0))
415                 goto bail;
416
417         /* Perform the authenticated encryption on CTXT...
418          * ...the AAD is b64u(protected JOSE header) */
419
420         n = lws_jwe_encrypt_cbc_hs(jwe, cek,
421                                    (uint8_t *)jwe->jws.map_b64.buf[LJWE_JOSE],
422                                    jwe->jws.map_b64.len[LJWE_JOSE]);
423         if (n < 0) {
424                 lwsl_notice("%s: lws_jwe_encrypt_cbc_hs failed\n", __func__);
425                 goto bail;
426         }
427
428         ret = 0;
429
430 bail:
431         /* if fail or direct CEK, cleanse and remove EKEY */
432         if (ret || jwe->jose.enc_alg->algtype_crypto == LWS_JOSE_ENCTYPE_NONE) {
433                 if (jwe->jws.map.len[LJWE_EKEY])
434                         lws_explicit_bzero((void *)jwe->jws.map.buf[LJWE_EKEY],
435                                            jwe->jws.map.len[LJWE_EKEY]);
436                 jwe->jws.map.len[LJWE_EKEY] = 0;
437         }
438
439         lws_explicit_bzero(cek, ekbytes);
440
441         return ret;
442 }
443
444 /*
445  * jwe->jws.jwk is recipient private key
446  *
447  * If kw mode, then EKEY is the wrapped CEK
448  *
449  *
450  */
451
452 static int
453 lws_jwe_auth_and_decrypt_ecdh(struct lws_jwe *jwe)
454 {
455         uint8_t shared_secret[LWS_JWE_LIMIT_KEY_ELEMENT_BYTES],
456                 derived[LWS_JWE_LIMIT_KEY_ELEMENT_BYTES];
457         int ekbytes = jwe->jose.enc_alg->keybits_fixed / 8,
458                       enc_hlen = lws_genhmac_size(jwe->jose.enc_alg->hmac_type);
459         struct lws_genec_ctx ecctx;
460         int n, ret = -1, ss_len = sizeof(shared_secret);
461
462         if (jwe->jws.jwk->kty != LWS_GENCRYPTO_KTY_EC) {
463                 lwsl_err("%s: unexpected kty %d\n", __func__, jwe->jws.jwk->kty);
464
465                 return -1;
466         }
467
468         if (jwe->jose.recipient[jwe->recip].jwk_ephemeral.kty !=
469                         LWS_GENCRYPTO_KTY_EC) {
470                 lwsl_err("%s: missing epk\n", __func__);
471
472                 return -1;
473         }
474
475         /*
476          * Recompute the shared secret...
477          *
478          * - direct:  it's the CEK
479          *
480          * - aeskw: apply it as AES keywrap to EKEY to get the CEK
481          */
482
483         /* Generate jose.jwk_ephemeral on the peer public key curve */
484
485         if (lws_genecdh_create(&ecctx, jwe->jws.context, NULL))
486                 goto bail;
487
488         /* Load our private key into our side of the ecdh context */
489
490         if (lws_genecdh_set_key(&ecctx, jwe->jws.jwk->e, LDHS_OURS)) {
491                 lwsl_err("%s: setting our private key failed\n", __func__);
492                 goto bail;
493         }
494
495         /* Import the ephemeral public key into the peer side */
496         if (lws_genecdh_set_key(&ecctx,
497                         jwe->jose.recipient[jwe->recip].jwk_ephemeral.e,
498                         LDHS_THEIRS)) {
499                 lwsl_err("%s: setting epk pubkey failed\n", __func__);
500                 goto bail;
501         }
502
503         /* combine their ephemeral key and our private key to get the secret */
504
505         if (lws_genecdh_compute_shared_secret(&ecctx, shared_secret, &ss_len)) {
506                 lwsl_notice("%s: lws_genecdh_compute_shared_secret failed\n",
507                                 __func__);
508
509                 goto bail;
510         }
511
512         lws_genec_destroy(&ecctx);
513
514         if (ss_len < enc_hlen) {
515                 lwsl_err("%s: ss_len %d ekbytes %d\n", __func__, ss_len, enc_hlen);
516                 goto bail;
517         }
518
519         /*
520          * Derive the CEK from the shared secret... amount of bytes written to
521          * cek[] matches bitcount in jwe->jose.enc_alg->keybits_fixed
522          */
523
524         if (lws_jwa_concat_kdf(jwe,
525                         jwe->jose.alg->algtype_crypto == LWS_JOSE_ENCTYPE_NONE,
526                         derived, shared_secret, ss_len)) {
527                 lwsl_notice("%s: lws_jwa_concat_kdf failed\n", __func__);
528
529                 goto bail;
530         }
531
532         /*
533          * "ECDH-ES": derived is the CEK
534          * "ECDH-ES-AES[128,192,256]KW": wrapped key is in EKEY,
535          *                               "derived" contains KEK
536          */
537
538         if (jwe->jose.alg->algtype_crypto != LWS_JOSE_ENCTYPE_NONE) {
539                 struct lws_gencrypto_keyelem el;
540                 struct lws_genaes_ctx aesctx;
541                 int m;
542
543                 /* Confirm space for EKEY */
544
545                 if (jwe->jws.map.len[LJWE_EKEY] < (unsigned int)enc_hlen) {
546                         lwsl_err("%s: missing EKEY\n", __func__);
547
548                         goto bail;
549                 }
550
551                 /* unwrap with the KEK we derived */
552
553                 el.buf = derived;
554                 el.len = enc_hlen / 2;
555
556                 if (lws_genaes_create(&aesctx, LWS_GAESO_DEC, LWS_GAESM_KW,
557                                       &el, 1, NULL)) {
558
559                         lwsl_notice("%s: lws_genaes_create\n", __func__);
560                         goto bail;
561                 }
562
563                 /* decrypt the EKEY to end up with CEK in "shared_secret" */
564
565                 n = lws_genaes_crypt(&aesctx,
566                                      (const uint8_t *)jwe->jws.map.buf[LJWE_EKEY],
567                                      jwe->jws.map.len[LJWE_EKEY],
568                                      (uint8_t *)shared_secret,
569                                      NULL, NULL, NULL, 0);
570                 m = lws_genaes_destroy(&aesctx, NULL, 0);
571                 if (n < 0) {
572                         lwsl_err("%s: decrypt cek fail\n", __func__);
573                         goto bail;
574                 }
575                 if (m < 0) {
576                         lwsl_err("%s: lws_genaes_destroy fail\n", __func__);
577                         goto bail;
578                 }
579         } else
580                 memcpy(shared_secret, derived, enc_hlen);
581
582         /* either way, the recovered CEK is in shared_secret */
583
584         if (lws_jwe_auth_and_decrypt_cbc_hs(jwe, shared_secret,
585                         (uint8_t *)jwe->jws.map_b64.buf[LJWE_JOSE],
586                         jwe->jws.map_b64.len[LJWE_JOSE]) < 0) {
587                 lwsl_err("%s: lws_jwe_auth_and_decrypt_cbc_hs fail\n", __func__);
588                 goto bail;
589         }
590
591         /* if all went well, then CTXT is now the plaintext */
592         ret = 0;
593
594 bail:
595         /* cleanse wrapped on stack that contained the CEK / wrapped key */
596         lws_explicit_bzero(derived, ekbytes);
597         /* cleanse the shared secret */
598         lws_explicit_bzero(shared_secret, ekbytes);
599
600         return ret;
601 }
602
603 int
604 lws_jwe_auth_and_decrypt_ecdh_cbc_hs(struct lws_jwe *jwe,
605                                      char *temp, int *temp_len)
606 {
607         /* create a b64 version of the JOSE header, needed later for AAD */
608
609         if (lws_jws_encode_b64_element(&jwe->jws.map_b64, LJWE_JOSE,
610                                        temp, temp_len,
611                                        jwe->jws.map.buf[LJWE_JOSE],
612                                        jwe->jws.map.len[LJWE_JOSE]))
613                 return -1;
614
615         return lws_jwe_auth_and_decrypt_ecdh(jwe);
616 }