• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2020 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 = (int)lws_genhmac_size(jwe->jose.enc_alg->hmac_type),
50 	    ot = *temp_len;
51 	char ekey[LWS_GENHASH_LARGEST];
52 	struct lws_genrsa_ctx rsactx;
53 
54 	if (jwe->jws.jwk->kty != LWS_GENCRYPTO_KTY_RSA) {
55 		lwsl_err("%s: unexpected kty %d\n", __func__, jwe->jws.jwk->kty);
56 
57 		return -1;
58 	}
59 
60 	/*
61 	 * Notice that the unencrypted EKEY coming in is smaller than the
62 	 * RSA-encrypted EKEY going out, which is going to be the RSA key size
63 	 *
64 	 * Create a b64 version of the JOSE header, needed as aad
65 	 */
66 	if (lws_jws_encode_b64_element(&jwe->jws.map_b64, LJWE_JOSE,
67 				       temp, temp_len,
68 				       jwe->jws.map.buf[LJWE_JOSE],
69 				       jwe->jws.map.len[LJWE_JOSE]))
70 		return -1;
71 
72 	if (lws_jws_alloc_element(&jwe->jws.map, LJWE_ATAG, temp + (ot - *temp_len),
73 				  temp_len, (unsigned int)hlen / 2, 0))
74 		return -1;
75 
76 	if (lws_jws_alloc_element(&jwe->jws.map, LJWE_IV, temp + (ot - *temp_len),
77 				  temp_len, LWS_JWE_AES_IV_BYTES, 0))
78 		return -1;
79 
80 	/*
81 	 * Without changing the unencrypted CEK in EKEY, reallocate enough
82 	 * space to write the RSA-encrypted version in-situ.
83 	 */
84 	if (lws_jws_dup_element(&jwe->jws.map, LJWE_EKEY, temp + (ot - *temp_len),
85 				temp_len, jwe->jws.map.buf[LJWE_EKEY],
86 				jwe->jws.map.len[LJWE_EKEY],
87 				jwe->jws.jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len))
88 		return -1;
89 
90 	/* Encrypt using the raw CEK (treated as MAC KEY | ENC KEY) */
91 
92 	n = lws_jwe_encrypt_cbc_hs(jwe, (uint8_t *)jwe->jws.map.buf[LJWE_EKEY],
93 				     (uint8_t *)jwe->jws.map_b64.buf[LJWE_JOSE],
94 				     (int)jwe->jws.map_b64.len[LJWE_JOSE]);
95 	if (n < 0) {
96 		lwsl_err("%s: lws_jwe_encrypt_cbc_hs failed\n", __func__);
97 		return -1;
98 	}
99 
100 	if (lws_genrsa_create(&rsactx, jwe->jws.jwk->e, jwe->jws.context,
101 			!strcmp(jwe->jose.alg->alg,   "RSA-OAEP") ?
102 					LGRSAM_PKCS1_OAEP_PSS : LGRSAM_PKCS1_1_5,
103 					LWS_GENHASH_TYPE_UNKNOWN)) {
104 		lwsl_notice("%s: lws_genrsa_create\n",
105 			    __func__);
106 		return -1;
107 	}
108 
109 	/* encrypt the CEK using RSA, mbedtls can't handle both in and out are
110 	 * the EKEY, so copy the unencrypted ekey out temporarily */
111 
112 	memcpy(ekey, jwe->jws.map.buf[LJWE_EKEY], (unsigned int)hlen);
113 
114 	n = lws_genrsa_public_encrypt(&rsactx, (uint8_t *)ekey, (unsigned int)hlen,
115 				      (uint8_t *)jwe->jws.map.buf[LJWE_EKEY]);
116 	lws_genrsa_destroy(&rsactx);
117 	lws_explicit_bzero(ekey, (unsigned int)hlen); /* cleanse the temp CEK copy */
118 	if (n < 0) {
119 		lwsl_err("%s: encrypt cek fail\n", __func__);
120 		return -1;
121 	}
122 	jwe->jws.map.len[LJWE_EKEY] = (unsigned int)n; /* update to encrypted EKEY size */
123 
124 	/*
125 	 * We end up with IV, ATAG, set, EKEY encrypted and CTXT is ciphertext,
126 	 * and b64u version of ATAG in map_b64.
127 	 */
128 
129 	return 0;
130 }
131 
132 int
lws_jwe_auth_and_decrypt_rsa_aes_cbc_hs(struct lws_jwe * jwe)133 lws_jwe_auth_and_decrypt_rsa_aes_cbc_hs(struct lws_jwe *jwe)
134 {
135 	int n;
136 	struct lws_genrsa_ctx rsactx;
137 	uint8_t enc_cek[512];
138 
139 	if (jwe->jws.jwk->kty != LWS_GENCRYPTO_KTY_RSA) {
140 		lwsl_err("%s: unexpected kty %d\n", __func__, jwe->jws.jwk->kty);
141 
142 		return -1;
143 	}
144 
145 	if (jwe->jws.map.len[LJWE_EKEY] < 40) {
146 		lwsl_err("%s: EKEY length too short %d\n", __func__,
147 				jwe->jws.map.len[LJWE_EKEY]);
148 
149 		return -1;
150 	}
151 
152 	/* Decrypt the JWE Encrypted Key to get the raw MAC || CEK */
153 
154 	if (lws_genrsa_create(&rsactx, jwe->jws.jwk->e, jwe->jws.context,
155 			!strcmp(jwe->jose.alg->alg,   "RSA-OAEP") ?
156 				LGRSAM_PKCS1_OAEP_PSS : LGRSAM_PKCS1_1_5,
157 				LWS_GENHASH_TYPE_UNKNOWN)) {
158 		lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
159 			    __func__);
160 		return -1;
161 	}
162 
163 	n = lws_genrsa_private_decrypt(&rsactx,
164 				       (uint8_t *)jwe->jws.map.buf[LJWE_EKEY],
165 				       jwe->jws.map.len[LJWE_EKEY], enc_cek,
166 				       sizeof(enc_cek));
167 	lws_genrsa_destroy(&rsactx);
168 	if (n < 0) {
169 		lwsl_err("%s: decrypt cek fail: \n", __func__);
170 		return -1;
171 	}
172 
173 	n = lws_jwe_auth_and_decrypt_cbc_hs(jwe, enc_cek,
174 			     (uint8_t *)jwe->jws.map_b64.buf[LJWE_JOSE],
175 			     (int)jwe->jws.map_b64.len[LJWE_JOSE]);
176 	if (n < 0) {
177 		lwsl_err("%s: lws_jwe_auth_and_decrypt_cbc_hs failed\n",
178 			 __func__);
179 		return -1;
180 	}
181 
182 #if defined(LWS_WITH_MBEDTLS) && defined(LWS_PLAT_OPTEE)
183 
184 	/* strip padding */
185 
186 	n = jwe->jws.map.buf[LJWE_CTXT][jwe->jws.map.len[LJWE_CTXT] - 1];
187 	if (n > 16) {
188 		lwsl_err("%s: n == %d, plen %d\n", __func__, n,
189 				(int)jwe->jws.map.len[LJWE_CTXT]);
190 		return -1;
191 	}
192 	jwe->jws.map.len[LJWE_CTXT] -= n;
193 #endif
194 
195 	return (int)jwe->jws.map.len[LJWE_CTXT];
196 }
197