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