/* * libwebsockets - small server side websockets and web server implementation * * Copyright (C) 2010 - 2019 Andy Green * * 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, 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, 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], 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, 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] = n; ret = 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__, 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], 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 jwe->jws.map.len[LJWE_CTXT]; }