1 /*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 */
24
25 #include "private-lib-core.h"
26 #include "private-lib-jose-jwe.h"
27
28 /*
29 * Requirements on entry:
30 *
31 * - jwe->jws.map LJWE_JOSE contains the ASCII JOSE header
32 * - jwe->jws.map LJWE_EKEY contains cek of enc_alg hmac length
33 * - jwe->jws.map LJWE_CTXT contains the plaintext
34 *
35 * On successful exit:
36 *
37 * - jwe->jws.map LJWE_ATAG contains the tag
38 * - jwe->jws.map LJWE_IV contains the new random IV that was used
39 * - jwe->jws.map LJWE_EKEY contains the encrypted CEK
40 * - jwe->jws.map LJWE_CTXT contains the ciphertext
41 *
42 * Return the amount of temp used, or -1
43 */
44
45 int
lws_jwe_encrypt_rsa_aes_cbc_hs(struct lws_jwe * jwe,char * temp,int * temp_len)46 lws_jwe_encrypt_rsa_aes_cbc_hs(struct lws_jwe *jwe,
47 char *temp, int *temp_len)
48 {
49 int n, hlen = lws_genhmac_size(jwe->jose.enc_alg->hmac_type), ot = *temp_len;
50 char ekey[LWS_GENHASH_LARGEST];
51 struct lws_genrsa_ctx rsactx;
52
53 if (jwe->jws.jwk->kty != LWS_GENCRYPTO_KTY_RSA) {
54 lwsl_err("%s: unexpected kty %d\n", __func__, jwe->jws.jwk->kty);
55
56 return -1;
57 }
58
59 /*
60 * Notice that the unencrypted EKEY coming in is smaller than the
61 * RSA-encrypted EKEY going out, which is going to be the RSA key size
62 *
63 * Create a b64 version of the JOSE header, needed as aad
64 */
65 if (lws_jws_encode_b64_element(&jwe->jws.map_b64, LJWE_JOSE,
66 temp, temp_len,
67 jwe->jws.map.buf[LJWE_JOSE],
68 jwe->jws.map.len[LJWE_JOSE]))
69 return -1;
70
71 if (lws_jws_alloc_element(&jwe->jws.map, LJWE_ATAG, temp + (ot - *temp_len),
72 temp_len, hlen / 2, 0))
73 return -1;
74
75 if (lws_jws_alloc_element(&jwe->jws.map, LJWE_IV, temp + (ot - *temp_len),
76 temp_len, LWS_JWE_AES_IV_BYTES, 0))
77 return -1;
78
79 /*
80 * Without changing the unencrypted CEK in EKEY, reallocate enough
81 * space to write the RSA-encrypted version in-situ.
82 */
83 if (lws_jws_dup_element(&jwe->jws.map, LJWE_EKEY, temp + (ot - *temp_len),
84 temp_len, jwe->jws.map.buf[LJWE_EKEY],
85 jwe->jws.map.len[LJWE_EKEY],
86 jwe->jws.jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len))
87 return -1;
88
89 /* Encrypt using the raw CEK (treated as MAC KEY | ENC KEY) */
90
91 n = lws_jwe_encrypt_cbc_hs(jwe, (uint8_t *)jwe->jws.map.buf[LJWE_EKEY],
92 (uint8_t *)jwe->jws.map_b64.buf[LJWE_JOSE],
93 jwe->jws.map_b64.len[LJWE_JOSE]);
94 if (n < 0) {
95 lwsl_err("%s: lws_jwe_encrypt_cbc_hs failed\n", __func__);
96 return -1;
97 }
98
99 if (lws_genrsa_create(&rsactx, jwe->jws.jwk->e, jwe->jws.context,
100 !strcmp(jwe->jose.alg->alg, "RSA-OAEP") ?
101 LGRSAM_PKCS1_OAEP_PSS : LGRSAM_PKCS1_1_5,
102 LWS_GENHASH_TYPE_UNKNOWN)) {
103 lwsl_notice("%s: lws_genrsa_create\n",
104 __func__);
105 return -1;
106 }
107
108 /* encrypt the CEK using RSA, mbedtls can't handle both in and out are
109 * the EKEY, so copy the unencrypted ekey out temporarily */
110
111 memcpy(ekey, jwe->jws.map.buf[LJWE_EKEY], hlen);
112
113 n = lws_genrsa_public_encrypt(&rsactx, (uint8_t *)ekey, hlen,
114 (uint8_t *)jwe->jws.map.buf[LJWE_EKEY]);
115 lws_genrsa_destroy(&rsactx);
116 lws_explicit_bzero(ekey, hlen); /* cleanse the temp CEK copy */
117 if (n < 0) {
118 lwsl_err("%s: encrypt cek fail\n", __func__);
119 return -1;
120 }
121 jwe->jws.map.len[LJWE_EKEY] = n; /* update to encrypted EKEY size */
122
123 /*
124 * We end up with IV, ATAG, set, EKEY encrypted and CTXT is ciphertext,
125 * and b64u version of ATAG in map_b64.
126 */
127
128 return 0;
129 }
130
131 int
lws_jwe_auth_and_decrypt_rsa_aes_cbc_hs(struct lws_jwe * jwe)132 lws_jwe_auth_and_decrypt_rsa_aes_cbc_hs(struct lws_jwe *jwe)
133 {
134 int n;
135 struct lws_genrsa_ctx rsactx;
136 uint8_t enc_cek[512];
137
138 if (jwe->jws.jwk->kty != LWS_GENCRYPTO_KTY_RSA) {
139 lwsl_err("%s: unexpected kty %d\n", __func__, jwe->jws.jwk->kty);
140
141 return -1;
142 }
143
144 if (jwe->jws.map.len[LJWE_EKEY] < 40) {
145 lwsl_err("%s: EKEY length too short %d\n", __func__,
146 jwe->jws.map.len[LJWE_EKEY]);
147
148 return -1;
149 }
150
151 /* Decrypt the JWE Encrypted Key to get the raw MAC || CEK */
152
153 if (lws_genrsa_create(&rsactx, jwe->jws.jwk->e, jwe->jws.context,
154 !strcmp(jwe->jose.alg->alg, "RSA-OAEP") ?
155 LGRSAM_PKCS1_OAEP_PSS : LGRSAM_PKCS1_1_5,
156 LWS_GENHASH_TYPE_UNKNOWN)) {
157 lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
158 __func__);
159 return -1;
160 }
161
162 n = lws_genrsa_private_decrypt(&rsactx,
163 (uint8_t *)jwe->jws.map.buf[LJWE_EKEY],
164 jwe->jws.map.len[LJWE_EKEY], enc_cek,
165 sizeof(enc_cek));
166 lws_genrsa_destroy(&rsactx);
167 if (n < 0) {
168 lwsl_err("%s: decrypt cek fail: \n", __func__);
169 return -1;
170 }
171
172 n = lws_jwe_auth_and_decrypt_cbc_hs(jwe, enc_cek,
173 (uint8_t *)jwe->jws.map_b64.buf[LJWE_JOSE],
174 jwe->jws.map_b64.len[LJWE_JOSE]);
175 if (n < 0) {
176 lwsl_err("%s: lws_jwe_auth_and_decrypt_cbc_hs failed\n",
177 __func__);
178 return -1;
179 }
180
181 #if defined(LWS_WITH_MBEDTLS) && defined(LWS_PLAT_OPTEE)
182
183 /* strip padding */
184
185 n = jwe->jws.map.buf[LJWE_CTXT][jwe->jws.map.len[LJWE_CTXT] - 1];
186 if (n > 16) {
187 lwsl_err("%s: n == %d, plen %d\n", __func__, n,
188 (int)jwe->jws.map.len[LJWE_CTXT]);
189 return -1;
190 }
191 jwe->jws.map.len[LJWE_CTXT] -= n;
192 #endif
193
194 return jwe->jws.map.len[LJWE_CTXT];
195 }
196