1/* 2 * S3 Put Object via Secure Streams minimal sigv4 example 3 * 4 * Written in 2010-2021 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 <stdio.h> 14#include <string.h> 15#include <signal.h> 16 17#include "ss-s3-put.h" 18#if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY) 19#include "static_policy.h" 20#endif 21 22int interrupted, bad = 1; 23static lws_state_notify_link_t nl; 24extern const lws_ss_info_t s3_ssi; 25 26#if !defined(LWS_SS_USE_SSPC) 27 28#if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY) 29static const char * const default_ss_policy = 30 "{" 31 "\"release\":" "\"01234567\"," 32 "\"product\":" "\"myproduct\"," 33 "\"schema-version\":" "1," 34 35 "\"retry\": [" /* named backoff / retry strategies */ 36 "{\"default\": {" 37 "\"backoff\": [" "100," 38 "200," 39 "300," 40 "500," 41 "1000" 42 "]," 43 "\"conceal\":" "5," 44 "\"jitterpc\":" "20," 45 "\"svalidping\":" "30," 46 "\"svalidhup\":" "35" 47 "}}" 48 "]," 49 "\"certs\": [" /* named individual certificates in BASE64 DER */ 50 "{\"amazon_root_ca_1\": \"" 51 "MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFA" 52 "DA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b2" 53 "4gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAk" 54 "GA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg" 55 "Q0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXjca9Hg" 56 "FB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM9O6II8" 57 "c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHr" 58 "QgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5" 59 "SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6" 60 "pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg" 61 "0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0" 62 "OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUAA4IBAQCY8jda" 63 "QZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PMCCjjmCXPI" 64 "6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbv" 65 "Xy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtP" 66 "HRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJi" 67 "oaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5W" 68 "TP468SQvvG5" 69 "\"}," 70 "{\"starfield_services_root_ca\": \"" 71 "MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx" 72 "EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT" 73 "HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs" 74 "ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5" 75 "MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD" 76 "VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy" 77 "ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy" 78 "dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI" 79 "hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p" 80 "OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2" 81 "8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K" 82 "Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe" 83 "hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk" 84 "6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw" 85 "DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q" 86 "AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI" 87 "bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB" 88 "ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z" 89 "qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd" 90 "iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn" 91 "0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN" 92 "sSi6" 93 "\"}," 94 "{\"baltimore_cybertrust_root\": \"" /* LE X3 signed by ISRG X1 root */ 95 "MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ" 96 "RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD" 97 "VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX" 98 "DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y" 99 "ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy" 100 "VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr" 101 "mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr" 102 "IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK" 103 "mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu" 104 "XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy" 105 "dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye" 106 "jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1" 107 "BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3" 108 "DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92" 109 "9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx" 110 "jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0" 111 "Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz" 112 "ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS" 113 "R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp" 114 "\"}" 115 "]," 116 "\"trust_stores\": [" /* named cert chains */ 117 "{" 118 "\"name\": \"s3-root-cert\"," 119 "\"stack\": [" 120 "\"baltimore_cybertrust_root\"," 121 "\"amazon_root_ca_1\"," 122 "\"starfield_services_root_ca\"" 123 "]" 124 "}" 125 "]," 126 "\"auth\": [" /* named cert chains */ 127 "{" 128 "\"name\": \"sigv4_br\"," 129 "\"type\": \"sigv4\"," 130 "\"blob\": 0" 131 "}" 132 133 "]," 134 "\"s\": [" 135 "{\"s3PutObj\": {" 136 "\"endpoint\":" "\"${s3bucket}.s3.amazonaws.com\"," 137 "\"port\":" "443," 138 "\"protocol\":" "\"h1\"," 139 "\"http_method\":" "\"PUT\"," 140 "\"http_url\":" "\"${s3Obj}\"," 141 "\"http_no_content_length\": false," 142 "\"tls\":" "true," 143 "\"tls_trust_store\":" "\"s3-root-cert\"," 144 "\"opportunistic\":" "true," 145 "\"retry\":" "\"default\"," 146 "\"use_auth\":" "\"sigv4_br\"," 147 "\"aws_region\":" "\"region\"," 148 "\"aws_service\":" "\"service\"," 149 "\"metadata\": [" 150 "{\"region\": \"\"}," 151 "{\"service\": \"\"}," 152 "{\"s3bucket\": \"\"}," 153 "{\"s3Obj\": \"\"}," 154 "{\"ctype\": \"content-type:\"}," 155 "{\"xcsha256\": \"x-amz-content-sha256:\"}," 156 "{\"xdate\": \"x-amz-date:\"}," 157 "{\"xacl\": \"x-amz-acl:\"}" 158 "]" 159 "}}" 160 "]" 161 "}" 162; 163#endif 164 165static char *aws_keyid, *aws_key; 166#endif 167 168static int 169app_system_state_nf(lws_state_manager_t *mgr, lws_state_notify_link_t *link, 170 int current, int target) 171{ 172 struct lws_context *context = lws_system_context_from_system_mgr(mgr); 173 struct lws_ss_handle *h; 174 175 switch (target) { 176 case LWS_SYSTATE_REGISTERED: 177 break; 178 179 case LWS_SYSTATE_OPERATIONAL: 180 if (current != LWS_SYSTATE_OPERATIONAL) 181 break; 182 183#if !defined(LWS_SS_USE_SSPC) 184 if (lws_aws_filesystem_credentials_helper( 185 "~/.aws/credentials", 186 "aws_access_key_id", 187 "aws_secret_access_key", 188 &aws_keyid, &aws_key)) 189 return -1; 190 lws_ss_sigv4_set_aws_key(context, 0, aws_keyid, aws_key); 191#endif 192 193 if (lws_ss_create(context, 0, &s3_ssi, NULL, &h, 194 NULL, NULL)) { 195 lwsl_err("%s: failed to create secure stream\n", 196 __func__); 197 198 return -1; 199 } 200 break; 201 } 202 203 return 0; 204} 205 206static lws_state_notify_link_t * const app_notifier_list[] = { 207 &nl, NULL 208}; 209 210static void 211sigint_handler(int sig) 212{ 213 interrupted = 1; 214} 215 216int main(int argc, const char **argv) 217{ 218 int logs = LLL_USER | LLL_ERR | LLL_WARN /* | LLL_NOTICE */ ; 219 struct lws_context_creation_info info; 220 struct lws_context *context; 221 int n = 0; 222 223 signal(SIGINT, sigint_handler); 224 lws_set_log_level(logs, NULL); 225 226 memset(&info, 0, sizeof info); 227 lws_cmdline_option_handle_builtin(argc, argv, &info); 228 229 lwsl_user("LWS minimal secure streams sigv4 \n"); 230 231 info.fd_limit_per_thread = 1 + 6 + 1; 232 info.port = CONTEXT_PORT_NO_LISTEN; 233 234#if defined(LWS_SS_USE_SSPC) 235 info.protocols = lws_sspc_protocols; 236 { 237 const char *p; 238 239 /* connect to ssproxy via UDS by default, else via 240 * tcp connection to this port */ 241 if ((p = lws_cmdline_option(argc, argv, "-p"))) 242 info.ss_proxy_port = (uint16_t)atoi(p); 243 244 /* UDS "proxy.ss.lws" in abstract namespace, else this socket 245 * path; when -p given this can specify the network interface 246 * to bind to */ 247 if ((p = lws_cmdline_option(argc, argv, "-i"))) 248 info.ss_proxy_bind = p; 249 250 /* if -p given, -a specifies the proxy address to connect to */ 251 if ((p = lws_cmdline_option(argc, argv, "-a"))) 252 info.ss_proxy_address = p; 253 } 254#else 255#if defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY) 256 info.pss_policies = &_ss_static_policy_entry; 257#else 258 info.pss_policies_json = default_ss_policy; 259#endif 260 261 info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS | 262 LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; 263#endif 264 265 /* integrate us with lws system state management when context created */ 266 267 nl.name = "app"; 268 nl.notify_cb = app_system_state_nf; 269 info.register_notifier_list = app_notifier_list; 270 271 /* create the context */ 272 273 context = lws_create_context(&info); 274 if (!context) { 275 lwsl_err("lws init failed\n"); 276 return 1; 277 } 278 279 lws_system_blob_heap_append(lws_system_get_blob(context, 280 LWS_SYSBLOB_TYPE_DEVICE_TYPE, 0), 281 (const uint8_t *)"beerfountain", 12); 282 283 /* the event loop */ 284 285 while (n >= 0 && !interrupted) 286 n = lws_service(context, 0); 287 288 lws_context_destroy(context); 289 290#if !defined(LWS_SS_USE_SSPC) 291 if (aws_key) 292 free(aws_key); 293 if (aws_keyid) 294 free(aws_keyid); 295#endif 296 297 lwsl_user("Completed: %s\n", bad ? "failed" : "OK"); 298 299 return bad; 300} 301