1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * Sigv4 support for Secure Streams
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation
5d4afb5ceSopenharmony_ci *
6d4afb5ceSopenharmony_ci * Copyright (C) 2020 Andy Green <andy@warmcat.com>
7d4afb5ceSopenharmony_ci *                    securestreams-dev@amazon.com
8d4afb5ceSopenharmony_ci *
9d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
10d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to
11d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the
12d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
13d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is
14d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions:
15d4afb5ceSopenharmony_ci *
16d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in
17d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software.
18d4afb5ceSopenharmony_ci *
19d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25d4afb5ceSopenharmony_ci * IN THE SOFTWARE.
26d4afb5ceSopenharmony_ci */
27d4afb5ceSopenharmony_ci
28d4afb5ceSopenharmony_ci#include <private-lib-core.h>
29d4afb5ceSopenharmony_ci
30d4afb5ceSopenharmony_cistruct sigv4_header {
31d4afb5ceSopenharmony_ci	const char * name;
32d4afb5ceSopenharmony_ci	const char * value;
33d4afb5ceSopenharmony_ci};
34d4afb5ceSopenharmony_ci
35d4afb5ceSopenharmony_ci#define MAX_HEADER_NUM 8
36d4afb5ceSopenharmony_cistruct sigv4 {
37d4afb5ceSopenharmony_ci	struct sigv4_header headers[MAX_HEADER_NUM];
38d4afb5ceSopenharmony_ci	uint8_t	hnum;
39d4afb5ceSopenharmony_ci	char	ymd[10];     /*YYYYMMDD*/
40d4afb5ceSopenharmony_ci	const char *timestamp;
41d4afb5ceSopenharmony_ci	const char *payload_hash;
42d4afb5ceSopenharmony_ci	const char *region;
43d4afb5ceSopenharmony_ci	const char *service;
44d4afb5ceSopenharmony_ci};
45d4afb5ceSopenharmony_ci
46d4afb5ceSopenharmony_cistatic const uint8_t blob_idx[] = {
47d4afb5ceSopenharmony_ci	LWS_SYSBLOB_TYPE_EXT_AUTH1,
48d4afb5ceSopenharmony_ci	LWS_SYSBLOB_TYPE_EXT_AUTH2,
49d4afb5ceSopenharmony_ci	LWS_SYSBLOB_TYPE_EXT_AUTH3,
50d4afb5ceSopenharmony_ci	LWS_SYSBLOB_TYPE_EXT_AUTH4,
51d4afb5ceSopenharmony_ci};
52d4afb5ceSopenharmony_ci
53d4afb5ceSopenharmony_cienum {
54d4afb5ceSopenharmony_ci	LWS_SS_SIGV4_KEYID,
55d4afb5ceSopenharmony_ci	LWS_SS_SIGV4_KEY,
56d4afb5ceSopenharmony_ci	LWS_SS_SIGV4_BLOB_SLOTS
57d4afb5ceSopenharmony_ci};
58d4afb5ceSopenharmony_ci
59d4afb5ceSopenharmony_cistatic inline int add_header(struct sigv4 *s, const char *name, const char *value)
60d4afb5ceSopenharmony_ci{
61d4afb5ceSopenharmony_ci	if (s->hnum >= MAX_HEADER_NUM) {
62d4afb5ceSopenharmony_ci		lwsl_err("%s too many sigv4 headers\n", __func__);
63d4afb5ceSopenharmony_ci		return -1;
64d4afb5ceSopenharmony_ci	}
65d4afb5ceSopenharmony_ci
66d4afb5ceSopenharmony_ci	s->headers[s->hnum].name = name;
67d4afb5ceSopenharmony_ci	s->headers[s->hnum].value = value;
68d4afb5ceSopenharmony_ci	s->hnum++;
69d4afb5ceSopenharmony_ci
70d4afb5ceSopenharmony_ci	if (!strncmp(name, "x-amz-content-sha256", strlen("x-amz-content-sha256")))
71d4afb5ceSopenharmony_ci		s->payload_hash = value;
72d4afb5ceSopenharmony_ci
73d4afb5ceSopenharmony_ci	if (!strncmp(name, "x-amz-date", strlen("x-amz-date"))) {
74d4afb5ceSopenharmony_ci		s->timestamp = value;
75d4afb5ceSopenharmony_ci		strncpy(s->ymd, value, 8);
76d4afb5ceSopenharmony_ci	}
77d4afb5ceSopenharmony_ci
78d4afb5ceSopenharmony_ci	return 0;
79d4afb5ceSopenharmony_ci}
80d4afb5ceSopenharmony_ci
81d4afb5ceSopenharmony_cistatic int
82d4afb5ceSopenharmony_cicmp_header(const void * a, const void * b)
83d4afb5ceSopenharmony_ci{
84d4afb5ceSopenharmony_ci	return strcmp(((struct sigv4_header *)a)->name,
85d4afb5ceSopenharmony_ci			((struct sigv4_header *)b)->name);
86d4afb5ceSopenharmony_ci}
87d4afb5ceSopenharmony_ci
88d4afb5ceSopenharmony_cistatic int
89d4afb5ceSopenharmony_ciinit_sigv4(struct lws *wsi, struct lws_ss_handle *h, struct sigv4 *s)
90d4afb5ceSopenharmony_ci{
91d4afb5ceSopenharmony_ci	lws_ss_metadata_t *polmd = h->policy->metadata;
92d4afb5ceSopenharmony_ci	int m = 0;
93d4afb5ceSopenharmony_ci
94d4afb5ceSopenharmony_ci	add_header(s, "host:", lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST));
95d4afb5ceSopenharmony_ci
96d4afb5ceSopenharmony_ci	while (polmd) {
97d4afb5ceSopenharmony_ci		if (polmd->value__may_own_heap &&
98d4afb5ceSopenharmony_ci		    ((uint8_t *)polmd->value__may_own_heap)[0] &&
99d4afb5ceSopenharmony_ci		    h->metadata[m].value__may_own_heap) {
100d4afb5ceSopenharmony_ci			/* consider all headers start with "x-amz-" need to be signed */
101d4afb5ceSopenharmony_ci			if (!strncmp(polmd->value__may_own_heap, "x-amz-",
102d4afb5ceSopenharmony_ci				     strlen("x-amz-"))) {
103d4afb5ceSopenharmony_ci				if (add_header(s, polmd->value__may_own_heap,
104d4afb5ceSopenharmony_ci					       h->metadata[m].value__may_own_heap))
105d4afb5ceSopenharmony_ci					return -1;
106d4afb5ceSopenharmony_ci			}
107d4afb5ceSopenharmony_ci		}
108d4afb5ceSopenharmony_ci		if (!strcmp(h->metadata[m].name, h->policy->aws_region) &&
109d4afb5ceSopenharmony_ci		    h->metadata[m].value__may_own_heap)
110d4afb5ceSopenharmony_ci			s->region = h->metadata[m].value__may_own_heap;
111d4afb5ceSopenharmony_ci
112d4afb5ceSopenharmony_ci		if (!strcmp(h->metadata[m].name, h->policy->aws_service) &&
113d4afb5ceSopenharmony_ci		    h->metadata[m].value__may_own_heap)
114d4afb5ceSopenharmony_ci			s->service = h->metadata[m].value__may_own_heap;
115d4afb5ceSopenharmony_ci
116d4afb5ceSopenharmony_ci		m++;
117d4afb5ceSopenharmony_ci		polmd = polmd->next;
118d4afb5ceSopenharmony_ci	}
119d4afb5ceSopenharmony_ci
120d4afb5ceSopenharmony_ci	qsort(s->headers, s->hnum, sizeof(struct sigv4_header), cmp_header);
121d4afb5ceSopenharmony_ci
122d4afb5ceSopenharmony_ci#if 0
123d4afb5ceSopenharmony_ci	do {
124d4afb5ceSopenharmony_ci		int i;
125d4afb5ceSopenharmony_ci		for (i= 0; i<s->hnum; i++)
126d4afb5ceSopenharmony_ci			lwsl_debug("%s hdr %s %s\n", __func__,
127d4afb5ceSopenharmony_ci					s->headers[i].name, s->headers[i].value);
128d4afb5ceSopenharmony_ci
129d4afb5ceSopenharmony_ci		lwsl_debug("%s service: %s region: %s\n", __func__,
130d4afb5ceSopenharmony_ci				s->service, s->region);
131d4afb5ceSopenharmony_ci	} while(0);
132d4afb5ceSopenharmony_ci#endif
133d4afb5ceSopenharmony_ci
134d4afb5ceSopenharmony_ci	return 0;
135d4afb5ceSopenharmony_ci}
136d4afb5ceSopenharmony_ci
137d4afb5ceSopenharmony_cistatic void
138d4afb5ceSopenharmony_cibin2hex(uint8_t *in, size_t len, char *out)
139d4afb5ceSopenharmony_ci{
140d4afb5ceSopenharmony_ci	static const char *hex = "0123456789abcdef";
141d4afb5ceSopenharmony_ci	size_t n;
142d4afb5ceSopenharmony_ci
143d4afb5ceSopenharmony_ci	for (n = 0; n < len; n++) {
144d4afb5ceSopenharmony_ci		*out++ = hex[(in[n] >> 4) & 0xf];
145d4afb5ceSopenharmony_ci		*out++ = hex[in[n] & 15];
146d4afb5ceSopenharmony_ci	}
147d4afb5ceSopenharmony_ci	*out = '\0';
148d4afb5ceSopenharmony_ci}
149d4afb5ceSopenharmony_ci
150d4afb5ceSopenharmony_cistatic int
151d4afb5ceSopenharmony_cihmacsha256(const uint8_t *key, size_t keylen, const uint8_t *txt,
152d4afb5ceSopenharmony_ci			size_t txtlen, uint8_t *digest)
153d4afb5ceSopenharmony_ci{
154d4afb5ceSopenharmony_ci	struct lws_genhmac_ctx hmacctx;
155d4afb5ceSopenharmony_ci
156d4afb5ceSopenharmony_ci	if (lws_genhmac_init(&hmacctx, LWS_GENHMAC_TYPE_SHA256,
157d4afb5ceSopenharmony_ci				key, keylen))
158d4afb5ceSopenharmony_ci		return -1;
159d4afb5ceSopenharmony_ci
160d4afb5ceSopenharmony_ci	if (lws_genhmac_update(&hmacctx, txt, txtlen)) {
161d4afb5ceSopenharmony_ci		lwsl_err("%s: hmac computation failed\n", __func__);
162d4afb5ceSopenharmony_ci		lws_genhmac_destroy(&hmacctx, NULL);
163d4afb5ceSopenharmony_ci		return -1;
164d4afb5ceSopenharmony_ci	}
165d4afb5ceSopenharmony_ci
166d4afb5ceSopenharmony_ci	if (lws_genhmac_destroy(&hmacctx, digest)) {
167d4afb5ceSopenharmony_ci		lwsl_err("%s: problem destroying hmac\n", __func__);
168d4afb5ceSopenharmony_ci		return -1;
169d4afb5ceSopenharmony_ci	}
170d4afb5ceSopenharmony_ci
171d4afb5ceSopenharmony_ci	return 0;
172d4afb5ceSopenharmony_ci}
173d4afb5ceSopenharmony_ci
174d4afb5ceSopenharmony_ci/* cut the last byte of the str */
175d4afb5ceSopenharmony_cistatic inline int hash_update_bite_str(struct lws_genhash_ctx *ctx, const char * str)
176d4afb5ceSopenharmony_ci{
177d4afb5ceSopenharmony_ci	int ret = 0;
178d4afb5ceSopenharmony_ci	if ((ret = lws_genhash_update(ctx, (void *)str, strlen(str)-1))) {
179d4afb5ceSopenharmony_ci		lws_genhash_destroy(ctx, NULL);
180d4afb5ceSopenharmony_ci		lwsl_err("%s err %d line \n", __func__, ret);
181d4afb5ceSopenharmony_ci	}
182d4afb5ceSopenharmony_ci	return ret;
183d4afb5ceSopenharmony_ci}
184d4afb5ceSopenharmony_ci
185d4afb5ceSopenharmony_cistatic inline int hash_update_str(struct lws_genhash_ctx *ctx, const char * str)
186d4afb5ceSopenharmony_ci{
187d4afb5ceSopenharmony_ci	int ret = 0;
188d4afb5ceSopenharmony_ci	if ((ret = lws_genhash_update(ctx, (void *)str, strlen(str)))) {
189d4afb5ceSopenharmony_ci		lws_genhash_destroy(ctx, NULL);
190d4afb5ceSopenharmony_ci		lwsl_err("%s err %d \n", __func__, ret);
191d4afb5ceSopenharmony_ci	}
192d4afb5ceSopenharmony_ci	return ret;
193d4afb5ceSopenharmony_ci}
194d4afb5ceSopenharmony_ci
195d4afb5ceSopenharmony_cistatic int
196d4afb5ceSopenharmony_cibuild_sign_string(struct lws *wsi, char *buf, size_t bufsz,
197d4afb5ceSopenharmony_ci		struct lws_ss_handle *h, struct sigv4 *s)
198d4afb5ceSopenharmony_ci{
199d4afb5ceSopenharmony_ci	char hash[65], *end = &buf[bufsz - 1], *start;
200d4afb5ceSopenharmony_ci	struct lws_genhash_ctx hash_ctx;
201d4afb5ceSopenharmony_ci	uint8_t hash_bin[32];
202d4afb5ceSopenharmony_ci	int i, ret = 0;
203d4afb5ceSopenharmony_ci
204d4afb5ceSopenharmony_ci	start = buf;
205d4afb5ceSopenharmony_ci
206d4afb5ceSopenharmony_ci	if ((ret = lws_genhash_init(&hash_ctx, LWS_GENHASH_TYPE_SHA256))) {
207d4afb5ceSopenharmony_ci		lws_genhash_destroy(&hash_ctx, NULL);
208d4afb5ceSopenharmony_ci		lwsl_err("%s genhash init err %d \n", __func__, ret);
209d4afb5ceSopenharmony_ci		return -1;
210d4afb5ceSopenharmony_ci	}
211d4afb5ceSopenharmony_ci	/*
212d4afb5ceSopenharmony_ci	 * hash canonical_request
213d4afb5ceSopenharmony_ci	 */
214d4afb5ceSopenharmony_ci
215d4afb5ceSopenharmony_ci	if (hash_update_str(&hash_ctx, h->policy->u.http.method) ||
216d4afb5ceSopenharmony_ci			hash_update_str(&hash_ctx, "\n"))
217d4afb5ceSopenharmony_ci		return -1;
218d4afb5ceSopenharmony_ci	if (hash_update_str(&hash_ctx, lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI)) ||
219d4afb5ceSopenharmony_ci			hash_update_str(&hash_ctx, "\n"))
220d4afb5ceSopenharmony_ci		return -1;
221d4afb5ceSopenharmony_ci
222d4afb5ceSopenharmony_ci	/* TODO, append query string */
223d4afb5ceSopenharmony_ci	if (hash_update_str(&hash_ctx, "\n"))
224d4afb5ceSopenharmony_ci		return -1;
225d4afb5ceSopenharmony_ci
226d4afb5ceSopenharmony_ci	for (i = 0; i < s->hnum; i++) {
227d4afb5ceSopenharmony_ci		if (hash_update_str(&hash_ctx, s->headers[i].name) ||
228d4afb5ceSopenharmony_ci		    hash_update_str(&hash_ctx, s->headers[i].value) ||
229d4afb5ceSopenharmony_ci		    hash_update_str(&hash_ctx, "\n"))
230d4afb5ceSopenharmony_ci		return -1;
231d4afb5ceSopenharmony_ci
232d4afb5ceSopenharmony_ci	}
233d4afb5ceSopenharmony_ci	if (hash_update_str(&hash_ctx, "\n"))
234d4afb5ceSopenharmony_ci		return -1;
235d4afb5ceSopenharmony_ci
236d4afb5ceSopenharmony_ci	for (i = 0; i < s->hnum-1; i++) {
237d4afb5ceSopenharmony_ci		if (hash_update_bite_str(&hash_ctx, s->headers[i].name) ||
238d4afb5ceSopenharmony_ci		    hash_update_str(&hash_ctx, ";"))
239d4afb5ceSopenharmony_ci			return -1;
240d4afb5ceSopenharmony_ci	}
241d4afb5ceSopenharmony_ci	if (hash_update_bite_str(&hash_ctx, s->headers[i].name) ||
242d4afb5ceSopenharmony_ci	    hash_update_str(&hash_ctx, "\n") ||
243d4afb5ceSopenharmony_ci	    hash_update_str(&hash_ctx, s->payload_hash))
244d4afb5ceSopenharmony_ci		return -1;
245d4afb5ceSopenharmony_ci
246d4afb5ceSopenharmony_ci	if ((ret = lws_genhash_destroy(&hash_ctx, hash_bin))) {
247d4afb5ceSopenharmony_ci		lws_genhash_destroy(&hash_ctx, NULL);
248d4afb5ceSopenharmony_ci		lwsl_err("%s lws_genhash error \n", __func__);
249d4afb5ceSopenharmony_ci		return -1;
250d4afb5ceSopenharmony_ci	}
251d4afb5ceSopenharmony_ci
252d4afb5ceSopenharmony_ci	bin2hex(hash_bin, sizeof(hash_bin), hash);
253d4afb5ceSopenharmony_ci	/*
254d4afb5ceSopenharmony_ci	 * build sign string like the following
255d4afb5ceSopenharmony_ci	 *
256d4afb5ceSopenharmony_ci	 * "AWS4-HMAC-SHA256" + "\n" +
257d4afb5ceSopenharmony_ci	 * timeStampISO8601Format + "\n" +
258d4afb5ceSopenharmony_ci	 * date.Format(<YYYYMMDD>) + "/" + <region> + "/" + <service> + "/aws4_request" + "\n" +
259d4afb5ceSopenharmony_ci	 * Hex(SHA256Hash(<CanonicalRequest>))
260d4afb5ceSopenharmony_ci	 */
261d4afb5ceSopenharmony_ci	buf = start;
262d4afb5ceSopenharmony_ci
263d4afb5ceSopenharmony_ci	buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "%s\n",
264d4afb5ceSopenharmony_ci							"AWS4-HMAC-SHA256");
265d4afb5ceSopenharmony_ci	buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "%s\n",
266d4afb5ceSopenharmony_ci							s->timestamp);
267d4afb5ceSopenharmony_ci	buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "%s/%s/%s/%s\n",
268d4afb5ceSopenharmony_ci				s->ymd, s->region, s->service, "aws4_request");
269d4afb5ceSopenharmony_ci
270d4afb5ceSopenharmony_ci	buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "%s", hash);
271d4afb5ceSopenharmony_ci	*buf++ = '\0';
272d4afb5ceSopenharmony_ci
273d4afb5ceSopenharmony_ci	assert(buf <= start + bufsz);
274d4afb5ceSopenharmony_ci
275d4afb5ceSopenharmony_ci	return 0;
276d4afb5ceSopenharmony_ci}
277d4afb5ceSopenharmony_ci
278d4afb5ceSopenharmony_ci/*
279d4afb5ceSopenharmony_ci * DateKey              = HMAC-SHA256("AWS4"+"<SecretAccessKey>", "<YYYYMMDD>")
280d4afb5ceSopenharmony_ci * DateRegionKey        = HMAC-SHA256(<DateKey>, "<aws-region>")
281d4afb5ceSopenharmony_ci * DateRegionServiceKey = HMAC-SHA256(<DateRegionKey>, "<aws-service>")
282d4afb5ceSopenharmony_ci * SigningKey           = HMAC-SHA256(<DateRegionServiceKey>, "aws4_request")
283d4afb5ceSopenharmony_ci */
284d4afb5ceSopenharmony_cistatic int
285d4afb5ceSopenharmony_cicalc_signing_key(struct lws *wsi, struct lws_ss_handle *h,
286d4afb5ceSopenharmony_ci		struct sigv4 *s, uint8_t *sign_key)
287d4afb5ceSopenharmony_ci{
288d4afb5ceSopenharmony_ci	uint8_t key[128], date_key[32], and_region_key[32],
289d4afb5ceSopenharmony_ci		and_service_key[32], *kb;
290d4afb5ceSopenharmony_ci	lws_system_blob_t *ab;
291d4afb5ceSopenharmony_ci	size_t keylen;
292d4afb5ceSopenharmony_ci	int n;
293d4afb5ceSopenharmony_ci
294d4afb5ceSopenharmony_ci	ab = lws_system_get_blob(wsi->a.context,
295d4afb5ceSopenharmony_ci				 blob_idx[h->policy->auth->blob_index],
296d4afb5ceSopenharmony_ci				 LWS_SS_SIGV4_KEY);
297d4afb5ceSopenharmony_ci	if (!ab)
298d4afb5ceSopenharmony_ci		return -1;
299d4afb5ceSopenharmony_ci
300d4afb5ceSopenharmony_ci	kb = key;
301d4afb5ceSopenharmony_ci
302d4afb5ceSopenharmony_ci	*kb++ = 'A';
303d4afb5ceSopenharmony_ci	*kb++ = 'W';
304d4afb5ceSopenharmony_ci	*kb++ = 'S';
305d4afb5ceSopenharmony_ci	*kb++ = '4';
306d4afb5ceSopenharmony_ci
307d4afb5ceSopenharmony_ci	keylen = sizeof(key) - 4;
308d4afb5ceSopenharmony_ci	if (lws_system_blob_get_size(ab) > keylen - 1)
309d4afb5ceSopenharmony_ci		return -1;
310d4afb5ceSopenharmony_ci
311d4afb5ceSopenharmony_ci	n = lws_system_blob_get(ab, kb, &keylen, 0);
312d4afb5ceSopenharmony_ci	if (n < 0)
313d4afb5ceSopenharmony_ci		return -1;
314d4afb5ceSopenharmony_ci
315d4afb5ceSopenharmony_ci	kb[keylen] = '\0';
316d4afb5ceSopenharmony_ci
317d4afb5ceSopenharmony_ci	hmacsha256((const uint8_t *)key, strlen((const char *)key),
318d4afb5ceSopenharmony_ci		   (const uint8_t *)s->ymd, strlen(s->ymd), date_key);
319d4afb5ceSopenharmony_ci
320d4afb5ceSopenharmony_ci	hmacsha256(date_key, sizeof(date_key), (const uint8_t *)s->region,
321d4afb5ceSopenharmony_ci		   strlen(s->region), and_region_key);
322d4afb5ceSopenharmony_ci
323d4afb5ceSopenharmony_ci	hmacsha256(and_region_key, sizeof(and_region_key),
324d4afb5ceSopenharmony_ci		   (const uint8_t *)s->service,
325d4afb5ceSopenharmony_ci		   strlen(s->service), and_service_key);
326d4afb5ceSopenharmony_ci
327d4afb5ceSopenharmony_ci	hmacsha256(and_service_key, sizeof(and_service_key),
328d4afb5ceSopenharmony_ci		   (uint8_t *)"aws4_request",
329d4afb5ceSopenharmony_ci		   strlen("aws4_request"), sign_key);
330d4afb5ceSopenharmony_ci
331d4afb5ceSopenharmony_ci	return 0;
332d4afb5ceSopenharmony_ci}
333d4afb5ceSopenharmony_ci
334d4afb5ceSopenharmony_ci/* Sample auth string:
335d4afb5ceSopenharmony_ci *
336d4afb5ceSopenharmony_ci * 'Authorization: AWS4-HMAC-SHA256 Credential=AKIAVHWASOFE7TJ7ZUQY/20200731/us-west-2/s3/aws4_request,
337d4afb5ceSopenharmony_ci* SignedHeaders=host;x-amz-content-sha256;x-amz-date, \
338d4afb5ceSopenharmony_ci* Signature=ad9fb75ff3b46c7990e3e8f090abfdd6c01fd67761a517111694377e20698377'
339d4afb5ceSopenharmony_ci*/
340d4afb5ceSopenharmony_cistatic int
341d4afb5ceSopenharmony_cibuild_auth_string(struct lws *wsi, char * buf, size_t bufsz,
342d4afb5ceSopenharmony_ci		struct lws_ss_handle *h, struct sigv4 *s,
343d4afb5ceSopenharmony_ci		uint8_t *signature_bin)
344d4afb5ceSopenharmony_ci{
345d4afb5ceSopenharmony_ci	char *start = buf, *end = &buf[bufsz - 1];
346d4afb5ceSopenharmony_ci	char *c;
347d4afb5ceSopenharmony_ci	lws_system_blob_t *ab;
348d4afb5ceSopenharmony_ci	size_t keyidlen = 128; // max keyid len is 128
349d4afb5ceSopenharmony_ci	int n;
350d4afb5ceSopenharmony_ci
351d4afb5ceSopenharmony_ci	buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "%s",
352d4afb5ceSopenharmony_ci			    "AWS4-HMAC-SHA256 ");
353d4afb5ceSopenharmony_ci
354d4afb5ceSopenharmony_ci	ab = lws_system_get_blob(wsi->a.context,
355d4afb5ceSopenharmony_ci				 blob_idx[h->policy->auth->blob_index],
356d4afb5ceSopenharmony_ci				 LWS_SS_SIGV4_KEYID);
357d4afb5ceSopenharmony_ci	if (!ab)
358d4afb5ceSopenharmony_ci		return -1;
359d4afb5ceSopenharmony_ci
360d4afb5ceSopenharmony_ci	buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "%s",
361d4afb5ceSopenharmony_ci							"Credential=");
362d4afb5ceSopenharmony_ci	n = lws_system_blob_get(ab,(uint8_t *)buf, &keyidlen, 0);
363d4afb5ceSopenharmony_ci	if (n < 0)
364d4afb5ceSopenharmony_ci		return -1;
365d4afb5ceSopenharmony_ci	buf += keyidlen;
366d4afb5ceSopenharmony_ci
367d4afb5ceSopenharmony_ci	buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "/%s/%s/%s/%s, ",
368d4afb5ceSopenharmony_ci				s->ymd, s->region, s->service, "aws4_request");
369d4afb5ceSopenharmony_ci	buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf), "%s",
370d4afb5ceSopenharmony_ci							"SignedHeaders=");
371d4afb5ceSopenharmony_ci	for (n = 0; n < s->hnum; n++) {
372d4afb5ceSopenharmony_ci		buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
373d4afb5ceSopenharmony_ci					"%s",s->headers[n].name);
374d4afb5ceSopenharmony_ci		buf--; /* remove ':' */
375d4afb5ceSopenharmony_ci		*buf++ = ';';
376d4afb5ceSopenharmony_ci	}
377d4afb5ceSopenharmony_ci	c = buf - 1;
378d4afb5ceSopenharmony_ci	*c = ','; /* overwrite ';' back to ',' */
379d4afb5ceSopenharmony_ci
380d4afb5ceSopenharmony_ci	buf += lws_snprintf(buf, lws_ptr_diff_size_t(end, buf),
381d4afb5ceSopenharmony_ci			    "%s", " Signature=");
382d4afb5ceSopenharmony_ci	bin2hex(signature_bin, 32, buf);
383d4afb5ceSopenharmony_ci
384d4afb5ceSopenharmony_ci	assert(buf+65 <= start + bufsz);
385d4afb5ceSopenharmony_ci
386d4afb5ceSopenharmony_ci	lwsl_debug("%s %s\n", __func__, start);
387d4afb5ceSopenharmony_ci
388d4afb5ceSopenharmony_ci	return 0;
389d4afb5ceSopenharmony_ci
390d4afb5ceSopenharmony_ci}
391d4afb5ceSopenharmony_ci
392d4afb5ceSopenharmony_ciint
393d4afb5ceSopenharmony_cilws_ss_apply_sigv4(struct lws *wsi, struct lws_ss_handle *h,
394d4afb5ceSopenharmony_ci		     unsigned char **p, unsigned char *end)
395d4afb5ceSopenharmony_ci{
396d4afb5ceSopenharmony_ci	uint8_t buf[512], sign_key[32], signature_bin[32], *bp;
397d4afb5ceSopenharmony_ci	struct sigv4 s;
398d4afb5ceSopenharmony_ci
399d4afb5ceSopenharmony_ci	memset(&s, 0, sizeof(s));
400d4afb5ceSopenharmony_ci
401d4afb5ceSopenharmony_ci	bp = buf;
402d4afb5ceSopenharmony_ci
403d4afb5ceSopenharmony_ci	init_sigv4(wsi, h, &s);
404d4afb5ceSopenharmony_ci	if (!s.timestamp || !s.payload_hash) {
405d4afb5ceSopenharmony_ci		lwsl_err("%s missing headers\n", __func__);
406d4afb5ceSopenharmony_ci		return -1;
407d4afb5ceSopenharmony_ci	}
408d4afb5ceSopenharmony_ci
409d4afb5ceSopenharmony_ci	if (build_sign_string(wsi, (char *)bp, sizeof(buf), h, &s))
410d4afb5ceSopenharmony_ci		return -1;
411d4afb5ceSopenharmony_ci
412d4afb5ceSopenharmony_ci	if (calc_signing_key(wsi, h, &s, sign_key))
413d4afb5ceSopenharmony_ci		return -1;
414d4afb5ceSopenharmony_ci
415d4afb5ceSopenharmony_ci	hmacsha256(sign_key, sizeof(sign_key), (const uint8_t *)buf,
416d4afb5ceSopenharmony_ci			      strlen((const char *)buf), signature_bin);
417d4afb5ceSopenharmony_ci
418d4afb5ceSopenharmony_ci	bp = buf; /* reuse for auth_str */
419d4afb5ceSopenharmony_ci	if (build_auth_string(wsi, (char *)bp, sizeof(buf), h, &s,
420d4afb5ceSopenharmony_ci				signature_bin))
421d4afb5ceSopenharmony_ci		return -1;
422d4afb5ceSopenharmony_ci
423d4afb5ceSopenharmony_ci	if (lws_add_http_header_by_name(wsi,
424d4afb5ceSopenharmony_ci					(const uint8_t *)"Authorization:", buf,
425d4afb5ceSopenharmony_ci					(int)strlen((const char*)buf), p, end))
426d4afb5ceSopenharmony_ci		return -1;
427d4afb5ceSopenharmony_ci
428d4afb5ceSopenharmony_ci	return 0;
429d4afb5ceSopenharmony_ci}
430d4afb5ceSopenharmony_ci
431d4afb5ceSopenharmony_ciint
432d4afb5ceSopenharmony_cilws_ss_sigv4_set_aws_key(struct lws_context* context, uint8_t idx,
433d4afb5ceSopenharmony_ci		                const char * keyid, const char * key)
434d4afb5ceSopenharmony_ci{
435d4afb5ceSopenharmony_ci	const char * s[] = { keyid, key };
436d4afb5ceSopenharmony_ci	lws_system_blob_t *ab;
437d4afb5ceSopenharmony_ci	int i;
438d4afb5ceSopenharmony_ci
439d4afb5ceSopenharmony_ci	if (idx > LWS_ARRAY_SIZE(blob_idx))
440d4afb5ceSopenharmony_ci		return -1;
441d4afb5ceSopenharmony_ci
442d4afb5ceSopenharmony_ci	for (i = 0; i < LWS_SS_SIGV4_BLOB_SLOTS; i++) {
443d4afb5ceSopenharmony_ci		ab = lws_system_get_blob(context, blob_idx[idx], i);
444d4afb5ceSopenharmony_ci		if (!ab)
445d4afb5ceSopenharmony_ci			return -1;
446d4afb5ceSopenharmony_ci
447d4afb5ceSopenharmony_ci		lws_system_blob_heap_empty(ab);
448d4afb5ceSopenharmony_ci
449d4afb5ceSopenharmony_ci		if (lws_system_blob_heap_append(ab, (const uint8_t *)s[i],
450d4afb5ceSopenharmony_ci						strlen(s[i]))) {
451d4afb5ceSopenharmony_ci			lwsl_err("%s: can't store %d \n", __func__, i);
452d4afb5ceSopenharmony_ci
453d4afb5ceSopenharmony_ci			return -1;
454d4afb5ceSopenharmony_ci		}
455d4afb5ceSopenharmony_ci	}
456d4afb5ceSopenharmony_ci
457d4afb5ceSopenharmony_ci	return 0;
458d4afb5ceSopenharmony_ci}
459d4afb5ceSopenharmony_ci
460d4afb5ceSopenharmony_ci#if defined(__linux__) || defined(__APPLE__) || defined(WIN32) || \
461d4afb5ceSopenharmony_ci	defined(__FreeBSD__) || defined(__NetBSD__) || defined(__ANDROID__) || \
462d4afb5ceSopenharmony_ci	defined(__sun) || defined(__OpenBSD__)
463d4afb5ceSopenharmony_ci
464d4afb5ceSopenharmony_ci/* ie, if we have filesystem ops */
465d4afb5ceSopenharmony_ci
466d4afb5ceSopenharmony_ciint
467d4afb5ceSopenharmony_cilws_aws_filesystem_credentials_helper(const char *path, const char *kid,
468d4afb5ceSopenharmony_ci				      const char *ak, char **aws_keyid,
469d4afb5ceSopenharmony_ci				      char **aws_key)
470d4afb5ceSopenharmony_ci{
471d4afb5ceSopenharmony_ci	char *str = NULL, *val = NULL, *line = NULL, sth[128];
472d4afb5ceSopenharmony_ci	size_t len = sizeof(sth);
473d4afb5ceSopenharmony_ci	const char *home = "";
474d4afb5ceSopenharmony_ci	int i, poff = 0;
475d4afb5ceSopenharmony_ci	ssize_t rd;
476d4afb5ceSopenharmony_ci	FILE *fp;
477d4afb5ceSopenharmony_ci
478d4afb5ceSopenharmony_ci	*aws_keyid = *aws_key = NULL;
479d4afb5ceSopenharmony_ci
480d4afb5ceSopenharmony_ci	if (path[0] == '~') {
481d4afb5ceSopenharmony_ci		home = getenv("HOME");
482d4afb5ceSopenharmony_ci		if (home && strlen(home) > sizeof(sth) - 1) /* coverity */
483d4afb5ceSopenharmony_ci			return -1;
484d4afb5ceSopenharmony_ci		else {
485d4afb5ceSopenharmony_ci			if (!home)
486d4afb5ceSopenharmony_ci				home = "";
487d4afb5ceSopenharmony_ci
488d4afb5ceSopenharmony_ci			poff = 1;
489d4afb5ceSopenharmony_ci		}
490d4afb5ceSopenharmony_ci	}
491d4afb5ceSopenharmony_ci	lws_snprintf(sth, sizeof(sth), "%s%s", home, path + poff);
492d4afb5ceSopenharmony_ci
493d4afb5ceSopenharmony_ci	fp = fopen(sth, "r");
494d4afb5ceSopenharmony_ci	if (!fp) {
495d4afb5ceSopenharmony_ci		lwsl_err("%s can't open '%s'\n", __func__, sth);
496d4afb5ceSopenharmony_ci
497d4afb5ceSopenharmony_ci		return -1;
498d4afb5ceSopenharmony_ci	}
499d4afb5ceSopenharmony_ci
500d4afb5ceSopenharmony_ci	while ((rd = getline(&line, &len, fp)) != -1) {
501d4afb5ceSopenharmony_ci		for (i = 0; i < 2; i++) {
502d4afb5ceSopenharmony_ci			size_t slen;
503d4afb5ceSopenharmony_ci
504d4afb5ceSopenharmony_ci			if (strncmp(line, i ? kid : ak, strlen(i ? kid : ak)))
505d4afb5ceSopenharmony_ci				continue;
506d4afb5ceSopenharmony_ci
507d4afb5ceSopenharmony_ci			str = strchr(line, '=');
508d4afb5ceSopenharmony_ci			if (!str)
509d4afb5ceSopenharmony_ci				continue;
510d4afb5ceSopenharmony_ci
511d4afb5ceSopenharmony_ci			str++;
512d4afb5ceSopenharmony_ci
513d4afb5ceSopenharmony_ci			/* only read the first key for each */
514d4afb5ceSopenharmony_ci			if (*(i ? aws_keyid : aws_key))
515d4afb5ceSopenharmony_ci				continue;
516d4afb5ceSopenharmony_ci
517d4afb5ceSopenharmony_ci			/*
518d4afb5ceSopenharmony_ci			 * Trim whitespace from the start and end
519d4afb5ceSopenharmony_ci			 */
520d4afb5ceSopenharmony_ci
521d4afb5ceSopenharmony_ci			slen = (size_t)(rd - lws_ptr_diff(str, line));
522d4afb5ceSopenharmony_ci
523d4afb5ceSopenharmony_ci			while (slen && *str == ' ') {
524d4afb5ceSopenharmony_ci				str++;
525d4afb5ceSopenharmony_ci				slen--;
526d4afb5ceSopenharmony_ci			}
527d4afb5ceSopenharmony_ci
528d4afb5ceSopenharmony_ci			while (slen && (str[slen - 1] == '\r' ||
529d4afb5ceSopenharmony_ci					str[slen - 1] == '\n' ||
530d4afb5ceSopenharmony_ci					str[slen - 1] == ' '))
531d4afb5ceSopenharmony_ci				slen--;
532d4afb5ceSopenharmony_ci
533d4afb5ceSopenharmony_ci			val = malloc(slen + 1);
534d4afb5ceSopenharmony_ci			if (!val)
535d4afb5ceSopenharmony_ci				goto bail;
536d4afb5ceSopenharmony_ci
537d4afb5ceSopenharmony_ci			strncpy(val, str, slen);
538d4afb5ceSopenharmony_ci			val[slen] = '\0';
539d4afb5ceSopenharmony_ci
540d4afb5ceSopenharmony_ci			*(i ? aws_keyid : aws_key) = val;
541d4afb5ceSopenharmony_ci
542d4afb5ceSopenharmony_ci		}
543d4afb5ceSopenharmony_ci	}
544d4afb5ceSopenharmony_ci
545d4afb5ceSopenharmony_cibail:
546d4afb5ceSopenharmony_ci	fclose(fp);
547d4afb5ceSopenharmony_ci
548d4afb5ceSopenharmony_ci	if (line)
549d4afb5ceSopenharmony_ci		free(line);
550d4afb5ceSopenharmony_ci
551d4afb5ceSopenharmony_ci	if (!*aws_keyid || !*aws_key) {
552d4afb5ceSopenharmony_ci		if (*aws_keyid) {
553d4afb5ceSopenharmony_ci			free(*aws_keyid);
554d4afb5ceSopenharmony_ci			*aws_keyid = NULL;
555d4afb5ceSopenharmony_ci		}
556d4afb5ceSopenharmony_ci		if (*aws_key) {
557d4afb5ceSopenharmony_ci			free(*aws_key);
558d4afb5ceSopenharmony_ci			*aws_key = NULL;
559d4afb5ceSopenharmony_ci		}
560d4afb5ceSopenharmony_ci		lwsl_err("%s can't find aws credentials! \
561d4afb5ceSopenharmony_ci				please check %s\n", __func__, path);
562d4afb5ceSopenharmony_ci		return -1;
563d4afb5ceSopenharmony_ci	}
564d4afb5ceSopenharmony_ci
565d4afb5ceSopenharmony_ci	lwsl_info("%s: '%s' '%s'\n", __func__, *aws_keyid, *aws_key);
566d4afb5ceSopenharmony_ci
567d4afb5ceSopenharmony_ci	return 0;
568d4afb5ceSopenharmony_ci}
569d4afb5ceSopenharmony_ci#endif
570