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