1*1c60b9acSAndroid Build Coastguard Worker /*
2*1c60b9acSAndroid Build Coastguard Worker * libwebsockets - small server side websockets and web server implementation
3*1c60b9acSAndroid Build Coastguard Worker *
4*1c60b9acSAndroid Build Coastguard Worker * Copyright (C) 2010 - 2020 Andy Green <[email protected]>
5*1c60b9acSAndroid Build Coastguard Worker *
6*1c60b9acSAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining a copy
7*1c60b9acSAndroid Build Coastguard Worker * of this software and associated documentation files (the "Software"), to
8*1c60b9acSAndroid Build Coastguard Worker * deal in the Software without restriction, including without limitation the
9*1c60b9acSAndroid Build Coastguard Worker * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10*1c60b9acSAndroid Build Coastguard Worker * sell copies of the Software, and to permit persons to whom the Software is
11*1c60b9acSAndroid Build Coastguard Worker * furnished to do so, subject to the following conditions:
12*1c60b9acSAndroid Build Coastguard Worker *
13*1c60b9acSAndroid Build Coastguard Worker * The above copyright notice and this permission notice shall be included in
14*1c60b9acSAndroid Build Coastguard Worker * all copies or substantial portions of the Software.
15*1c60b9acSAndroid Build Coastguard Worker *
16*1c60b9acSAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*1c60b9acSAndroid Build Coastguard Worker * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*1c60b9acSAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19*1c60b9acSAndroid Build Coastguard Worker * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*1c60b9acSAndroid Build Coastguard Worker * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21*1c60b9acSAndroid Build Coastguard Worker * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22*1c60b9acSAndroid Build Coastguard Worker * IN THE SOFTWARE.
23*1c60b9acSAndroid Build Coastguard Worker */
24*1c60b9acSAndroid Build Coastguard Worker
25*1c60b9acSAndroid Build Coastguard Worker #include "private-lib-core.h"
26*1c60b9acSAndroid Build Coastguard Worker #include "private-lib-jose-jwe.h"
27*1c60b9acSAndroid Build Coastguard Worker
28*1c60b9acSAndroid Build Coastguard Worker #define LWS_AESGCM_IV 12
29*1c60b9acSAndroid Build Coastguard Worker
30*1c60b9acSAndroid Build Coastguard Worker
31*1c60b9acSAndroid Build Coastguard Worker int
lws_jwe_encrypt_rsa_aes_gcm(struct lws_jwe * jwe,char * temp,int * temp_len)32*1c60b9acSAndroid Build Coastguard Worker lws_jwe_encrypt_rsa_aes_gcm(struct lws_jwe *jwe, char *temp, int *temp_len)
33*1c60b9acSAndroid Build Coastguard Worker {
34*1c60b9acSAndroid Build Coastguard Worker int ekbytes = jwe->jose.enc_alg->keybits_fixed / 8;
35*1c60b9acSAndroid Build Coastguard Worker struct lws_genrsa_ctx rsactx;
36*1c60b9acSAndroid Build Coastguard Worker int n, ret = -1, ot = *temp_len;
37*1c60b9acSAndroid Build Coastguard Worker
38*1c60b9acSAndroid Build Coastguard Worker if (jwe->jws.jwk->kty != LWS_GENCRYPTO_KTY_RSA) {
39*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: wrong kty %d\n", __func__, jwe->jws.jwk->kty);
40*1c60b9acSAndroid Build Coastguard Worker
41*1c60b9acSAndroid Build Coastguard Worker return -1;
42*1c60b9acSAndroid Build Coastguard Worker }
43*1c60b9acSAndroid Build Coastguard Worker
44*1c60b9acSAndroid Build Coastguard Worker /* create the IV + CEK */
45*1c60b9acSAndroid Build Coastguard Worker
46*1c60b9acSAndroid Build Coastguard Worker if (lws_jws_randomize_element(jwe->jws.context, &jwe->jws.map, LJWE_IV,
47*1c60b9acSAndroid Build Coastguard Worker temp, temp_len,
48*1c60b9acSAndroid Build Coastguard Worker LWS_AESGCM_IV, 0))
49*1c60b9acSAndroid Build Coastguard Worker return -1;
50*1c60b9acSAndroid Build Coastguard Worker
51*1c60b9acSAndroid Build Coastguard Worker if (lws_jws_alloc_element(&jwe->jws.map, LJWE_ATAG,
52*1c60b9acSAndroid Build Coastguard Worker temp + (ot - *temp_len),
53*1c60b9acSAndroid Build Coastguard Worker temp_len, LWS_AESGCM_TAG, 0))
54*1c60b9acSAndroid Build Coastguard Worker return -1;
55*1c60b9acSAndroid Build Coastguard Worker
56*1c60b9acSAndroid Build Coastguard Worker /* create a b64 version of the JOSE header, needed as aad */
57*1c60b9acSAndroid Build Coastguard Worker
58*1c60b9acSAndroid Build Coastguard Worker if (lws_jws_encode_b64_element(&jwe->jws.map_b64, LJWE_JOSE,
59*1c60b9acSAndroid Build Coastguard Worker temp + (ot - *temp_len), temp_len,
60*1c60b9acSAndroid Build Coastguard Worker jwe->jws.map.buf[LJWE_JOSE],
61*1c60b9acSAndroid Build Coastguard Worker jwe->jws.map.len[LJWE_JOSE]))
62*1c60b9acSAndroid Build Coastguard Worker return -1;
63*1c60b9acSAndroid Build Coastguard Worker
64*1c60b9acSAndroid Build Coastguard Worker /*
65*1c60b9acSAndroid Build Coastguard Worker * If none already, create a new, random CEK in the JWE (so it can be
66*1c60b9acSAndroid Build Coastguard Worker * reused for other recipients on same payload). If it already exists,
67*1c60b9acSAndroid Build Coastguard Worker * just reuse it. It will be cleansed in the JWE destroy.
68*1c60b9acSAndroid Build Coastguard Worker */
69*1c60b9acSAndroid Build Coastguard Worker if (!jwe->cek_valid) {
70*1c60b9acSAndroid Build Coastguard Worker if (lws_get_random(jwe->jws.context, jwe->cek, (unsigned int)ekbytes) !=
71*1c60b9acSAndroid Build Coastguard Worker (size_t)ekbytes) {
72*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: Problem getting random\n", __func__);
73*1c60b9acSAndroid Build Coastguard Worker return -1;
74*1c60b9acSAndroid Build Coastguard Worker }
75*1c60b9acSAndroid Build Coastguard Worker jwe->cek_valid = 1;
76*1c60b9acSAndroid Build Coastguard Worker }
77*1c60b9acSAndroid Build Coastguard Worker
78*1c60b9acSAndroid Build Coastguard Worker if (lws_jws_dup_element(&jwe->jws.map, LJWE_EKEY,
79*1c60b9acSAndroid Build Coastguard Worker temp + (ot - *temp_len), temp_len,
80*1c60b9acSAndroid Build Coastguard Worker jwe->cek, (unsigned int)ekbytes, 0))
81*1c60b9acSAndroid Build Coastguard Worker return -1;
82*1c60b9acSAndroid Build Coastguard Worker
83*1c60b9acSAndroid Build Coastguard Worker /* encrypt the payload */
84*1c60b9acSAndroid Build Coastguard Worker
85*1c60b9acSAndroid Build Coastguard Worker n = lws_jwe_encrypt_gcm(jwe, (uint8_t *)jwe->jws.map.buf[LJWE_EKEY],
86*1c60b9acSAndroid Build Coastguard Worker (uint8_t *)jwe->jws.map_b64.buf[LJWE_JOSE],
87*1c60b9acSAndroid Build Coastguard Worker (int)jwe->jws.map_b64.len[LJWE_JOSE]);
88*1c60b9acSAndroid Build Coastguard Worker if (n < 0) {
89*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: lws_jwe_encrypt_gcm failed\n",
90*1c60b9acSAndroid Build Coastguard Worker __func__);
91*1c60b9acSAndroid Build Coastguard Worker goto bail;
92*1c60b9acSAndroid Build Coastguard Worker }
93*1c60b9acSAndroid Build Coastguard Worker
94*1c60b9acSAndroid Build Coastguard Worker /* Encrypt the CEK into EKEY to make the JWE Encrypted Key */
95*1c60b9acSAndroid Build Coastguard Worker
96*1c60b9acSAndroid Build Coastguard Worker if (lws_genrsa_create(&rsactx, jwe->jws.jwk->e, jwe->jws.context,
97*1c60b9acSAndroid Build Coastguard Worker !strcmp(jwe->jose.alg->alg, "RSA-OAEP") ?
98*1c60b9acSAndroid Build Coastguard Worker LGRSAM_PKCS1_OAEP_PSS : LGRSAM_PKCS1_1_5,
99*1c60b9acSAndroid Build Coastguard Worker LWS_GENHASH_TYPE_SHA1 /* !!! */)) {
100*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
101*1c60b9acSAndroid Build Coastguard Worker __func__);
102*1c60b9acSAndroid Build Coastguard Worker goto bail;
103*1c60b9acSAndroid Build Coastguard Worker }
104*1c60b9acSAndroid Build Coastguard Worker
105*1c60b9acSAndroid Build Coastguard Worker n = lws_genrsa_public_encrypt(&rsactx, jwe->cek, (unsigned int)ekbytes,
106*1c60b9acSAndroid Build Coastguard Worker (uint8_t *)jwe->jws.map.buf[LJWE_EKEY]);
107*1c60b9acSAndroid Build Coastguard Worker lws_genrsa_destroy(&rsactx);
108*1c60b9acSAndroid Build Coastguard Worker if (n < 0) {
109*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: encrypt cek fail: \n", __func__);
110*1c60b9acSAndroid Build Coastguard Worker goto bail;
111*1c60b9acSAndroid Build Coastguard Worker }
112*1c60b9acSAndroid Build Coastguard Worker
113*1c60b9acSAndroid Build Coastguard Worker /* set the EKEY length to the actual enciphered length */
114*1c60b9acSAndroid Build Coastguard Worker jwe->jws.map.len[LJWE_EKEY] = (unsigned int)n;
115*1c60b9acSAndroid Build Coastguard Worker
116*1c60b9acSAndroid Build Coastguard Worker ret = (int32_t)jwe->jws.map.len[LJWE_CTXT];
117*1c60b9acSAndroid Build Coastguard Worker
118*1c60b9acSAndroid Build Coastguard Worker bail:
119*1c60b9acSAndroid Build Coastguard Worker
120*1c60b9acSAndroid Build Coastguard Worker return ret;
121*1c60b9acSAndroid Build Coastguard Worker }
122*1c60b9acSAndroid Build Coastguard Worker
123*1c60b9acSAndroid Build Coastguard Worker int
lws_jwe_auth_and_decrypt_rsa_aes_gcm(struct lws_jwe * jwe)124*1c60b9acSAndroid Build Coastguard Worker lws_jwe_auth_and_decrypt_rsa_aes_gcm(struct lws_jwe *jwe)
125*1c60b9acSAndroid Build Coastguard Worker {
126*1c60b9acSAndroid Build Coastguard Worker int n;
127*1c60b9acSAndroid Build Coastguard Worker struct lws_genrsa_ctx rsactx;
128*1c60b9acSAndroid Build Coastguard Worker uint8_t enc_cek[LWS_JWE_LIMIT_KEY_ELEMENT_BYTES];
129*1c60b9acSAndroid Build Coastguard Worker
130*1c60b9acSAndroid Build Coastguard Worker if (jwe->jws.jwk->kty != LWS_GENCRYPTO_KTY_RSA) {
131*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: unexpected kty %d\n", __func__, jwe->jws.jwk->kty);
132*1c60b9acSAndroid Build Coastguard Worker
133*1c60b9acSAndroid Build Coastguard Worker return -1;
134*1c60b9acSAndroid Build Coastguard Worker }
135*1c60b9acSAndroid Build Coastguard Worker
136*1c60b9acSAndroid Build Coastguard Worker if (jwe->jws.map.len[LJWE_EKEY] < 32) {
137*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: EKEY length too short %d\n", __func__,
138*1c60b9acSAndroid Build Coastguard Worker jwe->jws.map.len[LJWE_EKEY]);
139*1c60b9acSAndroid Build Coastguard Worker
140*1c60b9acSAndroid Build Coastguard Worker return -1;
141*1c60b9acSAndroid Build Coastguard Worker }
142*1c60b9acSAndroid Build Coastguard Worker
143*1c60b9acSAndroid Build Coastguard Worker /* Decrypt the JWE Encrypted Key to get the direct CEK */
144*1c60b9acSAndroid Build Coastguard Worker
145*1c60b9acSAndroid Build Coastguard Worker if (lws_genrsa_create(&rsactx, jwe->jws.jwk->e, jwe->jws.context,
146*1c60b9acSAndroid Build Coastguard Worker !strcmp(jwe->jose.alg->alg, "RSA-OAEP") ?
147*1c60b9acSAndroid Build Coastguard Worker LGRSAM_PKCS1_OAEP_PSS : LGRSAM_PKCS1_1_5,
148*1c60b9acSAndroid Build Coastguard Worker LWS_GENHASH_TYPE_SHA1 /* !!! */)) {
149*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
150*1c60b9acSAndroid Build Coastguard Worker __func__);
151*1c60b9acSAndroid Build Coastguard Worker return -1;
152*1c60b9acSAndroid Build Coastguard Worker }
153*1c60b9acSAndroid Build Coastguard Worker
154*1c60b9acSAndroid Build Coastguard Worker n = lws_genrsa_private_decrypt(&rsactx,
155*1c60b9acSAndroid Build Coastguard Worker (uint8_t *)jwe->jws.map.buf[LJWE_EKEY],
156*1c60b9acSAndroid Build Coastguard Worker jwe->jws.map.len[LJWE_EKEY], enc_cek,
157*1c60b9acSAndroid Build Coastguard Worker sizeof(enc_cek));
158*1c60b9acSAndroid Build Coastguard Worker lws_genrsa_destroy(&rsactx);
159*1c60b9acSAndroid Build Coastguard Worker if (n < 0) {
160*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: decrypt cek fail: \n", __func__);
161*1c60b9acSAndroid Build Coastguard Worker return -1;
162*1c60b9acSAndroid Build Coastguard Worker }
163*1c60b9acSAndroid Build Coastguard Worker
164*1c60b9acSAndroid Build Coastguard Worker n = lws_jwe_auth_and_decrypt_gcm(jwe, enc_cek,
165*1c60b9acSAndroid Build Coastguard Worker (uint8_t *)jwe->jws.map_b64.buf[LJWE_JOSE],
166*1c60b9acSAndroid Build Coastguard Worker (int)jwe->jws.map_b64.len[LJWE_JOSE]);
167*1c60b9acSAndroid Build Coastguard Worker if (n < 0) {
168*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: lws_jwe_auth_and_decrypt_gcm_hs failed\n",
169*1c60b9acSAndroid Build Coastguard Worker __func__);
170*1c60b9acSAndroid Build Coastguard Worker return -1;
171*1c60b9acSAndroid Build Coastguard Worker }
172*1c60b9acSAndroid Build Coastguard Worker
173*1c60b9acSAndroid Build Coastguard Worker #if defined(LWS_WITH_MBEDTLS) && defined(LWS_PLAT_OPTEE)
174*1c60b9acSAndroid Build Coastguard Worker /* strip padding */
175*1c60b9acSAndroid Build Coastguard Worker
176*1c60b9acSAndroid Build Coastguard Worker n = jwe->jws.map.buf[LJWE_CTXT][jwe->jws.map.len[LJWE_CTXT] - 1];
177*1c60b9acSAndroid Build Coastguard Worker if (n > 16)
178*1c60b9acSAndroid Build Coastguard Worker return -1;
179*1c60b9acSAndroid Build Coastguard Worker jwe->jws.map.len[LJWE_CTXT] -= n;
180*1c60b9acSAndroid Build Coastguard Worker #endif
181*1c60b9acSAndroid Build Coastguard Worker
182*1c60b9acSAndroid Build Coastguard Worker return (int)jwe->jws.map.len[LJWE_CTXT];
183*1c60b9acSAndroid Build Coastguard Worker }
184