1/*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2010 - 2021 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-cose.h"
27
28lws_cose_sig_alg_t *
29lws_cose_val_alg_create(struct lws_context *cx, lws_cose_key_t *ck,
30		        cose_param_t cose_alg, int op)
31{
32	lws_cose_sig_alg_t *alg = lws_zalloc(sizeof(*alg), __func__);
33	struct lws_gencrypto_keyelem *ke;
34	enum lws_genhmac_types ghm;
35	enum lws_genhash_types gh;
36	const char *crv;
37
38	if (!alg)
39		return NULL;
40
41	alg->cose_alg = cose_alg;
42	alg->cose_key = ck;
43
44	switch (cose_alg) {
45
46	/* ECDSA algs */
47
48	case LWSCOSE_WKAECDSA_ALG_ES256: /* ECDSA w/ SHA-256 */
49		crv = "P-256";
50		gh = LWS_GENHASH_TYPE_SHA256;
51		alg->keybits = 256;
52		goto ecdsa;
53	case LWSCOSE_WKAECDSA_ALG_ES384: /* ECDSA w/ SHA-384 */
54		crv = "P-384";
55		gh = LWS_GENHASH_TYPE_SHA384;
56		alg->keybits = 384;
57		goto ecdsa;
58	case LWSCOSE_WKAECDSA_ALG_ES512: /* ECDSA w/ SHA-512 */
59		crv = "P-521";
60		gh = LWS_GENHASH_TYPE_SHA512;
61		alg->keybits = 521;
62ecdsa:
63
64		/* the key is good for this? */
65
66		if (lws_cose_key_checks(ck, LWSCOSE_WKKTV_EC2, cose_alg,
67					op, crv))
68			goto bail_ecdsa;
69
70		if (lws_genhash_init(&alg->hash_ctx, gh))
71			goto bail_ecdsa;
72
73		if (lws_genecdsa_create(&alg->u.ecdsactx, cx, lws_ec_curves)) {
74			lwsl_notice("%s: lws_genrsa_public_decrypt_create\n",
75				    __func__);
76			goto bail_ecdsa1;
77		}
78
79		if (lws_genecdsa_set_key(&alg->u.ecdsactx, ck->e)) {
80			lwsl_notice("%s: ec key import fail\n", __func__);
81			goto bail_ecdsa2;
82		}
83
84		break;
85
86	/* HMAC algs */
87
88	case LWSCOSE_WKAHMAC_256_64:
89		ghm = LWS_GENHMAC_TYPE_SHA256;
90		alg->keybits = 64;
91		goto hmac;
92	case LWSCOSE_WKAHMAC_256_256:
93		ghm = LWS_GENHMAC_TYPE_SHA256;
94		alg->keybits = 256;
95		goto hmac;
96	case LWSCOSE_WKAHMAC_384_384:
97		ghm = LWS_GENHMAC_TYPE_SHA384;
98		alg->keybits = 384;
99		goto hmac;
100	case LWSCOSE_WKAHMAC_512_512:
101		ghm = LWS_GENHMAC_TYPE_SHA512;
102		alg->keybits = 512;
103
104hmac:
105		if (lws_cose_key_checks(ck, LWSCOSE_WKKTV_SYMMETRIC,
106					cose_alg, op, NULL))
107			goto bail_hmac;
108
109		ke = &ck->e[LWS_GENCRYPTO_OCT_KEYEL_K];
110		if (lws_genhmac_init(&alg->u.hmacctx, ghm, ke->buf, ke->len))
111			goto bail_hmac;
112
113		break;
114
115	/* RSASSA algs */
116
117	case LWSCOSE_WKARSA_ALG_RS256:
118		gh = LWS_GENHASH_TYPE_SHA256;
119		goto rsassa;
120
121	case LWSCOSE_WKARSA_ALG_RS384:
122		gh = LWS_GENHASH_TYPE_SHA384;
123		goto rsassa;
124
125	case LWSCOSE_WKARSA_ALG_RS512:
126		gh = LWS_GENHASH_TYPE_SHA512;
127
128rsassa:
129		if (lws_cose_key_checks(ck, LWSCOSE_WKKTV_RSA, cose_alg,
130					op, NULL))
131			goto bail_hmac;
132		alg->keybits = (int)ck->e[LWS_GENCRYPTO_RSA_KEYEL_N].len * 8;
133
134		if (lws_genhash_init(&alg->hash_ctx, gh))
135			goto bail_ecdsa;
136
137		if (lws_genrsa_create(&alg->u.rsactx, ck->e, cx,
138				      LGRSAM_PKCS1_1_5, gh)) {
139			lwsl_notice("%s: lws_genrsa_create fail\n", __func__);
140			goto bail_ecdsa1;
141		}
142		break;
143
144	default:
145		lwsl_warn("%s: unsupported alg %lld\n", __func__,
146				(long long)cose_alg);
147		goto bail_hmac;
148	}
149
150	return alg;
151
152bail_ecdsa2:
153	lws_genec_destroy(&alg->u.ecdsactx);
154bail_ecdsa1:
155	lws_genhash_destroy(&alg->hash_ctx, NULL);
156bail_ecdsa:
157	lws_free(alg);
158
159	lwsl_notice("%s: failed\n", __func__);
160
161	return NULL;
162
163bail_hmac:
164	lws_free(alg);
165
166	return NULL;
167}
168
169int
170lws_cose_val_alg_hash(lws_cose_sig_alg_t *alg, const uint8_t *in, size_t in_len)
171{
172#if defined(VERBOSE)
173	lwsl_hexdump_warn(in, in_len);
174#endif
175
176	switch (alg->cose_alg) {
177	case LWSCOSE_WKAHMAC_256_64:
178	case LWSCOSE_WKAHMAC_256_256:
179	case LWSCOSE_WKAHMAC_384_384:
180	case LWSCOSE_WKAHMAC_512_512:
181		return lws_genhmac_update(&alg->u.hmacctx, in, in_len);
182	}
183
184	return lws_genhash_update(&alg->hash_ctx, in, in_len);
185}
186
187void
188lws_cose_val_alg_destroy(struct lws_cose_validate_context *cps,
189			 lws_cose_sig_alg_t **_alg, const uint8_t *against,
190			 size_t against_len)
191{
192	uint8_t digest[LWS_GENHASH_LARGEST];
193	lws_cose_sig_alg_t *alg = *_alg;
194	lws_cose_validate_res_t *res;
195	size_t hs, shs;
196	int keybits;
197	uint8_t ht;
198
199	lws_dll2_remove(&alg->list);
200	ht = alg->hash_ctx.type;
201	keybits = alg->keybits;
202
203	res = lws_zalloc(sizeof(*res), __func__);
204	if (res) {
205
206		res->cose_key = alg->cose_key;
207		res->cose_alg = alg->cose_alg;
208		res->result = -999;
209
210		lws_dll2_add_tail(&res->list, &cps->results);
211	}
212
213	switch (alg->cose_alg) {
214	case LWSCOSE_WKAECDSA_ALG_ES256: /* ECDSA w/ SHA-256 */
215	case LWSCOSE_WKAECDSA_ALG_ES384: /* ECDSA w/ SHA-384 */
216	case LWSCOSE_WKAECDSA_ALG_ES512: /* ECDSA w/ SHA-512 */
217		hs = lws_genhash_size(alg->hash_ctx.type);
218		lws_genhash_destroy(&alg->hash_ctx, digest);
219
220		lwsl_notice("%d %d %d\n", (int)hs, (int)keybits, (int)against_len);
221
222		if (res && against)
223			res->result = lws_genecdsa_hash_sig_verify_jws(
224						&alg->u.ecdsactx, digest, ht,
225						keybits, against, against_len);
226		lws_genec_destroy(&alg->u.ecdsactx);
227		break;
228
229	case LWSCOSE_WKAHMAC_256_64:
230	case LWSCOSE_WKAHMAC_256_256:
231	case LWSCOSE_WKAHMAC_384_384:
232	case LWSCOSE_WKAHMAC_512_512:
233		shs = hs = lws_genhmac_size(alg->u.hmacctx.type);
234		if (alg->cose_alg == LWSCOSE_WKAHMAC_256_64)
235			shs = 8;
236
237		if (lws_genhmac_destroy(&alg->u.hmacctx, digest)) {
238			lwsl_err("%s: destroy failed\n", __func__);
239			break;
240		}
241
242		if (cps->mac_pos != shs) {
243			lwsl_warn("%s: mac wrong size\n", __func__);
244			/* we can't compare it, leave it at fail */
245			break;
246		}
247		if (res && against) {
248			res->result = lws_timingsafe_bcmp(digest, cps->mac,
249								(uint32_t)shs);
250			if (res->result)
251				lwsl_warn("%s: hash mismatch\n", __func__);
252		}
253		break;
254
255	case LWSCOSE_WKARSA_ALG_RS256:
256	case LWSCOSE_WKARSA_ALG_RS384:
257	case LWSCOSE_WKARSA_ALG_RS512:
258
259		if (!lws_genhash_destroy(&alg->hash_ctx, digest) &&
260		    !alg->failed &&
261		    lws_genrsa_hash_sig_verify(&alg->u.rsactx, digest,
262					 alg->hash_ctx.type,
263					 against, against_len) >= 0) {
264			if (res)
265				res->result = 0;
266		} else
267			lwsl_err("%s: lws_genrsa_hash_verify\n", __func__);
268
269		lws_genrsa_destroy(&alg->u.rsactx);
270		break;
271	}
272
273	lws_free_set_NULL(*_alg);
274}
275