Update Files
This commit is contained in:
271
Kinc/Sources/kinc/libs/jose/jwe/enc/aescbc.c
Executable file
271
Kinc/Sources/kinc/libs/jose/jwe/enc/aescbc.c
Executable file
@ -0,0 +1,271 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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"
|
||||
|
||||
int
|
||||
lws_jwe_encrypt_cbc_hs(struct lws_jwe *jwe, uint8_t *cek,
|
||||
uint8_t *aad, int aad_len)
|
||||
{
|
||||
int n, hlen = (int)lws_genhmac_size(jwe->jose.enc_alg->hmac_type);
|
||||
uint8_t digest[LWS_GENHASH_LARGEST];
|
||||
struct lws_gencrypto_keyelem el;
|
||||
struct lws_genhmac_ctx hmacctx;
|
||||
struct lws_genaes_ctx aesctx;
|
||||
size_t paddedlen;
|
||||
uint8_t al[8];
|
||||
|
||||
/* Caller must have prepared space for the results */
|
||||
|
||||
if (jwe->jws.map.len[LJWE_ATAG] != (unsigned int)hlen / 2) {
|
||||
lwsl_notice("%s: expected tag len %d, got %d\n", __func__,
|
||||
hlen / 2, (int)jwe->jws.map.len[LJWE_ATAG]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (jwe->jws.map.len[LJWE_IV] != 16) {
|
||||
lwsl_notice("expected iv len %d, got %d\n", 16,
|
||||
(int)jwe->jws.map.len[LJWE_IV]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* first create the authentication hmac */
|
||||
|
||||
/* JWA Section 5.2.2.1
|
||||
*
|
||||
* 1. The secondary keys MAC_KEY and ENC_KEY are generated from the
|
||||
* input key K as follows. Each of these two keys is an octet
|
||||
* string.
|
||||
*
|
||||
* MAC_KEY consists of the initial MAC_KEY_LEN octets of K, in
|
||||
* order.
|
||||
* ENC_KEY consists of the final ENC_KEY_LEN octets of K, in
|
||||
* order.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 2. The IV used is a 128-bit value generated randomly or
|
||||
* pseudorandomly for use in the cipher.
|
||||
*/
|
||||
lws_get_random(jwe->jws.context, (void *)jwe->jws.map.buf[LJWE_IV], 16);
|
||||
|
||||
/*
|
||||
* 3. The plaintext is CBC encrypted using PKCS #7 padding using
|
||||
* ENC_KEY as the key and the IV. We denote the ciphertext output
|
||||
* from this step as E.
|
||||
*/
|
||||
|
||||
/* second half is the AES ENC_KEY */
|
||||
el.buf = cek + (hlen / 2);
|
||||
el.len = (uint32_t)(hlen / 2);
|
||||
|
||||
if (lws_genaes_create(&aesctx, LWS_GAESO_ENC, LWS_GAESM_CBC, &el,
|
||||
LWS_GAESP_WITH_PADDING, NULL)) {
|
||||
lwsl_err("%s: lws_genaes_create failed\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* the plaintext gets delivered to us in LJWE_CTXT, this replaces the
|
||||
* plaintext there with the ciphertext, which will be larger by some
|
||||
* padding bytes
|
||||
*/
|
||||
n = lws_genaes_crypt(&aesctx, (uint8_t *)jwe->jws.map.buf[LJWE_CTXT],
|
||||
jwe->jws.map.len[LJWE_CTXT],
|
||||
(uint8_t *)jwe->jws.map.buf[LJWE_CTXT],
|
||||
(uint8_t *)jwe->jws.map.buf[LJWE_IV],
|
||||
NULL, NULL, LWS_AES_CBC_BLOCKLEN);
|
||||
paddedlen = lws_gencrypto_padded_length(LWS_AES_CBC_BLOCKLEN,
|
||||
jwe->jws.map.len[LJWE_CTXT]);
|
||||
jwe->jws.map.len[LJWE_CTXT] = (uint32_t)paddedlen;
|
||||
lws_genaes_destroy(&aesctx, (uint8_t *)jwe->jws.map.buf[LJWE_CTXT] +
|
||||
paddedlen - LWS_AES_CBC_BLOCKLEN, LWS_AES_CBC_BLOCKLEN);
|
||||
if (n) {
|
||||
lwsl_err("%s: lws_genaes_crypt failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 4. The octet string AL is equal to the number of bits in the
|
||||
* Additional Authenticated Data A expressed as a 64-bit unsigned
|
||||
* big-endian integer.
|
||||
*/
|
||||
lws_jwe_be64((unsigned int)aad_len * 8, al);
|
||||
|
||||
/* first half of the CEK is the MAC key */
|
||||
if (lws_genhmac_init(&hmacctx, jwe->jose.enc_alg->hmac_type,
|
||||
cek, (unsigned int)hlen / 2))
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* 5. A message Authentication Tag T is computed by applying HMAC
|
||||
* [RFC2104] to the following data, in order:
|
||||
*
|
||||
* - the Additional Authenticated Data A,
|
||||
* - the Initialization Vector IV,
|
||||
* - the ciphertext E computed in the previous step, and
|
||||
* - the octet string AL defined above.
|
||||
*
|
||||
* The string MAC_KEY is used as the MAC key. We denote the output
|
||||
* of the MAC computed in this step as M. The first T_LEN octets of
|
||||
* M are used as T.
|
||||
*/
|
||||
|
||||
if (lws_genhmac_update(&hmacctx, aad, (unsigned int)aad_len) ||
|
||||
lws_genhmac_update(&hmacctx, jwe->jws.map.buf[LJWE_IV],
|
||||
LWS_JWE_AES_IV_BYTES) ||
|
||||
/* since we encrypted it, this is the ciphertext */
|
||||
lws_genhmac_update(&hmacctx,
|
||||
(uint8_t *)jwe->jws.map.buf[LJWE_CTXT],
|
||||
jwe->jws.map.len[LJWE_CTXT]) ||
|
||||
lws_genhmac_update(&hmacctx, al, 8)) {
|
||||
lwsl_err("%s: hmac computation failed\n", __func__);
|
||||
lws_genhmac_destroy(&hmacctx, NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lws_genhmac_destroy(&hmacctx, digest)) {
|
||||
lwsl_err("%s: problem destroying hmac\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* create tag */
|
||||
memcpy((void *)jwe->jws.map.buf[LJWE_ATAG], digest, (unsigned int)hlen / 2);
|
||||
|
||||
return (int)jwe->jws.map.len[LJWE_CTXT];
|
||||
}
|
||||
|
||||
int
|
||||
lws_jwe_auth_and_decrypt_cbc_hs(struct lws_jwe *jwe, uint8_t *enc_cek,
|
||||
uint8_t *aad, int aad_len)
|
||||
{
|
||||
int n, hlen = (int)lws_genhmac_size(jwe->jose.enc_alg->hmac_type);
|
||||
uint8_t digest[LWS_GENHASH_LARGEST];
|
||||
struct lws_gencrypto_keyelem el;
|
||||
struct lws_genhmac_ctx hmacctx;
|
||||
struct lws_genaes_ctx aesctx;
|
||||
uint8_t al[8];
|
||||
|
||||
/* Some sanity checks on what came in */
|
||||
|
||||
if (jwe->jws.map.len[LJWE_ATAG] != (unsigned int)hlen / 2) {
|
||||
lwsl_notice("%s: expected tag len %d, got %d\n", __func__,
|
||||
hlen / 2, (int)jwe->jws.map.len[LJWE_ATAG]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (jwe->jws.map.len[LJWE_IV] != 16) {
|
||||
lwsl_notice("expected iv len %d, got %d\n", 16,
|
||||
(int)jwe->jws.map.len[LJWE_IV]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Prepare to check authentication
|
||||
*
|
||||
* AAD is the b64 JOSE header.
|
||||
*
|
||||
* The octet string AL, which is the number of bits in AAD expressed as
|
||||
* a big-endian 64-bit unsigned integer is:
|
||||
*
|
||||
* [0, 0, 0, 0, 0, 0, 1, 152]
|
||||
*
|
||||
* Concatenate the AAD, the Initialization Vector, the ciphertext, and
|
||||
* the AL value.
|
||||
*
|
||||
*/
|
||||
|
||||
lws_jwe_be64((unsigned int)aad_len * 8, al);
|
||||
|
||||
/* first half of enc_cek is the MAC key */
|
||||
if (lws_genhmac_init(&hmacctx, jwe->jose.enc_alg->hmac_type, enc_cek,
|
||||
(unsigned int)hlen / 2)) {
|
||||
lwsl_err("%s: lws_genhmac_init fail\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lws_genhmac_update(&hmacctx, aad, (unsigned int)aad_len) ||
|
||||
lws_genhmac_update(&hmacctx, (uint8_t *)jwe->jws.map.buf[LJWE_IV],
|
||||
jwe->jws.map.len[LJWE_IV]) ||
|
||||
lws_genhmac_update(&hmacctx, (uint8_t *)jwe->jws.map.buf[LJWE_CTXT],
|
||||
jwe->jws.map.len[LJWE_CTXT]) ||
|
||||
lws_genhmac_update(&hmacctx, al, 8)) {
|
||||
lwsl_err("%s: hmac computation failed\n", __func__);
|
||||
lws_genhmac_destroy(&hmacctx, NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lws_genhmac_destroy(&hmacctx, digest)) {
|
||||
lwsl_err("%s: problem destroying hmac\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* first half of digest is the auth tag */
|
||||
|
||||
if (lws_timingsafe_bcmp(digest, jwe->jws.map.buf[LJWE_ATAG], (unsigned int)hlen / 2)) {
|
||||
lwsl_err("%s: auth failed: hmac tag (%d) != ATAG (%d)\n",
|
||||
__func__, hlen / 2, (int)jwe->jws.map.len[LJWE_ATAG]);
|
||||
lwsl_hexdump_notice(jwe->jws.map.buf[LJWE_ATAG], (unsigned int)hlen / 2);
|
||||
lwsl_hexdump_notice(digest, (unsigned int)hlen / 2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* second half of enc cek is the CEK KEY */
|
||||
el.buf = enc_cek + (hlen / 2);
|
||||
el.len = (unsigned int)hlen / 2;
|
||||
|
||||
if (lws_genaes_create(&aesctx, LWS_GAESO_DEC, LWS_GAESM_CBC,
|
||||
&el, LWS_GAESP_NO_PADDING, NULL)) {
|
||||
lwsl_err("%s: lws_genaes_create failed\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
n = lws_genaes_crypt(&aesctx, (uint8_t *)jwe->jws.map.buf[LJWE_CTXT],
|
||||
jwe->jws.map.len[LJWE_CTXT],
|
||||
(uint8_t *)jwe->jws.map.buf[LJWE_CTXT],
|
||||
(uint8_t *)jwe->jws.map.buf[LJWE_IV], NULL, NULL, 16);
|
||||
|
||||
/* Strip the PKCS #7 padding */
|
||||
|
||||
if (jwe->jws.map.len[LJWE_CTXT] < LWS_AES_CBC_BLOCKLEN ||
|
||||
jwe->jws.map.len[LJWE_CTXT] <= (unsigned char)jwe->jws.map.buf[LJWE_CTXT]
|
||||
[jwe->jws.map.len[LJWE_CTXT] - 1]) {
|
||||
lwsl_err("%s: invalid padded ciphertext length: %d. Corrupt data?\n",
|
||||
__func__, (int)jwe->jws.map.len[LJWE_CTXT]);
|
||||
return -1;
|
||||
}
|
||||
jwe->jws.map.len[LJWE_CTXT] = (uint32_t)((int)jwe->jws.map.len[LJWE_CTXT] -
|
||||
jwe->jws.map.buf[LJWE_CTXT][jwe->jws.map.len[LJWE_CTXT] - 1]);
|
||||
|
||||
n |= lws_genaes_destroy(&aesctx, NULL, 0);
|
||||
if (n) {
|
||||
lwsl_err("%s: lws_genaes_crypt failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int)jwe->jws.map.len[LJWE_CTXT];
|
||||
}
|
||||
|
173
Kinc/Sources/kinc/libs/jose/jwe/enc/aesgcm.c
Normal file
173
Kinc/Sources/kinc/libs/jose/jwe/enc/aesgcm.c
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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"
|
||||
|
||||
/*
|
||||
* NOTICE this is AESGCM content encryption, it's not AES GCM key wrapping
|
||||
*
|
||||
*
|
||||
* This section defines the specifics of performing authenticated
|
||||
* encryption with AES in Galois/Counter Mode (GCM) ([AES] and
|
||||
* [NIST.800-38D]).
|
||||
*
|
||||
* The CEK is used as the encryption key.
|
||||
*
|
||||
* Use of an IV of size 96 bits is REQUIRED with this algorithm.
|
||||
*
|
||||
* The requested size of the Authentication Tag output MUST be 128 bits,
|
||||
* regardless of the key size.
|
||||
*
|
||||
* For decrypt: decrypt the KEK, then decrypt the payload
|
||||
*
|
||||
* For encrypt: encrypt the payload, then encrypt the KEK
|
||||
*/
|
||||
|
||||
/*
|
||||
* encrypting... enc_cek is unencrypted
|
||||
*/
|
||||
|
||||
int
|
||||
lws_jwe_encrypt_gcm(struct lws_jwe *jwe,
|
||||
uint8_t *enc_cek, uint8_t *aad, int aad_len)
|
||||
{
|
||||
struct lws_gencrypto_keyelem el;
|
||||
struct lws_genaes_ctx aesctx;
|
||||
size_t ivs = LWS_AESGCM_IV;
|
||||
int n;
|
||||
|
||||
/* Some sanity checks on what came in */
|
||||
|
||||
/* MUST be 128-bit for all sizes */
|
||||
if (jwe->jws.map.len[LJWE_ATAG] != LWS_AESGCM_TAG) {
|
||||
lwsl_notice("%s: AESGCM tag size must be 128b, got %d\n",
|
||||
__func__, (int)jwe->jws.map.len[LJWE_ATAG]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (jwe->jws.map.len[LJWE_IV] != LWS_AESGCM_IV) { /* MUST be 96-bit */
|
||||
lwsl_notice("%s: AESGCM IV must be 128b, got %d\n", __func__,
|
||||
(int)jwe->jws.map.len[LJWE_IV]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* EKEY is directly the CEK KEY */
|
||||
el.buf = enc_cek;
|
||||
el.len = jwe->jose.enc_alg->keybits_fixed / 8;
|
||||
|
||||
if (lws_genaes_create(&aesctx, LWS_GAESO_ENC, LWS_GAESM_GCM,
|
||||
&el, LWS_GAESP_NO_PADDING, NULL)) {
|
||||
lwsl_err("%s: lws_genaes_create failed\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* aad */
|
||||
|
||||
n = lws_genaes_crypt(&aesctx, aad, (unsigned int)aad_len, NULL,
|
||||
(uint8_t *)jwe->jws.map.buf[LJWE_IV],
|
||||
(uint8_t *)jwe->jws.map.buf[LJWE_ATAG], &ivs,
|
||||
LWS_AESGCM_TAG);
|
||||
if (n) {
|
||||
lwsl_err("%s: lws_genaes_crypt aad failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* payload */
|
||||
n = lws_genaes_crypt(&aesctx, (uint8_t *)jwe->jws.map.buf[LJWE_CTXT],
|
||||
jwe->jws.map.len[LJWE_CTXT],
|
||||
(uint8_t *)jwe->jws.map.buf[LJWE_CTXT],
|
||||
(uint8_t *)jwe->jws.map.buf[LJWE_IV],
|
||||
NULL, &ivs,
|
||||
LWS_AESGCM_TAG);
|
||||
|
||||
n |= lws_genaes_destroy(&aesctx, (uint8_t *)jwe->jws.map.buf[LJWE_ATAG],
|
||||
LWS_AESGCM_TAG);
|
||||
if (n) {
|
||||
lwsl_err("%s: lws_genaes_crypt failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int)jwe->jws.map.len[LJWE_CTXT];
|
||||
}
|
||||
|
||||
int
|
||||
lws_jwe_auth_and_decrypt_gcm(struct lws_jwe *jwe,
|
||||
uint8_t *enc_cek, uint8_t *aad, int aad_len)
|
||||
{
|
||||
struct lws_gencrypto_keyelem el;
|
||||
struct lws_genaes_ctx aesctx;
|
||||
size_t ivs = LWS_AESGCM_IV;
|
||||
uint8_t tag[LWS_AESGCM_TAG];
|
||||
int n;
|
||||
|
||||
/* Some sanity checks on what came in */
|
||||
|
||||
/* Tag MUST be 128-bit for all sizes */
|
||||
if (jwe->jws.map.len[LJWE_ATAG] != LWS_AESGCM_TAG) {
|
||||
lwsl_notice("%s: AESGCM tag size must be 128b, got %d\n",
|
||||
__func__, (int)jwe->jws.map.len[LJWE_ATAG]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (jwe->jws.map.len[LJWE_IV] != LWS_AESGCM_IV) { /* MUST be 96-bit */
|
||||
lwsl_notice("%s: AESGCM IV must be 128b, got %d\n", __func__,
|
||||
(int)jwe->jws.map.len[LJWE_IV]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* EKEY is directly the CEK KEY */
|
||||
el.buf = enc_cek;
|
||||
el.len = jwe->jose.enc_alg->keybits_fixed / 8;
|
||||
|
||||
if (lws_genaes_create(&aesctx, LWS_GAESO_DEC, LWS_GAESM_GCM,
|
||||
&el, LWS_GAESP_NO_PADDING, NULL)) {
|
||||
lwsl_err("%s: lws_genaes_create failed\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
n = lws_genaes_crypt(&aesctx, aad, (unsigned int)aad_len,
|
||||
NULL,
|
||||
(uint8_t *)jwe->jws.map.buf[LJWE_IV],
|
||||
(uint8_t *)jwe->jws.map.buf[LJWE_ATAG], &ivs, 16);
|
||||
if (n) {
|
||||
lwsl_err("%s: lws_genaes_crypt aad failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
n = lws_genaes_crypt(&aesctx, (uint8_t *)jwe->jws.map.buf[LJWE_CTXT],
|
||||
jwe->jws.map.len[LJWE_CTXT],
|
||||
(uint8_t *)jwe->jws.map.buf[LJWE_CTXT],
|
||||
(uint8_t *)jwe->jws.map.buf[LJWE_IV],
|
||||
(uint8_t *)jwe->jws.map.buf[LJWE_ATAG], &ivs, 16);
|
||||
|
||||
n |= lws_genaes_destroy(&aesctx, tag, sizeof(tag));
|
||||
if (n) {
|
||||
lwsl_err("%s: lws_genaes_crypt failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int)jwe->jws.map.len[LJWE_CTXT];
|
||||
}
|
177
Kinc/Sources/kinc/libs/jose/jwe/enc/aeskw.c
Normal file
177
Kinc/Sources/kinc/libs/jose/jwe/enc/aeskw.c
Normal file
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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"
|
||||
|
||||
/*
|
||||
* RFC3394 Key Wrap uses a 128-bit key, and bloats what it is wrapping by
|
||||
* one 8-byte block. So, if you had a 32 byte plaintext CEK to wrap, after
|
||||
* wrapping it becomes a 40 byte wrapped, enciphered, key.
|
||||
*
|
||||
* The CEK comes in from and goes out in LJWE_EKEY. So LJWE_EKEY length
|
||||
* increases by 8 from calling this.
|
||||
*/
|
||||
|
||||
int
|
||||
lws_jwe_encrypt_aeskw_cbc_hs(struct lws_jwe *jwe, char *temp, int *temp_len)
|
||||
{
|
||||
struct lws_genaes_ctx aesctx;
|
||||
/* we are wrapping a key, so size for the worst case after wrap */
|
||||
uint8_t enc_cek[LWS_JWE_LIMIT_KEY_ELEMENT_BYTES +
|
||||
LWS_JWE_RFC3394_OVERHEAD_BYTES];
|
||||
int n, m, hlen = (int)lws_genhmac_size(jwe->jose.enc_alg->hmac_type),
|
||||
ot = *temp_len;
|
||||
|
||||
if (jwe->jws.jwk->kty != LWS_GENCRYPTO_KTY_OCT) {
|
||||
lwsl_err("%s: unexpected kty %d\n", __func__, jwe->jws.jwk->kty);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* create a b64 version of the JOSE header, needed for hashing */
|
||||
|
||||
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;
|
||||
|
||||
/* Allocate temp space for ATAG and IV */
|
||||
|
||||
if (lws_jws_alloc_element(&jwe->jws.map, LJWE_ATAG, temp + (ot - *temp_len),
|
||||
temp_len, (unsigned int)hlen / 2, 0))
|
||||
return -1;
|
||||
|
||||
if (lws_jws_alloc_element(&jwe->jws.map, LJWE_IV, temp + (ot - *temp_len),
|
||||
temp_len, LWS_JWE_AES_IV_BYTES, 0))
|
||||
return -1;
|
||||
|
||||
/* 1) Encrypt the payload... */
|
||||
|
||||
/* the CEK is 256-bit in the example encrypted with a 128-bit key */
|
||||
|
||||
n = lws_jwe_encrypt_cbc_hs(jwe, (uint8_t *)jwe->jws.map.buf[LJWE_EKEY],
|
||||
(uint8_t *)jwe->jws.map_b64.buf[LJWE_JOSE],
|
||||
(int)jwe->jws.map_b64.len[LJWE_JOSE]);
|
||||
if (n < 0) {
|
||||
lwsl_err("%s: lws_jwe_encrypt_cbc_hs failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 2) Encrypt the JWE Encrypted Key: RFC3394 Key Wrap uses 64 bit blocks
|
||||
* and 128-bit input key*/
|
||||
|
||||
if (lws_genaes_create(&aesctx, LWS_GAESO_ENC, LWS_GAESM_KW,
|
||||
jwe->jws.jwk->e, 1, NULL)) {
|
||||
|
||||
lwsl_notice("%s: lws_genaes_create\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* tag size is determined by enc cipher key length */
|
||||
|
||||
n = lws_genaes_crypt(&aesctx, (uint8_t *)jwe->jws.map.buf[LJWE_EKEY],
|
||||
jwe->jws.map.len[LJWE_EKEY], enc_cek, NULL, NULL, NULL,
|
||||
lws_gencrypto_bits_to_bytes(
|
||||
jwe->jose.enc_alg->keybits_fixed));
|
||||
m = lws_genaes_destroy(&aesctx, NULL, 0);
|
||||
if (n < 0) {
|
||||
lwsl_err("%s: encrypt cek fail\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
if (m < 0) {
|
||||
lwsl_err("%s: lws_genaes_destroy fail\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
jwe->jws.map.len[LJWE_EKEY] += LWS_JWE_RFC3394_OVERHEAD_BYTES;
|
||||
memcpy((uint8_t *)jwe->jws.map.buf[LJWE_EKEY], enc_cek,
|
||||
jwe->jws.map.len[LJWE_EKEY]);
|
||||
|
||||
return (int)jwe->jws.map.len[LJWE_CTXT];
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lws_jwe_auth_and_decrypt_aeskw_cbc_hs(struct lws_jwe *jwe)
|
||||
{
|
||||
struct lws_genaes_ctx aesctx;
|
||||
uint8_t enc_cek[LWS_JWE_LIMIT_KEY_ELEMENT_BYTES +
|
||||
LWS_JWE_RFC3394_OVERHEAD_BYTES];
|
||||
int n, m;
|
||||
|
||||
if (jwe->jws.jwk->kty != LWS_GENCRYPTO_KTY_OCT) {
|
||||
lwsl_err("%s: unexpected kty %d\n", __func__, jwe->jws.jwk->kty);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* the CEK is 256-bit in the example encrypted with a 128-bit key */
|
||||
|
||||
if (jwe->jws.map.len[LJWE_EKEY] > sizeof(enc_cek))
|
||||
return -1;
|
||||
|
||||
/* 1) Decrypt the JWE Encrypted Key to get the raw MAC / CEK */
|
||||
|
||||
if (lws_genaes_create(&aesctx, LWS_GAESO_DEC, LWS_GAESM_KW,
|
||||
jwe->jws.jwk->e, 1, NULL)) {
|
||||
|
||||
lwsl_notice("%s: lws_genaes_create\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrypt the CEK into enc_cek
|
||||
* tag size is determined by enc cipher key length */
|
||||
|
||||
n = lws_genaes_crypt(&aesctx, (uint8_t *)jwe->jws.map.buf[LJWE_EKEY],
|
||||
jwe->jws.map.len[LJWE_EKEY], enc_cek, NULL, NULL, NULL,
|
||||
lws_gencrypto_bits_to_bytes(
|
||||
jwe->jose.enc_alg->keybits_fixed));
|
||||
m = lws_genaes_destroy(&aesctx, NULL, 0);
|
||||
if (n < 0) {
|
||||
lwsl_err("%s: decrypt CEK fail\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
if (m < 0) {
|
||||
lwsl_err("%s: lws_genaes_destroy fail\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 2) Decrypt the payload */
|
||||
|
||||
n = lws_jwe_auth_and_decrypt_cbc_hs(jwe, enc_cek,
|
||||
(uint8_t *)jwe->jws.map_b64.buf[LJWE_JOSE],
|
||||
(int)jwe->jws.map_b64.len[LJWE_JOSE]);
|
||||
if (n < 0) {
|
||||
lwsl_err("%s: lws_jwe_auth_and_decrypt_cbc_hs failed\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int)jwe->jws.map.len[LJWE_CTXT];
|
||||
}
|
||||
|
||||
|
616
Kinc/Sources/kinc/libs/jose/jwe/jwe-ecdh-es-aeskw.c
Normal file
616
Kinc/Sources/kinc/libs/jose/jwe/jwe-ecdh-es-aeskw.c
Normal file
@ -0,0 +1,616 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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, (unsigned int)enc_hlen) !=
|
||||
(size_t)enc_hlen) {
|
||||
lwsl_err("Problem getting random\n");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* wrap with the derived key */
|
||||
|
||||
el.buf = derived;
|
||||
el.len = (unsigned int)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, (unsigned int)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] = (unsigned int)enc_hlen + 8;
|
||||
|
||||
/* Wrapped CEK is in EKEY. Random CEK is in cek. */
|
||||
|
||||
} else /* direct derived CEK is in cek */
|
||||
memcpy(cek, derived, (unsigned int)enc_hlen);
|
||||
|
||||
/* rewrite the protected JOSE header to have the epk pieces */
|
||||
|
||||
jwe->jws.map.buf[LJWE_JOSE] = temp;
|
||||
|
||||
m = n = lws_snprintf(temp, (size_t)*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), (size_t)*temp_len, "}");
|
||||
*temp_len -= n + 1;
|
||||
m += n;
|
||||
jwe->jws.map.len[LJWE_JOSE] = (unsigned int)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, (unsigned int)ekbytes);
|
||||
lws_explicit_bzero(derived, (unsigned int)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,
|
||||
(unsigned int)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, (unsigned int)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],
|
||||
(int)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, (unsigned int)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 = (unsigned int)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, (unsigned int)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],
|
||||
(int)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, (unsigned int)ekbytes);
|
||||
/* cleanse the shared secret */
|
||||
lws_explicit_bzero(shared_secret, (unsigned int)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);
|
||||
}
|
196
Kinc/Sources/kinc/libs/jose/jwe/jwe-rsa-aescbc.c
Normal file
196
Kinc/Sources/kinc/libs/jose/jwe/jwe-rsa-aescbc.c
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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"
|
||||
|
||||
/*
|
||||
* Requirements on entry:
|
||||
*
|
||||
* - jwe->jws.map LJWE_JOSE contains the ASCII JOSE header
|
||||
* - jwe->jws.map LJWE_EKEY contains cek of enc_alg hmac length
|
||||
* - jwe->jws.map LJWE_CTXT contains the plaintext
|
||||
*
|
||||
* On successful exit:
|
||||
*
|
||||
* - jwe->jws.map LJWE_ATAG contains the tag
|
||||
* - jwe->jws.map LJWE_IV contains the new random IV that was used
|
||||
* - jwe->jws.map LJWE_EKEY contains the encrypted CEK
|
||||
* - jwe->jws.map LJWE_CTXT contains the ciphertext
|
||||
*
|
||||
* Return the amount of temp used, or -1
|
||||
*/
|
||||
|
||||
int
|
||||
lws_jwe_encrypt_rsa_aes_cbc_hs(struct lws_jwe *jwe,
|
||||
char *temp, int *temp_len)
|
||||
{
|
||||
int n, hlen = (int)lws_genhmac_size(jwe->jose.enc_alg->hmac_type),
|
||||
ot = *temp_len;
|
||||
char ekey[LWS_GENHASH_LARGEST];
|
||||
struct lws_genrsa_ctx rsactx;
|
||||
|
||||
if (jwe->jws.jwk->kty != LWS_GENCRYPTO_KTY_RSA) {
|
||||
lwsl_err("%s: unexpected kty %d\n", __func__, jwe->jws.jwk->kty);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Notice that the unencrypted EKEY coming in is smaller than the
|
||||
* RSA-encrypted EKEY going out, which is going to be the RSA key size
|
||||
*
|
||||
* Create a b64 version of the JOSE header, needed as 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;
|
||||
|
||||
if (lws_jws_alloc_element(&jwe->jws.map, LJWE_ATAG, temp + (ot - *temp_len),
|
||||
temp_len, (unsigned int)hlen / 2, 0))
|
||||
return -1;
|
||||
|
||||
if (lws_jws_alloc_element(&jwe->jws.map, LJWE_IV, temp + (ot - *temp_len),
|
||||
temp_len, LWS_JWE_AES_IV_BYTES, 0))
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Without changing the unencrypted CEK in EKEY, reallocate enough
|
||||
* space to write the RSA-encrypted version in-situ.
|
||||
*/
|
||||
if (lws_jws_dup_element(&jwe->jws.map, LJWE_EKEY, temp + (ot - *temp_len),
|
||||
temp_len, jwe->jws.map.buf[LJWE_EKEY],
|
||||
jwe->jws.map.len[LJWE_EKEY],
|
||||
jwe->jws.jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len))
|
||||
return -1;
|
||||
|
||||
/* Encrypt using the raw CEK (treated as MAC KEY | ENC KEY) */
|
||||
|
||||
n = lws_jwe_encrypt_cbc_hs(jwe, (uint8_t *)jwe->jws.map.buf[LJWE_EKEY],
|
||||
(uint8_t *)jwe->jws.map_b64.buf[LJWE_JOSE],
|
||||
(int)jwe->jws.map_b64.len[LJWE_JOSE]);
|
||||
if (n < 0) {
|
||||
lwsl_err("%s: lws_jwe_encrypt_cbc_hs failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lws_genrsa_create(&rsactx, jwe->jws.jwk->e, jwe->jws.context,
|
||||
!strcmp(jwe->jose.alg->alg, "RSA-OAEP") ?
|
||||
LGRSAM_PKCS1_OAEP_PSS : LGRSAM_PKCS1_1_5,
|
||||
LWS_GENHASH_TYPE_UNKNOWN)) {
|
||||
lwsl_notice("%s: lws_genrsa_create\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* encrypt the CEK using RSA, mbedtls can't handle both in and out are
|
||||
* the EKEY, so copy the unencrypted ekey out temporarily */
|
||||
|
||||
memcpy(ekey, jwe->jws.map.buf[LJWE_EKEY], (unsigned int)hlen);
|
||||
|
||||
n = lws_genrsa_public_encrypt(&rsactx, (uint8_t *)ekey, (unsigned int)hlen,
|
||||
(uint8_t *)jwe->jws.map.buf[LJWE_EKEY]);
|
||||
lws_genrsa_destroy(&rsactx);
|
||||
lws_explicit_bzero(ekey, (unsigned int)hlen); /* cleanse the temp CEK copy */
|
||||
if (n < 0) {
|
||||
lwsl_err("%s: encrypt cek fail\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
jwe->jws.map.len[LJWE_EKEY] = (unsigned int)n; /* update to encrypted EKEY size */
|
||||
|
||||
/*
|
||||
* We end up with IV, ATAG, set, EKEY encrypted and CTXT is ciphertext,
|
||||
* and b64u version of ATAG in map_b64.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_jwe_auth_and_decrypt_rsa_aes_cbc_hs(struct lws_jwe *jwe)
|
||||
{
|
||||
int n;
|
||||
struct lws_genrsa_ctx rsactx;
|
||||
uint8_t enc_cek[512];
|
||||
|
||||
if (jwe->jws.jwk->kty != LWS_GENCRYPTO_KTY_RSA) {
|
||||
lwsl_err("%s: unexpected kty %d\n", __func__, jwe->jws.jwk->kty);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (jwe->jws.map.len[LJWE_EKEY] < 40) {
|
||||
lwsl_err("%s: EKEY length too short %d\n", __func__,
|
||||
(int)jwe->jws.map.len[LJWE_EKEY]);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Decrypt the JWE Encrypted Key to get the raw MAC || CEK */
|
||||
|
||||
if (lws_genrsa_create(&rsactx, jwe->jws.jwk->e, jwe->jws.context,
|
||||
!strcmp(jwe->jose.alg->alg, "RSA-OAEP") ?
|
||||
LGRSAM_PKCS1_OAEP_PSS : LGRSAM_PKCS1_1_5,
|
||||
LWS_GENHASH_TYPE_UNKNOWN)) {
|
||||
lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
n = lws_genrsa_private_decrypt(&rsactx,
|
||||
(uint8_t *)jwe->jws.map.buf[LJWE_EKEY],
|
||||
jwe->jws.map.len[LJWE_EKEY], enc_cek,
|
||||
sizeof(enc_cek));
|
||||
lws_genrsa_destroy(&rsactx);
|
||||
if (n < 0) {
|
||||
lwsl_err("%s: decrypt cek fail: \n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
n = lws_jwe_auth_and_decrypt_cbc_hs(jwe, enc_cek,
|
||||
(uint8_t *)jwe->jws.map_b64.buf[LJWE_JOSE],
|
||||
(int)jwe->jws.map_b64.len[LJWE_JOSE]);
|
||||
if (n < 0) {
|
||||
lwsl_err("%s: lws_jwe_auth_and_decrypt_cbc_hs failed\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_MBEDTLS) && defined(LWS_PLAT_OPTEE)
|
||||
|
||||
/* strip padding */
|
||||
|
||||
n = jwe->jws.map.buf[LJWE_CTXT][jwe->jws.map.len[LJWE_CTXT] - 1];
|
||||
if (n > 16) {
|
||||
lwsl_err("%s: n == %d, plen %d\n", __func__, n,
|
||||
(int)jwe->jws.map.len[LJWE_CTXT]);
|
||||
return -1;
|
||||
}
|
||||
jwe->jws.map.len[LJWE_CTXT] -= n;
|
||||
#endif
|
||||
|
||||
return (int)jwe->jws.map.len[LJWE_CTXT];
|
||||
}
|
183
Kinc/Sources/kinc/libs/jose/jwe/jwe-rsa-aesgcm.c
Normal file
183
Kinc/Sources/kinc/libs/jose/jwe/jwe-rsa-aesgcm.c
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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"
|
||||
|
||||
#define LWS_AESGCM_IV 12
|
||||
|
||||
|
||||
int
|
||||
lws_jwe_encrypt_rsa_aes_gcm(struct lws_jwe *jwe, char *temp, int *temp_len)
|
||||
{
|
||||
int ekbytes = jwe->jose.enc_alg->keybits_fixed / 8;
|
||||
struct lws_genrsa_ctx rsactx;
|
||||
int n, ret = -1, ot = *temp_len;
|
||||
|
||||
if (jwe->jws.jwk->kty != LWS_GENCRYPTO_KTY_RSA) {
|
||||
lwsl_err("%s: wrong kty %d\n", __func__, jwe->jws.jwk->kty);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* create the IV + CEK */
|
||||
|
||||
if (lws_jws_randomize_element(jwe->jws.context, &jwe->jws.map, LJWE_IV,
|
||||
temp, temp_len,
|
||||
LWS_AESGCM_IV, 0))
|
||||
return -1;
|
||||
|
||||
if (lws_jws_alloc_element(&jwe->jws.map, LJWE_ATAG,
|
||||
temp + (ot - *temp_len),
|
||||
temp_len, LWS_AESGCM_TAG, 0))
|
||||
return -1;
|
||||
|
||||
/* create a b64 version of the JOSE header, needed as 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;
|
||||
|
||||
/*
|
||||
* If none already, create a new, random CEK in the JWE (so it can be
|
||||
* reused for other recipients on same payload). If it already exists,
|
||||
* just reuse it. It will be cleansed in the JWE destroy.
|
||||
*/
|
||||
if (!jwe->cek_valid) {
|
||||
if (lws_get_random(jwe->jws.context, jwe->cek, (unsigned int)ekbytes) !=
|
||||
(size_t)ekbytes) {
|
||||
lwsl_err("%s: Problem getting random\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
jwe->cek_valid = 1;
|
||||
}
|
||||
|
||||
if (lws_jws_dup_element(&jwe->jws.map, LJWE_EKEY,
|
||||
temp + (ot - *temp_len), temp_len,
|
||||
jwe->cek, (unsigned int)ekbytes, 0))
|
||||
return -1;
|
||||
|
||||
/* encrypt the payload */
|
||||
|
||||
n = lws_jwe_encrypt_gcm(jwe, (uint8_t *)jwe->jws.map.buf[LJWE_EKEY],
|
||||
(uint8_t *)jwe->jws.map_b64.buf[LJWE_JOSE],
|
||||
(int)jwe->jws.map_b64.len[LJWE_JOSE]);
|
||||
if (n < 0) {
|
||||
lwsl_err("%s: lws_jwe_encrypt_gcm failed\n",
|
||||
__func__);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* Encrypt the CEK into EKEY to make the JWE Encrypted Key */
|
||||
|
||||
if (lws_genrsa_create(&rsactx, jwe->jws.jwk->e, jwe->jws.context,
|
||||
!strcmp(jwe->jose.alg->alg, "RSA-OAEP") ?
|
||||
LGRSAM_PKCS1_OAEP_PSS : LGRSAM_PKCS1_1_5,
|
||||
LWS_GENHASH_TYPE_SHA1 /* !!! */)) {
|
||||
lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
|
||||
__func__);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
n = lws_genrsa_public_encrypt(&rsactx, jwe->cek, (unsigned int)ekbytes,
|
||||
(uint8_t *)jwe->jws.map.buf[LJWE_EKEY]);
|
||||
lws_genrsa_destroy(&rsactx);
|
||||
if (n < 0) {
|
||||
lwsl_err("%s: encrypt cek fail: \n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* set the EKEY length to the actual enciphered length */
|
||||
jwe->jws.map.len[LJWE_EKEY] = (unsigned int)n;
|
||||
|
||||
ret = (int32_t)jwe->jws.map.len[LJWE_CTXT];
|
||||
|
||||
bail:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
lws_jwe_auth_and_decrypt_rsa_aes_gcm(struct lws_jwe *jwe)
|
||||
{
|
||||
int n;
|
||||
struct lws_genrsa_ctx rsactx;
|
||||
uint8_t enc_cek[LWS_JWE_LIMIT_KEY_ELEMENT_BYTES];
|
||||
|
||||
if (jwe->jws.jwk->kty != LWS_GENCRYPTO_KTY_RSA) {
|
||||
lwsl_err("%s: unexpected kty %d\n", __func__, jwe->jws.jwk->kty);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (jwe->jws.map.len[LJWE_EKEY] < 32) {
|
||||
lwsl_err("%s: EKEY length too short %d\n", __func__,
|
||||
(int)jwe->jws.map.len[LJWE_EKEY]);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Decrypt the JWE Encrypted Key to get the direct CEK */
|
||||
|
||||
if (lws_genrsa_create(&rsactx, jwe->jws.jwk->e, jwe->jws.context,
|
||||
!strcmp(jwe->jose.alg->alg, "RSA-OAEP") ?
|
||||
LGRSAM_PKCS1_OAEP_PSS : LGRSAM_PKCS1_1_5,
|
||||
LWS_GENHASH_TYPE_SHA1 /* !!! */)) {
|
||||
lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
n = lws_genrsa_private_decrypt(&rsactx,
|
||||
(uint8_t *)jwe->jws.map.buf[LJWE_EKEY],
|
||||
jwe->jws.map.len[LJWE_EKEY], enc_cek,
|
||||
sizeof(enc_cek));
|
||||
lws_genrsa_destroy(&rsactx);
|
||||
if (n < 0) {
|
||||
lwsl_err("%s: decrypt cek fail: \n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
n = lws_jwe_auth_and_decrypt_gcm(jwe, enc_cek,
|
||||
(uint8_t *)jwe->jws.map_b64.buf[LJWE_JOSE],
|
||||
(int)jwe->jws.map_b64.len[LJWE_JOSE]);
|
||||
if (n < 0) {
|
||||
lwsl_err("%s: lws_jwe_auth_and_decrypt_gcm_hs failed\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_MBEDTLS) && defined(LWS_PLAT_OPTEE)
|
||||
/* strip padding */
|
||||
|
||||
n = jwe->jws.map.buf[LJWE_CTXT][jwe->jws.map.len[LJWE_CTXT] - 1];
|
||||
if (n > 16)
|
||||
return -1;
|
||||
jwe->jws.map.len[LJWE_CTXT] -= n;
|
||||
#endif
|
||||
|
||||
return (int)jwe->jws.map.len[LJWE_CTXT];
|
||||
}
|
791
Kinc/Sources/kinc/libs/jose/jwe/jwe.c
Executable file
791
Kinc/Sources/kinc/libs/jose/jwe/jwe.c
Executable file
@ -0,0 +1,791 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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.h"
|
||||
#include "private-lib-jose-jwe.h"
|
||||
|
||||
/*
|
||||
* Currently only support flattened or compact (implicitly single signature)
|
||||
*/
|
||||
|
||||
static const char * const jwe_json[] = {
|
||||
"protected",
|
||||
"iv",
|
||||
"ciphertext",
|
||||
"tag",
|
||||
"encrypted_key"
|
||||
};
|
||||
|
||||
enum enum_jwe_complete_tokens {
|
||||
LWS_EJCT_PROTECTED,
|
||||
LWS_EJCT_IV,
|
||||
LWS_EJCT_CIPHERTEXT,
|
||||
LWS_EJCT_TAG,
|
||||
LWS_EJCT_RECIP_ENC_KEY,
|
||||
};
|
||||
|
||||
/* parse a JWS complete or flattened JSON object */
|
||||
|
||||
struct jwe_cb_args {
|
||||
struct lws_jws *jws;
|
||||
|
||||
char *temp;
|
||||
int *temp_len;
|
||||
};
|
||||
|
||||
static signed char
|
||||
lws_jwe_json_cb(struct lejp_ctx *ctx, char reason)
|
||||
{
|
||||
struct jwe_cb_args *args = (struct jwe_cb_args *)ctx->user;
|
||||
int n, m;
|
||||
|
||||
if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match)
|
||||
return 0;
|
||||
|
||||
switch (ctx->path_match - 1) {
|
||||
|
||||
/* strings */
|
||||
|
||||
case LWS_EJCT_PROTECTED: /* base64u: JOSE: must contain 'alg' */
|
||||
m = LJWS_JOSE;
|
||||
goto append_string;
|
||||
case LWS_EJCT_IV: /* base64u */
|
||||
m = LJWE_IV;
|
||||
goto append_string;
|
||||
case LWS_EJCT_CIPHERTEXT: /* base64u */
|
||||
m = LJWE_CTXT;
|
||||
goto append_string;
|
||||
case LWS_EJCT_TAG: /* base64u */
|
||||
m = LJWE_ATAG;
|
||||
goto append_string;
|
||||
case LWS_EJCT_RECIP_ENC_KEY: /* base64u */
|
||||
m = LJWE_EKEY;
|
||||
goto append_string;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
append_string:
|
||||
|
||||
if (*args->temp_len < ctx->npos) {
|
||||
lwsl_err("%s: out of parsing space\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* We keep both b64u and decoded in temp mapped using map / map_b64,
|
||||
* the jws signature is actually over the b64 content not the plaintext,
|
||||
* and we can't do it until we see the protected alg.
|
||||
*/
|
||||
|
||||
if (!args->jws->map_b64.buf[m]) {
|
||||
args->jws->map_b64.buf[m] = args->temp;
|
||||
args->jws->map_b64.len[m] = 0;
|
||||
}
|
||||
|
||||
memcpy(args->temp, ctx->buf, ctx->npos);
|
||||
args->temp += ctx->npos;
|
||||
*args->temp_len -= ctx->npos;
|
||||
args->jws->map_b64.len[m] += ctx->npos;
|
||||
|
||||
if (reason == LEJPCB_VAL_STR_END) {
|
||||
args->jws->map.buf[m] = args->temp;
|
||||
|
||||
n = lws_b64_decode_string_len(
|
||||
(const char *)args->jws->map_b64.buf[m],
|
||||
(int)args->jws->map_b64.len[m],
|
||||
(char *)args->temp, *args->temp_len);
|
||||
if (n < 0) {
|
||||
lwsl_err("%s: b64 decode failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
args->temp += n;
|
||||
*args->temp_len -= n;
|
||||
args->jws->map.len[m] = (uint32_t)n;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_jwe_json_parse(struct lws_jwe *jwe, const uint8_t *buf, int len,
|
||||
char *temp, int *temp_len)
|
||||
{
|
||||
struct jwe_cb_args args;
|
||||
struct lejp_ctx jctx;
|
||||
int m = 0;
|
||||
|
||||
args.jws = &jwe->jws;
|
||||
args.temp = temp;
|
||||
args.temp_len = temp_len;
|
||||
|
||||
lejp_construct(&jctx, lws_jwe_json_cb, &args, jwe_json,
|
||||
LWS_ARRAY_SIZE(jwe_json));
|
||||
|
||||
m = lejp_parse(&jctx, (uint8_t *)buf, len);
|
||||
lejp_destruct(&jctx);
|
||||
if (m < 0) {
|
||||
lwsl_notice("%s: parse returned %d\n", __func__, m);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_jwe_init(struct lws_jwe *jwe, struct lws_context *context)
|
||||
{
|
||||
lws_jose_init(&jwe->jose);
|
||||
lws_jws_init(&jwe->jws, &jwe->jwk, context);
|
||||
memset(&jwe->jwk, 0, sizeof(jwe->jwk));
|
||||
jwe->recip = 0;
|
||||
jwe->cek_valid = 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_jwe_destroy(struct lws_jwe *jwe)
|
||||
{
|
||||
lws_jws_destroy(&jwe->jws);
|
||||
lws_jose_destroy(&jwe->jose);
|
||||
lws_jwk_destroy(&jwe->jwk);
|
||||
/* cleanse the CEK we held on to in case of further encryptions of it */
|
||||
lws_explicit_bzero(jwe->cek, sizeof(jwe->cek));
|
||||
jwe->cek_valid = 0;
|
||||
}
|
||||
|
||||
static uint8_t *
|
||||
be32(uint32_t i, uint32_t *p32)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)p32;
|
||||
|
||||
*p++ = (uint8_t)((i >> 24) & 0xff);
|
||||
*p++ = (uint8_t)((i >> 16) & 0xff);
|
||||
*p++ = (uint8_t)((i >> 8) & 0xff);
|
||||
*p++ = (uint8_t)(i & 0xff);
|
||||
|
||||
return (uint8_t *)p32;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* out must be prepared to take at least 32 bytes or the encrypted key size,
|
||||
* whichever is larger.
|
||||
*/
|
||||
|
||||
int
|
||||
lws_jwa_concat_kdf(struct lws_jwe *jwe, int direct, uint8_t *out,
|
||||
const uint8_t *shared_secret, int sslen)
|
||||
{
|
||||
int hlen = (int)lws_genhash_size(LWS_GENHASH_TYPE_SHA256), aidlen;
|
||||
struct lws_genhash_ctx hash_ctx;
|
||||
uint32_t ctr = 1, t;
|
||||
const char *aid;
|
||||
|
||||
if (!jwe->jose.enc_alg || !jwe->jose.alg)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Hash
|
||||
*
|
||||
* AlgorithmID || PartyUInfo || PartyVInfo
|
||||
* {|| SuppPubInfo }{|| SuppPrivInfo }
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
aid = direct ? jwe->jose.enc_alg->alg : jwe->jose.alg->alg;
|
||||
aidlen = (int)strlen(aid);
|
||||
|
||||
/*
|
||||
* PartyUInfo (PartyVInfo is the same deal)
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* SuppPubInfo
|
||||
*
|
||||
* This is set to the keydatalen represented as a 32-bit big-endian
|
||||
* integer.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Compute Hash i = H(counter || Z || OtherInfo).
|
||||
*
|
||||
* We must iteratively hash over key material that's larger than
|
||||
* one hash output size (256b for SHA-256)
|
||||
*/
|
||||
|
||||
while (ctr <= (uint32_t)((jwe->jose.enc_alg->keybits_fixed + (hlen - 1)) / hlen)) {
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
if (lws_genhash_init(&hash_ctx, LWS_GENHASH_TYPE_SHA256))
|
||||
return -1;
|
||||
|
||||
if (/* counter */
|
||||
lws_genhash_update(&hash_ctx, be32(ctr++, &t), 4) ||
|
||||
/* Z */
|
||||
lws_genhash_update(&hash_ctx, shared_secret, (unsigned int)sslen) ||
|
||||
/* other info */
|
||||
lws_genhash_update(&hash_ctx, be32((uint32_t)strlen(aid), &t), 4) ||
|
||||
lws_genhash_update(&hash_ctx, aid, (unsigned int)aidlen) ||
|
||||
lws_genhash_update(&hash_ctx,
|
||||
be32(jwe->jose.e[LJJHI_APU].len, &t), 4) ||
|
||||
lws_genhash_update(&hash_ctx, jwe->jose.e[LJJHI_APU].buf,
|
||||
jwe->jose.e[LJJHI_APU].len) ||
|
||||
lws_genhash_update(&hash_ctx,
|
||||
be32(jwe->jose.e[LJJHI_APV].len, &t), 4) ||
|
||||
lws_genhash_update(&hash_ctx, jwe->jose.e[LJJHI_APV].buf,
|
||||
jwe->jose.e[LJJHI_APV].len) ||
|
||||
lws_genhash_update(&hash_ctx,
|
||||
be32(jwe->jose.enc_alg->keybits_fixed, &t),
|
||||
4) ||
|
||||
lws_genhash_destroy(&hash_ctx, out)) {
|
||||
lwsl_err("%s: fail\n", __func__);
|
||||
lws_genhash_destroy(&hash_ctx, NULL);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
out += hlen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_jwe_be64(uint64_t c, uint8_t *p8)
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = 56; n >= 0; n -= 8)
|
||||
*p8++ = (uint8_t)((c >> n) & 0xff);
|
||||
}
|
||||
|
||||
int
|
||||
lws_jwe_auth_and_decrypt(struct lws_jwe *jwe, char *temp, int *temp_len)
|
||||
{
|
||||
int valid_aescbc_hmac, valid_aesgcm;
|
||||
char dotstar[96];
|
||||
|
||||
if (lws_jwe_parse_jose(&jwe->jose, jwe->jws.map.buf[LJWS_JOSE],
|
||||
(int)jwe->jws.map.len[LJWS_JOSE],
|
||||
temp, temp_len) < 0) {
|
||||
lws_strnncpy(dotstar, jwe->jws.map.buf[LJWS_JOSE],
|
||||
jwe->jws.map.len[LJWS_JOSE], sizeof(dotstar));
|
||||
lwsl_err("%s: JOSE parse '%s' failed\n", __func__, dotstar);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!jwe->jose.alg) {
|
||||
lws_strnncpy(dotstar, jwe->jws.map.buf[LJWS_JOSE],
|
||||
jwe->jws.map.len[LJWS_JOSE], sizeof(dotstar));
|
||||
lwsl_err("%s: no jose.alg: %s\n", __func__, dotstar);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
valid_aescbc_hmac = jwe->jose.enc_alg &&
|
||||
jwe->jose.enc_alg->algtype_crypto == LWS_JOSE_ENCTYPE_AES_CBC &&
|
||||
(jwe->jose.enc_alg->hmac_type == LWS_GENHMAC_TYPE_SHA256 ||
|
||||
jwe->jose.enc_alg->hmac_type == LWS_GENHMAC_TYPE_SHA384 ||
|
||||
jwe->jose.enc_alg->hmac_type == LWS_GENHMAC_TYPE_SHA512);
|
||||
|
||||
valid_aesgcm = jwe->jose.enc_alg &&
|
||||
jwe->jose.enc_alg->algtype_crypto == LWS_JOSE_ENCTYPE_AES_GCM;
|
||||
|
||||
if ((jwe->jose.alg->algtype_signing == LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5 ||
|
||||
jwe->jose.alg->algtype_signing == LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP)) {
|
||||
/* RSA + AESCBC */
|
||||
if (valid_aescbc_hmac)
|
||||
return lws_jwe_auth_and_decrypt_rsa_aes_cbc_hs(jwe);
|
||||
/* RSA + AESGCM */
|
||||
if (valid_aesgcm)
|
||||
return lws_jwe_auth_and_decrypt_rsa_aes_gcm(jwe);
|
||||
}
|
||||
|
||||
/* AESKW */
|
||||
|
||||
if (jwe->jose.alg->algtype_signing == LWS_JOSE_ENCTYPE_AES_ECB &&
|
||||
valid_aescbc_hmac)
|
||||
return lws_jwe_auth_and_decrypt_aeskw_cbc_hs(jwe);
|
||||
|
||||
/* ECDH-ES + AESKW */
|
||||
|
||||
if (jwe->jose.alg->algtype_signing == LWS_JOSE_ENCTYPE_ECDHES &&
|
||||
valid_aescbc_hmac)
|
||||
return lws_jwe_auth_and_decrypt_ecdh_cbc_hs(jwe,
|
||||
temp, temp_len);
|
||||
|
||||
lwsl_err("%s: unknown cipher alg combo %s / %s\n", __func__,
|
||||
jwe->jose.alg->alg, jwe->jose.enc_alg ?
|
||||
jwe->jose.enc_alg->alg : "NULL");
|
||||
|
||||
return -1;
|
||||
}
|
||||
int
|
||||
lws_jwe_encrypt(struct lws_jwe *jwe, char *temp, int *temp_len)
|
||||
{
|
||||
int valid_aescbc_hmac, valid_aesgcm, ot = *temp_len, ret = -1;
|
||||
|
||||
if (jwe->jose.recipients >= (int)LWS_ARRAY_SIZE(jwe->jose.recipient)) {
|
||||
lwsl_err("%s: max recipients reached\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
valid_aesgcm = jwe->jose.enc_alg &&
|
||||
jwe->jose.enc_alg->algtype_crypto == LWS_JOSE_ENCTYPE_AES_GCM;
|
||||
|
||||
if (lws_jwe_parse_jose(&jwe->jose, jwe->jws.map.buf[LJWS_JOSE],
|
||||
(int)jwe->jws.map.len[LJWS_JOSE], temp, temp_len) < 0) {
|
||||
lwsl_err("%s: JOSE parse failed\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
temp += ot - *temp_len;
|
||||
|
||||
valid_aescbc_hmac = jwe->jose.enc_alg &&
|
||||
jwe->jose.enc_alg->algtype_crypto == LWS_JOSE_ENCTYPE_AES_CBC &&
|
||||
(jwe->jose.enc_alg->hmac_type == LWS_GENHMAC_TYPE_SHA256 ||
|
||||
jwe->jose.enc_alg->hmac_type == LWS_GENHMAC_TYPE_SHA384 ||
|
||||
jwe->jose.enc_alg->hmac_type == LWS_GENHMAC_TYPE_SHA512);
|
||||
|
||||
if ((jwe->jose.alg->algtype_signing == LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5 ||
|
||||
jwe->jose.alg->algtype_signing == LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP)) {
|
||||
/* RSA + AESCBC */
|
||||
if (valid_aescbc_hmac) {
|
||||
ret = lws_jwe_encrypt_rsa_aes_cbc_hs(jwe, temp, temp_len);
|
||||
goto bail;
|
||||
}
|
||||
/* RSA + AESGCM */
|
||||
if (valid_aesgcm) {
|
||||
ret = lws_jwe_encrypt_rsa_aes_gcm(jwe, temp, temp_len);
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
/* AESKW */
|
||||
|
||||
if (jwe->jose.alg->algtype_signing == LWS_JOSE_ENCTYPE_AES_ECB &&
|
||||
valid_aescbc_hmac) {
|
||||
ret = lws_jwe_encrypt_aeskw_cbc_hs(jwe, temp, temp_len);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* ECDH-ES + AESKW */
|
||||
|
||||
if (jwe->jose.alg->algtype_signing == LWS_JOSE_ENCTYPE_ECDHES &&
|
||||
valid_aescbc_hmac) {
|
||||
ret = lws_jwe_encrypt_ecdh_cbc_hs(jwe, temp, temp_len);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
lwsl_err("%s: unknown cipher alg combo %s / %s\n", __func__,
|
||||
jwe->jose.alg->alg, jwe->jose.enc_alg ?
|
||||
jwe->jose.enc_alg->alg : "NULL");
|
||||
|
||||
bail:
|
||||
if (ret)
|
||||
memset(&jwe->jose.recipient[jwe->jose.recipients], 0,
|
||||
sizeof(jwe->jose.recipient[0]));
|
||||
else
|
||||
jwe->jose.recipients++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* JWE Compact Serialization consists of
|
||||
*
|
||||
* BASE64URL(UTF8(JWE Protected Header)) || '.' ||
|
||||
* BASE64URL(JWE Encrypted Key) || '.' ||
|
||||
* BASE64URL(JWE Initialization Vector) || '.' ||
|
||||
* BASE64URL(JWE Ciphertext) || '.' ||
|
||||
* BASE64URL(JWE Authentication Tag)
|
||||
*
|
||||
*
|
||||
* In the JWE Compact Serialization, no JWE Shared Unprotected Header or
|
||||
* JWE Per-Recipient Unprotected Header are used. In this case, the
|
||||
* JOSE Header and the JWE Protected Header are the same.
|
||||
*
|
||||
* Therefore:
|
||||
*
|
||||
* - Everything needed in the header part must go in the protected header
|
||||
* (it's the only part emitted). We expect the caller did this.
|
||||
*
|
||||
* - You can't emit Compact representation if there are multiple recipients
|
||||
*/
|
||||
|
||||
int
|
||||
lws_jwe_render_compact(struct lws_jwe *jwe, char *out, size_t out_len)
|
||||
{
|
||||
size_t orig = out_len;
|
||||
int n;
|
||||
|
||||
if (jwe->jose.recipients > 1) {
|
||||
lwsl_notice("%s: can't issue compact representation for"
|
||||
" multiple recipients (%d)\n", __func__,
|
||||
jwe->jose.recipients);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
n = lws_jws_base64_enc(jwe->jws.map.buf[LJWS_JOSE],
|
||||
jwe->jws.map.len[LJWS_JOSE], out, out_len);
|
||||
if (n < 0 || (int)out_len == n) {
|
||||
lwsl_info("%s: unable to encode JOSE\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
out += n;
|
||||
*out++ = '.';
|
||||
out_len -= (unsigned int)n + 1;
|
||||
|
||||
n = lws_jws_base64_enc(jwe->jws.map.buf[LJWE_EKEY],
|
||||
jwe->jws.map.len[LJWE_EKEY], out, out_len);
|
||||
if (n < 0 || (int)out_len == n) {
|
||||
lwsl_info("%s: unable to encode EKEY\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
out += n;
|
||||
*out++ = '.';
|
||||
out_len -= (unsigned int)n + 1;
|
||||
n = lws_jws_base64_enc(jwe->jws.map.buf[LJWE_IV],
|
||||
jwe->jws.map.len[LJWE_IV], out, out_len);
|
||||
if (n < 0 || (int)out_len == n) {
|
||||
lwsl_info("%s: unable to encode IV\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
out += n;
|
||||
*out++ = '.';
|
||||
out_len -= (unsigned int)n + 1;
|
||||
|
||||
n = lws_jws_base64_enc(jwe->jws.map.buf[LJWE_CTXT],
|
||||
jwe->jws.map.len[LJWE_CTXT], out, out_len);
|
||||
if (n < 0 || (int)out_len == n) {
|
||||
lwsl_info("%s: unable to encode CTXT\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
out += n;
|
||||
*out++ = '.';
|
||||
out_len -= (unsigned int)n + 1;
|
||||
n = lws_jws_base64_enc(jwe->jws.map.buf[LJWE_ATAG],
|
||||
jwe->jws.map.len[LJWE_ATAG], out, out_len);
|
||||
if (n < 0 || (int)out_len == n) {
|
||||
lwsl_info("%s: unable to encode ATAG\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
out += n;
|
||||
*out++ = '\0';
|
||||
out_len -= (unsigned int)n;
|
||||
|
||||
return (int)(orig - out_len);
|
||||
}
|
||||
|
||||
int
|
||||
lws_jwe_create_packet(struct lws_jwe *jwe, const char *payload, size_t len,
|
||||
const char *nonce, char *out, size_t out_len,
|
||||
struct lws_context *context)
|
||||
{
|
||||
char *buf, *start, *p, *end, *p1, *end1;
|
||||
struct lws_jws jws;
|
||||
int n, m;
|
||||
|
||||
lws_jws_init(&jws, &jwe->jwk, context);
|
||||
|
||||
/*
|
||||
* This buffer is local to the function, the actual output is prepared
|
||||
* into out. Only the plaintext protected header
|
||||
* (which contains the public key, 512 bytes for 4096b) goes in
|
||||
* here temporarily.
|
||||
*/
|
||||
n = LWS_PRE + 2048;
|
||||
buf = malloc((unsigned int)n);
|
||||
if (!buf) {
|
||||
lwsl_notice("%s: malloc %d failed\n", __func__, n);
|
||||
return -1;
|
||||
}
|
||||
|
||||
p = start = buf + LWS_PRE;
|
||||
end = buf + n - LWS_PRE - 1;
|
||||
|
||||
/*
|
||||
* temporary JWS protected header plaintext
|
||||
*/
|
||||
|
||||
if (!jwe->jose.alg || !jwe->jose.alg->alg)
|
||||
goto bail;
|
||||
|
||||
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "{\"alg\":\"%s\",\"jwk\":",
|
||||
jwe->jose.alg->alg);
|
||||
m = lws_ptr_diff(end, p);
|
||||
n = lws_jwk_export(&jwe->jwk, 0, p, &m);
|
||||
if (n < 0) {
|
||||
lwsl_notice("failed to export jwk\n");
|
||||
|
||||
goto bail;
|
||||
}
|
||||
p += n;
|
||||
p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), ",\"nonce\":\"%s\"}", nonce);
|
||||
|
||||
/*
|
||||
* prepare the signed outer JSON with all the parts in
|
||||
*/
|
||||
|
||||
p1 = out;
|
||||
end1 = out + out_len - 1;
|
||||
|
||||
p1 += lws_snprintf(p1, lws_ptr_diff_size_t(end1, p1), "{\"protected\":\"");
|
||||
jws.map_b64.buf[LJWS_JOSE] = p1;
|
||||
n = lws_jws_base64_enc(start, lws_ptr_diff_size_t(p, start), p1, lws_ptr_diff_size_t(end1, p1));
|
||||
if (n < 0) {
|
||||
lwsl_notice("%s: failed to encode protected\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
jws.map_b64.len[LJWS_JOSE] = (unsigned int)n;
|
||||
p1 += n;
|
||||
|
||||
p1 += lws_snprintf(p1, lws_ptr_diff_size_t(end1, p1), "\",\"payload\":\"");
|
||||
jws.map_b64.buf[LJWS_PYLD] = p1;
|
||||
n = lws_jws_base64_enc(payload, len, p1, lws_ptr_diff_size_t(end1, p1));
|
||||
if (n < 0) {
|
||||
lwsl_notice("%s: failed to encode payload\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
jws.map_b64.len[LJWS_PYLD] = (unsigned int)n;
|
||||
p1 += n;
|
||||
|
||||
p1 += lws_snprintf(p1, lws_ptr_diff_size_t(end1, p1), "\",\"header\":\"");
|
||||
jws.map_b64.buf[LJWS_UHDR] = p1;
|
||||
n = lws_jws_base64_enc(payload, len, p1, lws_ptr_diff_size_t(end1, p1));
|
||||
if (n < 0) {
|
||||
lwsl_notice("%s: failed to encode payload\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
jws.map_b64.len[LJWS_UHDR] = (unsigned int)n;
|
||||
|
||||
p1 += n;
|
||||
p1 += lws_snprintf(p1, lws_ptr_diff_size_t(end1, p1), "\",\"signature\":\"");
|
||||
|
||||
/*
|
||||
* taking the b64 protected header and the b64 payload, sign them
|
||||
* and place the signature into the packet
|
||||
*/
|
||||
n = lws_jws_sign_from_b64(&jwe->jose, &jws, p1, lws_ptr_diff_size_t(end1, p1));
|
||||
if (n < 0) {
|
||||
lwsl_notice("sig gen failed\n");
|
||||
|
||||
goto bail;
|
||||
}
|
||||
jws.map_b64.buf[LJWS_SIG] = p1;
|
||||
jws.map_b64.len[LJWS_SIG] = (unsigned int)n;
|
||||
|
||||
p1 += n;
|
||||
p1 += lws_snprintf(p1, lws_ptr_diff_size_t(end1, p1), "\"}");
|
||||
|
||||
free(buf);
|
||||
|
||||
return lws_ptr_diff(p1, out);
|
||||
|
||||
bail:
|
||||
lws_jws_destroy(&jws);
|
||||
free(buf);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const char *protected_en[] = {
|
||||
"encrypted_key", "aad", "iv", "ciphertext", "tag"
|
||||
};
|
||||
|
||||
static int protected_idx[] = {
|
||||
LJWE_EKEY, LJWE_AAD, LJWE_IV, LJWE_CTXT, LJWE_ATAG
|
||||
};
|
||||
|
||||
/*
|
||||
* The complete JWE may look something like this:
|
||||
*
|
||||
* {
|
||||
* "protected":
|
||||
* "eyJlbmMiOiJBMTI4Q0JDLUhTMjU2In0",
|
||||
* "unprotected":
|
||||
* {"jku":"https://server.example.com/keys.jwks"},
|
||||
* "recipients":[
|
||||
* {"header":
|
||||
* {"alg":"RSA1_5","kid":"2011-04-29"},
|
||||
* "encrypted_key":
|
||||
* "UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-
|
||||
* kFm1NJn8LE9XShH59_i8J0PH5ZZyNfGy2xGdULU7sHNF6Gp2vPLgNZ__deLKx
|
||||
* GHZ7PcHALUzoOegEI-8E66jX2E4zyJKx-YxzZIItRzC5hlRirb6Y5Cl_p-ko3
|
||||
* YvkkysZIFNPccxRU7qve1WYPxqbb2Yw8kZqa2rMWI5ng8OtvzlV7elprCbuPh
|
||||
* cCdZ6XDP0_F8rkXds2vE4X-ncOIM8hAYHHi29NX0mcKiRaD0-D-ljQTP-cFPg
|
||||
* wCp6X-nZZd9OHBv-B3oWh2TbqmScqXMR4gp_A"},
|
||||
* {"header":
|
||||
* {"alg":"A128KW","kid":"7"},
|
||||
* "encrypted_key":
|
||||
* "6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ"}],
|
||||
* "iv":
|
||||
* "AxY8DCtDaGlsbGljb3RoZQ",
|
||||
* "ciphertext":
|
||||
* "KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY",
|
||||
* "tag":
|
||||
* "Mz-VPPyU4RlcuYv1IwIvzw"
|
||||
* }
|
||||
*
|
||||
* The flattened JWE ends up like this
|
||||
*
|
||||
* {
|
||||
* "protected": "eyJlbmMiOiJBMTI4Q0JDLUhTMjU2In0",
|
||||
* "unprotected": {"jku":"https://server.example.com/keys.jwks"},
|
||||
* "header": {"alg":"A128KW","kid":"7"},
|
||||
* "encrypted_key": "6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ",
|
||||
* "iv": "AxY8DCtDaGlsbGljb3RoZQ",
|
||||
* "ciphertext": "KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY",
|
||||
* "tag": "Mz-VPPyU4RlcuYv1IwIvzw"
|
||||
* }
|
||||
*
|
||||
* {
|
||||
* "protected":"<integrity-protected header contents>",
|
||||
* "unprotected":<non-integrity-protected header contents>,
|
||||
* "header":<more non-integrity-protected header contents>,
|
||||
* "encrypted_key":"<encrypted key contents>",
|
||||
* "aad":"<additional authenticated data contents>",
|
||||
* "iv":"<initialization vector contents>",
|
||||
* "ciphertext":"<ciphertext contents>",
|
||||
* "tag":"<authentication tag contents>"
|
||||
* }
|
||||
*/
|
||||
|
||||
int
|
||||
lws_jwe_render_flattened(struct lws_jwe *jwe, char *out, size_t out_len)
|
||||
{
|
||||
char buf[3072], *p1, *end1, protected[128];
|
||||
int m, n, jlen, plen;
|
||||
|
||||
jlen = lws_jose_render(&jwe->jose, jwe->jws.jwk, buf, sizeof(buf));
|
||||
if (jlen < 0) {
|
||||
lwsl_err("%s: lws_jose_render failed\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* prepare the JWE JSON with all the parts in
|
||||
*/
|
||||
|
||||
p1 = out;
|
||||
end1 = out + out_len - 1;
|
||||
|
||||
/*
|
||||
* The protected header is b64url encoding of the JOSE header part
|
||||
*/
|
||||
|
||||
plen = lws_snprintf(protected, sizeof(protected),
|
||||
"{\"alg\":\"%s\",\"enc\":\"%s\"}",
|
||||
jwe->jose.alg->alg, jwe->jose.enc_alg->alg);
|
||||
|
||||
p1 += lws_snprintf(p1, lws_ptr_diff_size_t(end1, p1), "{\"protected\":\"");
|
||||
jwe->jws.map_b64.buf[LJWS_JOSE] = p1;
|
||||
n = lws_jws_base64_enc(protected, (size_t)plen, p1, lws_ptr_diff_size_t(end1, p1));
|
||||
if (n < 0) {
|
||||
lwsl_notice("%s: failed to encode protected\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
jwe->jws.map_b64.len[LJWS_JOSE] = (unsigned int)n;
|
||||
p1 += n;
|
||||
|
||||
/* unprotected not supported atm */
|
||||
|
||||
p1 += lws_snprintf(p1, lws_ptr_diff_size_t(end1, p1), "\",\n\"header\":");
|
||||
lws_strnncpy(p1, buf, jlen, end1 - p1);
|
||||
p1 += strlen(p1);
|
||||
|
||||
for (m = 0; m < (int)LWS_ARRAY_SIZE(protected_en); m++)
|
||||
if (jwe->jws.map.buf[protected_idx[m]]) {
|
||||
p1 += lws_snprintf(p1, lws_ptr_diff_size_t(end1, p1), ",\n\"%s\":\"",
|
||||
protected_en[m]);
|
||||
//jwe->jws.map_b64.buf[protected_idx[m]] = p1;
|
||||
n = lws_jws_base64_enc(jwe->jws.map.buf[protected_idx[m]],
|
||||
jwe->jws.map.len[protected_idx[m]],
|
||||
p1, lws_ptr_diff_size_t(end1, p1));
|
||||
if (n < 0) {
|
||||
lwsl_notice("%s: failed to encode %s\n",
|
||||
__func__, protected_en[m]);
|
||||
goto bail;
|
||||
}
|
||||
//jwe->jws.map_b64.len[protected_idx[m]] = n;
|
||||
p1 += n;
|
||||
p1 += lws_snprintf(p1, lws_ptr_diff_size_t(end1, p1), "\"");
|
||||
}
|
||||
|
||||
p1 += lws_snprintf(p1, lws_ptr_diff_size_t(end1, p1), "\n}\n");
|
||||
|
||||
return lws_ptr_diff(p1, out);
|
||||
|
||||
bail:
|
||||
lws_jws_destroy(&jwe->jws);
|
||||
|
||||
return -1;
|
||||
}
|
88
Kinc/Sources/kinc/libs/jose/jwe/private-lib-jose-jwe.h
Normal file
88
Kinc/Sources/kinc/libs/jose/jwe/private-lib-jose-jwe.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define LWS_AESGCM_IV 12
|
||||
#define LWS_AESGCM_TAG 16
|
||||
|
||||
/* jwe-rsa-aescbc.c */
|
||||
|
||||
int
|
||||
lws_jwe_auth_and_decrypt_rsa_aes_cbc_hs(struct lws_jwe *jwe);
|
||||
|
||||
|
||||
int
|
||||
lws_jwe_encrypt_rsa_aes_cbc_hs(struct lws_jwe *jwe,
|
||||
char *temp, int *temp_len);
|
||||
|
||||
int
|
||||
lws_jwe_auth_and_decrypt_cbc_hs(struct lws_jwe *jwe, uint8_t *enc_cek,
|
||||
uint8_t *aad, int aad_len);
|
||||
|
||||
|
||||
/* jws-rsa-aesgcm.c */
|
||||
|
||||
int
|
||||
lws_jwe_auth_and_decrypt_gcm(struct lws_jwe *jwe, uint8_t *enc_cek,
|
||||
uint8_t *aad, int aad_len);
|
||||
|
||||
int
|
||||
lws_jwe_auth_and_decrypt_rsa_aes_gcm(struct lws_jwe *jwe);
|
||||
|
||||
int
|
||||
lws_jwe_encrypt_gcm(struct lws_jwe *jwe,
|
||||
uint8_t *enc_cek, uint8_t *aad, int aad_len);
|
||||
|
||||
int
|
||||
lws_jwe_encrypt_rsa_aes_gcm(struct lws_jwe *jwe,
|
||||
char *temp, int *temp_len);
|
||||
|
||||
|
||||
|
||||
|
||||
/* jwe-rsa-aeskw.c */
|
||||
|
||||
int
|
||||
lws_jwe_encrypt_aeskw_cbc_hs(struct lws_jwe *jwe,
|
||||
char *temp, int *temp_len);
|
||||
|
||||
int
|
||||
lws_jwe_auth_and_decrypt_aeskw_cbc_hs(struct lws_jwe *jwe);
|
||||
|
||||
/* aescbc.c */
|
||||
|
||||
int
|
||||
lws_jwe_auth_and_decrypt_cbc_hs(struct lws_jwe *jwe, uint8_t *enc_cek,
|
||||
uint8_t *aad, int aad_len);
|
||||
|
||||
int
|
||||
lws_jwe_encrypt_cbc_hs(struct lws_jwe *jwe,
|
||||
uint8_t *cek, uint8_t *aad, int aad_len);
|
||||
|
||||
int
|
||||
lws_jwe_auth_and_decrypt_ecdh_cbc_hs(struct lws_jwe *jwe,
|
||||
char *temp, int *temp_len);
|
||||
|
||||
int
|
||||
lws_jwe_encrypt_ecdh_cbc_hs(struct lws_jwe *jwe,
|
||||
char *temp, int *temp_len);
|
Reference in New Issue
Block a user