1/* 2 * S3 Put Object via Secure Streams minimal siv4 example 3 * 4 * Written in 2010-2020 by Andy Green <andy@warmcat.com> 5 * Amit Pachore <apachor@amazon.com> 6 * securestreams-dev@amazon.com 7 * 8 * This file is made available under the Creative Commons CC0 1.0 9 * Universal Public Domain Dedication. 10 */ 11 12#include <libwebsockets.h> 13#include <assert.h> 14#include "ss-s3-put.h" 15 16extern int interrupted, bad; 17 18static lws_ss_state_return_t 19ss_s3_rx(void *userobj, const uint8_t *buf, size_t len, int flags) 20{ 21 // ss_s3_put_t *m = (ss_s3_put_t *)userobj; 22 23 if (flags & LWSSS_FLAG_EOM) { 24 bad = 0; 25 interrupted = 1; /* this example wants to exit after rx */ 26 return LWSSSSRET_DESTROY_ME; 27 } 28 29 lwsl_user("%s: len %d, flags: %d\n", __func__, (int)len, flags); 30 lwsl_hexdump_err(buf, len); 31 32 return LWSSSSRET_OK; 33} 34 35static lws_ss_state_return_t 36ss_s3_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len, 37 int *flags) 38{ 39 ss_s3_put_t *m = (ss_s3_put_t *)userobj; 40 41 if (!m->pos) 42 *flags |= LWSSS_FLAG_SOM; 43 44 lwsl_user("%s: Send... total: %ld, pos: %ld\n", __func__, 45 (long)m->total, (long)m->pos); 46 47 if (*len > m->total - m->pos) 48 *len = m->total - m->pos; 49 50 if (!*len) 51 return LWSSSSRET_TX_DONT_SEND; 52 53 memcpy(buf, m->buf + m->pos, *len); 54 m->pos += *len; 55 56 if (m->pos == m->total) { 57 *flags |= LWSSS_FLAG_EOM; 58 // m->pos = 0; /* we only want to send once */ 59 } else 60 return lws_ss_request_tx(m->ss); 61 62 return LWSSSSRET_OK; 63} 64 65static const char *awsService = "s3", 66 *awsRegion = "us-west-2", 67 *s3bucketName = "sstest2020", 68#if 1 69 *s3ObjName = "SSs3upload2.txt"; 70#else 71 /* test huge string sigv4 hashing works */ 72 *s3ObjName = "SSs3uploadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2.txt"; 73#endif 74static char timestamp[32], payload_hash[65]; 75static uint8_t jpl[1 * 1024]; 76 77 78static void 79create_payload(uint8_t *buf, size_t s) 80{ 81 int i; 82 83 for (i = 0; i < (int)s; i++) 84 buf[i] = (uint8_t)('a' + i % 16); 85} 86 87static void set_time(char *t) 88{ 89 /*20150830T123600Z*/ 90 time_t ti = time(NULL); 91#if defined(LWS_HAVE_GMTIME_R) 92 struct tm tmp; 93 struct tm *tm = gmtime_r(&ti, &tmp); 94#else 95 struct tm *tm = gmtime(&ti); 96#endif 97 assert(tm); 98 strftime(t, 20, "%Y%m%dT%H%M%SZ", tm); 99} 100 101static void bin2hex(uint8_t *in, size_t len, char *out) 102{ 103 static const char *hex = "0123456789abcdef"; 104 size_t n; 105 106 for (n = 0; n < len; n++) { 107 *out++ = hex[(in[n] >> 4) & 0xf]; 108 *out++ = hex[in[n] & 15]; 109 } 110 *out = '\0'; 111} 112 113static void sigv4_sha256hash_payload(uint8_t *payload, size_t len, char *hash) 114{ 115 struct lws_genhash_ctx hash_ctx; 116 uint8_t hash_bin[32]; 117 118 if (lws_genhash_init(&hash_ctx, LWS_GENHASH_TYPE_SHA256) || 119 /* 120 * If there is no payload, you must provide the hash of an 121 * empty string... 122 */ 123 lws_genhash_update(&hash_ctx, 124 payload ? (void *)payload : (void *)"", 125 payload ? len : 0u) || 126 lws_genhash_destroy(&hash_ctx, hash_bin)) 127 { 128 129 lws_genhash_destroy(&hash_ctx, NULL); 130 lwsl_err("%s lws_genhash failed\n", __func__); 131 132 return; 133 } 134 135 bin2hex(hash_bin, 32, hash); 136} 137 138static lws_ss_state_return_t 139ss_s3_state(void *userobj, void *sh, lws_ss_constate_t state, 140 lws_ss_tx_ordinal_t ack) 141{ 142 ss_s3_put_t *m = (ss_s3_put_t *)userobj; 143 144 lwsl_user("%s: %s %s, ord 0x%x\n", __func__, lws_ss_tag(m->ss), 145 lws_ss_state_name((int)state), (unsigned int)ack); 146 147 switch (state) { 148 case LWSSSCS_CREATING: 149 create_payload(jpl, sizeof(jpl)); 150 m->buf = (uint8_t *)jpl; 151 m->total = sizeof(jpl); 152 153 sigv4_sha256hash_payload(m->buf, m->total, payload_hash); 154 memset(timestamp, 0, sizeof(timestamp)); 155 set_time(timestamp); 156 157 if (lws_ss_set_metadata(m->ss, "s3bucket", 158 s3bucketName, strlen(s3bucketName)) || 159 lws_ss_set_metadata(m->ss, "s3Obj", 160 s3ObjName, strlen(s3ObjName)) || 161 lws_ss_set_metadata(m->ss, "ctype", 162 "text/plain", strlen("text/plain")) || 163 lws_ss_set_metadata(m->ss, "region", 164 awsRegion, strlen(awsRegion)) || 165 lws_ss_set_metadata(m->ss, "service", 166 awsService, strlen(awsService)) || 167 lws_ss_set_metadata(m->ss, "xacl", 168 "bucket-owner-full-control", 169 strlen("bucket-owner-full-control")) || 170 lws_ss_set_metadata(m->ss, "xcsha256", 171 payload_hash, strlen(payload_hash)) || 172 lws_ss_set_metadata(m->ss, "xdate", 173 timestamp, strlen(timestamp))) 174 return LWSSSSRET_DESTROY_ME; 175 176 return lws_ss_request_tx_len(m->ss, m->total); 177 178 case LWSSSCS_CONNECTED: 179 return lws_ss_request_tx(m->ss); 180 181 case LWSSSCS_DISCONNECTED: 182 return LWSSSSRET_DESTROY_ME; 183 184 case LWSSSCS_ALL_RETRIES_FAILED: 185 /* if we're out of retries, we want to close the app and FAIL */ 186 bad = 1; 187 return LWSSSSRET_DESTROY_ME; 188 189 case LWSSSCS_QOS_ACK_REMOTE: 190 bad = 0; 191 break; 192 193 case LWSSSCS_QOS_NACK_REMOTE: 194 bad = 1; 195 break; 196 197 case LWSSSCS_DESTROYING: 198 interrupted = 1; 199 break; 200 201 default: 202 break; 203 } 204 205 return 0; 206} 207 208const lws_ss_info_t s3_ssi = { 209 .handle_offset = offsetof(ss_s3_put_t, ss), 210 .opaque_user_data_offset = offsetof(ss_s3_put_t, opaque_data), 211 .rx = ss_s3_rx, 212 .tx = ss_s3_tx, 213 .state = ss_s3_state, 214 .user_alloc = sizeof(ss_s3_put_t), 215 .streamtype = "s3PutObj" 216}; 217