1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
5d4afb5ceSopenharmony_ci *
6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to
8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the
9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is
11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions:
12d4afb5ceSopenharmony_ci *
13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in
14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software.
15d4afb5ceSopenharmony_ci *
16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22d4afb5ceSopenharmony_ci * IN THE SOFTWARE.
23d4afb5ceSopenharmony_ci */
24d4afb5ceSopenharmony_ci
25d4afb5ceSopenharmony_ci#include "private-lib-core.h"
26d4afb5ceSopenharmony_ci#include "private-lib-cose.h"
27d4afb5ceSopenharmony_ci
28d4afb5ceSopenharmony_cistruct lws_cose_sign_context *
29d4afb5ceSopenharmony_cilws_cose_sign_create(const lws_cose_sign_create_info_t *info)
30d4afb5ceSopenharmony_ci{
31d4afb5ceSopenharmony_ci	struct lws_cose_sign_context *csc;
32d4afb5ceSopenharmony_ci
33d4afb5ceSopenharmony_ci	/* you have to have prepared a cbor output context for us to use */
34d4afb5ceSopenharmony_ci	assert(info->lec);
35d4afb5ceSopenharmony_ci	/* you have to provide at least one key in a cose_keyset */
36d4afb5ceSopenharmony_ci	assert(info->keyset);
37d4afb5ceSopenharmony_ci	/* you have to provide an lws_context (for crypto random) */
38d4afb5ceSopenharmony_ci	assert(info->cx);
39d4afb5ceSopenharmony_ci
40d4afb5ceSopenharmony_ci	if (info->sigtype == SIGTYPE_MAC) {
41d4afb5ceSopenharmony_ci		lwsl_err("%s: only mac0 supported for signing\n", __func__);
42d4afb5ceSopenharmony_ci		return NULL;
43d4afb5ceSopenharmony_ci	}
44d4afb5ceSopenharmony_ci
45d4afb5ceSopenharmony_ci	csc = lws_zalloc(sizeof(*csc), __func__);
46d4afb5ceSopenharmony_ci	if (!csc)
47d4afb5ceSopenharmony_ci		return NULL;
48d4afb5ceSopenharmony_ci
49d4afb5ceSopenharmony_ci	csc->info = *info;
50d4afb5ceSopenharmony_ci
51d4afb5ceSopenharmony_ci	return csc;
52d4afb5ceSopenharmony_ci}
53d4afb5ceSopenharmony_ci
54d4afb5ceSopenharmony_ciint
55d4afb5ceSopenharmony_cilws_cose_sign_add(struct lws_cose_sign_context *csc, cose_param_t alg,
56d4afb5ceSopenharmony_ci		  const lws_cose_key_t *ck)
57d4afb5ceSopenharmony_ci{
58d4afb5ceSopenharmony_ci	lws_cose_sig_alg_t *si = lws_cose_sign_alg_create(csc->info.cx, ck, alg,
59d4afb5ceSopenharmony_ci							  LWSCOSE_WKKO_SIGN);
60d4afb5ceSopenharmony_ci
61d4afb5ceSopenharmony_ci	if (!si)
62d4afb5ceSopenharmony_ci		return 1;
63d4afb5ceSopenharmony_ci
64d4afb5ceSopenharmony_ci	lws_dll2_add_tail(&si->list, &csc->algs);
65d4afb5ceSopenharmony_ci
66d4afb5ceSopenharmony_ci	return 0;
67d4afb5ceSopenharmony_ci}
68d4afb5ceSopenharmony_ci
69d4afb5ceSopenharmony_cistatic signed char cose_tags[] = {
70d4afb5ceSopenharmony_ci	0,
71d4afb5ceSopenharmony_ci	LWSCOAP_CONTENTFORMAT_COSE_SIGN,
72d4afb5ceSopenharmony_ci	LWSCOAP_CONTENTFORMAT_COSE_SIGN1,
73d4afb5ceSopenharmony_ci	LWSCOAP_CONTENTFORMAT_COSE_SIGN,
74d4afb5ceSopenharmony_ci	LWSCOAP_CONTENTFORMAT_COSE_MAC,
75d4afb5ceSopenharmony_ci	LWSCOAP_CONTENTFORMAT_COSE_MAC0
76d4afb5ceSopenharmony_ci};
77d4afb5ceSopenharmony_ci
78d4afb5ceSopenharmony_cistatic void
79d4afb5ceSopenharmony_cilws_cose_sign_hashing(struct lws_cose_sign_context *csc,
80d4afb5ceSopenharmony_ci		      const uint8_t *in, size_t in_len)
81d4afb5ceSopenharmony_ci{
82d4afb5ceSopenharmony_ci	//lwsl_hexdump_warn(in, in_len);
83d4afb5ceSopenharmony_ci
84d4afb5ceSopenharmony_ci	assert(in_len);
85d4afb5ceSopenharmony_ci
86d4afb5ceSopenharmony_ci	lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
87d4afb5ceSopenharmony_ci				   lws_dll2_get_head(&csc->algs)) {
88d4afb5ceSopenharmony_ci		lws_cose_sig_alg_t *alg = lws_container_of(p,
89d4afb5ceSopenharmony_ci						lws_cose_sig_alg_t, list);
90d4afb5ceSopenharmony_ci
91d4afb5ceSopenharmony_ci		if (lws_cose_sign_alg_hash(alg, in, in_len))
92d4afb5ceSopenharmony_ci			alg->failed = 1;
93d4afb5ceSopenharmony_ci	} lws_end_foreach_dll_safe(p, tp);
94d4afb5ceSopenharmony_ci}
95d4afb5ceSopenharmony_ci
96d4afb5ceSopenharmony_ci/*
97d4afb5ceSopenharmony_ci * These chunks may be payload or application AAD being emitted into the
98d4afb5ceSopenharmony_ci * signed object somewhere else.  But we do not emit them ourselves here
99d4afb5ceSopenharmony_ci * (since other non-emitted things are also hashed by us) and so can always
100d4afb5ceSopenharmony_ci * deal with the whole in_len in one step.
101d4afb5ceSopenharmony_ci */
102d4afb5ceSopenharmony_ci
103d4afb5ceSopenharmony_cienum lws_lec_pctx_ret
104d4afb5ceSopenharmony_cilws_cose_sign_payload_chunk(struct lws_cose_sign_context *csc,
105d4afb5ceSopenharmony_ci			    const uint8_t *in, size_t in_len)
106d4afb5ceSopenharmony_ci{
107d4afb5ceSopenharmony_ci	uint8_t lbuf[MAX_BLOBBED_PARAMS], lb[9];
108d4afb5ceSopenharmony_ci	const struct lws_gencrypto_keyelem *ke;
109d4afb5ceSopenharmony_ci	enum lws_lec_pctx_ret ret;
110d4afb5ceSopenharmony_ci	lws_lec_pctx_t lec, lec1;
111d4afb5ceSopenharmony_ci	lws_cose_sig_alg_t *alg;
112d4afb5ceSopenharmony_ci	uint8_t c;
113d4afb5ceSopenharmony_ci	size_t s;
114d4afb5ceSopenharmony_ci
115d4afb5ceSopenharmony_ci	switch (csc->tli) {
116d4afb5ceSopenharmony_ci	case ST_UNKNOWN:
117d4afb5ceSopenharmony_ci		/*
118d4afb5ceSopenharmony_ci		 * We need to figure out what signing structure we need to use,
119d4afb5ceSopenharmony_ci		 * given the algorithms that are in it.  So let's have a look
120d4afb5ceSopenharmony_ci		 * and decide.
121d4afb5ceSopenharmony_ci		 */
122d4afb5ceSopenharmony_ci
123d4afb5ceSopenharmony_ci		if (!csc->algs.count) {
124d4afb5ceSopenharmony_ci			lwsl_err("%s: must add at least one signature\n", __func__);
125d4afb5ceSopenharmony_ci			return 1;
126d4afb5ceSopenharmony_ci		}
127d4afb5ceSopenharmony_ci
128d4afb5ceSopenharmony_ci		csc->type = SIGTYPE_MULTI;
129d4afb5ceSopenharmony_ci		alg = lws_container_of(csc->algs.head, lws_cose_sig_alg_t, list);
130d4afb5ceSopenharmony_ci
131d4afb5ceSopenharmony_ci		switch (alg->cose_alg) {
132d4afb5ceSopenharmony_ci		case LWSCOSE_WKAHMAC_256_64:
133d4afb5ceSopenharmony_ci		case LWSCOSE_WKAHMAC_256_256:
134d4afb5ceSopenharmony_ci		case LWSCOSE_WKAHMAC_384_384:
135d4afb5ceSopenharmony_ci		case LWSCOSE_WKAHMAC_512_512:
136d4afb5ceSopenharmony_ci//			if (csc->info.sigtype == SIGTYPE_MAC0)
137d4afb5ceSopenharmony_ci				csc->type = SIGTYPE_MAC0;
138d4afb5ceSopenharmony_ci//			else
139d4afb5ceSopenharmony_ci//				csc->type = SIGTYPE_MAC;
140d4afb5ceSopenharmony_ci			break;
141d4afb5ceSopenharmony_ci		}
142d4afb5ceSopenharmony_ci
143d4afb5ceSopenharmony_ci		if (csc->algs.count == 1) {
144d4afb5ceSopenharmony_ci			if (!csc->info.sigtype && csc->type == SIGTYPE_MAC) {
145d4afb5ceSopenharmony_ci			    if (csc->info.flags & LCSC_FL_ADD_CBOR_PREFER_MAC0)
146d4afb5ceSopenharmony_ci				csc->type = SIGTYPE_MAC0;
147d4afb5ceSopenharmony_ci			} else
148d4afb5ceSopenharmony_ci				if (!csc->info.sigtype ||
149d4afb5ceSopenharmony_ci				    csc->info.sigtype == SIGTYPE_SINGLE) /* ie, if no hint */
150d4afb5ceSopenharmony_ci					csc->type = SIGTYPE_SINGLE;
151d4afb5ceSopenharmony_ci		}
152d4afb5ceSopenharmony_ci
153d4afb5ceSopenharmony_ci		lwsl_notice("%s: decided on type %d\n", __func__, csc->type);
154d4afb5ceSopenharmony_ci
155d4afb5ceSopenharmony_ci		/*
156d4afb5ceSopenharmony_ci		 * Start emitting the appropriate tag if that's requested
157d4afb5ceSopenharmony_ci		 */
158d4afb5ceSopenharmony_ci
159d4afb5ceSopenharmony_ci		if (csc->info.flags & LCSC_FL_ADD_CBOR_TAG) {
160d4afb5ceSopenharmony_ci			ret = lws_lec_printf(csc->info.lec, "%t(",
161d4afb5ceSopenharmony_ci					       cose_tags[csc->type]);
162d4afb5ceSopenharmony_ci
163d4afb5ceSopenharmony_ci			if (ret != LWS_LECPCTX_RET_FINISHED)
164d4afb5ceSopenharmony_ci				return ret;
165d4afb5ceSopenharmony_ci		}
166d4afb5ceSopenharmony_ci
167d4afb5ceSopenharmony_ci		/* The */
168d4afb5ceSopenharmony_ci		c = 0;
169d4afb5ceSopenharmony_ci		switch (csc->type) {
170d4afb5ceSopenharmony_ci		case SIGTYPE_MAC0:
171d4afb5ceSopenharmony_ci		case SIGTYPE_MULTI:
172d4afb5ceSopenharmony_ci		case SIGTYPE_SINGLE:
173d4afb5ceSopenharmony_ci			c = 0x84;
174d4afb5ceSopenharmony_ci			break;
175d4afb5ceSopenharmony_ci		case SIGTYPE_MAC:
176d4afb5ceSopenharmony_ci			c = 0x85;
177d4afb5ceSopenharmony_ci			break;
178d4afb5ceSopenharmony_ci		default:
179d4afb5ceSopenharmony_ci			break;
180d4afb5ceSopenharmony_ci		}
181d4afb5ceSopenharmony_ci
182d4afb5ceSopenharmony_ci		/* The outer array */
183d4afb5ceSopenharmony_ci		csc->info.lec->scratch[csc->info.lec->scratch_len++] = c;
184d4afb5ceSopenharmony_ci
185d4afb5ceSopenharmony_ci		/*
186d4afb5ceSopenharmony_ci		 * Then, let's start hashing with the sigtype constant part
187d4afb5ceSopenharmony_ci		 */
188d4afb5ceSopenharmony_ci
189d4afb5ceSopenharmony_ci		lws_cose_sign_hashing(csc, sig_mctx[csc->type],
190d4afb5ceSopenharmony_ci					   sig_mctx_len[csc->type]);
191d4afb5ceSopenharmony_ci
192d4afb5ceSopenharmony_ci		csc->tli = ST_OUTER_PROTECTED;
193d4afb5ceSopenharmony_ci		csc->subsequent = 0;
194d4afb5ceSopenharmony_ci
195d4afb5ceSopenharmony_ci		/* fallthru */
196d4afb5ceSopenharmony_ci
197d4afb5ceSopenharmony_ci	case ST_OUTER_PROTECTED:
198d4afb5ceSopenharmony_ci
199d4afb5ceSopenharmony_ci		/*
200d4afb5ceSopenharmony_ci		 * We need to list and emit any outer protected data as a map
201d4afb5ceSopenharmony_ci		 * into its own buffer, then emit that into the output as a bstr
202d4afb5ceSopenharmony_ci		 */
203d4afb5ceSopenharmony_ci
204d4afb5ceSopenharmony_ci		switch (csc->type) {
205d4afb5ceSopenharmony_ci		case SIGTYPE_SINGLE:
206d4afb5ceSopenharmony_ci		case SIGTYPE_MAC0:
207d4afb5ceSopenharmony_ci			alg = lws_container_of(csc->algs.head,
208d4afb5ceSopenharmony_ci					       lws_cose_sig_alg_t, list);
209d4afb5ceSopenharmony_ci
210d4afb5ceSopenharmony_ci			lws_lec_init(&lec, lbuf, sizeof(lbuf));
211d4afb5ceSopenharmony_ci
212d4afb5ceSopenharmony_ci			/* we know it will fit... but coverity doesn't */
213d4afb5ceSopenharmony_ci			ret = lws_lec_printf(&lec, "{1:%lld}",
214d4afb5ceSopenharmony_ci					     (long long)alg->cose_alg);
215d4afb5ceSopenharmony_ci		       if (ret != LWS_LECPCTX_RET_FINISHED)
216d4afb5ceSopenharmony_ci			       return ret;
217d4afb5ceSopenharmony_ci
218d4afb5ceSopenharmony_ci			lws_lec_scratch(&lec);
219d4afb5ceSopenharmony_ci
220d4afb5ceSopenharmony_ci			if (!csc->subsequent) {
221d4afb5ceSopenharmony_ci				lws_lec_init(&lec1, lb, sizeof(lb));
222d4afb5ceSopenharmony_ci				lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0,
223d4afb5ceSopenharmony_ci						lec.used);
224d4afb5ceSopenharmony_ci				lws_cose_sign_hashing(csc, lec1.scratch,
225d4afb5ceSopenharmony_ci							   lec1.scratch_len);
226d4afb5ceSopenharmony_ci				lws_cose_sign_hashing(csc, lec.start, lec.used);
227d4afb5ceSopenharmony_ci				ret = lws_lec_printf(csc->info.lec, "%.*b",
228d4afb5ceSopenharmony_ci						     (int)lec.used, lec.start);
229d4afb5ceSopenharmony_ci
230d4afb5ceSopenharmony_ci				if (ret != LWS_LECPCTX_RET_FINISHED)
231d4afb5ceSopenharmony_ci					return ret;
232d4afb5ceSopenharmony_ci				csc->subsequent = 1;
233d4afb5ceSopenharmony_ci			}
234d4afb5ceSopenharmony_ci			break;
235d4afb5ceSopenharmony_ci		case SIGTYPE_MAC:
236d4afb5ceSopenharmony_ci		case SIGTYPE_MULTI:
237d4afb5ceSopenharmony_ci			lws_lec_init(&lec, lbuf, sizeof(lbuf));
238d4afb5ceSopenharmony_ci			lws_lec_int(&lec, LWS_CBOR_MAJTYP_BSTR, 0, 0);
239d4afb5ceSopenharmony_ci			lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_BSTR, 0, 0);
240d4afb5ceSopenharmony_ci			lws_lec_scratch(&lec);
241d4afb5ceSopenharmony_ci			lec.used = lws_ptr_diff_size_t(lec.buf, lec.start);
242d4afb5ceSopenharmony_ci			lws_cose_sign_hashing(csc, lec.start,
243d4afb5ceSopenharmony_ci						   lec.used);
244d4afb5ceSopenharmony_ci			break;
245d4afb5ceSopenharmony_ci		default:
246d4afb5ceSopenharmony_ci			lec.used = 0;
247d4afb5ceSopenharmony_ci			break;
248d4afb5ceSopenharmony_ci		}
249d4afb5ceSopenharmony_ci
250d4afb5ceSopenharmony_ci		csc->tli = ST_OUTER_UNPROTECTED;
251d4afb5ceSopenharmony_ci
252d4afb5ceSopenharmony_ci		/* fallthru */
253d4afb5ceSopenharmony_ci
254d4afb5ceSopenharmony_ci	case ST_OUTER_UNPROTECTED:
255d4afb5ceSopenharmony_ci
256d4afb5ceSopenharmony_ci		/*
257d4afb5ceSopenharmony_ci		 * We need to list and emit any outer unprotected data, as
258d4afb5ceSopenharmony_ci		 * an inline cbor map
259d4afb5ceSopenharmony_ci		 */
260d4afb5ceSopenharmony_ci
261d4afb5ceSopenharmony_ci		switch (csc->type) {
262d4afb5ceSopenharmony_ci		case SIGTYPE_SINGLE:
263d4afb5ceSopenharmony_ci		case SIGTYPE_MAC0:
264d4afb5ceSopenharmony_ci			alg = lws_container_of(csc->algs.head,
265d4afb5ceSopenharmony_ci					       lws_cose_sig_alg_t, list);
266d4afb5ceSopenharmony_ci			ke = &alg->cose_key->meta[COSEKEY_META_KID];
267d4afb5ceSopenharmony_ci			if (ke->len) {
268d4afb5ceSopenharmony_ci				ret = lws_lec_printf(csc->info.lec, "{%d:%.*b}",
269d4afb5ceSopenharmony_ci						     LWSCOSE_WKL_KID,
270d4afb5ceSopenharmony_ci						     (int)ke->len, ke->buf);
271d4afb5ceSopenharmony_ci
272d4afb5ceSopenharmony_ci				if (ret != LWS_LECPCTX_RET_FINISHED)
273d4afb5ceSopenharmony_ci					return ret;
274d4afb5ceSopenharmony_ci			}
275d4afb5ceSopenharmony_ci			/* hack for no extra data */
276d4afb5ceSopenharmony_ci
277d4afb5ceSopenharmony_ci			lws_lec_init(&lec1, lb, sizeof(lb));
278d4afb5ceSopenharmony_ci			lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0, 0);
279d4afb5ceSopenharmony_ci			lws_cose_sign_hashing(csc, lec1.scratch,
280d4afb5ceSopenharmony_ci						   lec1.scratch_len);
281d4afb5ceSopenharmony_ci			break;
282d4afb5ceSopenharmony_ci		case SIGTYPE_MAC:
283d4afb5ceSopenharmony_ci		case SIGTYPE_MULTI:
284d4afb5ceSopenharmony_ci
285d4afb5ceSopenharmony_ci			lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_BSTR, 0, 0);
286d4afb5ceSopenharmony_ci
287d4afb5ceSopenharmony_ci			/*
288d4afb5ceSopenharmony_ci			 * For cose-sign, we need to feed each sig alg its alg-
289d4afb5ceSopenharmony_ci			 * specific protected data into the hash before letting
290d4afb5ceSopenharmony_ci			 * all the hashes see the payload
291d4afb5ceSopenharmony_ci			 */
292d4afb5ceSopenharmony_ci
293d4afb5ceSopenharmony_ci			lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
294d4afb5ceSopenharmony_ci						   lws_dll2_get_head(&csc->algs)) {
295d4afb5ceSopenharmony_ci				alg = lws_container_of(p, lws_cose_sig_alg_t, list);
296d4afb5ceSopenharmony_ci
297d4afb5ceSopenharmony_ci				lws_lec_init(&lec, lbuf, sizeof(lbuf));
298d4afb5ceSopenharmony_ci
299d4afb5ceSopenharmony_ci				/* we know it will fit... but coverity doesn't... */
300d4afb5ceSopenharmony_ci				ret = lws_lec_printf(&lec, "{1:%lld}",
301d4afb5ceSopenharmony_ci						     (long long)alg->cose_alg);
302d4afb5ceSopenharmony_ci			       if (ret != LWS_LECPCTX_RET_FINISHED)
303d4afb5ceSopenharmony_ci				       return ret;
304d4afb5ceSopenharmony_ci
305d4afb5ceSopenharmony_ci				lws_lec_init(&lec1, lb, sizeof(lb));
306d4afb5ceSopenharmony_ci				lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0,
307d4afb5ceSopenharmony_ci						lec.used);
308d4afb5ceSopenharmony_ci
309d4afb5ceSopenharmony_ci				// lwsl_hexdump_warn(lec1.scratch, lec1.scratch_len);
310d4afb5ceSopenharmony_ci				// lwsl_hexdump_warn(lec.start, lec.used);
311d4afb5ceSopenharmony_ci				if (lws_cose_sign_alg_hash(alg, lec1.scratch,
312d4afb5ceSopenharmony_ci							   lec1.scratch_len))
313d4afb5ceSopenharmony_ci					alg->failed = 1;
314d4afb5ceSopenharmony_ci				if (lws_cose_sign_alg_hash(alg, lec.start,
315d4afb5ceSopenharmony_ci							   lec.used))
316d4afb5ceSopenharmony_ci					alg->failed = 1;
317d4afb5ceSopenharmony_ci
318d4afb5ceSopenharmony_ci			} lws_end_foreach_dll_safe(p, tp);
319d4afb5ceSopenharmony_ci
320d4afb5ceSopenharmony_ci			lws_lec_init(&lec1, lb, sizeof(lb));
321d4afb5ceSopenharmony_ci			lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0, 0);
322d4afb5ceSopenharmony_ci			lws_cose_sign_hashing(csc, lec1.scratch,
323d4afb5ceSopenharmony_ci						   lec1.scratch_len);
324d4afb5ceSopenharmony_ci
325d4afb5ceSopenharmony_ci			break;
326d4afb5ceSopenharmony_ci		default:
327d4afb5ceSopenharmony_ci			ret = lws_lec_printf(csc->info.lec, "{}");
328d4afb5ceSopenharmony_ci			if (ret != LWS_LECPCTX_RET_FINISHED)
329d4afb5ceSopenharmony_ci				return ret;
330d4afb5ceSopenharmony_ci			break;
331d4afb5ceSopenharmony_ci		}
332d4afb5ceSopenharmony_ci
333d4afb5ceSopenharmony_ci		csc->tli = ST_OUTER_PAYLOAD;
334d4afb5ceSopenharmony_ci		csc->subsequent = 0;
335d4afb5ceSopenharmony_ci
336d4afb5ceSopenharmony_ci		/* Prepare the payload BSTR */
337d4afb5ceSopenharmony_ci
338d4afb5ceSopenharmony_ci		lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_BSTR, 0,
339d4afb5ceSopenharmony_ci					   csc->info.inline_payload_len);
340d4afb5ceSopenharmony_ci
341d4afb5ceSopenharmony_ci		lws_lec_init(&lec1, lb, sizeof(lb));
342d4afb5ceSopenharmony_ci		lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0,
343d4afb5ceSopenharmony_ci			    csc->info.inline_payload_len);
344d4afb5ceSopenharmony_ci		lws_cose_sign_hashing(csc, lec1.scratch,
345d4afb5ceSopenharmony_ci					   lec1.scratch_len);
346d4afb5ceSopenharmony_ci
347d4afb5ceSopenharmony_ci		lws_lec_scratch(csc->info.lec);
348d4afb5ceSopenharmony_ci
349d4afb5ceSopenharmony_ci		csc->rem_pay = csc->info.inline_payload_len;
350d4afb5ceSopenharmony_ci
351d4afb5ceSopenharmony_ci		/* fallthru */
352d4afb5ceSopenharmony_ci
353d4afb5ceSopenharmony_ci	case ST_OUTER_PAYLOAD:
354d4afb5ceSopenharmony_ci
355d4afb5ceSopenharmony_ci		if (csc->along) {
356d4afb5ceSopenharmony_ci			in += csc->along;
357d4afb5ceSopenharmony_ci			in_len -= csc->along;
358d4afb5ceSopenharmony_ci		}
359d4afb5ceSopenharmony_ci
360d4afb5ceSopenharmony_ci		lws_lec_scratch(csc->info.lec);
361d4afb5ceSopenharmony_ci
362d4afb5ceSopenharmony_ci		if (csc->rem_pay) {
363d4afb5ceSopenharmony_ci
364d4afb5ceSopenharmony_ci			lws_cose_sign_hashing(csc, in, in_len);
365d4afb5ceSopenharmony_ci
366d4afb5ceSopenharmony_ci			/*
367d4afb5ceSopenharmony_ci			 * in / in_len is the payload chunk
368d4afb5ceSopenharmony_ci			 */
369d4afb5ceSopenharmony_ci
370d4afb5ceSopenharmony_ci			s = lws_ptr_diff_size_t(csc->info.lec->end,
371d4afb5ceSopenharmony_ci						csc->info.lec->buf);
372d4afb5ceSopenharmony_ci			if (s > (size_t)csc->rem_pay)
373d4afb5ceSopenharmony_ci				s = (size_t)csc->rem_pay;
374d4afb5ceSopenharmony_ci			if (s > in_len)
375d4afb5ceSopenharmony_ci				s = in_len;
376d4afb5ceSopenharmony_ci
377d4afb5ceSopenharmony_ci			memcpy(csc->info.lec->buf, in, s);
378d4afb5ceSopenharmony_ci			csc->info.lec->buf += s;
379d4afb5ceSopenharmony_ci			csc->info.lec->used = lws_ptr_diff_size_t(
380d4afb5ceSopenharmony_ci					csc->info.lec->buf,
381d4afb5ceSopenharmony_ci					csc->info.lec->start);
382d4afb5ceSopenharmony_ci			csc->rem_pay -= s;
383d4afb5ceSopenharmony_ci
384d4afb5ceSopenharmony_ci			csc->along = s;
385d4afb5ceSopenharmony_ci
386d4afb5ceSopenharmony_ci			return LWS_LECPCTX_RET_AGAIN;
387d4afb5ceSopenharmony_ci		}
388d4afb5ceSopenharmony_ci
389d4afb5ceSopenharmony_ci		/* finished with rem_pay */
390d4afb5ceSopenharmony_ci
391d4afb5ceSopenharmony_ci		if (csc->type == SIGTYPE_MULTI) {
392d4afb5ceSopenharmony_ci
393d4afb5ceSopenharmony_ci			csc->alg = lws_container_of(csc->algs.head,
394d4afb5ceSopenharmony_ci						lws_cose_sig_alg_t, list);
395d4afb5ceSopenharmony_ci			lws_lec_init(&lec1, lb, sizeof(lb));
396d4afb5ceSopenharmony_ci			lws_lec_int(&lec1, LWS_CBOR_MAJTYP_ARRAY, 0,
397d4afb5ceSopenharmony_ci				    csc->algs.count);
398d4afb5ceSopenharmony_ci			lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_ARRAY, 0,
399d4afb5ceSopenharmony_ci					csc->algs.count);
400d4afb5ceSopenharmony_ci			csc->tli = ST_INNER_PROTECTED;
401d4afb5ceSopenharmony_ci			goto inner_protected;
402d4afb5ceSopenharmony_ci		}
403d4afb5ceSopenharmony_ci		csc->tli = ST_OUTER_SIGN1_SIGNATURE;
404d4afb5ceSopenharmony_ci		csc->along = 0;
405d4afb5ceSopenharmony_ci
406d4afb5ceSopenharmony_ci		/* fallthru */
407d4afb5ceSopenharmony_ci
408d4afb5ceSopenharmony_ci	case ST_OUTER_SIGN1_SIGNATURE:
409d4afb5ceSopenharmony_ci
410d4afb5ceSopenharmony_ci		alg = lws_container_of(lws_dll2_get_head(&csc->algs),
411d4afb5ceSopenharmony_ci				       lws_cose_sig_alg_t, list);
412d4afb5ceSopenharmony_ci
413d4afb5ceSopenharmony_ci		if (!alg->completed)
414d4afb5ceSopenharmony_ci			lws_cose_sign_alg_complete(alg);
415d4afb5ceSopenharmony_ci		if (alg->failed)
416d4afb5ceSopenharmony_ci			return LWS_LECPCTX_RET_FAIL;
417d4afb5ceSopenharmony_ci
418d4afb5ceSopenharmony_ci		ret = lws_lec_printf(csc->info.lec, "%.*b",
419d4afb5ceSopenharmony_ci				     (int)alg->rhash_len, alg->rhash);
420d4afb5ceSopenharmony_ci		if (ret != LWS_LECPCTX_RET_FINISHED)
421d4afb5ceSopenharmony_ci				return ret;
422d4afb5ceSopenharmony_ci
423d4afb5ceSopenharmony_ci		if (csc->type == SIGTYPE_MAC) {
424d4afb5ceSopenharmony_ci			csc->alg = lws_container_of(csc->algs.head,
425d4afb5ceSopenharmony_ci						lws_cose_sig_alg_t, list);
426d4afb5ceSopenharmony_ci			lws_lec_init(&lec1, lb, sizeof(lb));
427d4afb5ceSopenharmony_ci			lws_lec_int(&lec1, LWS_CBOR_MAJTYP_ARRAY, 0,
428d4afb5ceSopenharmony_ci				    csc->algs.count);
429d4afb5ceSopenharmony_ci			lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_ARRAY, 0,
430d4afb5ceSopenharmony_ci					csc->algs.count);
431d4afb5ceSopenharmony_ci			csc->tli = ST_INNER_PROTECTED;
432d4afb5ceSopenharmony_ci			goto inner_protected;
433d4afb5ceSopenharmony_ci		}
434d4afb5ceSopenharmony_ci
435d4afb5ceSopenharmony_ci		break;
436d4afb5ceSopenharmony_ci
437d4afb5ceSopenharmony_ci	case ST_INNER_PROTECTED:
438d4afb5ceSopenharmony_ciinner_protected:
439d4afb5ceSopenharmony_ci
440d4afb5ceSopenharmony_ci		/*
441d4afb5ceSopenharmony_ci		 * We need to list and emit any outer protected data as a map
442d4afb5ceSopenharmony_ci		 * into its own buffer, then emit that into the output as a bstr
443d4afb5ceSopenharmony_ci		 */
444d4afb5ceSopenharmony_ci
445d4afb5ceSopenharmony_ci		switch (csc->type) {
446d4afb5ceSopenharmony_ci		case SIGTYPE_MAC:
447d4afb5ceSopenharmony_ci		case SIGTYPE_MULTI:
448d4afb5ceSopenharmony_ci			lws_lec_init(&lec1, lb, sizeof(lb));
449d4afb5ceSopenharmony_ci			lws_lec_int(&lec1, LWS_CBOR_MAJTYP_ARRAY, 0, 3);
450d4afb5ceSopenharmony_ci
451d4afb5ceSopenharmony_ci			lws_lec_int(csc->info.lec, LWS_CBOR_MAJTYP_ARRAY, 0, 3);
452d4afb5ceSopenharmony_ci
453d4afb5ceSopenharmony_ci			lws_lec_init(&lec, lbuf, sizeof(lbuf));
454d4afb5ceSopenharmony_ci
455d4afb5ceSopenharmony_ci			/* we know it will fit */
456d4afb5ceSopenharmony_ci			lws_lec_printf(&lec, "{1:%lld}",
457d4afb5ceSopenharmony_ci					     (long long)csc->alg->cose_alg);
458d4afb5ceSopenharmony_ci
459d4afb5ceSopenharmony_ci			lws_lec_init(&lec1, lb, sizeof(lb));
460d4afb5ceSopenharmony_ci			lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0,
461d4afb5ceSopenharmony_ci					lec.used);
462d4afb5ceSopenharmony_ci			if (lws_lec_printf(csc->info.lec, "{1:%lld}",
463d4afb5ceSopenharmony_ci					     (long long)csc->alg->cose_alg) != LWS_LECPCTX_RET_FINISHED)
464d4afb5ceSopenharmony_ci				/* coverity */
465d4afb5ceSopenharmony_ci				return 0;
466d4afb5ceSopenharmony_ci			break;
467d4afb5ceSopenharmony_ci		default:
468d4afb5ceSopenharmony_ci			lec.used = 0;
469d4afb5ceSopenharmony_ci			break;
470d4afb5ceSopenharmony_ci		}
471d4afb5ceSopenharmony_ci
472d4afb5ceSopenharmony_ci
473d4afb5ceSopenharmony_ci		csc->tli = ST_INNER_UNPROTECTED;
474d4afb5ceSopenharmony_ci
475d4afb5ceSopenharmony_ci		/* fallthru */
476d4afb5ceSopenharmony_ci
477d4afb5ceSopenharmony_ci	case ST_INNER_UNPROTECTED:
478d4afb5ceSopenharmony_ci
479d4afb5ceSopenharmony_ci		switch (csc->type) {
480d4afb5ceSopenharmony_ci		case SIGTYPE_MULTI:
481d4afb5ceSopenharmony_ci			alg = lws_container_of(csc->algs.head,
482d4afb5ceSopenharmony_ci					       lws_cose_sig_alg_t, list);
483d4afb5ceSopenharmony_ci			ke = &alg->cose_key->meta[COSEKEY_META_KID];
484d4afb5ceSopenharmony_ci			if (ke->len) {
485d4afb5ceSopenharmony_ci				ret = lws_lec_printf(csc->info.lec, "{%d:%.*b}",
486d4afb5ceSopenharmony_ci						     LWSCOSE_WKL_KID,
487d4afb5ceSopenharmony_ci						     (int)ke->len, ke->buf);
488d4afb5ceSopenharmony_ci
489d4afb5ceSopenharmony_ci				if (ret != LWS_LECPCTX_RET_FINISHED)
490d4afb5ceSopenharmony_ci					return ret;
491d4afb5ceSopenharmony_ci			}
492d4afb5ceSopenharmony_ci			break;
493d4afb5ceSopenharmony_ci		default:
494d4afb5ceSopenharmony_ci			ret = lws_lec_printf(csc->info.lec, "{}");
495d4afb5ceSopenharmony_ci			if (ret != LWS_LECPCTX_RET_FINISHED)
496d4afb5ceSopenharmony_ci				return ret;
497d4afb5ceSopenharmony_ci			break;
498d4afb5ceSopenharmony_ci		}
499d4afb5ceSopenharmony_ci
500d4afb5ceSopenharmony_ci		lws_cose_sign_alg_complete(csc->alg);
501d4afb5ceSopenharmony_ci		if (csc->alg->failed)
502d4afb5ceSopenharmony_ci			return LWS_LECPCTX_RET_FAIL;
503d4afb5ceSopenharmony_ci		csc->tli = ST_INNER_SIGNATURE;
504d4afb5ceSopenharmony_ci
505d4afb5ceSopenharmony_ci		/* fallthru */
506d4afb5ceSopenharmony_ci
507d4afb5ceSopenharmony_ci	case ST_INNER_SIGNATURE:
508d4afb5ceSopenharmony_ci
509d4afb5ceSopenharmony_ci		ret = lws_lec_printf(csc->info.lec, "%.*b",
510d4afb5ceSopenharmony_ci				     (int)csc->alg->rhash_len, csc->alg->rhash);
511d4afb5ceSopenharmony_ci		if (ret != LWS_LECPCTX_RET_FINISHED)
512d4afb5ceSopenharmony_ci			return ret;
513d4afb5ceSopenharmony_ci
514d4afb5ceSopenharmony_ci		if (csc->alg->list.next) {
515d4afb5ceSopenharmony_ci			csc->alg = (lws_cose_sig_alg_t *)csc->alg->list.next;
516d4afb5ceSopenharmony_ci			csc->tli = ST_INNER_PROTECTED;
517d4afb5ceSopenharmony_ci		}
518d4afb5ceSopenharmony_ci		break;
519d4afb5ceSopenharmony_ci
520d4afb5ceSopenharmony_ci	}
521d4afb5ceSopenharmony_ci
522d4afb5ceSopenharmony_ci	return 0;
523d4afb5ceSopenharmony_ci}
524d4afb5ceSopenharmony_ci
525d4afb5ceSopenharmony_civoid
526d4afb5ceSopenharmony_cilws_cose_sign_destroy(struct lws_cose_sign_context **_csc)
527d4afb5ceSopenharmony_ci{
528d4afb5ceSopenharmony_ci	struct lws_cose_sign_context *csc = *_csc;
529d4afb5ceSopenharmony_ci
530d4afb5ceSopenharmony_ci	if (!csc)
531d4afb5ceSopenharmony_ci		return;
532d4afb5ceSopenharmony_ci
533d4afb5ceSopenharmony_ci	lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
534d4afb5ceSopenharmony_ci				   lws_dll2_get_head(&csc->algs)) {
535d4afb5ceSopenharmony_ci		lws_cose_sig_alg_t *alg = lws_container_of(p,
536d4afb5ceSopenharmony_ci						lws_cose_sig_alg_t, list);
537d4afb5ceSopenharmony_ci
538d4afb5ceSopenharmony_ci		lws_dll2_remove(p);
539d4afb5ceSopenharmony_ci		lws_cose_sign_alg_destroy(&alg);
540d4afb5ceSopenharmony_ci	} lws_end_foreach_dll_safe(p, tp);
541d4afb5ceSopenharmony_ci
542d4afb5ceSopenharmony_ci	lws_free_set_NULL(*_csc);
543d4afb5ceSopenharmony_ci}
544