1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2019 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 "libwebsockets.h"
26d4afb5ceSopenharmony_ci#include "lws-ssh.h"
27d4afb5ceSopenharmony_ci
28d4afb5ceSopenharmony_ci#include <string.h>
29d4afb5ceSopenharmony_ci#include <stdlib.h>
30d4afb5ceSopenharmony_ci
31d4afb5ceSopenharmony_civoid *sshd_zalloc(size_t s)
32d4afb5ceSopenharmony_ci{
33d4afb5ceSopenharmony_ci	void *p = malloc(s);
34d4afb5ceSopenharmony_ci
35d4afb5ceSopenharmony_ci	if (p)
36d4afb5ceSopenharmony_ci		memset(p, 0, s);
37d4afb5ceSopenharmony_ci
38d4afb5ceSopenharmony_ci	return p;
39d4afb5ceSopenharmony_ci}
40d4afb5ceSopenharmony_ci
41d4afb5ceSopenharmony_ciuint32_t
42d4afb5ceSopenharmony_cilws_g32(uint8_t **p)
43d4afb5ceSopenharmony_ci{
44d4afb5ceSopenharmony_ci	uint32_t v = 0;
45d4afb5ceSopenharmony_ci
46d4afb5ceSopenharmony_ci	v = (v << 8) | *((*p)++);
47d4afb5ceSopenharmony_ci	v = (v << 8) | *((*p)++);
48d4afb5ceSopenharmony_ci	v = (v << 8) | *((*p)++);
49d4afb5ceSopenharmony_ci	v = (v << 8) | *((*p)++);
50d4afb5ceSopenharmony_ci
51d4afb5ceSopenharmony_ci	return v;
52d4afb5ceSopenharmony_ci}
53d4afb5ceSopenharmony_ci
54d4afb5ceSopenharmony_ciuint32_t
55d4afb5ceSopenharmony_cilws_p32(uint8_t *p, uint32_t v)
56d4afb5ceSopenharmony_ci{
57d4afb5ceSopenharmony_ci	*p++ = (uint8_t)(v >> 24);
58d4afb5ceSopenharmony_ci	*p++ = (uint8_t)(v >> 16);
59d4afb5ceSopenharmony_ci	*p++ = (uint8_t)(v >> 8);
60d4afb5ceSopenharmony_ci	*p++ = (uint8_t)v;
61d4afb5ceSopenharmony_ci
62d4afb5ceSopenharmony_ci	return v;
63d4afb5ceSopenharmony_ci}
64d4afb5ceSopenharmony_ci
65d4afb5ceSopenharmony_ciint
66d4afb5ceSopenharmony_cilws_cstr(uint8_t **p, const char *s, uint32_t max)
67d4afb5ceSopenharmony_ci{
68d4afb5ceSopenharmony_ci	uint32_t n = (uint32_t)strlen(s);
69d4afb5ceSopenharmony_ci
70d4afb5ceSopenharmony_ci	if (n > max)
71d4afb5ceSopenharmony_ci		return 1;
72d4afb5ceSopenharmony_ci
73d4afb5ceSopenharmony_ci	lws_p32(*p, n);
74d4afb5ceSopenharmony_ci	*p += 4;
75d4afb5ceSopenharmony_ci	strcpy((char *)(*p), s);
76d4afb5ceSopenharmony_ci	*p += n;
77d4afb5ceSopenharmony_ci
78d4afb5ceSopenharmony_ci	return 0;
79d4afb5ceSopenharmony_ci}
80d4afb5ceSopenharmony_ci
81d4afb5ceSopenharmony_ciint
82d4afb5ceSopenharmony_cilws_buf(uint8_t **p, void *s, uint32_t len)
83d4afb5ceSopenharmony_ci{
84d4afb5ceSopenharmony_ci	lws_p32(*p, len);
85d4afb5ceSopenharmony_ci	*p += 4;
86d4afb5ceSopenharmony_ci	memcpy((char *)(*p), s, len);
87d4afb5ceSopenharmony_ci	*p += len;
88d4afb5ceSopenharmony_ci
89d4afb5ceSopenharmony_ci	return 0;
90d4afb5ceSopenharmony_ci}
91d4afb5ceSopenharmony_ci
92d4afb5ceSopenharmony_civoid
93d4afb5ceSopenharmony_ciwrite_task(struct per_session_data__sshd *pss, struct lws_ssh_channel *ch,
94d4afb5ceSopenharmony_ci	   int task)
95d4afb5ceSopenharmony_ci{
96d4afb5ceSopenharmony_ci	pss->write_task[pss->wt_head] = (uint8_t)task;
97d4afb5ceSopenharmony_ci	pss->write_channel[pss->wt_head] = ch;
98d4afb5ceSopenharmony_ci	pss->wt_head = (pss->wt_head + 1) & 7;
99d4afb5ceSopenharmony_ci	lws_callback_on_writable(pss->wsi);
100d4afb5ceSopenharmony_ci}
101d4afb5ceSopenharmony_ci
102d4afb5ceSopenharmony_civoid
103d4afb5ceSopenharmony_ciwrite_task_insert(struct per_session_data__sshd *pss, struct lws_ssh_channel *ch,
104d4afb5ceSopenharmony_ci	   int task)
105d4afb5ceSopenharmony_ci{
106d4afb5ceSopenharmony_ci	pss->wt_tail = (pss->wt_tail - 1) & 7;
107d4afb5ceSopenharmony_ci	pss->write_task[pss->wt_tail] = (uint8_t)task;
108d4afb5ceSopenharmony_ci	pss->write_channel[pss->wt_tail] = ch;
109d4afb5ceSopenharmony_ci	lws_callback_on_writable(pss->wsi);
110d4afb5ceSopenharmony_ci}
111d4afb5ceSopenharmony_ci
112d4afb5ceSopenharmony_ci
113d4afb5ceSopenharmony_civoid
114d4afb5ceSopenharmony_cilws_pad_set_length(struct per_session_data__sshd *pss, void *start, uint8_t **p,
115d4afb5ceSopenharmony_ci		   struct lws_ssh_keys *keys)
116d4afb5ceSopenharmony_ci{
117d4afb5ceSopenharmony_ci	uint32_t len = (uint32_t)lws_ptr_diff(*p, start);
118d4afb5ceSopenharmony_ci	uint8_t padc = 4, *bs = start;
119d4afb5ceSopenharmony_ci
120d4afb5ceSopenharmony_ci	if (keys->full_length)
121d4afb5ceSopenharmony_ci		len -= 4;
122d4afb5ceSopenharmony_ci
123d4afb5ceSopenharmony_ci	if ((len + padc) & (uint32_t)(keys->padding_alignment - 1))
124d4afb5ceSopenharmony_ci		padc = (uint8_t)((uint8_t)padc + (uint8_t)(keys->padding_alignment -
125d4afb5ceSopenharmony_ci			((len + padc) & (uint32_t)(keys->padding_alignment - 1))));
126d4afb5ceSopenharmony_ci
127d4afb5ceSopenharmony_ci	bs[4] = padc;
128d4afb5ceSopenharmony_ci	len += padc;
129d4afb5ceSopenharmony_ci
130d4afb5ceSopenharmony_ci	if (!keys->valid) /* no crypto = pad with 00 */
131d4afb5ceSopenharmony_ci		while (padc--)
132d4afb5ceSopenharmony_ci			*((*p)++) = 0;
133d4afb5ceSopenharmony_ci	else { /* crypto active = pad with random */
134d4afb5ceSopenharmony_ci		lws_get_random(pss->vhd->context, *p, padc);
135d4afb5ceSopenharmony_ci		(*p) += padc;
136d4afb5ceSopenharmony_ci	}
137d4afb5ceSopenharmony_ci	if (keys->full_length)
138d4afb5ceSopenharmony_ci		len += 4;
139d4afb5ceSopenharmony_ci
140d4afb5ceSopenharmony_ci	lws_p32(start, len - 4);
141d4afb5ceSopenharmony_ci}
142d4afb5ceSopenharmony_ci
143d4afb5ceSopenharmony_cistatic uint32_t
144d4afb5ceSopenharmony_cioffer(struct per_session_data__sshd *pss, uint8_t *p, uint32_t len, int first,
145d4afb5ceSopenharmony_ci      int *payload_len)
146d4afb5ceSopenharmony_ci{
147d4afb5ceSopenharmony_ci	uint8_t *op = p, *lp, *end = p + len - 1;
148d4afb5ceSopenharmony_ci	int n, padc = 4, keylen;
149d4afb5ceSopenharmony_ci	char keyt[32];
150d4afb5ceSopenharmony_ci	uint8_t keybuf[256];
151d4afb5ceSopenharmony_ci
152d4afb5ceSopenharmony_ci	keylen = (int)get_gen_server_key_25519(pss, keybuf, (int)sizeof(keybuf));
153d4afb5ceSopenharmony_ci	if (!keylen) {
154d4afb5ceSopenharmony_ci		lwsl_notice("get_gen_server_key failed\n");
155d4afb5ceSopenharmony_ci		return 1;
156d4afb5ceSopenharmony_ci	}
157d4afb5ceSopenharmony_ci	lwsl_info("keylen %d\n", keylen);
158d4afb5ceSopenharmony_ci	n = ed25519_key_parse(keybuf, (unsigned int)keylen,
159d4afb5ceSopenharmony_ci			      keyt, sizeof(keyt), NULL, NULL);
160d4afb5ceSopenharmony_ci	if (n) {
161d4afb5ceSopenharmony_ci		lwsl_notice("unable to parse server key: %d\n", n);
162d4afb5ceSopenharmony_ci		return 1;
163d4afb5ceSopenharmony_ci	}
164d4afb5ceSopenharmony_ci
165d4afb5ceSopenharmony_ci	/*
166d4afb5ceSopenharmony_ci	 *     byte         SSH_MSG_KEXINIT
167d4afb5ceSopenharmony_ci	 *     byte[16]     cookie (random bytes)
168d4afb5ceSopenharmony_ci	 *     name-list    kex_algorithms
169d4afb5ceSopenharmony_ci	 *     name-list    server_host_key_algorithms
170d4afb5ceSopenharmony_ci	 *     name-list    encryption_algorithms_client_to_server
171d4afb5ceSopenharmony_ci	 *     name-list    encryption_algorithms_server_to_client
172d4afb5ceSopenharmony_ci	 *     name-list    mac_algorithms_client_to_server
173d4afb5ceSopenharmony_ci	 *     name-list    mac_algorithms_server_to_client
174d4afb5ceSopenharmony_ci	 *     name-list    compression_algorithms_client_to_server
175d4afb5ceSopenharmony_ci	 *     name-list    compression_algorithms_server_to_client
176d4afb5ceSopenharmony_ci	 *     name-list    langua->es_client_to_server
177d4afb5ceSopenharmony_ci	 *     name-list    langua->es_server_to_client
178d4afb5ceSopenharmony_ci	 *     boolean      first_kex_packet_follows
179d4afb5ceSopenharmony_ci	 *     uint32       0 (reserved for future extension)
180d4afb5ceSopenharmony_ci      	 */
181d4afb5ceSopenharmony_ci
182d4afb5ceSopenharmony_ci	p += 5; /* msg len + padding */
183d4afb5ceSopenharmony_ci
184d4afb5ceSopenharmony_ci	*p++ = SSH_MSG_KEXINIT;
185d4afb5ceSopenharmony_ci	lws_get_random(pss->vhd->context, p, 16);
186d4afb5ceSopenharmony_ci	p += 16;
187d4afb5ceSopenharmony_ci
188d4afb5ceSopenharmony_ci	/* KEX algorithms */
189d4afb5ceSopenharmony_ci
190d4afb5ceSopenharmony_ci	lp = p;
191d4afb5ceSopenharmony_ci	p += 4;
192d4afb5ceSopenharmony_ci	n = lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "curve25519-sha256@libssh.org");
193d4afb5ceSopenharmony_ci	p += lws_p32(lp, (uint32_t)n);
194d4afb5ceSopenharmony_ci
195d4afb5ceSopenharmony_ci	/* Server Host Key Algorithms */
196d4afb5ceSopenharmony_ci
197d4afb5ceSopenharmony_ci	lp = p;
198d4afb5ceSopenharmony_ci	p += 4;
199d4afb5ceSopenharmony_ci	n = lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "%s", keyt);
200d4afb5ceSopenharmony_ci	p += lws_p32(lp, (uint32_t)n);
201d4afb5ceSopenharmony_ci
202d4afb5ceSopenharmony_ci	/* Encryption Algorithms: C -> S */
203d4afb5ceSopenharmony_ci
204d4afb5ceSopenharmony_ci	lp = p;
205d4afb5ceSopenharmony_ci	p += 4;
206d4afb5ceSopenharmony_ci//	n = lws_snprintf((char *)p, end - p, "aes256-gcm@openssh.com");
207d4afb5ceSopenharmony_ci	n = lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "chacha20-poly1305@openssh.com");
208d4afb5ceSopenharmony_ci	p += lws_p32(lp, (uint32_t)n);
209d4afb5ceSopenharmony_ci
210d4afb5ceSopenharmony_ci	/* Encryption Algorithms: S -> C */
211d4afb5ceSopenharmony_ci
212d4afb5ceSopenharmony_ci	lp = p;
213d4afb5ceSopenharmony_ci	p += 4;
214d4afb5ceSopenharmony_ci//	n = lws_snprintf((char *)p, end - p, "aes256-gcm@openssh.com");
215d4afb5ceSopenharmony_ci	n = lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "chacha20-poly1305@openssh.com");
216d4afb5ceSopenharmony_ci	p += lws_p32(lp, (uint32_t)n);
217d4afb5ceSopenharmony_ci
218d4afb5ceSopenharmony_ci	/* MAC Algorithms: C -> S */
219d4afb5ceSopenharmony_ci
220d4afb5ceSopenharmony_ci	lp = p;
221d4afb5ceSopenharmony_ci	p += 4;
222d4afb5ceSopenharmony_ci	/* bogus: chacha20 does not use MACs, but 'none' is not offered */
223d4afb5ceSopenharmony_ci	n = lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "hmac-sha2-256");
224d4afb5ceSopenharmony_ci	p += lws_p32(lp, (uint32_t)n);
225d4afb5ceSopenharmony_ci
226d4afb5ceSopenharmony_ci	/* MAC Algorithms: S -> C */
227d4afb5ceSopenharmony_ci
228d4afb5ceSopenharmony_ci	lp = p;
229d4afb5ceSopenharmony_ci	p += 4;
230d4afb5ceSopenharmony_ci	/* bogus: chacha20 does not use MACs, but 'none' is not offered */
231d4afb5ceSopenharmony_ci	n = lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "hmac-sha2-256");
232d4afb5ceSopenharmony_ci	p += lws_p32(lp, (uint32_t)n);
233d4afb5ceSopenharmony_ci
234d4afb5ceSopenharmony_ci	/* Compression Algorithms: C -> S */
235d4afb5ceSopenharmony_ci
236d4afb5ceSopenharmony_ci	lp = p;
237d4afb5ceSopenharmony_ci	p += 4;
238d4afb5ceSopenharmony_ci	n = lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "none");
239d4afb5ceSopenharmony_ci	p += lws_p32(lp, (uint32_t)n);
240d4afb5ceSopenharmony_ci
241d4afb5ceSopenharmony_ci	/* Compression Algorithms: S -> C */
242d4afb5ceSopenharmony_ci
243d4afb5ceSopenharmony_ci	lp = p;
244d4afb5ceSopenharmony_ci	p += 4;
245d4afb5ceSopenharmony_ci	n = lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "none");
246d4afb5ceSopenharmony_ci	p += lws_p32(lp, (uint32_t)n);
247d4afb5ceSopenharmony_ci
248d4afb5ceSopenharmony_ci	if (p - op < 13 + padc + 8)
249d4afb5ceSopenharmony_ci		return 0;
250d4afb5ceSopenharmony_ci
251d4afb5ceSopenharmony_ci	/* Languages: C -> S */
252d4afb5ceSopenharmony_ci
253d4afb5ceSopenharmony_ci	*p++ = 0;
254d4afb5ceSopenharmony_ci	*p++ = 0;
255d4afb5ceSopenharmony_ci	*p++ = 0;
256d4afb5ceSopenharmony_ci	*p++ = 0;
257d4afb5ceSopenharmony_ci
258d4afb5ceSopenharmony_ci	/* Languages: S -> C */
259d4afb5ceSopenharmony_ci
260d4afb5ceSopenharmony_ci	*p++ = 0;
261d4afb5ceSopenharmony_ci	*p++ = 0;
262d4afb5ceSopenharmony_ci	*p++ = 0;
263d4afb5ceSopenharmony_ci	*p++ = 0;
264d4afb5ceSopenharmony_ci
265d4afb5ceSopenharmony_ci	/* First KEX packet coming */
266d4afb5ceSopenharmony_ci
267d4afb5ceSopenharmony_ci	*p++ = !!first;
268d4afb5ceSopenharmony_ci
269d4afb5ceSopenharmony_ci	/* Reserved */
270d4afb5ceSopenharmony_ci
271d4afb5ceSopenharmony_ci	*p++ = 0;
272d4afb5ceSopenharmony_ci	*p++ = 0;
273d4afb5ceSopenharmony_ci	*p++ = 0;
274d4afb5ceSopenharmony_ci	*p++ = 0;
275d4afb5ceSopenharmony_ci
276d4afb5ceSopenharmony_ci	len = (uint32_t)lws_ptr_diff(p, op);
277d4afb5ceSopenharmony_ci	if (payload_len)
278d4afb5ceSopenharmony_ci		/* starts at buf + 5 and excludes padding */
279d4afb5ceSopenharmony_ci		*payload_len = (int)(len - 5);
280d4afb5ceSopenharmony_ci
281d4afb5ceSopenharmony_ci	/* we must give at least 4 bytes of 00 padding */
282d4afb5ceSopenharmony_ci
283d4afb5ceSopenharmony_ci	if (((int)len + padc) & 7)
284d4afb5ceSopenharmony_ci		padc += 8 - (((int)len + padc) & 7);
285d4afb5ceSopenharmony_ci
286d4afb5ceSopenharmony_ci	op[4] = (uint8_t)padc;
287d4afb5ceSopenharmony_ci	len += (uint32_t)padc;
288d4afb5ceSopenharmony_ci
289d4afb5ceSopenharmony_ci	while (padc--)
290d4afb5ceSopenharmony_ci		*p++ = 0;
291d4afb5ceSopenharmony_ci
292d4afb5ceSopenharmony_ci	/* recorded length does not include the uint32_t len itself */
293d4afb5ceSopenharmony_ci	lws_p32(op, len - 4);
294d4afb5ceSopenharmony_ci
295d4afb5ceSopenharmony_ci	return len;
296d4afb5ceSopenharmony_ci}
297d4afb5ceSopenharmony_ci
298d4afb5ceSopenharmony_cistatic int
299d4afb5ceSopenharmony_cihandle_name(struct per_session_data__sshd *pss)
300d4afb5ceSopenharmony_ci{
301d4afb5ceSopenharmony_ci	struct lws_kex *kex = pss->kex;
302d4afb5ceSopenharmony_ci	char keyt[32];
303d4afb5ceSopenharmony_ci	uint8_t keybuf[256];
304d4afb5ceSopenharmony_ci	int n = 0, len;
305d4afb5ceSopenharmony_ci
306d4afb5ceSopenharmony_ci	switch (pss->parser_state) {
307d4afb5ceSopenharmony_ci	case SSH_KEX_NL_KEX_ALGS:
308d4afb5ceSopenharmony_ci		if (!strcmp(pss->name, "curve25519-sha256@libssh.org"))
309d4afb5ceSopenharmony_ci			kex->match_bitfield |= 1;
310d4afb5ceSopenharmony_ci		break;
311d4afb5ceSopenharmony_ci	case SSH_KEX_NL_SHK_ALGS:
312d4afb5ceSopenharmony_ci		len = (int)get_gen_server_key_25519(pss, keybuf, (int)sizeof(keybuf));
313d4afb5ceSopenharmony_ci		if (!len)
314d4afb5ceSopenharmony_ci			break;
315d4afb5ceSopenharmony_ci		if (ed25519_key_parse(keybuf, (unsigned int)len,
316d4afb5ceSopenharmony_ci				      keyt, sizeof(keyt),
317d4afb5ceSopenharmony_ci				      NULL, NULL)) {
318d4afb5ceSopenharmony_ci			lwsl_err("Unable to parse host key %d\n", n);
319d4afb5ceSopenharmony_ci		} else {
320d4afb5ceSopenharmony_ci			if (!strcmp(pss->name, keyt)) {
321d4afb5ceSopenharmony_ci				kex->match_bitfield |= 2;
322d4afb5ceSopenharmony_ci				break;
323d4afb5ceSopenharmony_ci			}
324d4afb5ceSopenharmony_ci		}
325d4afb5ceSopenharmony_ci		break;
326d4afb5ceSopenharmony_ci	case SSH_KEX_NL_EACTS_ALGS:
327d4afb5ceSopenharmony_ci		if (!strcmp(pss->name, "chacha20-poly1305@openssh.com"))
328d4afb5ceSopenharmony_ci			kex->match_bitfield |= 4;
329d4afb5ceSopenharmony_ci		break;
330d4afb5ceSopenharmony_ci	case SSH_KEX_NL_EASTC_ALGS:
331d4afb5ceSopenharmony_ci		if (!strcmp(pss->name, "chacha20-poly1305@openssh.com"))
332d4afb5ceSopenharmony_ci			kex->match_bitfield |= 8;
333d4afb5ceSopenharmony_ci		break;
334d4afb5ceSopenharmony_ci	case SSH_KEX_NL_MACTS_ALGS:
335d4afb5ceSopenharmony_ci		if (!strcmp(pss->name, "hmac-sha2-256"))
336d4afb5ceSopenharmony_ci			kex->match_bitfield |= 16;
337d4afb5ceSopenharmony_ci		break;
338d4afb5ceSopenharmony_ci	case SSH_KEX_NL_MASTC_ALGS:
339d4afb5ceSopenharmony_ci		if (!strcmp(pss->name, "hmac-sha2-256"))
340d4afb5ceSopenharmony_ci			kex->match_bitfield |= 32;
341d4afb5ceSopenharmony_ci		break;
342d4afb5ceSopenharmony_ci	case SSH_KEX_NL_CACTS_ALGS:
343d4afb5ceSopenharmony_ci		if (!strcmp(pss->name, "none"))
344d4afb5ceSopenharmony_ci			kex->match_bitfield |= 64;
345d4afb5ceSopenharmony_ci		break;
346d4afb5ceSopenharmony_ci	case SSH_KEX_NL_CASTC_ALGS:
347d4afb5ceSopenharmony_ci		if (!strcmp(pss->name, "none"))
348d4afb5ceSopenharmony_ci			kex->match_bitfield |= 128;
349d4afb5ceSopenharmony_ci		break;
350d4afb5ceSopenharmony_ci	case SSH_KEX_NL_LCTS_ALGS:
351d4afb5ceSopenharmony_ci	case SSH_KEX_NL_LSTC_ALGS:
352d4afb5ceSopenharmony_ci		break;
353d4afb5ceSopenharmony_ci	default:
354d4afb5ceSopenharmony_ci		break;
355d4afb5ceSopenharmony_ci	}
356d4afb5ceSopenharmony_ci
357d4afb5ceSopenharmony_ci	return 0;
358d4afb5ceSopenharmony_ci}
359d4afb5ceSopenharmony_ci
360d4afb5ceSopenharmony_ci
361d4afb5ceSopenharmony_cistatic int
362d4afb5ceSopenharmony_cilws_kex_create(struct per_session_data__sshd *pss)
363d4afb5ceSopenharmony_ci{
364d4afb5ceSopenharmony_ci	pss->kex = sshd_zalloc(sizeof(struct lws_kex));
365d4afb5ceSopenharmony_ci	lwsl_info("%s\n", __func__);
366d4afb5ceSopenharmony_ci	return !pss->kex;
367d4afb5ceSopenharmony_ci}
368d4afb5ceSopenharmony_ci
369d4afb5ceSopenharmony_cistatic void
370d4afb5ceSopenharmony_cilws_kex_destroy(struct per_session_data__sshd *pss)
371d4afb5ceSopenharmony_ci{
372d4afb5ceSopenharmony_ci	if (!pss->kex)
373d4afb5ceSopenharmony_ci		return;
374d4afb5ceSopenharmony_ci
375d4afb5ceSopenharmony_ci	lwsl_info("Destroying KEX\n");
376d4afb5ceSopenharmony_ci
377d4afb5ceSopenharmony_ci	if (pss->kex->I_C) {
378d4afb5ceSopenharmony_ci		free(pss->kex->I_C);
379d4afb5ceSopenharmony_ci		pss->kex->I_C = NULL;
380d4afb5ceSopenharmony_ci	}
381d4afb5ceSopenharmony_ci	if (pss->kex->I_S) {
382d4afb5ceSopenharmony_ci		free(pss->kex->I_S);
383d4afb5ceSopenharmony_ci		pss->kex->I_S = NULL;
384d4afb5ceSopenharmony_ci	}
385d4afb5ceSopenharmony_ci
386d4afb5ceSopenharmony_ci	lws_explicit_bzero(pss->kex, sizeof(*pss->kex));
387d4afb5ceSopenharmony_ci	free(pss->kex);
388d4afb5ceSopenharmony_ci	pss->kex = NULL;
389d4afb5ceSopenharmony_ci}
390d4afb5ceSopenharmony_ci
391d4afb5ceSopenharmony_cistatic void
392d4afb5ceSopenharmony_cissh_free(void *p)
393d4afb5ceSopenharmony_ci{
394d4afb5ceSopenharmony_ci	if (!p)
395d4afb5ceSopenharmony_ci		return;
396d4afb5ceSopenharmony_ci
397d4afb5ceSopenharmony_ci	lwsl_debug("%s: FREE %p\n", __func__, p);
398d4afb5ceSopenharmony_ci	free(p);
399d4afb5ceSopenharmony_ci}
400d4afb5ceSopenharmony_ci
401d4afb5ceSopenharmony_ci#define ssh_free_set_NULL(x) if (x) { ssh_free(x); (x) = NULL; }
402d4afb5ceSopenharmony_ci
403d4afb5ceSopenharmony_cistatic void
404d4afb5ceSopenharmony_cilws_ua_destroy(struct per_session_data__sshd *pss)
405d4afb5ceSopenharmony_ci{
406d4afb5ceSopenharmony_ci	if (!pss->ua)
407d4afb5ceSopenharmony_ci		return;
408d4afb5ceSopenharmony_ci
409d4afb5ceSopenharmony_ci	lwsl_info("%s\n", __func__);
410d4afb5ceSopenharmony_ci
411d4afb5ceSopenharmony_ci	if (pss->ua->username)
412d4afb5ceSopenharmony_ci		ssh_free(pss->ua->username);
413d4afb5ceSopenharmony_ci	if (pss->ua->service)
414d4afb5ceSopenharmony_ci		ssh_free(pss->ua->service);
415d4afb5ceSopenharmony_ci	if (pss->ua->alg)
416d4afb5ceSopenharmony_ci		ssh_free(pss->ua->alg);
417d4afb5ceSopenharmony_ci	if (pss->ua->pubkey)
418d4afb5ceSopenharmony_ci		ssh_free(pss->ua->pubkey);
419d4afb5ceSopenharmony_ci	if (pss->ua->sig) {
420d4afb5ceSopenharmony_ci		lws_explicit_bzero(pss->ua->sig, pss->ua->sig_len);
421d4afb5ceSopenharmony_ci		ssh_free(pss->ua->sig);
422d4afb5ceSopenharmony_ci	}
423d4afb5ceSopenharmony_ci
424d4afb5ceSopenharmony_ci	lws_explicit_bzero(pss->ua, sizeof(*pss->ua));
425d4afb5ceSopenharmony_ci	free(pss->ua);
426d4afb5ceSopenharmony_ci	pss->ua = NULL;
427d4afb5ceSopenharmony_ci}
428d4afb5ceSopenharmony_ci
429d4afb5ceSopenharmony_ci
430d4afb5ceSopenharmony_cistatic int
431d4afb5ceSopenharmony_cirsa_hash_alg_from_ident(const char *ident)
432d4afb5ceSopenharmony_ci{
433d4afb5ceSopenharmony_ci	if (strcmp(ident, "ssh-rsa") == 0 ||
434d4afb5ceSopenharmony_ci	    strcmp(ident, "ssh-rsa-cert-v01@openssh.com") == 0)
435d4afb5ceSopenharmony_ci		return LWS_GENHASH_TYPE_SHA1;
436d4afb5ceSopenharmony_ci	if (strcmp(ident, "rsa-sha2-256") == 0)
437d4afb5ceSopenharmony_ci		return LWS_GENHASH_TYPE_SHA256;
438d4afb5ceSopenharmony_ci	if (strcmp(ident, "rsa-sha2-512") == 0)
439d4afb5ceSopenharmony_ci		return LWS_GENHASH_TYPE_SHA512;
440d4afb5ceSopenharmony_ci
441d4afb5ceSopenharmony_ci        return -1;
442d4afb5ceSopenharmony_ci}
443d4afb5ceSopenharmony_ci
444d4afb5ceSopenharmony_cistatic void
445d4afb5ceSopenharmony_cistate_get_string_alloc(struct per_session_data__sshd *pss, int next)
446d4afb5ceSopenharmony_ci{
447d4afb5ceSopenharmony_ci	pss->parser_state = SSHS_GET_STRING_LEN_ALLOC;
448d4afb5ceSopenharmony_ci        pss->state_after_string = (char)next;
449d4afb5ceSopenharmony_ci}
450d4afb5ceSopenharmony_ci
451d4afb5ceSopenharmony_cistatic void
452d4afb5ceSopenharmony_cistate_get_string(struct per_session_data__sshd *pss, int next)
453d4afb5ceSopenharmony_ci{
454d4afb5ceSopenharmony_ci	pss->parser_state = SSHS_GET_STRING_LEN;
455d4afb5ceSopenharmony_ci        pss->state_after_string = (char)next;
456d4afb5ceSopenharmony_ci}
457d4afb5ceSopenharmony_ci
458d4afb5ceSopenharmony_cistatic void
459d4afb5ceSopenharmony_cistate_get_u32(struct per_session_data__sshd *pss, int next)
460d4afb5ceSopenharmony_ci{
461d4afb5ceSopenharmony_ci	pss->parser_state = SSHS_GET_U32;
462d4afb5ceSopenharmony_ci        pss->state_after_string = (char)next;
463d4afb5ceSopenharmony_ci}
464d4afb5ceSopenharmony_ci
465d4afb5ceSopenharmony_cistatic struct lws_ssh_channel *
466d4afb5ceSopenharmony_cissh_get_server_ch(struct per_session_data__sshd *pss, uint32_t chi)
467d4afb5ceSopenharmony_ci{
468d4afb5ceSopenharmony_ci	struct lws_ssh_channel *ch = pss->ch_list;
469d4afb5ceSopenharmony_ci
470d4afb5ceSopenharmony_ci	while (ch) {
471d4afb5ceSopenharmony_ci		if (ch->server_ch == chi)
472d4afb5ceSopenharmony_ci			return ch;
473d4afb5ceSopenharmony_ci		ch = ch->next;
474d4afb5ceSopenharmony_ci	}
475d4afb5ceSopenharmony_ci
476d4afb5ceSopenharmony_ci	return NULL;
477d4afb5ceSopenharmony_ci}
478d4afb5ceSopenharmony_ci
479d4afb5ceSopenharmony_ci#if 0
480d4afb5ceSopenharmony_cistatic struct lws_ssh_channel *
481d4afb5ceSopenharmony_cissh_get_peer_ch(struct per_session_data__sshd *pss, uint32_t chi)
482d4afb5ceSopenharmony_ci{
483d4afb5ceSopenharmony_ci	struct lws_ssh_channel *ch = pss->ch_list;
484d4afb5ceSopenharmony_ci
485d4afb5ceSopenharmony_ci	while (ch) {
486d4afb5ceSopenharmony_ci		if (ch->sender_ch == chi)
487d4afb5ceSopenharmony_ci			return ch;
488d4afb5ceSopenharmony_ci		ch = ch->next;
489d4afb5ceSopenharmony_ci	}
490d4afb5ceSopenharmony_ci
491d4afb5ceSopenharmony_ci	return NULL;
492d4afb5ceSopenharmony_ci}
493d4afb5ceSopenharmony_ci#endif
494d4afb5ceSopenharmony_ci
495d4afb5ceSopenharmony_cistatic void
496d4afb5ceSopenharmony_cissh_destroy_channel(struct per_session_data__sshd *pss,
497d4afb5ceSopenharmony_ci		    struct lws_ssh_channel *ch)
498d4afb5ceSopenharmony_ci{
499d4afb5ceSopenharmony_ci	lws_start_foreach_llp(struct lws_ssh_channel **, ppch, pss->ch_list) {
500d4afb5ceSopenharmony_ci		if (*ppch == ch) {
501d4afb5ceSopenharmony_ci			lwsl_info("Deleting ch %p\n", ch);
502d4afb5ceSopenharmony_ci			if (pss->vhd && pss->vhd->ops &&
503d4afb5ceSopenharmony_ci			    pss->vhd->ops->channel_destroy)
504d4afb5ceSopenharmony_ci				pss->vhd->ops->channel_destroy(ch->priv);
505d4afb5ceSopenharmony_ci			*ppch = ch->next;
506d4afb5ceSopenharmony_ci			if (ch->sub)
507d4afb5ceSopenharmony_ci				free(ch->sub);
508d4afb5ceSopenharmony_ci			free(ch);
509d4afb5ceSopenharmony_ci
510d4afb5ceSopenharmony_ci			return;
511d4afb5ceSopenharmony_ci		}
512d4afb5ceSopenharmony_ci	} lws_end_foreach_llp(ppch, next);
513d4afb5ceSopenharmony_ci
514d4afb5ceSopenharmony_ci	lwsl_notice("Failed to delete ch\n");
515d4afb5ceSopenharmony_ci}
516d4afb5ceSopenharmony_ci
517d4afb5ceSopenharmony_cistatic void
518d4afb5ceSopenharmony_cilws_ssh_exec_finish(void *finish_handle, int retcode)
519d4afb5ceSopenharmony_ci{
520d4afb5ceSopenharmony_ci	struct lws_ssh_channel *ch = (struct lws_ssh_channel *)finish_handle;
521d4afb5ceSopenharmony_ci	struct per_session_data__sshd *pss = ch->pss;
522d4afb5ceSopenharmony_ci
523d4afb5ceSopenharmony_ci	ch->retcode = retcode;
524d4afb5ceSopenharmony_ci	write_task(pss, ch, SSH_WT_EXIT_STATUS);
525d4afb5ceSopenharmony_ci	ch->scheduled_close = 1;
526d4afb5ceSopenharmony_ci	write_task(pss, ch, SSH_WT_CH_CLOSE);
527d4afb5ceSopenharmony_ci}
528d4afb5ceSopenharmony_ci
529d4afb5ceSopenharmony_cistatic int
530d4afb5ceSopenharmony_cilws_ssh_parse_plaintext(struct per_session_data__sshd *pss, uint8_t *p, size_t len)
531d4afb5ceSopenharmony_ci{
532d4afb5ceSopenharmony_ci	struct lws_gencrypto_keyelem e[LWS_GENCRYPTO_RSA_KEYEL_COUNT];
533d4afb5ceSopenharmony_ci	struct lws_genrsa_ctx ctx;
534d4afb5ceSopenharmony_ci	struct lws_ssh_channel *ch;
535d4afb5ceSopenharmony_ci	struct lws_subprotocol_scp *scp;
536d4afb5ceSopenharmony_ci	uint8_t *pp, *ps, hash[64];
537d4afb5ceSopenharmony_ci#if !defined(MBEDTLS_VERSION_NUMBER) || MBEDTLS_VERSION_NUMBER < 0x03000000
538d4afb5ceSopenharmony_ci	uint8_t *otmp = NULL;
539d4afb5ceSopenharmony_ci#endif
540d4afb5ceSopenharmony_ci	uint32_t m;
541d4afb5ceSopenharmony_ci	int n;
542d4afb5ceSopenharmony_ci
543d4afb5ceSopenharmony_ci	while (len --) {
544d4afb5ceSopenharmony_ciagain:
545d4afb5ceSopenharmony_ci		switch(pss->parser_state) {
546d4afb5ceSopenharmony_ci		case SSH_INITIALIZE_TRANSIENT:
547d4afb5ceSopenharmony_ci			pss->parser_state = SSHS_IDSTRING;
548d4afb5ceSopenharmony_ci			pss->ctr = 0;
549d4afb5ceSopenharmony_ci			pss->copy_to_I_C = 0;
550d4afb5ceSopenharmony_ci
551d4afb5ceSopenharmony_ci			/* fallthru */
552d4afb5ceSopenharmony_ci		case SSHS_IDSTRING:
553d4afb5ceSopenharmony_ci			if (*p == 0x0d) {
554d4afb5ceSopenharmony_ci				pss->V_C[pss->npos] = '\0';
555d4afb5ceSopenharmony_ci				pss->npos = 0;
556d4afb5ceSopenharmony_ci				lwsl_info("peer id: %s\n", pss->V_C);
557d4afb5ceSopenharmony_ci				p++;
558d4afb5ceSopenharmony_ci				pss->parser_state = SSHS_IDSTRING_CR;
559d4afb5ceSopenharmony_ci				break;
560d4afb5ceSopenharmony_ci			}
561d4afb5ceSopenharmony_ci			if (pss->npos < sizeof(pss->V_C) - 1)
562d4afb5ceSopenharmony_ci				pss->V_C[pss->npos++] = (char)*p;
563d4afb5ceSopenharmony_ci			p++;
564d4afb5ceSopenharmony_ci			break;
565d4afb5ceSopenharmony_ci
566d4afb5ceSopenharmony_ci		case SSHS_IDSTRING_CR:
567d4afb5ceSopenharmony_ci			if (*p++ != 0x0a) {
568d4afb5ceSopenharmony_ci				lwsl_notice("mangled id string\n");
569d4afb5ceSopenharmony_ci				return 1;
570d4afb5ceSopenharmony_ci			}
571d4afb5ceSopenharmony_ci			pss->ssh_sequence_ctr_cts = 0;
572d4afb5ceSopenharmony_ci			pss->parser_state = SSHS_MSG_LEN;
573d4afb5ceSopenharmony_ci			break;
574d4afb5ceSopenharmony_ci
575d4afb5ceSopenharmony_ci		case SSHS_MSG_LEN:
576d4afb5ceSopenharmony_ci			pss->msg_len = (pss->msg_len << 8) | *p++;
577d4afb5ceSopenharmony_ci			if (++pss->ctr != 4)
578d4afb5ceSopenharmony_ci				break;
579d4afb5ceSopenharmony_ci
580d4afb5ceSopenharmony_ci			if (pss->active_keys_cts.valid) {
581d4afb5ceSopenharmony_ci				uint8_t b[4];
582d4afb5ceSopenharmony_ci
583d4afb5ceSopenharmony_ci				POKE_U32(b, (uint32_t)pss->msg_len);
584d4afb5ceSopenharmony_ci				pss->msg_len = lws_chachapoly_get_length(
585d4afb5ceSopenharmony_ci					&pss->active_keys_cts,
586d4afb5ceSopenharmony_ci					pss->ssh_sequence_ctr_cts, b);
587d4afb5ceSopenharmony_ci			} else
588d4afb5ceSopenharmony_ci				pss->ssh_sequence_ctr_cts++;
589d4afb5ceSopenharmony_ci
590d4afb5ceSopenharmony_ci			lwsl_info("msg len %d\n", pss->msg_len);
591d4afb5ceSopenharmony_ci
592d4afb5ceSopenharmony_ci			pss->parser_state = SSHS_MSG_PADDING;
593d4afb5ceSopenharmony_ci			pss->ctr = 0;
594d4afb5ceSopenharmony_ci			pss->pos = 4;
595d4afb5ceSopenharmony_ci			if (pss->msg_len < 2 + 4) {
596d4afb5ceSopenharmony_ci				lwsl_notice("illegal msg size\n");
597d4afb5ceSopenharmony_ci				goto bail;
598d4afb5ceSopenharmony_ci			}
599d4afb5ceSopenharmony_ci			break;
600d4afb5ceSopenharmony_ci
601d4afb5ceSopenharmony_ci		case SSHS_MSG_PADDING:
602d4afb5ceSopenharmony_ci			pss->msg_padding = *p++;
603d4afb5ceSopenharmony_ci			pss->parser_state = SSHS_MSG_ID;
604d4afb5ceSopenharmony_ci			break;
605d4afb5ceSopenharmony_ci
606d4afb5ceSopenharmony_ci		case SSHS_MSG_ID:
607d4afb5ceSopenharmony_ci			pss->msg_id = *p++;
608d4afb5ceSopenharmony_ci			pss->ctr = 0;
609d4afb5ceSopenharmony_ci			switch (pss->msg_id) {
610d4afb5ceSopenharmony_ci			case SSH_MSG_DISCONNECT:
611d4afb5ceSopenharmony_ci				/*
612d4afb5ceSopenharmony_ci				 *       byte      SSH_MSG_DISCONNECT
613d4afb5ceSopenharmony_ci      	      	      	         *	 uint32    reason code
614d4afb5ceSopenharmony_ci				 *	 string    description in ISO-10646
615d4afb5ceSopenharmony_ci				 *	 	   UTF-8 encoding [RFC3629]
616d4afb5ceSopenharmony_ci      	      	      	      	 *	 string    language tag [RFC3066]
617d4afb5ceSopenharmony_ci				 */
618d4afb5ceSopenharmony_ci				lwsl_notice("SSH_MSG_DISCONNECT\n");
619d4afb5ceSopenharmony_ci				state_get_u32(pss, SSHS_NVC_DISCONNECT_REASON);
620d4afb5ceSopenharmony_ci				break;
621d4afb5ceSopenharmony_ci			case SSH_MSG_IGNORE:
622d4afb5ceSopenharmony_ci				lwsl_notice("SSH_MSG_IGNORE\n");
623d4afb5ceSopenharmony_ci				break;
624d4afb5ceSopenharmony_ci			case SSH_MSG_UNIMPLEMENTED:
625d4afb5ceSopenharmony_ci				lwsl_notice("SSH_MSG_UNIMPLEMENTED\n");
626d4afb5ceSopenharmony_ci				break;
627d4afb5ceSopenharmony_ci			case SSH_MSG_DEBUG:
628d4afb5ceSopenharmony_ci				lwsl_notice("SSH_MSG_DEBUG\n");
629d4afb5ceSopenharmony_ci				break;
630d4afb5ceSopenharmony_ci			case SSH_MSG_SERVICE_REQUEST:
631d4afb5ceSopenharmony_ci				lwsl_info("SSH_MSG_SERVICE_REQUEST\n");
632d4afb5ceSopenharmony_ci				/* payload is a string */
633d4afb5ceSopenharmony_ci				state_get_string(pss, SSHS_DO_SERVICE_REQUEST);
634d4afb5ceSopenharmony_ci				break;
635d4afb5ceSopenharmony_ci			case SSH_MSG_SERVICE_ACCEPT:
636d4afb5ceSopenharmony_ci				lwsl_notice("SSH_MSG_ACCEPT\n");
637d4afb5ceSopenharmony_ci				break;
638d4afb5ceSopenharmony_ci
639d4afb5ceSopenharmony_ci			case SSH_MSG_KEXINIT:
640d4afb5ceSopenharmony_ci				if (pss->kex_state !=
641d4afb5ceSopenharmony_ci					    KEX_STATE_EXPECTING_CLIENT_OFFER) {
642d4afb5ceSopenharmony_ci					pss->parser_state = SSH_KEX_STATE_SKIP;
643d4afb5ceSopenharmony_ci					break;
644d4afb5ceSopenharmony_ci				}
645d4afb5ceSopenharmony_ci				if (!pss->kex) {
646d4afb5ceSopenharmony_ci					lwsl_notice("%s: SSH_MSG_KEXINIT: NULL pss->kex\n", __func__);
647d4afb5ceSopenharmony_ci					goto bail;
648d4afb5ceSopenharmony_ci				}
649d4afb5ceSopenharmony_ci				pss->parser_state = SSH_KEX_STATE_COOKIE;
650d4afb5ceSopenharmony_ci				pss->kex->I_C_payload_len = 0;
651d4afb5ceSopenharmony_ci				pss->kex->I_C_alloc_len = pss->msg_len;
652d4afb5ceSopenharmony_ci				pss->kex->I_C = sshd_zalloc(pss->kex->I_C_alloc_len);
653d4afb5ceSopenharmony_ci				if (!pss->kex->I_C) {
654d4afb5ceSopenharmony_ci					lwsl_notice("OOM 3\n");
655d4afb5ceSopenharmony_ci					goto bail;
656d4afb5ceSopenharmony_ci				}
657d4afb5ceSopenharmony_ci				pss->kex->I_C[pss->kex->I_C_payload_len++] =
658d4afb5ceSopenharmony_ci					pss->msg_id;
659d4afb5ceSopenharmony_ci				pss->copy_to_I_C = 1;
660d4afb5ceSopenharmony_ci				break;
661d4afb5ceSopenharmony_ci			case SSH_MSG_KEX_ECDH_INIT:
662d4afb5ceSopenharmony_ci				pss->parser_state = SSH_KEX_STATE_ECDH_KEYLEN;
663d4afb5ceSopenharmony_ci				break;
664d4afb5ceSopenharmony_ci
665d4afb5ceSopenharmony_ci			case SSH_MSG_NEWKEYS:
666d4afb5ceSopenharmony_ci				if (pss->kex_state !=
667d4afb5ceSopenharmony_ci						KEX_STATE_REPLIED_TO_OFFER &&
668d4afb5ceSopenharmony_ci				    pss->kex_state !=
669d4afb5ceSopenharmony_ci				    		KEX_STATE_CRYPTO_INITIALIZED) {
670d4afb5ceSopenharmony_ci					lwsl_notice("unexpected newkeys\n");
671d4afb5ceSopenharmony_ci
672d4afb5ceSopenharmony_ci					goto bail;
673d4afb5ceSopenharmony_ci				}
674d4afb5ceSopenharmony_ci				/*
675d4afb5ceSopenharmony_ci				 * it means we should now use the keys we
676d4afb5ceSopenharmony_ci				 * agreed on
677d4afb5ceSopenharmony_ci				 */
678d4afb5ceSopenharmony_ci				lwsl_info("Activating CTS keys\n");
679d4afb5ceSopenharmony_ci				pss->active_keys_cts = pss->kex->keys_next_cts;
680d4afb5ceSopenharmony_ci				if (lws_chacha_activate(&pss->active_keys_cts))
681d4afb5ceSopenharmony_ci					goto bail;
682d4afb5ceSopenharmony_ci
683d4afb5ceSopenharmony_ci				pss->kex->newkeys |= 2;
684d4afb5ceSopenharmony_ci				if (pss->kex->newkeys == 3)
685d4afb5ceSopenharmony_ci					lws_kex_destroy(pss);
686d4afb5ceSopenharmony_ci
687d4afb5ceSopenharmony_ci				if (pss->msg_padding) {
688d4afb5ceSopenharmony_ci					pss->copy_to_I_C = 0;
689d4afb5ceSopenharmony_ci					pss->parser_state =
690d4afb5ceSopenharmony_ci						SSHS_MSG_EAT_PADDING;
691d4afb5ceSopenharmony_ci					break;
692d4afb5ceSopenharmony_ci				} else {
693d4afb5ceSopenharmony_ci					pss->parser_state = SSHS_MSG_LEN;
694d4afb5ceSopenharmony_ci				}
695d4afb5ceSopenharmony_ci				break;
696d4afb5ceSopenharmony_ci
697d4afb5ceSopenharmony_ci			case SSH_MSG_USERAUTH_REQUEST:
698d4afb5ceSopenharmony_ci				/*
699d4afb5ceSopenharmony_ci				 *    byte      SSH_MSG_USERAUTH_REQUEST
700d4afb5ceSopenharmony_ci				 *    string    user name in UTF-8
701d4afb5ceSopenharmony_ci				 *    		encoding [RFC3629]
702d4afb5ceSopenharmony_ci				 *    string    service name in US-ASCII
703d4afb5ceSopenharmony_ci				 *    string    "publickey"
704d4afb5ceSopenharmony_ci				 *    boolean   FALSE
705d4afb5ceSopenharmony_ci				 *    string    public key alg
706d4afb5ceSopenharmony_ci				 *    string    public key blob
707d4afb5ceSopenharmony_ci				 */
708d4afb5ceSopenharmony_ci				lwsl_info("SSH_MSG_USERAUTH_REQUEST\n");
709d4afb5ceSopenharmony_ci				if (pss->ua) {
710d4afb5ceSopenharmony_ci					lwsl_notice("pss->ua overwrite\n");
711d4afb5ceSopenharmony_ci
712d4afb5ceSopenharmony_ci					goto bail;
713d4afb5ceSopenharmony_ci				}
714d4afb5ceSopenharmony_ci
715d4afb5ceSopenharmony_ci				pss->ua = sshd_zalloc(sizeof(*pss->ua));
716d4afb5ceSopenharmony_ci				if (!pss->ua)
717d4afb5ceSopenharmony_ci					goto bail;
718d4afb5ceSopenharmony_ci
719d4afb5ceSopenharmony_ci				state_get_string_alloc(pss, SSHS_DO_UAR_SVC);
720d4afb5ceSopenharmony_ci				/* username is destroyed with userauth struct */
721d4afb5ceSopenharmony_ci				if (!pss->sent_banner) {
722d4afb5ceSopenharmony_ci					if (pss->vhd->ops->banner)
723d4afb5ceSopenharmony_ci						write_task(pss, NULL,
724d4afb5ceSopenharmony_ci							   SSH_WT_UA_BANNER);
725d4afb5ceSopenharmony_ci					pss->sent_banner = 1;
726d4afb5ceSopenharmony_ci				}
727d4afb5ceSopenharmony_ci                                break;
728d4afb5ceSopenharmony_ci			case SSH_MSG_USERAUTH_FAILURE:
729d4afb5ceSopenharmony_ci				goto bail;
730d4afb5ceSopenharmony_ci			case SSH_MSG_USERAUTH_SUCCESS:
731d4afb5ceSopenharmony_ci				goto bail;
732d4afb5ceSopenharmony_ci			case SSH_MSG_USERAUTH_BANNER:
733d4afb5ceSopenharmony_ci				goto bail;
734d4afb5ceSopenharmony_ci
735d4afb5ceSopenharmony_ci			case SSH_MSG_CHANNEL_OPEN:
736d4afb5ceSopenharmony_ci				state_get_string(pss, SSHS_NVC_CHOPEN_TYPE);
737d4afb5ceSopenharmony_ci				break;
738d4afb5ceSopenharmony_ci
739d4afb5ceSopenharmony_ci			case SSH_MSG_CHANNEL_REQUEST:
740d4afb5ceSopenharmony_ci				/* RFC4254
741d4afb5ceSopenharmony_ci				 *
742d4afb5ceSopenharmony_ci				 *  byte      SSH_MSG_CHANNEL_REQUEST
743d4afb5ceSopenharmony_ci				 *  uint32    recipient channel
744d4afb5ceSopenharmony_ci				 *  string    "pty-req"
745d4afb5ceSopenharmony_ci				 *  boolean   want_reply
746d4afb5ceSopenharmony_ci				 *  string    TERM environment variable value
747d4afb5ceSopenharmony_ci				 *      		(e.g., vt100)
748d4afb5ceSopenharmony_ci				 *  uint32    terminal width, characters
749d4afb5ceSopenharmony_ci				 *      		(e.g., 80)
750d4afb5ceSopenharmony_ci				 *  uint32    terminal height, rows (e.g., 24)
751d4afb5ceSopenharmony_ci				 *  uint32    terminal width, px (e.g., 640)
752d4afb5ceSopenharmony_ci				 *  uint32    terminal height, px (e.g., 480)
753d4afb5ceSopenharmony_ci				 *  string    encoded terminal modes
754d4afb5ceSopenharmony_ci				 */
755d4afb5ceSopenharmony_ci				state_get_u32(pss, SSHS_NVC_CHRQ_RECIP);
756d4afb5ceSopenharmony_ci				break;
757d4afb5ceSopenharmony_ci
758d4afb5ceSopenharmony_ci			case SSH_MSG_CHANNEL_EOF:
759d4afb5ceSopenharmony_ci				/* RFC4254
760d4afb5ceSopenharmony_ci				 * When a party will no longer send more data
761d4afb5ceSopenharmony_ci				 * to a channel, it SHOULD send
762d4afb5ceSopenharmony_ci				 * SSH_MSG_CHANNEL_EOF.
763d4afb5ceSopenharmony_ci				 *
764d4afb5ceSopenharmony_ci				 *  byte      SSH_MSG_CHANNEL_EOF
765d4afb5ceSopenharmony_ci 	 	 	 	 *  uint32    recipient channel
766d4afb5ceSopenharmony_ci				 */
767d4afb5ceSopenharmony_ci				state_get_u32(pss, SSHS_NVC_CH_EOF);
768d4afb5ceSopenharmony_ci				break;
769d4afb5ceSopenharmony_ci
770d4afb5ceSopenharmony_ci			case SSH_MSG_CHANNEL_CLOSE:
771d4afb5ceSopenharmony_ci				/* RFC4254
772d4afb5ceSopenharmony_ci				 *
773d4afb5ceSopenharmony_ci				 *  byte      SSH_MSG_CHANNEL_CLOSE
774d4afb5ceSopenharmony_ci				 *  uint32    recipient channel
775d4afb5ceSopenharmony_ci				 *
776d4afb5ceSopenharmony_ci				 * This message does not consume window space
777d4afb5ceSopenharmony_ci				 * and can be sent even if no window space is
778d4afb5ceSopenharmony_ci				 * available.
779d4afb5ceSopenharmony_ci				 *
780d4afb5ceSopenharmony_ci				 * It is RECOMMENDED that all data sent before
781d4afb5ceSopenharmony_ci				 * this message be delivered to the actual
782d4afb5ceSopenharmony_ci				 * destination, if possible.
783d4afb5ceSopenharmony_ci				 */
784d4afb5ceSopenharmony_ci				state_get_u32(pss, SSHS_NVC_CH_CLOSE);
785d4afb5ceSopenharmony_ci				break;
786d4afb5ceSopenharmony_ci
787d4afb5ceSopenharmony_ci			case SSH_MSG_CHANNEL_DATA:
788d4afb5ceSopenharmony_ci				/* RFC4254
789d4afb5ceSopenharmony_ci				 *
790d4afb5ceSopenharmony_ci				 *      byte      SSH_MSG_CHANNEL_DATA
791d4afb5ceSopenharmony_ci				 *      uint32    recipient channel
792d4afb5ceSopenharmony_ci				 *      string    data
793d4afb5ceSopenharmony_ci				 */
794d4afb5ceSopenharmony_ci				state_get_u32(pss, SSHS_NVC_CD_RECIP);
795d4afb5ceSopenharmony_ci				break;
796d4afb5ceSopenharmony_ci
797d4afb5ceSopenharmony_ci			case SSH_MSG_CHANNEL_WINDOW_ADJUST:
798d4afb5ceSopenharmony_ci				/* RFC452
799d4afb5ceSopenharmony_ci				 *
800d4afb5ceSopenharmony_ci				 * byte      SSH_MSG_CHANNEL_WINDOW_ADJUST
801d4afb5ceSopenharmony_ci				 * uint32    recipient channel
802d4afb5ceSopenharmony_ci				 * uint32    bytes to add
803d4afb5ceSopenharmony_ci				 */
804d4afb5ceSopenharmony_ci				if (!pss->ch_list)
805d4afb5ceSopenharmony_ci					goto bail;
806d4afb5ceSopenharmony_ci
807d4afb5ceSopenharmony_ci				state_get_u32(pss, SSHS_NVC_WA_RECIP);
808d4afb5ceSopenharmony_ci				break;
809d4afb5ceSopenharmony_ci			default:
810d4afb5ceSopenharmony_ci				lwsl_notice("unk msg_id %d\n", pss->msg_id);
811d4afb5ceSopenharmony_ci
812d4afb5ceSopenharmony_ci				goto bail;
813d4afb5ceSopenharmony_ci			}
814d4afb5ceSopenharmony_ci			break;
815d4afb5ceSopenharmony_ci
816d4afb5ceSopenharmony_ci		case SSH_KEX_STATE_COOKIE:
817d4afb5ceSopenharmony_ci			if (pss->msg_len < 16 + 1 + 1 + (10 * 4) + 5) {
818d4afb5ceSopenharmony_ci				lwsl_notice("sanity: kex length failed\n");
819d4afb5ceSopenharmony_ci				goto bail;
820d4afb5ceSopenharmony_ci			}
821d4afb5ceSopenharmony_ci			pss->kex->kex_cookie[pss->ctr++] = *p++;
822d4afb5ceSopenharmony_ci			if (pss->ctr != sizeof(pss->kex->kex_cookie))
823d4afb5ceSopenharmony_ci				break;
824d4afb5ceSopenharmony_ci			pss->parser_state = SSH_KEX_NL_KEX_ALGS_LEN;
825d4afb5ceSopenharmony_ci			pss->ctr = 0;
826d4afb5ceSopenharmony_ci			break;
827d4afb5ceSopenharmony_ci		case SSH_KEX_NL_KEX_ALGS_LEN:
828d4afb5ceSopenharmony_ci		case SSH_KEX_NL_SHK_ALGS_LEN:
829d4afb5ceSopenharmony_ci		case SSH_KEX_NL_EACTS_ALGS_LEN:
830d4afb5ceSopenharmony_ci		case SSH_KEX_NL_EASTC_ALGS_LEN:
831d4afb5ceSopenharmony_ci		case SSH_KEX_NL_MACTS_ALGS_LEN:
832d4afb5ceSopenharmony_ci		case SSH_KEX_NL_MASTC_ALGS_LEN:
833d4afb5ceSopenharmony_ci		case SSH_KEX_NL_CACTS_ALGS_LEN:
834d4afb5ceSopenharmony_ci		case SSH_KEX_NL_CASTC_ALGS_LEN:
835d4afb5ceSopenharmony_ci		case SSH_KEX_NL_LCTS_ALGS_LEN:
836d4afb5ceSopenharmony_ci		case SSH_KEX_NL_LSTC_ALGS_LEN:
837d4afb5ceSopenharmony_ci		case SSH_KEX_STATE_ECDH_KEYLEN:
838d4afb5ceSopenharmony_ci
839d4afb5ceSopenharmony_ci			pss->len = (pss->len << 8) | *p++;
840d4afb5ceSopenharmony_ci			if (++pss->ctr != 4)
841d4afb5ceSopenharmony_ci				break;
842d4afb5ceSopenharmony_ci
843d4afb5ceSopenharmony_ci			switch (pss->parser_state) {
844d4afb5ceSopenharmony_ci			case SSH_KEX_STATE_ECDH_KEYLEN:
845d4afb5ceSopenharmony_ci				pss->parser_state = SSH_KEX_STATE_ECDH_Q_C;
846d4afb5ceSopenharmony_ci				break;
847d4afb5ceSopenharmony_ci			default:
848d4afb5ceSopenharmony_ci				pss->parser_state++;
849d4afb5ceSopenharmony_ci				if (pss->len == 0)
850d4afb5ceSopenharmony_ci					pss->parser_state++;
851d4afb5ceSopenharmony_ci				break;
852d4afb5ceSopenharmony_ci			}
853d4afb5ceSopenharmony_ci			pss->ctr = 0;
854d4afb5ceSopenharmony_ci			pss->npos = 0;
855d4afb5ceSopenharmony_ci			if (pss->msg_len - pss->pos < pss->len) {
856d4afb5ceSopenharmony_ci				lwsl_notice("sanity: length  %d - %d < %d\n",
857d4afb5ceSopenharmony_ci					    pss->msg_len, pss->pos, pss->len);
858d4afb5ceSopenharmony_ci				goto bail;
859d4afb5ceSopenharmony_ci			}
860d4afb5ceSopenharmony_ci			break;
861d4afb5ceSopenharmony_ci
862d4afb5ceSopenharmony_ci		case SSH_KEX_NL_KEX_ALGS:
863d4afb5ceSopenharmony_ci		case SSH_KEX_NL_SHK_ALGS:
864d4afb5ceSopenharmony_ci		case SSH_KEX_NL_EACTS_ALGS:
865d4afb5ceSopenharmony_ci		case SSH_KEX_NL_EASTC_ALGS:
866d4afb5ceSopenharmony_ci		case SSH_KEX_NL_MACTS_ALGS:
867d4afb5ceSopenharmony_ci		case SSH_KEX_NL_MASTC_ALGS:
868d4afb5ceSopenharmony_ci		case SSH_KEX_NL_CACTS_ALGS:
869d4afb5ceSopenharmony_ci		case SSH_KEX_NL_CASTC_ALGS:
870d4afb5ceSopenharmony_ci		case SSH_KEX_NL_LCTS_ALGS:
871d4afb5ceSopenharmony_ci		case SSH_KEX_NL_LSTC_ALGS:
872d4afb5ceSopenharmony_ci			if (*p != ',') {
873d4afb5ceSopenharmony_ci				if (pss->npos < sizeof(pss->name) - 1)
874d4afb5ceSopenharmony_ci					pss->name[pss->npos++] = (char)*p;
875d4afb5ceSopenharmony_ci			} else {
876d4afb5ceSopenharmony_ci				pss->name[pss->npos] = '\0';
877d4afb5ceSopenharmony_ci				pss->npos = 0;
878d4afb5ceSopenharmony_ci				handle_name(pss);
879d4afb5ceSopenharmony_ci			}
880d4afb5ceSopenharmony_ci			p++;
881d4afb5ceSopenharmony_ci			if (!--pss->len) {
882d4afb5ceSopenharmony_ci				pss->name[pss->npos] = '\0';
883d4afb5ceSopenharmony_ci				if (pss->npos)
884d4afb5ceSopenharmony_ci					handle_name(pss);
885d4afb5ceSopenharmony_ci				pss->parser_state++;
886d4afb5ceSopenharmony_ci				break;
887d4afb5ceSopenharmony_ci			}
888d4afb5ceSopenharmony_ci			break;
889d4afb5ceSopenharmony_ci
890d4afb5ceSopenharmony_ci		case SSH_KEX_FIRST_PKT:
891d4afb5ceSopenharmony_ci			pss->first_coming = !!*p++;
892d4afb5ceSopenharmony_ci			pss->parser_state = SSH_KEX_RESERVED;
893d4afb5ceSopenharmony_ci			break;
894d4afb5ceSopenharmony_ci
895d4afb5ceSopenharmony_ci		case SSH_KEX_RESERVED:
896d4afb5ceSopenharmony_ci			pss->len = (pss->len << 8) | *p++;
897d4afb5ceSopenharmony_ci			if (++pss->ctr != 4)
898d4afb5ceSopenharmony_ci				break;
899d4afb5ceSopenharmony_ci			pss->ctr = 0;
900d4afb5ceSopenharmony_ci			if (pss->msg_padding) {
901d4afb5ceSopenharmony_ci				pss->copy_to_I_C = 0;
902d4afb5ceSopenharmony_ci				pss->parser_state = SSHS_MSG_EAT_PADDING;
903d4afb5ceSopenharmony_ci				break;
904d4afb5ceSopenharmony_ci			}
905d4afb5ceSopenharmony_ci			pss->parser_state = SSHS_MSG_LEN;
906d4afb5ceSopenharmony_ci			break;
907d4afb5ceSopenharmony_ci
908d4afb5ceSopenharmony_ci		case SSH_KEX_STATE_ECDH_Q_C:
909d4afb5ceSopenharmony_ci			if (pss->len != 32) {
910d4afb5ceSopenharmony_ci				lwsl_notice("wrong key len\n");
911d4afb5ceSopenharmony_ci				goto bail;
912d4afb5ceSopenharmony_ci			}
913d4afb5ceSopenharmony_ci			pss->kex->Q_C[pss->ctr++] = *p++;
914d4afb5ceSopenharmony_ci			if (pss->ctr != 32)
915d4afb5ceSopenharmony_ci				break;
916d4afb5ceSopenharmony_ci			lwsl_info("Q_C parsed\n");
917d4afb5ceSopenharmony_ci			pss->parser_state = SSHS_MSG_EAT_PADDING;
918d4afb5ceSopenharmony_ci			break;
919d4afb5ceSopenharmony_ci
920d4afb5ceSopenharmony_ci		case SSH_KEX_STATE_SKIP:
921d4afb5ceSopenharmony_ci			if (pss->pos - 4 < pss->msg_len) {
922d4afb5ceSopenharmony_ci				p++;
923d4afb5ceSopenharmony_ci				break;
924d4afb5ceSopenharmony_ci			}
925d4afb5ceSopenharmony_ci			lwsl_debug("skip done pos %d, msg_len %d len=%ld, \n",
926d4afb5ceSopenharmony_ci				       pss->pos, pss->msg_len, (long)len);
927d4afb5ceSopenharmony_ci			pss->parser_state = SSHS_MSG_LEN;
928d4afb5ceSopenharmony_ci			pss->ctr = 0;
929d4afb5ceSopenharmony_ci			break;
930d4afb5ceSopenharmony_ci
931d4afb5ceSopenharmony_ci		case SSHS_MSG_EAT_PADDING:
932d4afb5ceSopenharmony_ci			p++;
933d4afb5ceSopenharmony_ci			if (--pss->msg_padding)
934d4afb5ceSopenharmony_ci				break;
935d4afb5ceSopenharmony_ci			if (pss->msg_len + 4 != pss->pos) {
936d4afb5ceSopenharmony_ci				lwsl_notice("sanity: kex end mismatch %d %d\n",
937d4afb5ceSopenharmony_ci						pss->pos, pss->msg_len);
938d4afb5ceSopenharmony_ci				goto bail;
939d4afb5ceSopenharmony_ci			}
940d4afb5ceSopenharmony_ci
941d4afb5ceSopenharmony_ci			switch (pss->msg_id) {
942d4afb5ceSopenharmony_ci			case SSH_MSG_KEX_ECDH_INIT:
943d4afb5ceSopenharmony_ci				if (pss->kex->match_bitfield != 0xff) {
944d4afb5ceSopenharmony_ci					lwsl_notice("unable to negotiate\n");
945d4afb5ceSopenharmony_ci					goto bail;
946d4afb5ceSopenharmony_ci				}
947d4afb5ceSopenharmony_ci				if (kex_ecdh(pss, pss->kex->kex_r,
948d4afb5ceSopenharmony_ci					     &pss->kex->kex_r_len)) {
949d4afb5ceSopenharmony_ci					lwsl_notice("hex_ecdh failed\n");
950d4afb5ceSopenharmony_ci					goto bail;
951d4afb5ceSopenharmony_ci				}
952d4afb5ceSopenharmony_ci				write_task(pss, NULL, SSH_WT_OFFER_REPLY);
953d4afb5ceSopenharmony_ci				break;
954d4afb5ceSopenharmony_ci			}
955d4afb5ceSopenharmony_ci
956d4afb5ceSopenharmony_ci			pss->parser_state = SSHS_MSG_LEN;
957d4afb5ceSopenharmony_ci			pss->ctr = 0;
958d4afb5ceSopenharmony_ci			break;
959d4afb5ceSopenharmony_ci
960d4afb5ceSopenharmony_ci		case SSHS_GET_STRING_LEN:
961d4afb5ceSopenharmony_ci			pss->npos = 0;
962d4afb5ceSopenharmony_ci			pss->len = (pss->len << 8) | *p++;
963d4afb5ceSopenharmony_ci                        if (++pss->ctr != 4)
964d4afb5ceSopenharmony_ci                                break;
965d4afb5ceSopenharmony_ci                        pss->ctr = 0;
966d4afb5ceSopenharmony_ci			pss->parser_state = SSHS_GET_STRING;
967d4afb5ceSopenharmony_ci			break;
968d4afb5ceSopenharmony_ci
969d4afb5ceSopenharmony_ci		case SSHS_GET_STRING:
970d4afb5ceSopenharmony_ci			if (pss->npos >= sizeof(pss->name) - 1) {
971d4afb5ceSopenharmony_ci				lwsl_notice("non-alloc string too big\n");
972d4afb5ceSopenharmony_ci				goto bail;
973d4afb5ceSopenharmony_ci			}
974d4afb5ceSopenharmony_ci			pss->name[pss->npos++] = (char)*p++;
975d4afb5ceSopenharmony_ci			if (pss->npos != pss->len)
976d4afb5ceSopenharmony_ci				break;
977d4afb5ceSopenharmony_ci
978d4afb5ceSopenharmony_ci			pss->name[pss->npos] = '\0';
979d4afb5ceSopenharmony_ci			pss->parser_state = pss->state_after_string;
980d4afb5ceSopenharmony_ci			goto again;
981d4afb5ceSopenharmony_ci
982d4afb5ceSopenharmony_ci		case SSHS_GET_STRING_LEN_ALLOC:
983d4afb5ceSopenharmony_ci			pss->npos = 0;
984d4afb5ceSopenharmony_ci			pss->len = (pss->len << 8) | *p++;
985d4afb5ceSopenharmony_ci                        if (++pss->ctr != 4)
986d4afb5ceSopenharmony_ci                                break;
987d4afb5ceSopenharmony_ci                        pss->ctr = 0;
988d4afb5ceSopenharmony_ci			pss->last_alloc = sshd_zalloc(pss->len + 1);
989d4afb5ceSopenharmony_ci			lwsl_debug("SSHS_GET_STRING_LEN_ALLOC: %p, state %d\n",
990d4afb5ceSopenharmony_ci				   pss->last_alloc, pss->state_after_string);
991d4afb5ceSopenharmony_ci			if (!pss->last_alloc) {
992d4afb5ceSopenharmony_ci				lwsl_notice("alloc string too big\n");
993d4afb5ceSopenharmony_ci				goto bail;
994d4afb5ceSopenharmony_ci			}
995d4afb5ceSopenharmony_ci			pss->parser_state = SSHS_GET_STRING_ALLOC;
996d4afb5ceSopenharmony_ci			break;
997d4afb5ceSopenharmony_ci
998d4afb5ceSopenharmony_ci		case SSHS_GET_STRING_ALLOC:
999d4afb5ceSopenharmony_ci			if (pss->npos >= pss->len)
1000d4afb5ceSopenharmony_ci				goto bail;
1001d4afb5ceSopenharmony_ci			pss->last_alloc[pss->npos++] = *p++;
1002d4afb5ceSopenharmony_ci			if (pss->npos != pss->len)
1003d4afb5ceSopenharmony_ci				break;
1004d4afb5ceSopenharmony_ci			pss->last_alloc[pss->npos] = '\0';
1005d4afb5ceSopenharmony_ci			pss->parser_state = pss->state_after_string;
1006d4afb5ceSopenharmony_ci			goto again;
1007d4afb5ceSopenharmony_ci
1008d4afb5ceSopenharmony_ci		/*
1009d4afb5ceSopenharmony_ci		 * User Authentication
1010d4afb5ceSopenharmony_ci		 */
1011d4afb5ceSopenharmony_ci
1012d4afb5ceSopenharmony_ci		case SSHS_DO_SERVICE_REQUEST:
1013d4afb5ceSopenharmony_ci			pss->okayed_userauth = 1;
1014d4afb5ceSopenharmony_ci			pss->parser_state = SSHS_MSG_EAT_PADDING;
1015d4afb5ceSopenharmony_ci			/*
1016d4afb5ceSopenharmony_ci			 * this only 'accepts' that we can negotiate auth for
1017d4afb5ceSopenharmony_ci			 * this service, not accepts the auth
1018d4afb5ceSopenharmony_ci			 */
1019d4afb5ceSopenharmony_ci			write_task(pss, NULL, SSH_WT_UA_ACCEPT);
1020d4afb5ceSopenharmony_ci			break;
1021d4afb5ceSopenharmony_ci
1022d4afb5ceSopenharmony_ci		case SSHS_DO_UAR_SVC:
1023d4afb5ceSopenharmony_ci			pss->ua->username = (char *)pss->last_alloc;
1024d4afb5ceSopenharmony_ci			pss->last_alloc = NULL; /* it was adopted */
1025d4afb5ceSopenharmony_ci			state_get_string_alloc(pss, SSHS_DO_UAR_PUBLICKEY);
1026d4afb5ceSopenharmony_ci			/* destroyed with UA struct */
1027d4afb5ceSopenharmony_ci			break;
1028d4afb5ceSopenharmony_ci
1029d4afb5ceSopenharmony_ci		case SSHS_DO_UAR_PUBLICKEY:
1030d4afb5ceSopenharmony_ci			pss->ua->service = (char *)pss->last_alloc;
1031d4afb5ceSopenharmony_ci			pss->last_alloc = NULL; /* it was adopted */
1032d4afb5ceSopenharmony_ci
1033d4afb5ceSopenharmony_ci			/* Sect 5, RFC4252
1034d4afb5ceSopenharmony_ci			 *
1035d4afb5ceSopenharmony_ci			 * The 'user name' and 'service name' are repeated in
1036d4afb5ceSopenharmony_ci			 * every new authentication attempt, and MAY change.
1037d4afb5ceSopenharmony_ci			 *
1038d4afb5ceSopenharmony_ci			 * The server implementation MUST carefully check them
1039d4afb5ceSopenharmony_ci			 * in every message, and MUST flush any accumulated
1040d4afb5ceSopenharmony_ci			 * authentication states if they change.  If it is
1041d4afb5ceSopenharmony_ci			 * unable to flush an authentication state, it MUST
1042d4afb5ceSopenharmony_ci			 * disconnect if the 'user name' or 'service name'
1043d4afb5ceSopenharmony_ci			 * changes.
1044d4afb5ceSopenharmony_ci			 */
1045d4afb5ceSopenharmony_ci
1046d4afb5ceSopenharmony_ci			if (pss->seen_auth_req_before && (
1047d4afb5ceSopenharmony_ci			     strcmp(pss->ua->username,
1048d4afb5ceSopenharmony_ci				    pss->last_auth_req_username) ||
1049d4afb5ceSopenharmony_ci			     strcmp(pss->ua->service,
1050d4afb5ceSopenharmony_ci				    pss->last_auth_req_service))) {
1051d4afb5ceSopenharmony_ci				lwsl_notice("username / svc changed\n");
1052d4afb5ceSopenharmony_ci
1053d4afb5ceSopenharmony_ci				goto bail;
1054d4afb5ceSopenharmony_ci			}
1055d4afb5ceSopenharmony_ci
1056d4afb5ceSopenharmony_ci			pss->seen_auth_req_before = 1;
1057d4afb5ceSopenharmony_ci			lws_strncpy(pss->last_auth_req_username,
1058d4afb5ceSopenharmony_ci				    pss->ua->username,
1059d4afb5ceSopenharmony_ci				    sizeof(pss->last_auth_req_username));
1060d4afb5ceSopenharmony_ci			lws_strncpy(pss->last_auth_req_service,
1061d4afb5ceSopenharmony_ci				    pss->ua->service,
1062d4afb5ceSopenharmony_ci				    sizeof(pss->last_auth_req_service));
1063d4afb5ceSopenharmony_ci
1064d4afb5ceSopenharmony_ci			if (strcmp(pss->ua->service, "ssh-connection"))
1065d4afb5ceSopenharmony_ci				goto ua_fail;
1066d4afb5ceSopenharmony_ci			state_get_string(pss, SSHS_NVC_DO_UAR_CHECK_PUBLICKEY);
1067d4afb5ceSopenharmony_ci			break;
1068d4afb5ceSopenharmony_ci
1069d4afb5ceSopenharmony_ci		case SSHS_NVC_DO_UAR_CHECK_PUBLICKEY:
1070d4afb5ceSopenharmony_ci			if (!strcmp(pss->name, "none")) {
1071d4afb5ceSopenharmony_ci				/* we must fail it */
1072d4afb5ceSopenharmony_ci				lwsl_info("got 'none' req, refusing\n");
1073d4afb5ceSopenharmony_ci				goto ua_fail;
1074d4afb5ceSopenharmony_ci			}
1075d4afb5ceSopenharmony_ci
1076d4afb5ceSopenharmony_ci			if (strcmp(pss->name, "publickey")) {
1077d4afb5ceSopenharmony_ci				lwsl_notice("expected 'publickey' got '%s'\n",
1078d4afb5ceSopenharmony_ci					    pss->name);
1079d4afb5ceSopenharmony_ci				goto ua_fail;
1080d4afb5ceSopenharmony_ci			}
1081d4afb5ceSopenharmony_ci			pss->parser_state = SSHS_DO_UAR_SIG_PRESENT;
1082d4afb5ceSopenharmony_ci			break;
1083d4afb5ceSopenharmony_ci
1084d4afb5ceSopenharmony_ci		case SSHS_DO_UAR_SIG_PRESENT:
1085d4afb5ceSopenharmony_ci			lwsl_info("SSHS_DO_UAR_SIG_PRESENT\n");
1086d4afb5ceSopenharmony_ci			pss->ua->sig_present = (char)*p++;
1087d4afb5ceSopenharmony_ci			state_get_string_alloc(pss, SSHS_NVC_DO_UAR_ALG);
1088d4afb5ceSopenharmony_ci			/* destroyed with UA struct */
1089d4afb5ceSopenharmony_ci			break;
1090d4afb5ceSopenharmony_ci
1091d4afb5ceSopenharmony_ci		case SSHS_NVC_DO_UAR_ALG:
1092d4afb5ceSopenharmony_ci			pss->ua->alg = (char *)pss->last_alloc;
1093d4afb5ceSopenharmony_ci			pss->last_alloc = NULL; /* it was adopted */
1094d4afb5ceSopenharmony_ci			if (rsa_hash_alg_from_ident(pss->ua->alg) < 0) {
1095d4afb5ceSopenharmony_ci				lwsl_notice("unknown alg\n");
1096d4afb5ceSopenharmony_ci				goto ua_fail;
1097d4afb5ceSopenharmony_ci			}
1098d4afb5ceSopenharmony_ci			state_get_string_alloc(pss, SSHS_NVC_DO_UAR_PUBKEY_BLOB);
1099d4afb5ceSopenharmony_ci			/* destroyed with UA struct */
1100d4afb5ceSopenharmony_ci			break;
1101d4afb5ceSopenharmony_ci
1102d4afb5ceSopenharmony_ci		case SSHS_NVC_DO_UAR_PUBKEY_BLOB:
1103d4afb5ceSopenharmony_ci			pss->ua->pubkey = pss->last_alloc;
1104d4afb5ceSopenharmony_ci			pss->last_alloc = NULL; /* it was adopted */
1105d4afb5ceSopenharmony_ci			pss->ua->pubkey_len = pss->npos;
1106d4afb5ceSopenharmony_ci			/*
1107d4afb5ceSopenharmony_ci			 * RFC4253
1108d4afb5ceSopenharmony_ci			 *
1109d4afb5ceSopenharmony_ci			 * ssh-rsa
1110d4afb5ceSopenharmony_ci			 *
1111d4afb5ceSopenharmony_ci			 * The structure inside the blob is
1112d4afb5ceSopenharmony_ci			 *
1113d4afb5ceSopenharmony_ci			 *   mpint e
1114d4afb5ceSopenharmony_ci			 *   mpint n
1115d4afb5ceSopenharmony_ci			 *
1116d4afb5ceSopenharmony_ci			 * Let's see if this key is authorized
1117d4afb5ceSopenharmony_ci			 */
1118d4afb5ceSopenharmony_ci
1119d4afb5ceSopenharmony_ci			n = 1;
1120d4afb5ceSopenharmony_ci			if (pss->vhd->ops && pss->vhd->ops->is_pubkey_authorized)
1121d4afb5ceSopenharmony_ci				n = pss->vhd->ops->is_pubkey_authorized(
1122d4afb5ceSopenharmony_ci					pss->ua->username, pss->ua->alg,
1123d4afb5ceSopenharmony_ci					pss->ua->pubkey, (int)pss->ua->pubkey_len);
1124d4afb5ceSopenharmony_ci			if (n) {
1125d4afb5ceSopenharmony_ci				lwsl_info("rejecting peer pubkey\n");
1126d4afb5ceSopenharmony_ci				goto ua_fail;
1127d4afb5ceSopenharmony_ci			}
1128d4afb5ceSopenharmony_ci
1129d4afb5ceSopenharmony_ci			if (pss->ua->sig_present) {
1130d4afb5ceSopenharmony_ci				state_get_string_alloc(pss, SSHS_NVC_DO_UAR_SIG);
1131d4afb5ceSopenharmony_ci				/* destroyed with UA struct */
1132d4afb5ceSopenharmony_ci				break;
1133d4afb5ceSopenharmony_ci			}
1134d4afb5ceSopenharmony_ci
1135d4afb5ceSopenharmony_ci			/*
1136d4afb5ceSopenharmony_ci			 * This key is at least one we would be prepared
1137d4afb5ceSopenharmony_ci			 * to accept if he really has it... since no sig
1138d4afb5ceSopenharmony_ci			 * client should resend everything with a sig
1139d4afb5ceSopenharmony_ci			 * appended.  OK it and delete this initial UA
1140d4afb5ceSopenharmony_ci			 */
1141d4afb5ceSopenharmony_ci			write_task(pss, NULL, SSH_WT_UA_PK_OK);
1142d4afb5ceSopenharmony_ci			pss->parser_state = SSHS_MSG_EAT_PADDING;
1143d4afb5ceSopenharmony_ci			break;
1144d4afb5ceSopenharmony_ci
1145d4afb5ceSopenharmony_ci		case SSHS_NVC_DO_UAR_SIG:
1146d4afb5ceSopenharmony_ci			/*
1147d4afb5ceSopenharmony_ci			 * Now the pubkey is coming with a sig
1148d4afb5ceSopenharmony_ci			 */
1149d4afb5ceSopenharmony_ci			/* Sect 5.1 RFC4252
1150d4afb5ceSopenharmony_ci			 *
1151d4afb5ceSopenharmony_ci			 * SSH_MSG_USERAUTH_SUCCESS MUST be sent only once.
1152d4afb5ceSopenharmony_ci			 * When SSH_MSG_USERAUTH_SUCCESS has been sent, any
1153d4afb5ceSopenharmony_ci			 * further authentication requests received after that
1154d4afb5ceSopenharmony_ci			 * SHOULD be silently ignored.
1155d4afb5ceSopenharmony_ci			 */
1156d4afb5ceSopenharmony_ci			if (pss->ssh_auth_state == SSH_AUTH_STATE_GAVE_AUTH_IGNORE_REQS) {
1157d4afb5ceSopenharmony_ci				lwsl_info("Silently ignoring auth req after accepted\n");
1158d4afb5ceSopenharmony_ci				goto ua_fail_silently;
1159d4afb5ceSopenharmony_ci			}
1160d4afb5ceSopenharmony_ci			lwsl_info("SSHS_DO_UAR_SIG\n");
1161d4afb5ceSopenharmony_ci			pss->ua->sig = pss->last_alloc;
1162d4afb5ceSopenharmony_ci			pss->last_alloc = NULL; /* it was adopted */
1163d4afb5ceSopenharmony_ci			pss->ua->sig_len = pss->npos;
1164d4afb5ceSopenharmony_ci			pss->parser_state = SSHS_MSG_EAT_PADDING;
1165d4afb5ceSopenharmony_ci
1166d4afb5ceSopenharmony_ci			/*
1167d4afb5ceSopenharmony_ci			 *   RFC 4252 p9
1168d4afb5ceSopenharmony_ci			 *
1169d4afb5ceSopenharmony_ci			 *   The value of 'signature' is a signature with
1170d4afb5ceSopenharmony_ci			 *   the private host key of the following data, in
1171d4afb5ceSopenharmony_ci			 *   this order:
1172d4afb5ceSopenharmony_ci			 *
1173d4afb5ceSopenharmony_ci			 *      string    session identifier
1174d4afb5ceSopenharmony_ci			 *      byte      SSH_MSG_USERAUTH_REQUEST
1175d4afb5ceSopenharmony_ci			 *      string    user name
1176d4afb5ceSopenharmony_ci			 *      string    service name
1177d4afb5ceSopenharmony_ci			 *      string    "publickey"
1178d4afb5ceSopenharmony_ci			 *      boolean   TRUE
1179d4afb5ceSopenharmony_ci			 *      string    public key algorithm name
1180d4afb5ceSopenharmony_ci			 *      string    public key to be used for auth
1181d4afb5ceSopenharmony_ci			 *
1182d4afb5ceSopenharmony_ci			 * We reproduce the signature plaintext and the
1183d4afb5ceSopenharmony_ci			 * hash, and then decrypt the incoming signed block.
1184d4afb5ceSopenharmony_ci			 * What comes out is some ASN1, in there is the
1185d4afb5ceSopenharmony_ci			 * hash decrypted.  We find it and confirm it
1186d4afb5ceSopenharmony_ci			 * matches the hash we computed ourselves.
1187d4afb5ceSopenharmony_ci			 *
1188d4afb5ceSopenharmony_ci			 * First step is generate the sig plaintext
1189d4afb5ceSopenharmony_ci			 */
1190d4afb5ceSopenharmony_ci			n = 4 + 32 +
1191d4afb5ceSopenharmony_ci			    1 +
1192d4afb5ceSopenharmony_ci			    4 + (int)strlen(pss->ua->username) +
1193d4afb5ceSopenharmony_ci			    4 + (int)strlen(pss->ua->service) +
1194d4afb5ceSopenharmony_ci			    4 + 9 +
1195d4afb5ceSopenharmony_ci			    1 +
1196d4afb5ceSopenharmony_ci			    4 + (int)strlen(pss->ua->alg) +
1197d4afb5ceSopenharmony_ci			    4 + (int)pss->ua->pubkey_len;
1198d4afb5ceSopenharmony_ci
1199d4afb5ceSopenharmony_ci			ps = sshd_zalloc((unsigned int)n);
1200d4afb5ceSopenharmony_ci			if (!ps) {
1201d4afb5ceSopenharmony_ci				lwsl_notice("OOM 4\n");
1202d4afb5ceSopenharmony_ci				goto ua_fail;
1203d4afb5ceSopenharmony_ci			}
1204d4afb5ceSopenharmony_ci
1205d4afb5ceSopenharmony_ci			pp = ps;
1206d4afb5ceSopenharmony_ci			lws_buf(&pp, pss->session_id, 32);
1207d4afb5ceSopenharmony_ci			*pp++ = SSH_MSG_USERAUTH_REQUEST;
1208d4afb5ceSopenharmony_ci			lws_cstr(&pp, pss->ua->username, 64);
1209d4afb5ceSopenharmony_ci			lws_cstr(&pp, pss->ua->service, 64);
1210d4afb5ceSopenharmony_ci			lws_cstr(&pp, "publickey", 64);
1211d4afb5ceSopenharmony_ci			*pp++ = 1;
1212d4afb5ceSopenharmony_ci			lws_cstr(&pp, pss->ua->alg, 64);
1213d4afb5ceSopenharmony_ci			lws_buf(&pp, pss->ua->pubkey, pss->ua->pubkey_len);
1214d4afb5ceSopenharmony_ci
1215d4afb5ceSopenharmony_ci			/* Next hash the plaintext */
1216d4afb5ceSopenharmony_ci
1217d4afb5ceSopenharmony_ci			if (lws_genhash_init(&pss->ua->hash_ctx,
1218d4afb5ceSopenharmony_ci				(enum lws_genhash_types)rsa_hash_alg_from_ident(pss->ua->alg))) {
1219d4afb5ceSopenharmony_ci				lwsl_notice("genhash init failed\n");
1220d4afb5ceSopenharmony_ci				free(ps);
1221d4afb5ceSopenharmony_ci				goto ua_fail;
1222d4afb5ceSopenharmony_ci			}
1223d4afb5ceSopenharmony_ci
1224d4afb5ceSopenharmony_ci			if (lws_genhash_update(&pss->ua->hash_ctx, ps, lws_ptr_diff_size_t(pp, ps))) {
1225d4afb5ceSopenharmony_ci				lwsl_notice("genhash update failed\n");
1226d4afb5ceSopenharmony_ci				free(ps);
1227d4afb5ceSopenharmony_ci				goto ua_fail;
1228d4afb5ceSopenharmony_ci			}
1229d4afb5ceSopenharmony_ci			lws_genhash_destroy(&pss->ua->hash_ctx, hash);
1230d4afb5ceSopenharmony_ci			free(ps);
1231d4afb5ceSopenharmony_ci
1232d4afb5ceSopenharmony_ci			/*
1233d4afb5ceSopenharmony_ci			 * Prepare the RSA decryption context: load in
1234d4afb5ceSopenharmony_ci			 * the E and N factors
1235d4afb5ceSopenharmony_ci			 */
1236d4afb5ceSopenharmony_ci
1237d4afb5ceSopenharmony_ci			memset(e, 0, sizeof(e));
1238d4afb5ceSopenharmony_ci			pp = pss->ua->pubkey;
1239d4afb5ceSopenharmony_ci			m = lws_g32(&pp);
1240d4afb5ceSopenharmony_ci			pp += m;
1241d4afb5ceSopenharmony_ci			m = lws_g32(&pp);
1242d4afb5ceSopenharmony_ci			e[LWS_GENCRYPTO_RSA_KEYEL_E].buf = pp;
1243d4afb5ceSopenharmony_ci			e[LWS_GENCRYPTO_RSA_KEYEL_E].len = m;
1244d4afb5ceSopenharmony_ci			pp += m;
1245d4afb5ceSopenharmony_ci			m = lws_g32(&pp);
1246d4afb5ceSopenharmony_ci			e[LWS_GENCRYPTO_RSA_KEYEL_N].buf = pp;
1247d4afb5ceSopenharmony_ci			e[LWS_GENCRYPTO_RSA_KEYEL_N].len = m;
1248d4afb5ceSopenharmony_ci
1249d4afb5ceSopenharmony_ci			if (lws_genrsa_create(&ctx, e, pss->vhd->context,
1250d4afb5ceSopenharmony_ci					      LGRSAM_PKCS1_1_5,
1251d4afb5ceSopenharmony_ci					      LWS_GENHASH_TYPE_UNKNOWN))
1252d4afb5ceSopenharmony_ci				goto ua_fail;
1253d4afb5ceSopenharmony_ci			/*
1254d4afb5ceSopenharmony_ci			 * point to the encrypted signature payload we
1255d4afb5ceSopenharmony_ci			 * were sent
1256d4afb5ceSopenharmony_ci			 */
1257d4afb5ceSopenharmony_ci			pp = pss->ua->sig;
1258d4afb5ceSopenharmony_ci			m = lws_g32(&pp);
1259d4afb5ceSopenharmony_ci			pp += m;
1260d4afb5ceSopenharmony_ci			m = lws_g32(&pp);
1261d4afb5ceSopenharmony_ci#if !defined(MBEDTLS_VERSION_NUMBER) || MBEDTLS_VERSION_NUMBER < 0x03000000
1262d4afb5ceSopenharmony_ci
1263d4afb5ceSopenharmony_ci			/*
1264d4afb5ceSopenharmony_ci			 * decrypt it, resulting in an error, or some ASN1
1265d4afb5ceSopenharmony_ci			 * including the decrypted signature
1266d4afb5ceSopenharmony_ci			 */
1267d4afb5ceSopenharmony_ci			otmp = sshd_zalloc(m);
1268d4afb5ceSopenharmony_ci			if (!otmp)
1269d4afb5ceSopenharmony_ci				/* ua_fail1 frees bn_e, bn_n and rsa */
1270d4afb5ceSopenharmony_ci				goto ua_fail1;
1271d4afb5ceSopenharmony_ci
1272d4afb5ceSopenharmony_ci			n = lws_genrsa_public_decrypt(&ctx, pp, m, otmp, m);
1273d4afb5ceSopenharmony_ci			if (n > 0) {
1274d4afb5ceSopenharmony_ci				/* the decrypted sig is in ASN1 format */
1275d4afb5ceSopenharmony_ci				m = 0;
1276d4afb5ceSopenharmony_ci				while ((int)m < n) {
1277d4afb5ceSopenharmony_ci					/* sig payload */
1278d4afb5ceSopenharmony_ci					if (otmp[m] == 0x04 &&
1279d4afb5ceSopenharmony_ci					    otmp[m + 1] == lws_genhash_size(
1280d4afb5ceSopenharmony_ci						  pss->ua->hash_ctx.type)) {
1281d4afb5ceSopenharmony_ci						m = (uint32_t)memcmp(&otmp[m + 2], hash,
1282d4afb5ceSopenharmony_ci							(unsigned int)lws_genhash_size(pss->ua->hash_ctx.type));
1283d4afb5ceSopenharmony_ci						break;
1284d4afb5ceSopenharmony_ci					}
1285d4afb5ceSopenharmony_ci					/* go into these */
1286d4afb5ceSopenharmony_ci					if (otmp[m] == 0x30) {
1287d4afb5ceSopenharmony_ci						m += 2;
1288d4afb5ceSopenharmony_ci						continue;
1289d4afb5ceSopenharmony_ci					}
1290d4afb5ceSopenharmony_ci					/* otherwise skip payloads */
1291d4afb5ceSopenharmony_ci					m += (uint32_t)(otmp[m + 1] + 2);
1292d4afb5ceSopenharmony_ci				}
1293d4afb5ceSopenharmony_ci			}
1294d4afb5ceSopenharmony_ci
1295d4afb5ceSopenharmony_ci			free(otmp);
1296d4afb5ceSopenharmony_ci		#else
1297d4afb5ceSopenharmony_ci			ctx.ctx->MBEDTLS_PRIVATE(len) = m;
1298d4afb5ceSopenharmony_ci			n = lws_genrsa_hash_sig_verify(&ctx, hash,
1299d4afb5ceSopenharmony_ci				(enum lws_genhash_types)rsa_hash_alg_from_ident(pss->ua->alg),
1300d4afb5ceSopenharmony_ci				pp, m) == 0 ? 1 : 0;
1301d4afb5ceSopenharmony_ci		#endif
1302d4afb5ceSopenharmony_ci			lws_genrsa_destroy(&ctx);
1303d4afb5ceSopenharmony_ci
1304d4afb5ceSopenharmony_ci			/*
1305d4afb5ceSopenharmony_ci			 * if no good, m is nonzero and inform peer
1306d4afb5ceSopenharmony_ci			 */
1307d4afb5ceSopenharmony_ci			if (n <= 0) {
1308d4afb5ceSopenharmony_ci				lwsl_notice("hash sig verify fail: %d\n", m);
1309d4afb5ceSopenharmony_ci				goto ua_fail;
1310d4afb5ceSopenharmony_ci			}
1311d4afb5ceSopenharmony_ci
1312d4afb5ceSopenharmony_ci			/* if it checks out, inform peer */
1313d4afb5ceSopenharmony_ci
1314d4afb5ceSopenharmony_ci			lwsl_info("sig check OK\n");
1315d4afb5ceSopenharmony_ci
1316d4afb5ceSopenharmony_ci			/* Sect 5.1 RFC4252
1317d4afb5ceSopenharmony_ci			 *
1318d4afb5ceSopenharmony_ci			 * SSH_MSG_USERAUTH_SUCCESS MUST be sent only once.
1319d4afb5ceSopenharmony_ci			 * When SSH_MSG_USERAUTH_SUCCESS has been sent, any
1320d4afb5ceSopenharmony_ci			 * further authentication requests received after that
1321d4afb5ceSopenharmony_ci			 * SHOULD be silently ignored.
1322d4afb5ceSopenharmony_ci			 */
1323d4afb5ceSopenharmony_ci			pss->ssh_auth_state = SSH_AUTH_STATE_GAVE_AUTH_IGNORE_REQS;
1324d4afb5ceSopenharmony_ci
1325d4afb5ceSopenharmony_ci			write_task(pss, NULL, SSH_WT_UA_SUCCESS);
1326d4afb5ceSopenharmony_ci			lws_ua_destroy(pss);
1327d4afb5ceSopenharmony_ci			break;
1328d4afb5ceSopenharmony_ci
1329d4afb5ceSopenharmony_ci			/*
1330d4afb5ceSopenharmony_ci			 * Channels
1331d4afb5ceSopenharmony_ci			 */
1332d4afb5ceSopenharmony_ci
1333d4afb5ceSopenharmony_ci		case SSHS_GET_U32:
1334d4afb5ceSopenharmony_ci			pss->len = (pss->len << 8) | *p++;
1335d4afb5ceSopenharmony_ci                        if (++pss->ctr != 4)
1336d4afb5ceSopenharmony_ci                                break;
1337d4afb5ceSopenharmony_ci                        pss->ctr = 0;
1338d4afb5ceSopenharmony_ci			pss->parser_state = pss->state_after_string;
1339d4afb5ceSopenharmony_ci			goto again;
1340d4afb5ceSopenharmony_ci
1341d4afb5ceSopenharmony_ci			/*
1342d4afb5ceSopenharmony_ci			 * Channel: Disconnect
1343d4afb5ceSopenharmony_ci			 */
1344d4afb5ceSopenharmony_ci
1345d4afb5ceSopenharmony_ci		case SSHS_NVC_DISCONNECT_REASON:
1346d4afb5ceSopenharmony_ci			pss->disconnect_reason = pss->len;
1347d4afb5ceSopenharmony_ci			state_get_string_alloc(pss, SSHS_NVC_DISCONNECT_DESC);
1348d4afb5ceSopenharmony_ci			break;
1349d4afb5ceSopenharmony_ci
1350d4afb5ceSopenharmony_ci		case SSHS_NVC_DISCONNECT_DESC:
1351d4afb5ceSopenharmony_ci			pss->disconnect_desc = (char *)pss->last_alloc;
1352d4afb5ceSopenharmony_ci			pss->last_alloc = NULL; /* it was adopted */
1353d4afb5ceSopenharmony_ci			state_get_string(pss, SSHS_NVC_DISCONNECT_LANG);
1354d4afb5ceSopenharmony_ci			break;
1355d4afb5ceSopenharmony_ci
1356d4afb5ceSopenharmony_ci		case SSHS_NVC_DISCONNECT_LANG:
1357d4afb5ceSopenharmony_ci			lwsl_notice("SSHS_NVC_DISCONNECT_LANG\n");
1358d4afb5ceSopenharmony_ci			if (pss->vhd->ops && pss->vhd->ops->disconnect_reason)
1359d4afb5ceSopenharmony_ci				pss->vhd->ops->disconnect_reason(
1360d4afb5ceSopenharmony_ci					pss->disconnect_reason,
1361d4afb5ceSopenharmony_ci					pss->disconnect_desc, pss->name);
1362d4afb5ceSopenharmony_ci			ssh_free_set_NULL(pss->last_alloc);
1363d4afb5ceSopenharmony_ci			break;
1364d4afb5ceSopenharmony_ci
1365d4afb5ceSopenharmony_ci			/*
1366d4afb5ceSopenharmony_ci			 * Channel: Open
1367d4afb5ceSopenharmony_ci			 */
1368d4afb5ceSopenharmony_ci
1369d4afb5ceSopenharmony_ci		case SSHS_NVC_CHOPEN_TYPE:
1370d4afb5ceSopenharmony_ci			/* channel open */
1371d4afb5ceSopenharmony_ci			if (strcmp(pss->name, "session")) {
1372d4afb5ceSopenharmony_ci				lwsl_notice("Failing on not session\n");
1373d4afb5ceSopenharmony_ci				pss->reason = 3;
1374d4afb5ceSopenharmony_ci				goto ch_fail;
1375d4afb5ceSopenharmony_ci			}
1376d4afb5ceSopenharmony_ci			lwsl_info("SSHS_NVC_CHOPEN_TYPE: creating session\n");
1377d4afb5ceSopenharmony_ci			pss->ch_temp = sshd_zalloc(sizeof(*pss->ch_temp));
1378d4afb5ceSopenharmony_ci			if (!pss->ch_temp)
1379d4afb5ceSopenharmony_ci				return -1;
1380d4afb5ceSopenharmony_ci
1381d4afb5ceSopenharmony_ci			pss->ch_temp->type = SSH_CH_TYPE_SESSION;
1382d4afb5ceSopenharmony_ci			pss->ch_temp->pss = pss;
1383d4afb5ceSopenharmony_ci			state_get_u32(pss, SSHS_NVC_CHOPEN_SENDER_CH);
1384d4afb5ceSopenharmony_ci			break;
1385d4afb5ceSopenharmony_ci
1386d4afb5ceSopenharmony_ci		case SSHS_NVC_CHOPEN_SENDER_CH:
1387d4afb5ceSopenharmony_ci			pss->ch_temp->sender_ch = pss->len;
1388d4afb5ceSopenharmony_ci			state_get_u32(pss, SSHS_NVC_CHOPEN_WINSIZE);
1389d4afb5ceSopenharmony_ci			break;
1390d4afb5ceSopenharmony_ci		case SSHS_NVC_CHOPEN_WINSIZE:
1391d4afb5ceSopenharmony_ci			lwsl_info("Initial window set to %d\n", pss->len);
1392d4afb5ceSopenharmony_ci			pss->ch_temp->window = (int32_t)pss->len;
1393d4afb5ceSopenharmony_ci			state_get_u32(pss, SSHS_NVC_CHOPEN_PKTSIZE);
1394d4afb5ceSopenharmony_ci			break;
1395d4afb5ceSopenharmony_ci		case SSHS_NVC_CHOPEN_PKTSIZE:
1396d4afb5ceSopenharmony_ci			pss->ch_temp->max_pkt = pss->len;
1397d4afb5ceSopenharmony_ci			pss->ch_temp->peer_window_est = LWS_SSH_INITIAL_WINDOW;
1398d4afb5ceSopenharmony_ci			pss->ch_temp->server_ch = (uint32_t)pss->next_ch_num++;
1399d4afb5ceSopenharmony_ci			/*
1400d4afb5ceSopenharmony_ci			 * add us to channel list... leave as ch_temp
1401d4afb5ceSopenharmony_ci			 * as write task needs it and will NULL down
1402d4afb5ceSopenharmony_ci			 */
1403d4afb5ceSopenharmony_ci			lwsl_info("creating new session ch\n");
1404d4afb5ceSopenharmony_ci			pss->ch_temp->next = pss->ch_list;
1405d4afb5ceSopenharmony_ci			pss->ch_list = pss->ch_temp;
1406d4afb5ceSopenharmony_ci			if (pss->vhd->ops && pss->vhd->ops->channel_create)
1407d4afb5ceSopenharmony_ci				pss->vhd->ops->channel_create(pss->wsi,
1408d4afb5ceSopenharmony_ci						&pss->ch_temp->priv);
1409d4afb5ceSopenharmony_ci			write_task(pss, pss->ch_temp, SSH_WT_CH_OPEN_CONF);
1410d4afb5ceSopenharmony_ci			pss->parser_state = SSHS_MSG_EAT_PADDING;
1411d4afb5ceSopenharmony_ci			break;
1412d4afb5ceSopenharmony_ci
1413d4afb5ceSopenharmony_ci		/*
1414d4afb5ceSopenharmony_ci		 * SSH_MSG_CHANNEL_REQUEST
1415d4afb5ceSopenharmony_ci		 */
1416d4afb5ceSopenharmony_ci
1417d4afb5ceSopenharmony_ci		case SSHS_NVC_CHRQ_RECIP:
1418d4afb5ceSopenharmony_ci			pss->ch_recip = pss->len;
1419d4afb5ceSopenharmony_ci			state_get_string(pss, SSHS_NVC_CHRQ_TYPE);
1420d4afb5ceSopenharmony_ci			break;
1421d4afb5ceSopenharmony_ci
1422d4afb5ceSopenharmony_ci		case SSHS_NVC_CHRQ_TYPE:
1423d4afb5ceSopenharmony_ci			pss->parser_state = SSHS_CHRQ_WANT_REPLY;
1424d4afb5ceSopenharmony_ci			break;
1425d4afb5ceSopenharmony_ci
1426d4afb5ceSopenharmony_ci		case SSHS_CHRQ_WANT_REPLY:
1427d4afb5ceSopenharmony_ci			pss->rq_want_reply = *p++;
1428d4afb5ceSopenharmony_ci			lwsl_info("SSHS_CHRQ_WANT_REPLY: %s, wantrep: %d\n",
1429d4afb5ceSopenharmony_ci					pss->name, pss->rq_want_reply);
1430d4afb5ceSopenharmony_ci
1431d4afb5ceSopenharmony_ci			pss->ch_temp = ssh_get_server_ch(pss, pss->ch_recip);
1432d4afb5ceSopenharmony_ci
1433d4afb5ceSopenharmony_ci			/* after this they differ by the request */
1434d4afb5ceSopenharmony_ci
1435d4afb5ceSopenharmony_ci			/*
1436d4afb5ceSopenharmony_ci			 * a PTY for a shell
1437d4afb5ceSopenharmony_ci			 */
1438d4afb5ceSopenharmony_ci			if (!strcmp(pss->name, "pty-req")) {
1439d4afb5ceSopenharmony_ci				state_get_string(pss, SSHS_NVC_CHRQ_TERM);
1440d4afb5ceSopenharmony_ci				break;
1441d4afb5ceSopenharmony_ci			}
1442d4afb5ceSopenharmony_ci			/*
1443d4afb5ceSopenharmony_ci			 * a shell
1444d4afb5ceSopenharmony_ci			 */
1445d4afb5ceSopenharmony_ci			if (!strcmp(pss->name, "shell")) {
1446d4afb5ceSopenharmony_ci				pss->channel_doing_spawn = pss->ch_temp->server_ch;
1447d4afb5ceSopenharmony_ci				if (pss->vhd->ops && pss->vhd->ops->shell &&
1448d4afb5ceSopenharmony_ci				    !pss->vhd->ops->shell(pss->ch_temp->priv,
1449d4afb5ceSopenharmony_ci						          pss->wsi,
1450d4afb5ceSopenharmony_ci						 lws_ssh_exec_finish, pss->ch_temp)) {
1451d4afb5ceSopenharmony_ci
1452d4afb5ceSopenharmony_ci					if (pss->rq_want_reply)
1453d4afb5ceSopenharmony_ci						write_task_insert(pss, pss->ch_temp,
1454d4afb5ceSopenharmony_ci							   SSH_WT_CHRQ_SUCC);
1455d4afb5ceSopenharmony_ci					pss->parser_state = SSHS_MSG_EAT_PADDING;
1456d4afb5ceSopenharmony_ci					break;
1457d4afb5ceSopenharmony_ci				}
1458d4afb5ceSopenharmony_ci
1459d4afb5ceSopenharmony_ci				goto chrq_fail;
1460d4afb5ceSopenharmony_ci			}
1461d4afb5ceSopenharmony_ci			/*
1462d4afb5ceSopenharmony_ci			 * env vars to be set in the shell
1463d4afb5ceSopenharmony_ci			 */
1464d4afb5ceSopenharmony_ci			if (!strcmp(pss->name, "env")) {
1465d4afb5ceSopenharmony_ci				state_get_string(pss, SSHS_NVC_CHRQ_ENV_NAME);
1466d4afb5ceSopenharmony_ci				break;
1467d4afb5ceSopenharmony_ci			}
1468d4afb5ceSopenharmony_ci
1469d4afb5ceSopenharmony_ci			/*
1470d4afb5ceSopenharmony_ci			 * exec something
1471d4afb5ceSopenharmony_ci			 */
1472d4afb5ceSopenharmony_ci			if (!strcmp(pss->name, "exec")) {
1473d4afb5ceSopenharmony_ci				state_get_string_alloc(pss, SSHS_NVC_CHRQ_EXEC_CMD);
1474d4afb5ceSopenharmony_ci				break;
1475d4afb5ceSopenharmony_ci			}
1476d4afb5ceSopenharmony_ci
1477d4afb5ceSopenharmony_ci			/*
1478d4afb5ceSopenharmony_ci			 * spawn a subsystem
1479d4afb5ceSopenharmony_ci			 */
1480d4afb5ceSopenharmony_ci			if (!strcmp(pss->name, "subsystem")) {
1481d4afb5ceSopenharmony_ci				lwsl_notice("subsystem\n");
1482d4afb5ceSopenharmony_ci				state_get_string_alloc(pss,
1483d4afb5ceSopenharmony_ci						       SSHS_NVC_CHRQ_SUBSYSTEM);
1484d4afb5ceSopenharmony_ci				break;
1485d4afb5ceSopenharmony_ci			}
1486d4afb5ceSopenharmony_ci			if (!strcmp(pss->name, "window-change")) {
1487d4afb5ceSopenharmony_ci				lwsl_info("%s: window-change\n", __func__);
1488d4afb5ceSopenharmony_ci				state_get_u32(pss,
1489d4afb5ceSopenharmony_ci					      SSHS_NVC_CHRQ_WNDCHANGE_TW);
1490d4afb5ceSopenharmony_ci				break;
1491d4afb5ceSopenharmony_ci			}
1492d4afb5ceSopenharmony_ci
1493d4afb5ceSopenharmony_ci			if (pss->rq_want_reply)
1494d4afb5ceSopenharmony_ci				goto chrq_fail;
1495d4afb5ceSopenharmony_ci
1496d4afb5ceSopenharmony_ci			pss->parser_state = SSH_KEX_STATE_SKIP;
1497d4afb5ceSopenharmony_ci			break;
1498d4afb5ceSopenharmony_ci
1499d4afb5ceSopenharmony_ci		/* CHRQ pty-req */
1500d4afb5ceSopenharmony_ci
1501d4afb5ceSopenharmony_ci		case SSHS_NVC_CHRQ_TERM:
1502d4afb5ceSopenharmony_ci			memcpy(pss->args.pty.term, pss->name,
1503d4afb5ceSopenharmony_ci				sizeof(pss->args.pty.term) - 1);
1504d4afb5ceSopenharmony_ci			state_get_u32(pss, SSHS_NVC_CHRQ_TW);
1505d4afb5ceSopenharmony_ci			break;
1506d4afb5ceSopenharmony_ci		case SSHS_NVC_CHRQ_TW:
1507d4afb5ceSopenharmony_ci			pss->args.pty.width_ch = pss->len;
1508d4afb5ceSopenharmony_ci			state_get_u32(pss, SSHS_NVC_CHRQ_TH);
1509d4afb5ceSopenharmony_ci			break;
1510d4afb5ceSopenharmony_ci		case SSHS_NVC_CHRQ_TH:
1511d4afb5ceSopenharmony_ci			pss->args.pty.height_ch = pss->len;
1512d4afb5ceSopenharmony_ci			state_get_u32(pss, SSHS_NVC_CHRQ_TWP);
1513d4afb5ceSopenharmony_ci			break;
1514d4afb5ceSopenharmony_ci		case SSHS_NVC_CHRQ_TWP:
1515d4afb5ceSopenharmony_ci			pss->args.pty.width_px = pss->len;
1516d4afb5ceSopenharmony_ci			state_get_u32(pss, SSHS_NVC_CHRQ_THP);
1517d4afb5ceSopenharmony_ci			break;
1518d4afb5ceSopenharmony_ci		case SSHS_NVC_CHRQ_THP:
1519d4afb5ceSopenharmony_ci			pss->args.pty.height_px = pss->len;
1520d4afb5ceSopenharmony_ci			state_get_string_alloc(pss, SSHS_NVC_CHRQ_MODES);
1521d4afb5ceSopenharmony_ci			break;
1522d4afb5ceSopenharmony_ci		case SSHS_NVC_CHRQ_MODES:
1523d4afb5ceSopenharmony_ci			/* modes is a stream of byte-pairs, not a string */
1524d4afb5ceSopenharmony_ci			pss->args.pty.modes = (char *)pss->last_alloc;
1525d4afb5ceSopenharmony_ci			pss->last_alloc = NULL; /* it was adopted */
1526d4afb5ceSopenharmony_ci			pss->args.pty.modes_len = pss->npos;
1527d4afb5ceSopenharmony_ci			n = 0;
1528d4afb5ceSopenharmony_ci			if (pss->vhd->ops && pss->vhd->ops->pty_req)
1529d4afb5ceSopenharmony_ci				n = pss->vhd->ops->pty_req(pss->ch_temp->priv,
1530d4afb5ceSopenharmony_ci							&pss->args.pty);
1531d4afb5ceSopenharmony_ci			ssh_free_set_NULL(pss->args.pty.modes);
1532d4afb5ceSopenharmony_ci			if (n)
1533d4afb5ceSopenharmony_ci				goto chrq_fail;
1534d4afb5ceSopenharmony_ci			if (pss->rq_want_reply)
1535d4afb5ceSopenharmony_ci				write_task(pss, pss->ch_temp, SSH_WT_CHRQ_SUCC);
1536d4afb5ceSopenharmony_ci			pss->parser_state = SSHS_MSG_EAT_PADDING;
1537d4afb5ceSopenharmony_ci			break;
1538d4afb5ceSopenharmony_ci
1539d4afb5ceSopenharmony_ci		/* CHRQ env */
1540d4afb5ceSopenharmony_ci
1541d4afb5ceSopenharmony_ci		case SSHS_NVC_CHRQ_ENV_NAME:
1542d4afb5ceSopenharmony_ci			strcpy(pss->args.aux, pss->name);
1543d4afb5ceSopenharmony_ci			state_get_string(pss, SSHS_NVC_CHRQ_ENV_VALUE);
1544d4afb5ceSopenharmony_ci			break;
1545d4afb5ceSopenharmony_ci
1546d4afb5ceSopenharmony_ci		case SSHS_NVC_CHRQ_ENV_VALUE:
1547d4afb5ceSopenharmony_ci			if (pss->vhd->ops && pss->vhd->ops->set_env)
1548d4afb5ceSopenharmony_ci				if (pss->vhd->ops->set_env(pss->ch_temp->priv,
1549d4afb5ceSopenharmony_ci						pss->args.aux, pss->name))
1550d4afb5ceSopenharmony_ci					goto chrq_fail;
1551d4afb5ceSopenharmony_ci			pss->parser_state = SSHS_MSG_EAT_PADDING;
1552d4afb5ceSopenharmony_ci			break;
1553d4afb5ceSopenharmony_ci
1554d4afb5ceSopenharmony_ci		/* CHRQ exec */
1555d4afb5ceSopenharmony_ci
1556d4afb5ceSopenharmony_ci		case SSHS_NVC_CHRQ_EXEC_CMD:
1557d4afb5ceSopenharmony_ci			/*
1558d4afb5ceSopenharmony_ci			 * byte      SSH_MSG_CHANNEL_REQUEST
1559d4afb5ceSopenharmony_ci			 * uint32    recipient channel
1560d4afb5ceSopenharmony_ci			 * string    "exec"
1561d4afb5ceSopenharmony_ci			 * boolean   want reply
1562d4afb5ceSopenharmony_ci			 * string    command
1563d4afb5ceSopenharmony_ci			 *
1564d4afb5ceSopenharmony_ci			 * This message will request that the server start the
1565d4afb5ceSopenharmony_ci			 * execution of the given command.  The 'command' string
1566d4afb5ceSopenharmony_ci			 * may contain a path.  Normal precautions MUST be taken
1567d4afb5ceSopenharmony_ci			 * to prevent the execution of unauthorized commands.
1568d4afb5ceSopenharmony_ci			 *
1569d4afb5ceSopenharmony_ci			 * scp sends "scp -t /path/..."
1570d4afb5ceSopenharmony_ci			 */
1571d4afb5ceSopenharmony_ci			lwsl_info("exec cmd: %s %02X\n", pss->last_alloc, *p);
1572d4afb5ceSopenharmony_ci
1573d4afb5ceSopenharmony_ci			pss->channel_doing_spawn = pss->ch_temp->server_ch;
1574d4afb5ceSopenharmony_ci
1575d4afb5ceSopenharmony_ci			if (pss->vhd->ops && pss->vhd->ops->exec &&
1576d4afb5ceSopenharmony_ci			    !pss->vhd->ops->exec(pss->ch_temp->priv, pss->wsi,
1577d4afb5ceSopenharmony_ci					    	 (const char *)pss->last_alloc,
1578d4afb5ceSopenharmony_ci						 lws_ssh_exec_finish, pss->ch_temp)) {
1579d4afb5ceSopenharmony_ci				ssh_free_set_NULL(pss->last_alloc);
1580d4afb5ceSopenharmony_ci				if (pss->rq_want_reply)
1581d4afb5ceSopenharmony_ci					write_task_insert(pss, pss->ch_temp,
1582d4afb5ceSopenharmony_ci						   SSH_WT_CHRQ_SUCC);
1583d4afb5ceSopenharmony_ci
1584d4afb5ceSopenharmony_ci				pss->parser_state = SSHS_MSG_EAT_PADDING;
1585d4afb5ceSopenharmony_ci				break;
1586d4afb5ceSopenharmony_ci			}
1587d4afb5ceSopenharmony_ci
1588d4afb5ceSopenharmony_ci			/*
1589d4afb5ceSopenharmony_ci			 * even if he doesn't want to exec it, we know how to
1590d4afb5ceSopenharmony_ci			 * fake scp
1591d4afb5ceSopenharmony_ci			 */
1592d4afb5ceSopenharmony_ci
1593d4afb5ceSopenharmony_ci			/* we only alloc "exec" of scp for scp destination */
1594d4afb5ceSopenharmony_ci			n = 1;
1595d4afb5ceSopenharmony_ci			if (pss->last_alloc[0] != 's' ||
1596d4afb5ceSopenharmony_ci			    pss->last_alloc[1] != 'c' ||
1597d4afb5ceSopenharmony_ci			    pss->last_alloc[2] != 'p' ||
1598d4afb5ceSopenharmony_ci			    pss->last_alloc[3] != ' ')
1599d4afb5ceSopenharmony_ci				/* disallow it */
1600d4afb5ceSopenharmony_ci				n = 0;
1601d4afb5ceSopenharmony_ci
1602d4afb5ceSopenharmony_ci			ssh_free_set_NULL(pss->last_alloc);
1603d4afb5ceSopenharmony_ci			if (!n)
1604d4afb5ceSopenharmony_ci				goto chrq_fail;
1605d4afb5ceSopenharmony_ci
1606d4afb5ceSopenharmony_ci			/* our channel speaks SCP protocol now */
1607d4afb5ceSopenharmony_ci
1608d4afb5ceSopenharmony_ci			scp = sshd_zalloc(sizeof(*scp));
1609d4afb5ceSopenharmony_ci			if (!scp)
1610d4afb5ceSopenharmony_ci				return -1;
1611d4afb5ceSopenharmony_ci
1612d4afb5ceSopenharmony_ci			pss->ch_temp->type = SSH_CH_TYPE_SCP;
1613d4afb5ceSopenharmony_ci			pss->ch_temp->sub = (lws_subprotocol *)scp;
1614d4afb5ceSopenharmony_ci
1615d4afb5ceSopenharmony_ci			scp->ips = SSHS_SCP_COLLECTSTR;
1616d4afb5ceSopenharmony_ci
1617d4afb5ceSopenharmony_ci			if (pss->rq_want_reply)
1618d4afb5ceSopenharmony_ci				write_task(pss, pss->ch_temp, SSH_WT_CHRQ_SUCC);
1619d4afb5ceSopenharmony_ci
1620d4afb5ceSopenharmony_ci			/* we start the scp protocol first by sending an ACK */
1621d4afb5ceSopenharmony_ci			write_task(pss, pss->ch_temp, SSH_WT_SCP_ACK_OKAY);
1622d4afb5ceSopenharmony_ci
1623d4afb5ceSopenharmony_ci			pss->parser_state = SSHS_MSG_EAT_PADDING;
1624d4afb5ceSopenharmony_ci			break;
1625d4afb5ceSopenharmony_ci
1626d4afb5ceSopenharmony_ci		case SSHS_NVC_CHRQ_SUBSYSTEM:
1627d4afb5ceSopenharmony_ci			lwsl_notice("subsystem: %s", pss->last_alloc);
1628d4afb5ceSopenharmony_ci			n = 0;
1629d4afb5ceSopenharmony_ci#if 0
1630d4afb5ceSopenharmony_ci			if (!strcmp(pss->name, "sftp")) {
1631d4afb5ceSopenharmony_ci				lwsl_notice("SFTP session\n");
1632d4afb5ceSopenharmony_ci				pss->ch_temp->type = SSH_CH_TYPE_SFTP;
1633d4afb5ceSopenharmony_ci				n = 1;
1634d4afb5ceSopenharmony_ci			}
1635d4afb5ceSopenharmony_ci#endif
1636d4afb5ceSopenharmony_ci			ssh_free_set_NULL(pss->last_alloc);
1637d4afb5ceSopenharmony_ci//			if (!n)
1638d4afb5ceSopenharmony_ci				goto ch_fail;
1639d4afb5ceSopenharmony_ci#if 0
1640d4afb5ceSopenharmony_ci			if (pss->rq_want_reply)
1641d4afb5ceSopenharmony_ci				write_task(pss, ssh_get_server_ch(pss,
1642d4afb5ceSopenharmony_ci					pss->ch_recip), SSH_WT_CHRQ_SUCC);
1643d4afb5ceSopenharmony_ci			pss->parser_state = SSHS_MSG_EAT_PADDING;
1644d4afb5ceSopenharmony_ci			break;
1645d4afb5ceSopenharmony_ci#endif
1646d4afb5ceSopenharmony_ci
1647d4afb5ceSopenharmony_ci		/* CHRQ window-change */
1648d4afb5ceSopenharmony_ci
1649d4afb5ceSopenharmony_ci	case SSHS_NVC_CHRQ_WNDCHANGE_TW:
1650d4afb5ceSopenharmony_ci		pss->args.pty.width_ch = pss->len;
1651d4afb5ceSopenharmony_ci		state_get_u32(pss, SSHS_NVC_CHRQ_WNDCHANGE_TH);
1652d4afb5ceSopenharmony_ci		break;
1653d4afb5ceSopenharmony_ci        case SSHS_NVC_CHRQ_WNDCHANGE_TH:
1654d4afb5ceSopenharmony_ci		pss->args.pty.height_ch = pss->len;
1655d4afb5ceSopenharmony_ci		state_get_u32(pss, SSHS_NVC_CHRQ_WNDCHANGE_TWP);
1656d4afb5ceSopenharmony_ci		break;
1657d4afb5ceSopenharmony_ci        case SSHS_NVC_CHRQ_WNDCHANGE_TWP:
1658d4afb5ceSopenharmony_ci		pss->args.pty.width_px = pss->len;
1659d4afb5ceSopenharmony_ci		state_get_u32(pss, SSHS_NVC_CHRQ_WNDCHANGE_THP);
1660d4afb5ceSopenharmony_ci		break;
1661d4afb5ceSopenharmony_ci        case SSHS_NVC_CHRQ_WNDCHANGE_THP:
1662d4afb5ceSopenharmony_ci		pss->args.pty.height_px = pss->len;
1663d4afb5ceSopenharmony_ci		pss->args.pty.term[0] = 0;
1664d4afb5ceSopenharmony_ci		pss->args.pty.modes = NULL;
1665d4afb5ceSopenharmony_ci		pss->args.pty.modes_len = 0;
1666d4afb5ceSopenharmony_ci		n = 0;
1667d4afb5ceSopenharmony_ci		if (pss->vhd->ops && pss->vhd->ops->pty_req)
1668d4afb5ceSopenharmony_ci			n = pss->vhd->ops->pty_req(pss->ch_temp->priv,
1669d4afb5ceSopenharmony_ci						   &pss->args.pty);
1670d4afb5ceSopenharmony_ci		if (n)
1671d4afb5ceSopenharmony_ci			goto chrq_fail;
1672d4afb5ceSopenharmony_ci		pss->parser_state = SSHS_MSG_EAT_PADDING;
1673d4afb5ceSopenharmony_ci		break;
1674d4afb5ceSopenharmony_ci
1675d4afb5ceSopenharmony_ci		/* SSH_MSG_CHANNEL_DATA */
1676d4afb5ceSopenharmony_ci
1677d4afb5ceSopenharmony_ci		case SSHS_NVC_CD_RECIP:
1678d4afb5ceSopenharmony_ci			pss->ch_recip = pss->len;
1679d4afb5ceSopenharmony_ci
1680d4afb5ceSopenharmony_ci			ch = ssh_get_server_ch(pss, pss->ch_recip);
1681d4afb5ceSopenharmony_ci			ch->peer_window_est -= (int32_t)pss->msg_len;
1682d4afb5ceSopenharmony_ci
1683d4afb5ceSopenharmony_ci			if (pss->msg_len < sizeof(pss->name))
1684d4afb5ceSopenharmony_ci				state_get_string(pss, SSHS_NVC_CD_DATA);
1685d4afb5ceSopenharmony_ci			else
1686d4afb5ceSopenharmony_ci				state_get_string_alloc(pss,
1687d4afb5ceSopenharmony_ci					SSHS_NVC_CD_DATA_ALLOC);
1688d4afb5ceSopenharmony_ci			break;
1689d4afb5ceSopenharmony_ci
1690d4afb5ceSopenharmony_ci		case SSHS_NVC_CD_DATA_ALLOC:
1691d4afb5ceSopenharmony_ci		case SSHS_NVC_CD_DATA:
1692d4afb5ceSopenharmony_ci			/*
1693d4afb5ceSopenharmony_ci			 * Actual protocol incoming payload
1694d4afb5ceSopenharmony_ci			 */
1695d4afb5ceSopenharmony_ci			if (pss->parser_state == SSHS_NVC_CD_DATA_ALLOC)
1696d4afb5ceSopenharmony_ci				pp = pss->last_alloc;
1697d4afb5ceSopenharmony_ci			else
1698d4afb5ceSopenharmony_ci				pp = (uint8_t *)pss->name;
1699d4afb5ceSopenharmony_ci			lwsl_info("SSHS_NVC_CD_DATA\n");
1700d4afb5ceSopenharmony_ci
1701d4afb5ceSopenharmony_ci			ch = ssh_get_server_ch(pss, pss->ch_recip);
1702d4afb5ceSopenharmony_ci			switch (ch->type) {
1703d4afb5ceSopenharmony_ci			case SSH_CH_TYPE_SCP:
1704d4afb5ceSopenharmony_ci				scp = &ch->sub->scp;
1705d4afb5ceSopenharmony_ci				switch (scp->ips) {
1706d4afb5ceSopenharmony_ci				case SSHS_SCP_COLLECTSTR:
1707d4afb5ceSopenharmony_ci					/* gather the ascii-coded headers */
1708d4afb5ceSopenharmony_ci					for (n = 0; n < (int)pss->npos; n++)
1709d4afb5ceSopenharmony_ci						lwsl_notice("0x%02X %c\n",
1710d4afb5ceSopenharmony_ci							    pp[n], pp[n]);
1711d4afb5ceSopenharmony_ci
1712d4afb5ceSopenharmony_ci					/* Header triggers the transfer? */
1713d4afb5ceSopenharmony_ci					if (pp[0] == 'C' && pp[pss->npos - 1] == '\x0a') {
1714d4afb5ceSopenharmony_ci						while (*pp != ' ' && *pp != '\x0a')
1715d4afb5ceSopenharmony_ci							pp++;
1716d4afb5ceSopenharmony_ci						if (*pp++ != ' ') {
1717d4afb5ceSopenharmony_ci							write_task(pss, ch,
1718d4afb5ceSopenharmony_ci							   SSH_WT_SCP_ACK_ERROR);
1719d4afb5ceSopenharmony_ci							pss->parser_state = SSHS_MSG_EAT_PADDING;
1720d4afb5ceSopenharmony_ci							break;
1721d4afb5ceSopenharmony_ci						}
1722d4afb5ceSopenharmony_ci						scp->len = (uint64_t)atoll((const char *)pp);
1723d4afb5ceSopenharmony_ci						lwsl_notice("scp payload %llu expected\n",
1724d4afb5ceSopenharmony_ci							    (unsigned long long)scp->len);
1725d4afb5ceSopenharmony_ci						scp->ips = SSHS_SCP_PAYLOADIN;
1726d4afb5ceSopenharmony_ci					}
1727d4afb5ceSopenharmony_ci					/* ack it */
1728d4afb5ceSopenharmony_ci					write_task(pss, pss->ch_temp,
1729d4afb5ceSopenharmony_ci						   SSH_WT_SCP_ACK_OKAY);
1730d4afb5ceSopenharmony_ci					break;
1731d4afb5ceSopenharmony_ci				case SSHS_SCP_PAYLOADIN:
1732d4afb5ceSopenharmony_ci					/* the scp file payload */
1733d4afb5ceSopenharmony_ci					if (pss->vhd->ops)
1734d4afb5ceSopenharmony_ci						pss->vhd->ops->rx(ch->priv,
1735d4afb5ceSopenharmony_ci							pss->wsi, pp, pss->npos);
1736d4afb5ceSopenharmony_ci					if (scp->len >= pss->npos)
1737d4afb5ceSopenharmony_ci						scp->len -= pss->npos;
1738d4afb5ceSopenharmony_ci					else
1739d4afb5ceSopenharmony_ci						scp->len = 0;
1740d4afb5ceSopenharmony_ci					if (!scp->len) {
1741d4afb5ceSopenharmony_ci						lwsl_notice("scp txfer completed\n");
1742d4afb5ceSopenharmony_ci						scp->ips = SSHS_SCP_COLLECTSTR;
1743d4afb5ceSopenharmony_ci						break;
1744d4afb5ceSopenharmony_ci					}
1745d4afb5ceSopenharmony_ci					break;
1746d4afb5ceSopenharmony_ci				}
1747d4afb5ceSopenharmony_ci				break;
1748d4afb5ceSopenharmony_ci			default: /* scp payload */
1749d4afb5ceSopenharmony_ci				if (pss->vhd->ops)
1750d4afb5ceSopenharmony_ci					pss->vhd->ops->rx(ch->priv, pss->wsi,
1751d4afb5ceSopenharmony_ci							  pp, pss->npos);
1752d4afb5ceSopenharmony_ci				break;
1753d4afb5ceSopenharmony_ci			}
1754d4afb5ceSopenharmony_ci			if (pss->parser_state == SSHS_NVC_CD_DATA_ALLOC)
1755d4afb5ceSopenharmony_ci				ssh_free_set_NULL(pss->last_alloc);
1756d4afb5ceSopenharmony_ci
1757d4afb5ceSopenharmony_ci			if (ch->peer_window_est < 32768) {
1758d4afb5ceSopenharmony_ci				write_task(pss, ch, SSH_WT_WINDOW_ADJUST);
1759d4afb5ceSopenharmony_ci				ch->peer_window_est += 32768;
1760d4afb5ceSopenharmony_ci				lwsl_info("extra peer WINDOW_ADJUST (~ %d)\n",
1761d4afb5ceSopenharmony_ci					    ch->peer_window_est);
1762d4afb5ceSopenharmony_ci			}
1763d4afb5ceSopenharmony_ci
1764d4afb5ceSopenharmony_ci			pss->parser_state = SSHS_MSG_EAT_PADDING;
1765d4afb5ceSopenharmony_ci			break;
1766d4afb5ceSopenharmony_ci
1767d4afb5ceSopenharmony_ci		case SSHS_NVC_WA_RECIP:
1768d4afb5ceSopenharmony_ci			pss->ch_recip = pss->len;
1769d4afb5ceSopenharmony_ci			state_get_u32(pss, SSHS_NVC_WA_ADD);
1770d4afb5ceSopenharmony_ci			break;
1771d4afb5ceSopenharmony_ci
1772d4afb5ceSopenharmony_ci		case SSHS_NVC_WA_ADD:
1773d4afb5ceSopenharmony_ci			ch = ssh_get_server_ch(pss, pss->ch_recip);
1774d4afb5ceSopenharmony_ci			if (ch) {
1775d4afb5ceSopenharmony_ci				ch->window += (int32_t)pss->len;
1776d4afb5ceSopenharmony_ci				lwsl_notice("got additional window %d (now %d)\n",
1777d4afb5ceSopenharmony_ci						pss->len, ch->window);
1778d4afb5ceSopenharmony_ci			}
1779d4afb5ceSopenharmony_ci			pss->parser_state = SSHS_MSG_EAT_PADDING;
1780d4afb5ceSopenharmony_ci			break;
1781d4afb5ceSopenharmony_ci
1782d4afb5ceSopenharmony_ci			/*
1783d4afb5ceSopenharmony_ci			 *  channel close
1784d4afb5ceSopenharmony_ci			 */
1785d4afb5ceSopenharmony_ci
1786d4afb5ceSopenharmony_ci		case SSHS_NVC_CH_EOF:
1787d4afb5ceSopenharmony_ci			/*
1788d4afb5ceSopenharmony_ci			 * No explicit response is sent to this
1789d4afb5ceSopenharmony_ci			 * message.  However, the application may send
1790d4afb5ceSopenharmony_ci			 * EOF to whatever is at the other end of the
1791d4afb5ceSopenharmony_ci			 * channel.  Note that the channel remains open
1792d4afb5ceSopenharmony_ci			 * after this message, and more data may still
1793d4afb5ceSopenharmony_ci			 * be sent in the other direction.  This message
1794d4afb5ceSopenharmony_ci			 * does not consume window space and can be sent
1795d4afb5ceSopenharmony_ci			 * even if no window space is available.
1796d4afb5ceSopenharmony_ci			 */
1797d4afb5ceSopenharmony_ci			lwsl_notice("SSH_MSG_CHANNEL_EOF: %d\n", pss->ch_recip);
1798d4afb5ceSopenharmony_ci			ch = ssh_get_server_ch(pss, pss->ch_recip);
1799d4afb5ceSopenharmony_ci			if (!ch) {
1800d4afb5ceSopenharmony_ci				lwsl_notice("unknown ch %d\n", pss->ch_recip);
1801d4afb5ceSopenharmony_ci				return -1;
1802d4afb5ceSopenharmony_ci			}
1803d4afb5ceSopenharmony_ci
1804d4afb5ceSopenharmony_ci			if (!ch->scheduled_close) {
1805d4afb5ceSopenharmony_ci				lwsl_notice("scheduling CLOSE\n");
1806d4afb5ceSopenharmony_ci				ch->scheduled_close = 1;
1807d4afb5ceSopenharmony_ci				write_task(pss, ch, SSH_WT_CH_CLOSE);
1808d4afb5ceSopenharmony_ci			}
1809d4afb5ceSopenharmony_ci			pss->parser_state = SSHS_MSG_EAT_PADDING;
1810d4afb5ceSopenharmony_ci			break;
1811d4afb5ceSopenharmony_ci
1812d4afb5ceSopenharmony_ci		case SSHS_NVC_CH_CLOSE:
1813d4afb5ceSopenharmony_ci			/*
1814d4afb5ceSopenharmony_ci			 * When either party wishes to terminate the
1815d4afb5ceSopenharmony_ci			 * channel, it sends SSH_MSG_CHANNEL_CLOSE.
1816d4afb5ceSopenharmony_ci			 * Upon receiving this message, a party MUST
1817d4afb5ceSopenharmony_ci			 * send back an SSH_MSG_CHANNEL_CLOSE unless it
1818d4afb5ceSopenharmony_ci			 * has already sent this message for the
1819d4afb5ceSopenharmony_ci			 * channel.  The channel is considered closed
1820d4afb5ceSopenharmony_ci			 * for a party when it has both sent and
1821d4afb5ceSopenharmony_ci			 * received SSH_MSG_CHANNEL_CLOSE, and the
1822d4afb5ceSopenharmony_ci			 * party may then reuse the channel number.
1823d4afb5ceSopenharmony_ci			 * A party MAY send SSH_MSG_CHANNEL_CLOSE
1824d4afb5ceSopenharmony_ci			 * without having sent or received
1825d4afb5ceSopenharmony_ci			 * SSH_MSG_CHANNEL_EOF.
1826d4afb5ceSopenharmony_ci			 */
1827d4afb5ceSopenharmony_ci			lwsl_notice("SSH_MSG_CHANNEL_CLOSE ch %d\n",
1828d4afb5ceSopenharmony_ci				    pss->ch_recip);
1829d4afb5ceSopenharmony_ci			ch = ssh_get_server_ch(pss, pss->ch_recip);
1830d4afb5ceSopenharmony_ci			if (!ch)
1831d4afb5ceSopenharmony_ci				goto bail;
1832d4afb5ceSopenharmony_ci
1833d4afb5ceSopenharmony_ci			pss->parser_state = SSHS_MSG_EAT_PADDING;
1834d4afb5ceSopenharmony_ci
1835d4afb5ceSopenharmony_ci			if (ch->sent_close) {
1836d4afb5ceSopenharmony_ci				/*
1837d4afb5ceSopenharmony_ci				 * This is acking our sent close...
1838d4afb5ceSopenharmony_ci				 * we can destroy the channel with no
1839d4afb5ceSopenharmony_ci				 * further communication.
1840d4afb5ceSopenharmony_ci				 */
1841d4afb5ceSopenharmony_ci				ssh_destroy_channel(pss, ch);
1842d4afb5ceSopenharmony_ci				break;
1843d4afb5ceSopenharmony_ci			}
1844d4afb5ceSopenharmony_ci
1845d4afb5ceSopenharmony_ci			ch->received_close = 1;
1846d4afb5ceSopenharmony_ci			ch->scheduled_close = 1;
1847d4afb5ceSopenharmony_ci			write_task(pss, ch, SSH_WT_CH_CLOSE);
1848d4afb5ceSopenharmony_ci			break;
1849d4afb5ceSopenharmony_ci
1850d4afb5ceSopenharmony_ci		default:
1851d4afb5ceSopenharmony_ci			break;
1852d4afb5ceSopenharmony_ci
1853d4afb5ceSopenharmony_cichrq_fail:
1854d4afb5ceSopenharmony_ci			lwsl_notice("chrq_fail\n");
1855d4afb5ceSopenharmony_ci			write_task(pss, pss->ch_temp, SSH_WT_CHRQ_FAILURE);
1856d4afb5ceSopenharmony_ci			pss->parser_state = SSH_KEX_STATE_SKIP;
1857d4afb5ceSopenharmony_ci			break;
1858d4afb5ceSopenharmony_ci
1859d4afb5ceSopenharmony_cich_fail:
1860d4afb5ceSopenharmony_ci			if (pss->ch_temp) {
1861d4afb5ceSopenharmony_ci				free(pss->ch_temp);
1862d4afb5ceSopenharmony_ci				pss->ch_temp = NULL;
1863d4afb5ceSopenharmony_ci			}
1864d4afb5ceSopenharmony_ci			write_task(pss, pss->ch_temp, SSH_WT_CH_FAILURE);
1865d4afb5ceSopenharmony_ci			pss->parser_state = SSH_KEX_STATE_SKIP;
1866d4afb5ceSopenharmony_ci			break;
1867d4afb5ceSopenharmony_ci
1868d4afb5ceSopenharmony_ci#if !defined(MBEDTLS_VERSION_NUMBER) || MBEDTLS_VERSION_NUMBER < 0x03000000
1869d4afb5ceSopenharmony_ciua_fail1:
1870d4afb5ceSopenharmony_ci#endif
1871d4afb5ceSopenharmony_ci			lws_genrsa_destroy(&ctx);
1872d4afb5ceSopenharmony_ciua_fail:
1873d4afb5ceSopenharmony_ci			write_task(pss, NULL, SSH_WT_UA_FAILURE);
1874d4afb5ceSopenharmony_ciua_fail_silently:
1875d4afb5ceSopenharmony_ci			lws_ua_destroy(pss);
1876d4afb5ceSopenharmony_ci			/* Sect 4, RFC4252
1877d4afb5ceSopenharmony_ci			 *
1878d4afb5ceSopenharmony_ci			 * Additionally, the implementation SHOULD limit the
1879d4afb5ceSopenharmony_ci			 * number of failed authentication attempts a client
1880d4afb5ceSopenharmony_ci			 * may perform in a single session (the RECOMMENDED
1881d4afb5ceSopenharmony_ci			 * limit is 20 attempts).  If the threshold is
1882d4afb5ceSopenharmony_ci			 * exceeded, the server SHOULD disconnect.
1883d4afb5ceSopenharmony_ci			 */
1884d4afb5ceSopenharmony_ci			if (pss->count_auth_attempts++ > 20)
1885d4afb5ceSopenharmony_ci				goto bail;
1886d4afb5ceSopenharmony_ci
1887d4afb5ceSopenharmony_ci			pss->parser_state = SSH_KEX_STATE_SKIP;
1888d4afb5ceSopenharmony_ci			break;
1889d4afb5ceSopenharmony_ci		}
1890d4afb5ceSopenharmony_ci
1891d4afb5ceSopenharmony_ci		pss->pos++;
1892d4afb5ceSopenharmony_ci	}
1893d4afb5ceSopenharmony_ci
1894d4afb5ceSopenharmony_ci	return 0;
1895d4afb5ceSopenharmony_cibail:
1896d4afb5ceSopenharmony_ci	lws_kex_destroy(pss);
1897d4afb5ceSopenharmony_ci	lws_ua_destroy(pss);
1898d4afb5ceSopenharmony_ci
1899d4afb5ceSopenharmony_ci	return SSH_DISCONNECT_KEY_EXCHANGE_FAILED;
1900d4afb5ceSopenharmony_ci}
1901d4afb5ceSopenharmony_ci
1902d4afb5ceSopenharmony_cistatic int
1903d4afb5ceSopenharmony_ciparse(struct per_session_data__sshd *pss, uint8_t *p, size_t len)
1904d4afb5ceSopenharmony_ci{
1905d4afb5ceSopenharmony_ci	while (len--) {
1906d4afb5ceSopenharmony_ci
1907d4afb5ceSopenharmony_ci		if (pss->copy_to_I_C && pss->kex->I_C_payload_len <
1908d4afb5ceSopenharmony_ci				pss->kex->I_C_alloc_len &&
1909d4afb5ceSopenharmony_ci				pss->parser_state != SSHS_MSG_EAT_PADDING)
1910d4afb5ceSopenharmony_ci			pss->kex->I_C[pss->kex->I_C_payload_len++] = *p;
1911d4afb5ceSopenharmony_ci
1912d4afb5ceSopenharmony_ci		if (pss->active_keys_cts.valid &&
1913d4afb5ceSopenharmony_ci		    pss->parser_state == SSHS_MSG_LEN)
1914d4afb5ceSopenharmony_ci			/* take a copy for full decrypt */
1915d4afb5ceSopenharmony_ci			pss->packet_assembly[pss->pa_pos++] = *p;
1916d4afb5ceSopenharmony_ci
1917d4afb5ceSopenharmony_ci		if (pss->active_keys_cts.valid &&
1918d4afb5ceSopenharmony_ci		    pss->parser_state == SSHS_MSG_PADDING &&
1919d4afb5ceSopenharmony_ci		    pss->msg_len) {
1920d4afb5ceSopenharmony_ci			/* we are going to have to decrypt it */
1921d4afb5ceSopenharmony_ci			uint32_t cp, l = pss->msg_len + 4 +
1922d4afb5ceSopenharmony_ci				pss->active_keys_cts.MAC_length;
1923d4afb5ceSopenharmony_ci			uint8_t pt[2048];
1924d4afb5ceSopenharmony_ci
1925d4afb5ceSopenharmony_ci			len++;
1926d4afb5ceSopenharmony_ci			cp = (uint32_t)len;
1927d4afb5ceSopenharmony_ci
1928d4afb5ceSopenharmony_ci			if (cp > l - pss->pa_pos)
1929d4afb5ceSopenharmony_ci				cp = l - pss->pa_pos;
1930d4afb5ceSopenharmony_ci
1931d4afb5ceSopenharmony_ci			if (cp > sizeof(pss->packet_assembly) -
1932d4afb5ceSopenharmony_ci					pss->pa_pos) {
1933d4afb5ceSopenharmony_ci				lwsl_err("Packet is too big to decrypt\n");
1934d4afb5ceSopenharmony_ci
1935d4afb5ceSopenharmony_ci				goto bail;
1936d4afb5ceSopenharmony_ci			}
1937d4afb5ceSopenharmony_ci			if (pss->msg_len < 2 + 4) {
1938d4afb5ceSopenharmony_ci				lwsl_err("packet too small\n");
1939d4afb5ceSopenharmony_ci
1940d4afb5ceSopenharmony_ci				goto bail;
1941d4afb5ceSopenharmony_ci			}
1942d4afb5ceSopenharmony_ci
1943d4afb5ceSopenharmony_ci			memcpy(&pss->packet_assembly[pss->pa_pos], p, cp);
1944d4afb5ceSopenharmony_ci			pss->pa_pos += cp;
1945d4afb5ceSopenharmony_ci			len -= cp;
1946d4afb5ceSopenharmony_ci			p += cp;
1947d4afb5ceSopenharmony_ci
1948d4afb5ceSopenharmony_ci			if (pss->pa_pos != l)
1949d4afb5ceSopenharmony_ci				return 0;
1950d4afb5ceSopenharmony_ci
1951d4afb5ceSopenharmony_ci			/* decrypt it */
1952d4afb5ceSopenharmony_ci			cp = (uint32_t)lws_chacha_decrypt(&pss->active_keys_cts,
1953d4afb5ceSopenharmony_ci					        pss->ssh_sequence_ctr_cts++,
1954d4afb5ceSopenharmony_ci					        pss->packet_assembly,
1955d4afb5ceSopenharmony_ci					        pss->pa_pos, pt);
1956d4afb5ceSopenharmony_ci			if (cp) {
1957d4afb5ceSopenharmony_ci				lwsl_notice("Decryption failed: %d\n", cp);
1958d4afb5ceSopenharmony_ci				goto bail;
1959d4afb5ceSopenharmony_ci			}
1960d4afb5ceSopenharmony_ci
1961d4afb5ceSopenharmony_ci			if (lws_ssh_parse_plaintext(pss, pt + 4, pss->msg_len))
1962d4afb5ceSopenharmony_ci				goto bail;
1963d4afb5ceSopenharmony_ci
1964d4afb5ceSopenharmony_ci			pss->pa_pos = 0;
1965d4afb5ceSopenharmony_ci			pss->ctr = 0;
1966d4afb5ceSopenharmony_ci			continue;
1967d4afb5ceSopenharmony_ci		}
1968d4afb5ceSopenharmony_ci
1969d4afb5ceSopenharmony_ci		if (lws_ssh_parse_plaintext(pss, p, 1))
1970d4afb5ceSopenharmony_ci			goto bail;
1971d4afb5ceSopenharmony_ci
1972d4afb5ceSopenharmony_ci		p++;
1973d4afb5ceSopenharmony_ci	}
1974d4afb5ceSopenharmony_ci
1975d4afb5ceSopenharmony_ci	return 0;
1976d4afb5ceSopenharmony_ci
1977d4afb5ceSopenharmony_cibail:
1978d4afb5ceSopenharmony_ci	lws_kex_destroy(pss);
1979d4afb5ceSopenharmony_ci	lws_ua_destroy(pss);
1980d4afb5ceSopenharmony_ci
1981d4afb5ceSopenharmony_ci	return SSH_DISCONNECT_KEY_EXCHANGE_FAILED;
1982d4afb5ceSopenharmony_ci}
1983d4afb5ceSopenharmony_ci
1984d4afb5ceSopenharmony_cistatic uint32_t
1985d4afb5ceSopenharmony_cipad_and_encrypt(uint8_t *dest, void *ps, uint8_t *pp,
1986d4afb5ceSopenharmony_ci		struct per_session_data__sshd *pss, int skip_pad)
1987d4afb5ceSopenharmony_ci{
1988d4afb5ceSopenharmony_ci	uint32_t n;
1989d4afb5ceSopenharmony_ci
1990d4afb5ceSopenharmony_ci	if (!skip_pad)
1991d4afb5ceSopenharmony_ci		lws_pad_set_length(pss, ps, &pp, &pss->active_keys_stc);
1992d4afb5ceSopenharmony_ci	n = (uint32_t)lws_ptr_diff(pp, ps);
1993d4afb5ceSopenharmony_ci
1994d4afb5ceSopenharmony_ci	if (!pss->active_keys_stc.valid) {
1995d4afb5ceSopenharmony_ci		memcpy(dest, ps, n);
1996d4afb5ceSopenharmony_ci		return n;
1997d4afb5ceSopenharmony_ci	}
1998d4afb5ceSopenharmony_ci
1999d4afb5ceSopenharmony_ci	lws_chacha_encrypt(&pss->active_keys_stc, pss->ssh_sequence_ctr_stc,
2000d4afb5ceSopenharmony_ci			   ps, n, dest);
2001d4afb5ceSopenharmony_ci	n += pss->active_keys_stc.MAC_length;
2002d4afb5ceSopenharmony_ci
2003d4afb5ceSopenharmony_ci	return n;
2004d4afb5ceSopenharmony_ci}
2005d4afb5ceSopenharmony_ci
2006d4afb5ceSopenharmony_cistatic int
2007d4afb5ceSopenharmony_cilws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason,
2008d4afb5ceSopenharmony_ci		      void *user, void *in, size_t len)
2009d4afb5ceSopenharmony_ci{
2010d4afb5ceSopenharmony_ci	struct per_session_data__sshd *pss =
2011d4afb5ceSopenharmony_ci			(struct per_session_data__sshd *)user, **p;
2012d4afb5ceSopenharmony_ci	struct per_vhost_data__sshd *vhd = NULL;
2013d4afb5ceSopenharmony_ci	uint8_t buf[LWS_PRE + 1024], *pp, *ps = &buf[LWS_PRE + 512], *ps1 = NULL;
2014d4afb5ceSopenharmony_ci	const struct lws_protocol_vhost_options *pvo;
2015d4afb5ceSopenharmony_ci	const struct lws_protocols *prot;
2016d4afb5ceSopenharmony_ci	struct lws_ssh_channel *ch;
2017d4afb5ceSopenharmony_ci	char lang[10] = "";
2018d4afb5ceSopenharmony_ci	int n, m, o;
2019d4afb5ceSopenharmony_ci
2020d4afb5ceSopenharmony_ci	/*
2021d4afb5ceSopenharmony_ci	 * Because we are an abstract protocol plugin, we will get called by
2022d4afb5ceSopenharmony_ci	 * wsi that actually bind to a plugin "on top of us" that calls thru
2023d4afb5ceSopenharmony_ci	 * to our callback.
2024d4afb5ceSopenharmony_ci	 *
2025d4afb5ceSopenharmony_ci	 * Under those circumstances, we can't simply get a pointer to our own
2026d4afb5ceSopenharmony_ci	 * protocol from the wsi.  If there's a pss already, we can get it from
2027d4afb5ceSopenharmony_ci	 * there, but the first time for each connection we have to look it up.
2028d4afb5ceSopenharmony_ci	 */
2029d4afb5ceSopenharmony_ci	if (pss && pss->vhd)
2030d4afb5ceSopenharmony_ci		vhd = (struct per_vhost_data__sshd *)
2031d4afb5ceSopenharmony_ci			lws_protocol_vh_priv_get(lws_get_vhost(wsi),
2032d4afb5ceSopenharmony_ci				pss->vhd->protocol);
2033d4afb5ceSopenharmony_ci	else
2034d4afb5ceSopenharmony_ci		if (lws_get_vhost(wsi))
2035d4afb5ceSopenharmony_ci			vhd = (struct per_vhost_data__sshd *)
2036d4afb5ceSopenharmony_ci				lws_protocol_vh_priv_get(lws_get_vhost(wsi),
2037d4afb5ceSopenharmony_ci				lws_vhost_name_to_protocol(
2038d4afb5ceSopenharmony_ci					lws_get_vhost(wsi), "lws-ssh-base"));
2039d4afb5ceSopenharmony_ci
2040d4afb5ceSopenharmony_ci	switch ((int)reason) {
2041d4afb5ceSopenharmony_ci	case LWS_CALLBACK_PROTOCOL_INIT:
2042d4afb5ceSopenharmony_ci		vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
2043d4afb5ceSopenharmony_ci						  lws_get_protocol(wsi),
2044d4afb5ceSopenharmony_ci						  sizeof(struct per_vhost_data__sshd));
2045d4afb5ceSopenharmony_ci		if (!vhd)
2046d4afb5ceSopenharmony_ci			return 0;
2047d4afb5ceSopenharmony_ci		vhd->context = lws_get_context(wsi);
2048d4afb5ceSopenharmony_ci		vhd->protocol = lws_get_protocol(wsi);
2049d4afb5ceSopenharmony_ci		vhd->vhost = lws_get_vhost(wsi);
2050d4afb5ceSopenharmony_ci
2051d4afb5ceSopenharmony_ci		pvo = (const struct lws_protocol_vhost_options *)in;
2052d4afb5ceSopenharmony_ci		while (pvo) {
2053d4afb5ceSopenharmony_ci			/*
2054d4afb5ceSopenharmony_ci			 * the user code passes the ops struct address to us
2055d4afb5ceSopenharmony_ci			 * using a pvo (per-vhost option)
2056d4afb5ceSopenharmony_ci			 */
2057d4afb5ceSopenharmony_ci			if (!strcmp(pvo->name, "ops"))
2058d4afb5ceSopenharmony_ci				vhd->ops = (const struct lws_ssh_ops *)pvo->value;
2059d4afb5ceSopenharmony_ci
2060d4afb5ceSopenharmony_ci			/*
2061d4afb5ceSopenharmony_ci			 * the user code is telling us to get the ops struct
2062d4afb5ceSopenharmony_ci			 * from another protocol's protocol.user pointer
2063d4afb5ceSopenharmony_ci			 */
2064d4afb5ceSopenharmony_ci			if (!strcmp(pvo->name, "ops-from")) {
2065d4afb5ceSopenharmony_ci				prot = lws_vhost_name_to_protocol(vhd->vhost,
2066d4afb5ceSopenharmony_ci								  pvo->value);
2067d4afb5ceSopenharmony_ci				if (prot)
2068d4afb5ceSopenharmony_ci					vhd->ops = (const struct lws_ssh_ops *)prot->user;
2069d4afb5ceSopenharmony_ci				else
2070d4afb5ceSopenharmony_ci					lwsl_err("%s: can't find protocol %s\n",
2071d4afb5ceSopenharmony_ci						    __func__, pvo->value);
2072d4afb5ceSopenharmony_ci			}
2073d4afb5ceSopenharmony_ci
2074d4afb5ceSopenharmony_ci			pvo = pvo->next;
2075d4afb5ceSopenharmony_ci		}
2076d4afb5ceSopenharmony_ci
2077d4afb5ceSopenharmony_ci		if (!vhd->ops) {
2078d4afb5ceSopenharmony_ci			lwsl_warn("ssh pvo \"ops\" is mandatory\n");
2079d4afb5ceSopenharmony_ci			return 0;
2080d4afb5ceSopenharmony_ci		}
2081d4afb5ceSopenharmony_ci		/*
2082d4afb5ceSopenharmony_ci		 * The user code ops api_version has to be current
2083d4afb5ceSopenharmony_ci		 */
2084d4afb5ceSopenharmony_ci		if (vhd->ops->api_version != LWS_SSH_OPS_VERSION) {
2085d4afb5ceSopenharmony_ci			lwsl_err("FATAL ops is api_version v%d but code is v%d\n",
2086d4afb5ceSopenharmony_ci				vhd->ops->api_version, LWS_SSH_OPS_VERSION);
2087d4afb5ceSopenharmony_ci			return 1;
2088d4afb5ceSopenharmony_ci		}
2089d4afb5ceSopenharmony_ci		break;
2090d4afb5ceSopenharmony_ci
2091d4afb5ceSopenharmony_ci        case LWS_CALLBACK_RAW_ADOPT:
2092d4afb5ceSopenharmony_ci		lwsl_info("LWS_CALLBACK_RAW_ADOPT\n");
2093d4afb5ceSopenharmony_ci		if (!vhd || !pss)
2094d4afb5ceSopenharmony_ci			return -1;
2095d4afb5ceSopenharmony_ci		pss->next = vhd->live_pss_list;
2096d4afb5ceSopenharmony_ci		vhd->live_pss_list = pss;
2097d4afb5ceSopenharmony_ci		pss->parser_state = SSH_INITIALIZE_TRANSIENT;
2098d4afb5ceSopenharmony_ci		pss->wsi = wsi;
2099d4afb5ceSopenharmony_ci		pss->vhd = vhd;
2100d4afb5ceSopenharmony_ci		pss->kex_state = KEX_STATE_EXPECTING_CLIENT_OFFER;
2101d4afb5ceSopenharmony_ci		pss->active_keys_cts.padding_alignment = 8;
2102d4afb5ceSopenharmony_ci		pss->active_keys_stc.padding_alignment = 8;
2103d4afb5ceSopenharmony_ci		if (lws_kex_create(pss))
2104d4afb5ceSopenharmony_ci			return -1;
2105d4afb5ceSopenharmony_ci		write_task(pss, NULL, SSH_WT_VERSION);
2106d4afb5ceSopenharmony_ci
2107d4afb5ceSopenharmony_ci		/* sect 4  RFC4252
2108d4afb5ceSopenharmony_ci		 *
2109d4afb5ceSopenharmony_ci		 * The server SHOULD have a timeout for authentication and
2110d4afb5ceSopenharmony_ci		 * disconnect if the authentication has not been accepted
2111d4afb5ceSopenharmony_ci		 * within the timeout period.
2112d4afb5ceSopenharmony_ci		 *
2113d4afb5ceSopenharmony_ci		 * The RECOMMENDED timeout period is 10 minutes.
2114d4afb5ceSopenharmony_ci		 */
2115d4afb5ceSopenharmony_ci		lws_set_timeout(wsi, (enum pending_timeout)
2116d4afb5ceSopenharmony_ci		       SSH_PENDING_TIMEOUT_CONNECT_TO_SUCCESSFUL_AUTH, 10 * 60);
2117d4afb5ceSopenharmony_ci                break;
2118d4afb5ceSopenharmony_ci
2119d4afb5ceSopenharmony_ci	case LWS_CALLBACK_RAW_CLOSE:
2120d4afb5ceSopenharmony_ci		if (!pss)
2121d4afb5ceSopenharmony_ci			return -1;
2122d4afb5ceSopenharmony_ci		lwsl_info("LWS_CALLBACK_RAW_CLOSE\n");
2123d4afb5ceSopenharmony_ci		lws_kex_destroy(pss);
2124d4afb5ceSopenharmony_ci		lws_ua_destroy(pss);
2125d4afb5ceSopenharmony_ci
2126d4afb5ceSopenharmony_ci		ssh_free_set_NULL(pss->last_alloc);
2127d4afb5ceSopenharmony_ci
2128d4afb5ceSopenharmony_ci		while (pss->ch_list)
2129d4afb5ceSopenharmony_ci			ssh_destroy_channel(pss, pss->ch_list);
2130d4afb5ceSopenharmony_ci
2131d4afb5ceSopenharmony_ci		lws_chacha_destroy(&pss->active_keys_cts);
2132d4afb5ceSopenharmony_ci		lws_chacha_destroy(&pss->active_keys_stc);
2133d4afb5ceSopenharmony_ci
2134d4afb5ceSopenharmony_ci		p = &vhd->live_pss_list;
2135d4afb5ceSopenharmony_ci
2136d4afb5ceSopenharmony_ci		while (*p) {
2137d4afb5ceSopenharmony_ci			if ((*p) == pss) {
2138d4afb5ceSopenharmony_ci				*p = pss->next;
2139d4afb5ceSopenharmony_ci				continue;
2140d4afb5ceSopenharmony_ci			}
2141d4afb5ceSopenharmony_ci			p = &((*p)->next);
2142d4afb5ceSopenharmony_ci		}
2143d4afb5ceSopenharmony_ci		break;
2144d4afb5ceSopenharmony_ci
2145d4afb5ceSopenharmony_ci	case LWS_CALLBACK_RAW_RX:
2146d4afb5ceSopenharmony_ci		if (!pss)
2147d4afb5ceSopenharmony_ci			return -1;
2148d4afb5ceSopenharmony_ci		if (parse(pss, in, len))
2149d4afb5ceSopenharmony_ci			return -1;
2150d4afb5ceSopenharmony_ci		break;
2151d4afb5ceSopenharmony_ci
2152d4afb5ceSopenharmony_ci	case LWS_CALLBACK_RAW_WRITEABLE:
2153d4afb5ceSopenharmony_ci		if (!pss)
2154d4afb5ceSopenharmony_ci			break;
2155d4afb5ceSopenharmony_ci		n = 0;
2156d4afb5ceSopenharmony_ci		o = pss->write_task[pss->wt_tail];
2157d4afb5ceSopenharmony_ci		ch = pss->write_channel[pss->wt_tail];
2158d4afb5ceSopenharmony_ci
2159d4afb5ceSopenharmony_ci		if (pss->wt_head == pss->wt_tail)
2160d4afb5ceSopenharmony_ci			o = SSH_WT_NONE;
2161d4afb5ceSopenharmony_ci
2162d4afb5ceSopenharmony_ci		switch (o) {
2163d4afb5ceSopenharmony_ci		case SSH_WT_VERSION:
2164d4afb5ceSopenharmony_ci			if (!pss->vhd)
2165d4afb5ceSopenharmony_ci				break;
2166d4afb5ceSopenharmony_ci			n = lws_snprintf((char *)buf + LWS_PRE,
2167d4afb5ceSopenharmony_ci					 sizeof(buf) - LWS_PRE - 1, "%s\r\n",
2168d4afb5ceSopenharmony_ci					 pss->vhd->ops->server_string);
2169d4afb5ceSopenharmony_ci			write_task(pss, NULL, SSH_WT_OFFER);
2170d4afb5ceSopenharmony_ci			break;
2171d4afb5ceSopenharmony_ci
2172d4afb5ceSopenharmony_ci		case SSH_WT_OFFER:
2173d4afb5ceSopenharmony_ci			if (!pss->vhd)
2174d4afb5ceSopenharmony_ci				break;
2175d4afb5ceSopenharmony_ci			m = 0;
2176d4afb5ceSopenharmony_ci			n = (int)offer(pss, buf + LWS_PRE,
2177d4afb5ceSopenharmony_ci				  sizeof(buf) - LWS_PRE, 0, &m);
2178d4afb5ceSopenharmony_ci			if (n == 0) {
2179d4afb5ceSopenharmony_ci				lwsl_notice("Too small\n");
2180d4afb5ceSopenharmony_ci
2181d4afb5ceSopenharmony_ci				return -1;
2182d4afb5ceSopenharmony_ci			}
2183d4afb5ceSopenharmony_ci
2184d4afb5ceSopenharmony_ci			if (!pss->kex) {
2185d4afb5ceSopenharmony_ci				lwsl_notice("%s: SSH_WT_OFFER: pss->kex is NULL\n",
2186d4afb5ceSopenharmony_ci					    __func__);
2187d4afb5ceSopenharmony_ci				return -1;
2188d4afb5ceSopenharmony_ci			}
2189d4afb5ceSopenharmony_ci
2190d4afb5ceSopenharmony_ci			/* we need a copy of it to generate the hash later */
2191d4afb5ceSopenharmony_ci			if (pss->kex->I_S)
2192d4afb5ceSopenharmony_ci				free(pss->kex->I_S);
2193d4afb5ceSopenharmony_ci			pss->kex->I_S = sshd_zalloc((unsigned int)m);
2194d4afb5ceSopenharmony_ci			if (!pss->kex->I_S) {
2195d4afb5ceSopenharmony_ci				lwsl_notice("OOM 5: %d\n", m);
2196d4afb5ceSopenharmony_ci
2197d4afb5ceSopenharmony_ci				return -1;
2198d4afb5ceSopenharmony_ci			}
2199d4afb5ceSopenharmony_ci			/* without length + padcount part */
2200d4afb5ceSopenharmony_ci			memcpy(pss->kex->I_S, buf + LWS_PRE + 5, (unsigned int)m);
2201d4afb5ceSopenharmony_ci			pss->kex->I_S_payload_len = (uint32_t)m; /* without padding */
2202d4afb5ceSopenharmony_ci			break;
2203d4afb5ceSopenharmony_ci
2204d4afb5ceSopenharmony_ci		case SSH_WT_OFFER_REPLY:
2205d4afb5ceSopenharmony_ci			memcpy(ps, pss->kex->kex_r, pss->kex->kex_r_len);
2206d4afb5ceSopenharmony_ci			n = (int)pad_and_encrypt(&buf[LWS_PRE], ps,
2207d4afb5ceSopenharmony_ci					    ps + pss->kex->kex_r_len, pss, 1);
2208d4afb5ceSopenharmony_ci			pss->kex_state = KEX_STATE_REPLIED_TO_OFFER;
2209d4afb5ceSopenharmony_ci			/* afterwards, must do newkeys */
2210d4afb5ceSopenharmony_ci			write_task(pss, NULL, SSH_WT_SEND_NEWKEYS);
2211d4afb5ceSopenharmony_ci			break;
2212d4afb5ceSopenharmony_ci
2213d4afb5ceSopenharmony_ci		case SSH_WT_SEND_NEWKEYS:
2214d4afb5ceSopenharmony_ci			pp = ps + 5;
2215d4afb5ceSopenharmony_ci			*pp++ = SSH_MSG_NEWKEYS;
2216d4afb5ceSopenharmony_ci			goto pac;
2217d4afb5ceSopenharmony_ci
2218d4afb5ceSopenharmony_ci		case SSH_WT_UA_ACCEPT:
2219d4afb5ceSopenharmony_ci			/*
2220d4afb5ceSopenharmony_ci			 *  If the server supports the service (and permits
2221d4afb5ceSopenharmony_ci			 *  the client to use it), it MUST respond with the
2222d4afb5ceSopenharmony_ci			 *  following:
2223d4afb5ceSopenharmony_ci			 *
2224d4afb5ceSopenharmony_ci			 *      byte      SSH_MSG_SERVICE_ACCEPT
2225d4afb5ceSopenharmony_ci			 *      string    service name
2226d4afb5ceSopenharmony_ci			 */
2227d4afb5ceSopenharmony_ci			pp = ps + 5;
2228d4afb5ceSopenharmony_ci			*pp++ = SSH_MSG_SERVICE_ACCEPT;
2229d4afb5ceSopenharmony_ci			lws_p32(pp, pss->npos);
2230d4afb5ceSopenharmony_ci			pp += 4;
2231d4afb5ceSopenharmony_ci			strcpy((char *)pp, pss->name);
2232d4afb5ceSopenharmony_ci			pp += pss->npos;
2233d4afb5ceSopenharmony_ci			goto pac;
2234d4afb5ceSopenharmony_ci
2235d4afb5ceSopenharmony_ci		case SSH_WT_UA_FAILURE:
2236d4afb5ceSopenharmony_ci			pp = ps + 5;
2237d4afb5ceSopenharmony_ci			*pp++ = SSH_MSG_USERAUTH_FAILURE;
2238d4afb5ceSopenharmony_ci			lws_p32(pp, 9);
2239d4afb5ceSopenharmony_ci			pp += 4;
2240d4afb5ceSopenharmony_ci			strcpy((char *)pp, "publickey");
2241d4afb5ceSopenharmony_ci			pp += 9;
2242d4afb5ceSopenharmony_ci			*pp++ = 0;
2243d4afb5ceSopenharmony_ci			goto pac;
2244d4afb5ceSopenharmony_ci
2245d4afb5ceSopenharmony_ci		case SSH_WT_UA_BANNER:
2246d4afb5ceSopenharmony_ci			pp = ps + 5;
2247d4afb5ceSopenharmony_ci			*pp++ = SSH_MSG_USERAUTH_BANNER;
2248d4afb5ceSopenharmony_ci			if (pss->vhd && pss->vhd->ops->banner)
2249d4afb5ceSopenharmony_ci				n = (int)pss->vhd->ops->banner((char *)&buf[650],
2250d4afb5ceSopenharmony_ci							  150 - 1,
2251d4afb5ceSopenharmony_ci							  lang, (int)sizeof(lang));
2252d4afb5ceSopenharmony_ci			lws_p32(pp, (uint32_t)n);
2253d4afb5ceSopenharmony_ci			pp += 4;
2254d4afb5ceSopenharmony_ci			strcpy((char *)pp, (char *)&buf[650]);
2255d4afb5ceSopenharmony_ci			pp += n;
2256d4afb5ceSopenharmony_ci			if (lws_cstr(&pp, lang, sizeof(lang)))
2257d4afb5ceSopenharmony_ci				goto bail;
2258d4afb5ceSopenharmony_ci			goto pac;
2259d4afb5ceSopenharmony_ci
2260d4afb5ceSopenharmony_ci		case SSH_WT_UA_PK_OK:
2261d4afb5ceSopenharmony_ci			/*
2262d4afb5ceSopenharmony_ci			 *  The server MUST respond to this message with
2263d4afb5ceSopenharmony_ci			 *  either SSH_MSG_USERAUTH_FAILURE or with the
2264d4afb5ceSopenharmony_ci			 *  following:
2265d4afb5ceSopenharmony_ci			 *
2266d4afb5ceSopenharmony_ci			 *    byte      SSH_MSG_USERAUTH_PK_OK
2267d4afb5ceSopenharmony_ci			 *    string    public key alg name from the request
2268d4afb5ceSopenharmony_ci			 *    string    public key blob from the request
2269d4afb5ceSopenharmony_ci      			 */
2270d4afb5ceSopenharmony_ci			n = 74 + (int)pss->ua->pubkey_len;
2271d4afb5ceSopenharmony_ci			if (n > (int)sizeof(buf) - LWS_PRE) {
2272d4afb5ceSopenharmony_ci				lwsl_notice("pubkey too large\n");
2273d4afb5ceSopenharmony_ci				goto bail;
2274d4afb5ceSopenharmony_ci			}
2275d4afb5ceSopenharmony_ci			ps1 = sshd_zalloc((unsigned int)n);
2276d4afb5ceSopenharmony_ci			if (!ps1)
2277d4afb5ceSopenharmony_ci				goto bail;
2278d4afb5ceSopenharmony_ci			ps = ps1;
2279d4afb5ceSopenharmony_ci			pp = ps1 + 5;
2280d4afb5ceSopenharmony_ci			*pp++ = SSH_MSG_USERAUTH_PK_OK;
2281d4afb5ceSopenharmony_ci			if (lws_cstr(&pp, pss->ua->alg, 64)) {
2282d4afb5ceSopenharmony_ci				free(ps1);
2283d4afb5ceSopenharmony_ci				goto bail;
2284d4afb5ceSopenharmony_ci			}
2285d4afb5ceSopenharmony_ci			lws_p32(pp, pss->ua->pubkey_len);
2286d4afb5ceSopenharmony_ci			pp += 4;
2287d4afb5ceSopenharmony_ci			memcpy(pp, pss->ua->pubkey, pss->ua->pubkey_len);
2288d4afb5ceSopenharmony_ci			pp += pss->ua->pubkey_len;
2289d4afb5ceSopenharmony_ci
2290d4afb5ceSopenharmony_ci			/* we no longer need the UA now we judged it */
2291d4afb5ceSopenharmony_ci			lws_ua_destroy(pss);
2292d4afb5ceSopenharmony_ci
2293d4afb5ceSopenharmony_ci			goto pac;
2294d4afb5ceSopenharmony_ci
2295d4afb5ceSopenharmony_ci		case SSH_WT_UA_SUCCESS:
2296d4afb5ceSopenharmony_ci			pp = ps + 5;
2297d4afb5ceSopenharmony_ci			*pp++ = SSH_MSG_USERAUTH_SUCCESS;
2298d4afb5ceSopenharmony_ci			/* end SSH_PENDING_TIMEOUT_CONNECT_TO_SUCCESSFUL_AUTH */
2299d4afb5ceSopenharmony_ci			lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
2300d4afb5ceSopenharmony_ci			goto pac;
2301d4afb5ceSopenharmony_ci
2302d4afb5ceSopenharmony_ci		case SSH_WT_CH_OPEN_CONF:
2303d4afb5ceSopenharmony_ci			pp = ps + 5;
2304d4afb5ceSopenharmony_ci			*pp++ = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
2305d4afb5ceSopenharmony_ci			lws_p32(pp, pss->ch_temp->sender_ch);
2306d4afb5ceSopenharmony_ci			pp += 4;
2307d4afb5ceSopenharmony_ci			lws_p32(pp, pss->ch_temp->server_ch);
2308d4afb5ceSopenharmony_ci			pp += 4;
2309d4afb5ceSopenharmony_ci			/* tx initial window size towards us */
2310d4afb5ceSopenharmony_ci			lws_p32(pp, LWS_SSH_INITIAL_WINDOW);
2311d4afb5ceSopenharmony_ci			pp += 4;
2312d4afb5ceSopenharmony_ci			/* maximum packet size towards us */
2313d4afb5ceSopenharmony_ci			lws_p32(pp, 800);
2314d4afb5ceSopenharmony_ci			pp += 4;
2315d4afb5ceSopenharmony_ci			lwsl_info("SSH_WT_CH_OPEN_CONF\n");
2316d4afb5ceSopenharmony_ci			/* it's on the linked-list */
2317d4afb5ceSopenharmony_ci			pss->ch_temp = NULL;
2318d4afb5ceSopenharmony_ci			goto pac;
2319d4afb5ceSopenharmony_ci
2320d4afb5ceSopenharmony_ci		case SSH_WT_CH_FAILURE:
2321d4afb5ceSopenharmony_ci			pp = ps + 5;
2322d4afb5ceSopenharmony_ci			*pp++ = SSH_MSG_CHANNEL_OPEN_FAILURE;
2323d4afb5ceSopenharmony_ci			lws_p32(pp, ch->sender_ch);
2324d4afb5ceSopenharmony_ci			pp += 4;
2325d4afb5ceSopenharmony_ci			lws_p32(pp, ch->server_ch);
2326d4afb5ceSopenharmony_ci			pp += 4;
2327d4afb5ceSopenharmony_ci			lws_cstr(&pp, "reason", 64);
2328d4afb5ceSopenharmony_ci			lws_cstr(&pp, "en/US", 64);
2329d4afb5ceSopenharmony_ci			lwsl_info("SSH_WT_CH_FAILURE\n");
2330d4afb5ceSopenharmony_ci			goto pac;
2331d4afb5ceSopenharmony_ci
2332d4afb5ceSopenharmony_ci		case SSH_WT_CHRQ_SUCC:
2333d4afb5ceSopenharmony_ci			pp = ps + 5;
2334d4afb5ceSopenharmony_ci			*pp++ = SSH_MSG_CHANNEL_SUCCESS;
2335d4afb5ceSopenharmony_ci			lws_p32(pp, ch->sender_ch);
2336d4afb5ceSopenharmony_ci			lwsl_info("SSH_WT_CHRQ_SUCC\n");
2337d4afb5ceSopenharmony_ci			pp += 4;
2338d4afb5ceSopenharmony_ci			goto pac;
2339d4afb5ceSopenharmony_ci
2340d4afb5ceSopenharmony_ci		case SSH_WT_CHRQ_FAILURE:
2341d4afb5ceSopenharmony_ci			pp = ps + 5;
2342d4afb5ceSopenharmony_ci			*pp++ = SSH_MSG_CHANNEL_FAILURE;
2343d4afb5ceSopenharmony_ci			lws_p32(pp, ch->sender_ch);
2344d4afb5ceSopenharmony_ci			pp += 4;
2345d4afb5ceSopenharmony_ci			lwsl_info("SSH_WT_CHRQ_FAILURE\n");
2346d4afb5ceSopenharmony_ci			goto pac;
2347d4afb5ceSopenharmony_ci
2348d4afb5ceSopenharmony_ci		case SSH_WT_CH_CLOSE:
2349d4afb5ceSopenharmony_ci			pp = ps + 5;
2350d4afb5ceSopenharmony_ci			*pp++ = SSH_MSG_CHANNEL_CLOSE;
2351d4afb5ceSopenharmony_ci			lws_p32(pp, ch->sender_ch);
2352d4afb5ceSopenharmony_ci			lwsl_info("SSH_WT_CH_CLOSE\n");
2353d4afb5ceSopenharmony_ci			pp += 4;
2354d4afb5ceSopenharmony_ci			goto pac;
2355d4afb5ceSopenharmony_ci
2356d4afb5ceSopenharmony_ci		case SSH_WT_CH_EOF:
2357d4afb5ceSopenharmony_ci			pp = ps + 5;
2358d4afb5ceSopenharmony_ci			*pp++ = SSH_MSG_CHANNEL_EOF;
2359d4afb5ceSopenharmony_ci			lws_p32(pp, ch->sender_ch);
2360d4afb5ceSopenharmony_ci			lwsl_info("SSH_WT_CH_EOF\n");
2361d4afb5ceSopenharmony_ci			pp += 4;
2362d4afb5ceSopenharmony_ci			goto pac;
2363d4afb5ceSopenharmony_ci
2364d4afb5ceSopenharmony_ci		case SSH_WT_SCP_ACK_ERROR:
2365d4afb5ceSopenharmony_ci		case SSH_WT_SCP_ACK_OKAY:
2366d4afb5ceSopenharmony_ci			pp = ps + 5;
2367d4afb5ceSopenharmony_ci			*pp++ = SSH_MSG_CHANNEL_DATA;
2368d4afb5ceSopenharmony_ci			/* ps + 6 */
2369d4afb5ceSopenharmony_ci			lws_p32(pp, ch->sender_ch);
2370d4afb5ceSopenharmony_ci			pp += 4;
2371d4afb5ceSopenharmony_ci			lws_p32(pp, 1);
2372d4afb5ceSopenharmony_ci			pp += 4;
2373d4afb5ceSopenharmony_ci			if (o == SSH_WT_SCP_ACK_ERROR)
2374d4afb5ceSopenharmony_ci				*pp++ = 2;
2375d4afb5ceSopenharmony_ci			else
2376d4afb5ceSopenharmony_ci				*pp++ = 0;
2377d4afb5ceSopenharmony_ci			lwsl_info("SSH_WT_SCP_ACK_OKAY\n");
2378d4afb5ceSopenharmony_ci			goto pac;
2379d4afb5ceSopenharmony_ci
2380d4afb5ceSopenharmony_ci		case SSH_WT_WINDOW_ADJUST:
2381d4afb5ceSopenharmony_ci			pp = ps + 5;
2382d4afb5ceSopenharmony_ci			*pp++ = SSH_MSG_CHANNEL_WINDOW_ADJUST;
2383d4afb5ceSopenharmony_ci			/* ps + 6 */
2384d4afb5ceSopenharmony_ci			lws_p32(pp, ch->sender_ch);
2385d4afb5ceSopenharmony_ci			pp += 4;
2386d4afb5ceSopenharmony_ci			lws_p32(pp, 32768);
2387d4afb5ceSopenharmony_ci			pp += 4;
2388d4afb5ceSopenharmony_ci			lwsl_info("send SSH_MSG_CHANNEL_WINDOW_ADJUST\n");
2389d4afb5ceSopenharmony_ci			goto pac;
2390d4afb5ceSopenharmony_ci
2391d4afb5ceSopenharmony_ci		case SSH_WT_EXIT_STATUS:
2392d4afb5ceSopenharmony_ci			pp = ps + 5;
2393d4afb5ceSopenharmony_ci			*pp++ = SSH_MSG_CHANNEL_REQUEST;
2394d4afb5ceSopenharmony_ci			lws_p32(pp, ch->sender_ch);
2395d4afb5ceSopenharmony_ci			pp += 4;
2396d4afb5ceSopenharmony_ci			lws_p32(pp, 11);
2397d4afb5ceSopenharmony_ci			pp += 4;
2398d4afb5ceSopenharmony_ci			strcpy((char *)pp, "exit-status");
2399d4afb5ceSopenharmony_ci			pp += 11;
2400d4afb5ceSopenharmony_ci			*pp++ = 0;
2401d4afb5ceSopenharmony_ci			lws_p32(pp, (uint32_t)ch->retcode);
2402d4afb5ceSopenharmony_ci			pp += 4;
2403d4afb5ceSopenharmony_ci			lwsl_info("send SSH_MSG_CHANNEL_EXIT_STATUS\n");
2404d4afb5ceSopenharmony_ci			goto pac;
2405d4afb5ceSopenharmony_ci
2406d4afb5ceSopenharmony_ci		case SSH_WT_NONE:
2407d4afb5ceSopenharmony_ci		default:
2408d4afb5ceSopenharmony_ci			/* sending payload */
2409d4afb5ceSopenharmony_ci
2410d4afb5ceSopenharmony_ci			ch = ssh_get_server_ch(pss, 0);
2411d4afb5ceSopenharmony_ci			/* have a channel up to send on? */
2412d4afb5ceSopenharmony_ci			if (!ch)
2413d4afb5ceSopenharmony_ci				break;
2414d4afb5ceSopenharmony_ci
2415d4afb5ceSopenharmony_ci			if (!pss->vhd || !pss->vhd->ops)
2416d4afb5ceSopenharmony_ci				break;
2417d4afb5ceSopenharmony_ci			n = pss->vhd->ops->tx_waiting(ch->priv);
2418d4afb5ceSopenharmony_ci			if (n < 0)
2419d4afb5ceSopenharmony_ci				return -1;
2420d4afb5ceSopenharmony_ci			if (!n)
2421d4afb5ceSopenharmony_ci				/* nothing to send */
2422d4afb5ceSopenharmony_ci				break;
2423d4afb5ceSopenharmony_ci
2424d4afb5ceSopenharmony_ci			if (n == (LWS_STDOUT | LWS_STDERR)) {
2425d4afb5ceSopenharmony_ci				/* pick one using round-robin */
2426d4afb5ceSopenharmony_ci				if (pss->serviced_stderr_last)
2427d4afb5ceSopenharmony_ci					n = LWS_STDOUT;
2428d4afb5ceSopenharmony_ci				else
2429d4afb5ceSopenharmony_ci					n = LWS_STDERR;
2430d4afb5ceSopenharmony_ci			}
2431d4afb5ceSopenharmony_ci
2432d4afb5ceSopenharmony_ci			pss->serviced_stderr_last = !!(n & LWS_STDERR);
2433d4afb5ceSopenharmony_ci
2434d4afb5ceSopenharmony_ci			/* stdout or stderr */
2435d4afb5ceSopenharmony_ci			pp = ps + 5;
2436d4afb5ceSopenharmony_ci			if (n == LWS_STDOUT)
2437d4afb5ceSopenharmony_ci				*pp++ = SSH_MSG_CHANNEL_DATA;
2438d4afb5ceSopenharmony_ci			else
2439d4afb5ceSopenharmony_ci				*pp++ = SSH_MSG_CHANNEL_EXTENDED_DATA;
2440d4afb5ceSopenharmony_ci			/* ps + 6 */
2441d4afb5ceSopenharmony_ci			lws_p32(pp, pss->ch_list->sender_ch);
2442d4afb5ceSopenharmony_ci			m = 14;
2443d4afb5ceSopenharmony_ci			if (n == LWS_STDERR) {
2444d4afb5ceSopenharmony_ci				pp += 4;
2445d4afb5ceSopenharmony_ci				/* data type code... 1 for stderr payload */
2446d4afb5ceSopenharmony_ci				lws_p32(pp, SSH_EXTENDED_DATA_STDERR);
2447d4afb5ceSopenharmony_ci				m = 18;
2448d4afb5ceSopenharmony_ci			}
2449d4afb5ceSopenharmony_ci			/* also skip another strlen u32 at + 10 / +14 */
2450d4afb5ceSopenharmony_ci			pp += 8;
2451d4afb5ceSopenharmony_ci			/* ps + 14 / + 18 */
2452d4afb5ceSopenharmony_ci
2453d4afb5ceSopenharmony_ci			pp += pss->vhd->ops->tx(ch->priv, n, pp,
2454d4afb5ceSopenharmony_ci						lws_ptr_diff_size_t(
2455d4afb5ceSopenharmony_ci							&buf[sizeof(buf) - 1], pp));
2456d4afb5ceSopenharmony_ci
2457d4afb5ceSopenharmony_ci			lws_p32(ps + m - 4, (uint32_t)lws_ptr_diff(pp, (ps + m)));
2458d4afb5ceSopenharmony_ci
2459d4afb5ceSopenharmony_ci			if (pss->vhd->ops->tx_waiting(ch->priv) > 0)
2460d4afb5ceSopenharmony_ci				lws_callback_on_writable(wsi);
2461d4afb5ceSopenharmony_ci
2462d4afb5ceSopenharmony_ci			ch->window -= lws_ptr_diff(pp, ps) - m;
2463d4afb5ceSopenharmony_ci			//lwsl_debug("our send window: %d\n", ch->window);
2464d4afb5ceSopenharmony_ci
2465d4afb5ceSopenharmony_ci			/* fallthru */
2466d4afb5ceSopenharmony_cipac:
2467d4afb5ceSopenharmony_ci			if (!pss->vhd)
2468d4afb5ceSopenharmony_ci				break;
2469d4afb5ceSopenharmony_ci			n = (int)pad_and_encrypt(&buf[LWS_PRE], ps, pp, pss, 0);
2470d4afb5ceSopenharmony_ci			break;
2471d4afb5ceSopenharmony_ci
2472d4afb5ceSopenharmony_cibail:
2473d4afb5ceSopenharmony_ci			lws_ua_destroy(pss);
2474d4afb5ceSopenharmony_ci			lws_kex_destroy(pss);
2475d4afb5ceSopenharmony_ci
2476d4afb5ceSopenharmony_ci			return 1;
2477d4afb5ceSopenharmony_ci
2478d4afb5ceSopenharmony_ci		}
2479d4afb5ceSopenharmony_ci
2480d4afb5ceSopenharmony_ci		if (n > 0) {
2481d4afb5ceSopenharmony_ci			m = lws_write(wsi, (unsigned char *)buf + LWS_PRE, (unsigned int)n,
2482d4afb5ceSopenharmony_ci				      LWS_WRITE_HTTP);
2483d4afb5ceSopenharmony_ci
2484d4afb5ceSopenharmony_ci			switch(o) {
2485d4afb5ceSopenharmony_ci			case SSH_WT_SEND_NEWKEYS:
2486d4afb5ceSopenharmony_ci				lwsl_info("Activating STC keys\n");
2487d4afb5ceSopenharmony_ci				pss->active_keys_stc = pss->kex->keys_next_stc;
2488d4afb5ceSopenharmony_ci				lws_chacha_activate(&pss->active_keys_stc);
2489d4afb5ceSopenharmony_ci				pss->kex_state = KEX_STATE_CRYPTO_INITIALIZED;
2490d4afb5ceSopenharmony_ci				pss->kex->newkeys |= 1;
2491d4afb5ceSopenharmony_ci				if (pss->kex->newkeys == 3)
2492d4afb5ceSopenharmony_ci					lws_kex_destroy(pss);
2493d4afb5ceSopenharmony_ci				break;
2494d4afb5ceSopenharmony_ci			case SSH_WT_UA_PK_OK:
2495d4afb5ceSopenharmony_ci				free(ps1);
2496d4afb5ceSopenharmony_ci				break;
2497d4afb5ceSopenharmony_ci			case SSH_WT_CH_CLOSE:
2498d4afb5ceSopenharmony_ci				if (ch->received_close) {
2499d4afb5ceSopenharmony_ci					/*
2500d4afb5ceSopenharmony_ci					 * We are sending this at the behest of
2501d4afb5ceSopenharmony_ci					 * the remote peer...
2502d4afb5ceSopenharmony_ci					 * we can destroy the channel with no
2503d4afb5ceSopenharmony_ci					 * further communication.
2504d4afb5ceSopenharmony_ci					 */
2505d4afb5ceSopenharmony_ci					ssh_destroy_channel(pss, ch);
2506d4afb5ceSopenharmony_ci					break;
2507d4afb5ceSopenharmony_ci				}
2508d4afb5ceSopenharmony_ci				ch->sent_close = 1;
2509d4afb5ceSopenharmony_ci				break;
2510d4afb5ceSopenharmony_ci			}
2511d4afb5ceSopenharmony_ci	                if (m < 0) {
2512d4afb5ceSopenharmony_ci	                        lwsl_err("ERR %d from write\n", m);
2513d4afb5ceSopenharmony_ci	                        goto bail;
2514d4afb5ceSopenharmony_ci	                }
2515d4afb5ceSopenharmony_ci
2516d4afb5ceSopenharmony_ci			if (o != SSH_WT_VERSION)
2517d4afb5ceSopenharmony_ci				pss->ssh_sequence_ctr_stc++;
2518d4afb5ceSopenharmony_ci
2519d4afb5ceSopenharmony_ci			if (o != SSH_WT_NONE)
2520d4afb5ceSopenharmony_ci				pss->wt_tail =
2521d4afb5ceSopenharmony_ci					(pss->wt_tail + 1) & 7;
2522d4afb5ceSopenharmony_ci		} else
2523d4afb5ceSopenharmony_ci			if (o == SSH_WT_UA_PK_OK) /* free it either way */
2524d4afb5ceSopenharmony_ci				free(ps1);
2525d4afb5ceSopenharmony_ci
2526d4afb5ceSopenharmony_ci		ch = ssh_get_server_ch(pss, 0);
2527d4afb5ceSopenharmony_ci
2528d4afb5ceSopenharmony_ci		if (pss->wt_head != pss->wt_tail ||
2529d4afb5ceSopenharmony_ci		    (ch && ch->priv && pss->vhd &&
2530d4afb5ceSopenharmony_ci		     pss->vhd->ops->tx_waiting(ch->priv)))
2531d4afb5ceSopenharmony_ci		       lws_callback_on_writable(wsi);
2532d4afb5ceSopenharmony_ci
2533d4afb5ceSopenharmony_ci		break;
2534d4afb5ceSopenharmony_ci
2535d4afb5ceSopenharmony_ci	case LWS_CALLBACK_SSH_UART_SET_RXFLOW:
2536d4afb5ceSopenharmony_ci		/*
2537d4afb5ceSopenharmony_ci		 * this is sent to set rxflow state on any connections that
2538d4afb5ceSopenharmony_ci		 * sink on a particular sink.  The sink index affected is in len
2539d4afb5ceSopenharmony_ci		 *
2540d4afb5ceSopenharmony_ci		 * More than one protocol may sink to the same uart, and the
2541d4afb5ceSopenharmony_ci		 * protocol may select the sink itself, eg, in the URL used
2542d4afb5ceSopenharmony_ci		 * to set up the connection.
2543d4afb5ceSopenharmony_ci		 */
2544d4afb5ceSopenharmony_ci		lwsl_notice("sshd LWS_CALLBACK_SSH_UART_SET_RXFLOW: wsi %p, %d\n",
2545d4afb5ceSopenharmony_ci				wsi, (int)len & 1);
2546d4afb5ceSopenharmony_ci		lws_rx_flow_control(wsi, len & 1);
2547d4afb5ceSopenharmony_ci		break;
2548d4afb5ceSopenharmony_ci
2549d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CGI:
2550d4afb5ceSopenharmony_ci		if (!pss)
2551d4afb5ceSopenharmony_ci			break;
2552d4afb5ceSopenharmony_ci		if (pss->vhd && pss->vhd->ops &&
2553d4afb5ceSopenharmony_ci		    pss->vhd->ops->child_process_io &&
2554d4afb5ceSopenharmony_ci		    pss->vhd->ops->child_process_io(pss->ch_temp->priv,
2555d4afb5ceSopenharmony_ci					pss->wsi, (struct lws_cgi_args *)in))
2556d4afb5ceSopenharmony_ci			return -1;
2557d4afb5ceSopenharmony_ci		break;
2558d4afb5ceSopenharmony_ci
2559d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CGI_PROCESS_ATTACH:
2560d4afb5ceSopenharmony_ci		if (!pss)
2561d4afb5ceSopenharmony_ci			break;
2562d4afb5ceSopenharmony_ci		ch = ssh_get_server_ch(pss, pss->channel_doing_spawn);
2563d4afb5ceSopenharmony_ci		if (ch) {
2564d4afb5ceSopenharmony_ci			ch->spawn_pid = (uint32_t)len; /* child process PID */
2565d4afb5ceSopenharmony_ci			lwsl_notice("associated PID %d to ch %d\n", (int)len,
2566d4afb5ceSopenharmony_ci				    pss->channel_doing_spawn);
2567d4afb5ceSopenharmony_ci		}
2568d4afb5ceSopenharmony_ci		break;
2569d4afb5ceSopenharmony_ci
2570d4afb5ceSopenharmony_ci	case LWS_CALLBACK_CGI_TERMINATED:
2571d4afb5ceSopenharmony_ci		if (!pss)
2572d4afb5ceSopenharmony_ci			break;
2573d4afb5ceSopenharmony_ci		if (pss->vhd && pss->vhd->ops &&
2574d4afb5ceSopenharmony_ci		    pss->vhd->ops->child_process_terminated)
2575d4afb5ceSopenharmony_ci		    pss->vhd->ops->child_process_terminated(pss->ch_temp->priv,
2576d4afb5ceSopenharmony_ci							    pss->wsi);
2577d4afb5ceSopenharmony_ci		/*
2578d4afb5ceSopenharmony_ci		 * we have the child PID in len... we need to match it to a
2579d4afb5ceSopenharmony_ci		 * channel that is on the wsi
2580d4afb5ceSopenharmony_ci		 */
2581d4afb5ceSopenharmony_ci		ch = pss->ch_list;
2582d4afb5ceSopenharmony_ci
2583d4afb5ceSopenharmony_ci		while (ch) {
2584d4afb5ceSopenharmony_ci			if (ch->spawn_pid == len) {
2585d4afb5ceSopenharmony_ci				lwsl_notice("starting close of ch with PID %d\n",
2586d4afb5ceSopenharmony_ci					    (int)len);
2587d4afb5ceSopenharmony_ci				ch->scheduled_close = 1;
2588d4afb5ceSopenharmony_ci				write_task(pss, ch, SSH_WT_CH_CLOSE);
2589d4afb5ceSopenharmony_ci				break;
2590d4afb5ceSopenharmony_ci			}
2591d4afb5ceSopenharmony_ci			ch = ch->next;
2592d4afb5ceSopenharmony_ci		}
2593d4afb5ceSopenharmony_ci		break;
2594d4afb5ceSopenharmony_ci
2595d4afb5ceSopenharmony_ci	default:
2596d4afb5ceSopenharmony_ci		break;
2597d4afb5ceSopenharmony_ci	}
2598d4afb5ceSopenharmony_ci
2599d4afb5ceSopenharmony_ci	return 0;
2600d4afb5ceSopenharmony_ci}
2601d4afb5ceSopenharmony_ci
2602d4afb5ceSopenharmony_ci#define LWS_PLUGIN_PROTOCOL_LWS_RAW_SSHD { \
2603d4afb5ceSopenharmony_ci		"lws-ssh-base",	\
2604d4afb5ceSopenharmony_ci		lws_callback_raw_sshd,	\
2605d4afb5ceSopenharmony_ci		sizeof(struct per_session_data__sshd),	\
2606d4afb5ceSopenharmony_ci		1024, 0, NULL, 900	\
2607d4afb5ceSopenharmony_ci	}
2608d4afb5ceSopenharmony_ci
2609d4afb5ceSopenharmony_ciLWS_VISIBLE const struct lws_protocols lws_ssh_base_protocols[] = {
2610d4afb5ceSopenharmony_ci	LWS_PLUGIN_PROTOCOL_LWS_RAW_SSHD,
2611d4afb5ceSopenharmony_ci	{ NULL, NULL, 0, 0, 0, NULL, 0 } /* terminator */
2612d4afb5ceSopenharmony_ci};
2613d4afb5ceSopenharmony_ci
2614d4afb5ceSopenharmony_ci#if !defined (LWS_PLUGIN_STATIC)
2615d4afb5ceSopenharmony_ci
2616d4afb5ceSopenharmony_ciLWS_VISIBLE const lws_plugin_protocol_t lws_ssh_base = {
2617d4afb5ceSopenharmony_ci	.hdr = {
2618d4afb5ceSopenharmony_ci		"ssh base",
2619d4afb5ceSopenharmony_ci		"lws_protocol_plugin",
2620d4afb5ceSopenharmony_ci		LWS_BUILD_HASH,
2621d4afb5ceSopenharmony_ci		LWS_PLUGIN_API_MAGIC
2622d4afb5ceSopenharmony_ci	},
2623d4afb5ceSopenharmony_ci
2624d4afb5ceSopenharmony_ci	.protocols = lws_ssh_base_protocols,
2625d4afb5ceSopenharmony_ci	.count_protocols = LWS_ARRAY_SIZE(lws_ssh_base_protocols),
2626d4afb5ceSopenharmony_ci	.extensions = NULL,
2627d4afb5ceSopenharmony_ci	.count_extensions = 0,
2628d4afb5ceSopenharmony_ci};
2629d4afb5ceSopenharmony_ci
2630d4afb5ceSopenharmony_ci#endif
2631