Skip to content

Commit ae3acea

Browse files
committed
implementated necessary methods
1 parent 6c7d1e1 commit ae3acea

File tree

4 files changed

+177
-281
lines changed

4 files changed

+177
-281
lines changed

src/common/AWSClient4.cpp

Lines changed: 130 additions & 231 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* AWSClient.cpp
33
*
44
* See AWSClient.h for description.
5+
* See http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html
56
*
67
*/
78

@@ -13,7 +14,6 @@
1314
#include <string.h>
1415
#include <stdlib.h>
1516
#include <stdio.h>
16-
#include <map>
1717

1818
//
1919
// /* Constants string, formats, and lengths. */
@@ -54,6 +54,8 @@ AWSClient4::AWSClient4() {
5454
awsKeyID = 0;
5555
httpClient = 0;
5656
dateTimeProvider = 0;
57+
method = 0;
58+
uri = 0;
5759
}
5860

5961
void AWSClient4::setAWSRegion(const char * awsRegion) {
@@ -92,235 +94,111 @@ void AWSClient4::setHttpClient(IHttpClient* httpClient) {
9294
void AWSClient4::setDateTimeProvider(IDateTimeProvider* dateTimeProvider) {
9395
this->dateTimeProvider = dateTimeProvider;
9496
}
95-
//
96-
// AWSClient4::~AWSClient4() {
97-
// if (awsRegion != 0)
98-
// delete[] awsRegion;
99-
// if (awsEndpoint != 0)
100-
// delete[] awsEndpoint;
101-
// if (awsSecKey != 0)
102-
// delete[] awsSecKey;
103-
// if (awsKeyID != 0)
104-
// delete[] awsKeyID;
105-
// }
106-
//
107-
// void AWSClient4::initSignedHeaders() {
108-
// /* For each of the formats for unsigned headers, determine the size of the
109-
// * formatted string, allocate that much space in the next available element
110-
// * in the headers array, create the string, and add it's length to the
111-
// * headerLens array. */
112-
//
113-
// int contentLen = payload.length();
114-
// int len = CONTENT_LENGTH_HEADER_LEN + digitCount(contentLen);
115-
// headers[headersCreated] = new char[len + 1]();
116-
// sprintf(headers[headersCreated], CONTENT_LENGTH_HEADER, contentLen);
117-
// headerLens[headersCreated++] = len;
118-
//
119-
// len = CONTENT_TYPE_HEADER_LEN + strlen(contentType);
120-
// headers[headersCreated] = new char[len + 1]();
121-
// sprintf(headers[headersCreated], CONTENT_TYPE_HEADER, contentType);
122-
// headerLens[headersCreated++] = len;
123-
//
124-
// char* host = createHostString();
125-
// len = HOST_HEADER_LEN + strlen(host);
126-
// headers[headersCreated] = new char[len + 1]();
127-
//
128-
// sprintf(headers[headersCreated], HOST_HEADER, host);
129-
// headerLens[headersCreated++] = len;
130-
//
131-
// len = X_AMZ_DATE_HEADER_LEN + AWS_DATE_LEN2 + AWS_TIME_LEN2;
132-
// headers[headersCreated] = new char[len + 1]();
133-
// sprintf(headers[headersCreated], X_AMZ_DATE_HEADER, awsDate, awsTime);
134-
// headerLens[headersCreated++] = len;
135-
// }
136-
//
137-
// char* AWSClient4::createHostString(void) {
138-
// if(awsDomain[0] != '\0') {
139-
// return awsDomain;
140-
// } else {
141-
// char* host = new char[200]();
142-
// sprintf(host, "%s.%s.%s", awsService, awsRegion, awsEndpoint);
143-
// return host;
144-
// }
145-
// }
146-
//
147-
// char* AWSClient4::createStringToSign(void) {
148-
// SHA256* sha256 = new SHA256();
149-
// char* hashed;
150-
// /* Calculate length of canonicalForm string. */
151-
// int canonicalFormLen = CANONICAL_FORM_POST_LINE_LEN;
152-
// for (int i = 0; i < headersCreated; i++) {
153-
// /* +1 for newlines */
154-
// canonicalFormLen += *(headerLens + i) + 1;
155-
// }
156-
// /* +2 for newlines. */
157-
// canonicalFormLen += SIGNED_HEADERS_LEN + HASH_HEX_LEN2 + 2;
158-
//
159-
// char* canonicalForm = new char[canonicalFormLen + 1]();
160-
//
161-
// /* Write the cannonicalForm string. */
162-
// int canonicalFormWritten = 0;
163-
// canonicalFormWritten += strlen(
164-
// strcpy(canonicalForm + canonicalFormWritten,
165-
// CANONICAL_FORM_POST_LINE));
166-
// for (int i = 0; i < headersCreated; i++) {
167-
// canonicalFormWritten += sprintf(canonicalForm + canonicalFormWritten,
168-
// "%s\n", *(headers + i));
169-
// }
170-
// canonicalFormWritten += sprintf(canonicalForm + canonicalFormWritten,
171-
// "\n%s\n", SIGNED_HEADERS);
172-
// hashed = (*sha256)(payload.getCStr(), payload.length());
173-
// strcpy(canonicalForm + canonicalFormWritten, hashed);
174-
// delete[] hashed;
175-
// canonicalFormWritten += HASH_HEX_LEN2;
176-
//
177-
// /* Hash the canonicalForm string. */
178-
// hashed = (*sha256)(canonicalForm, canonicalFormWritten);
179-
// delete sha256;
180-
//
181-
// delete[] canonicalForm;
182-
//
183-
// /* Determine the size to the string to sign. */
184-
// int toSignLen = TO_SIGN_TEMPLATE_LEN + 2 * AWS_DATE_LEN2 + AWS_TIME_LEN2
185-
// + strlen(awsRegion) + strlen(awsService) + HASH_HEX_LEN2;
186-
//
187-
// /* Create and return the string to sign. */
188-
// char* toSign = new char[toSignLen + 1]();
189-
// sprintf(toSign, TO_SIGN_TEMPLATE, awsDate, awsTime, awsDate, awsRegion,
190-
// awsService, hashed);
191-
// delete[] hashed;
192-
// return toSign;
193-
//
194-
// }
195-
// char* AWSClient4::createSignature(const char* toSign) {
196-
//
197-
// /* Allocate memory for the signature */
198-
// char* signature = new char[HASH_HEX_LEN2 + 1]();
199-
//
200-
// /* Create the signature key */
201-
// /* + 4 for "AWS4" */
202-
// int keyLen = strlen(awsSecKey) + 4;
203-
// char* key = new char[keyLen + 1]();
204-
// sprintf(key, "AWS4%s", awsSecKey);
205-
//
206-
// /* repeatedly apply hmac with the appropriate values. See
207-
// * http://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html
208-
// * for algorithm. */
209-
// char* k1 = hmacSha256(key, keyLen, awsDate, strlen(awsDate));
210-
// delete[] key;
211-
// char* k2 = hmacSha256(k1, SHA256_DEC_HASH_LEN, awsRegion,
212-
// strlen(awsRegion));
213-
// delete[] k1;
214-
// char* k3 = hmacSha256(k2, SHA256_DEC_HASH_LEN, awsService,
215-
// strlen(awsService));
216-
// delete[] k2;
217-
// char* k4 = hmacSha256(k3, SHA256_DEC_HASH_LEN, "aws4_request", 12);
218-
// delete[] k3;
219-
// char* k5 = hmacSha256(k4, SHA256_DEC_HASH_LEN, toSign, strlen(toSign));
220-
// delete[] k4;
221-
//
222-
// /* Convert the chars in hash to hex for signature. */
223-
// for (int i = 0; i < SHA256_DEC_HASH_LEN; ++i) {
224-
// sprintf(signature + 2 * i, "%02lx", 0xff & (unsigned long) k5[i]);
225-
// }
226-
// delete[] k5;
227-
// return signature;
228-
// }
229-
//
230-
// void AWSClient4::initUnsignedHeaders(const char* signature) {
231-
// int len = AUTHORIZATION_HEADER_LEN + strlen(awsKeyID) + AWS_DATE_LEN2
232-
// + strlen(awsRegion) + strlen(awsService) + SIGNED_HEADERS_LEN
233-
// + HASH_HEX_LEN2;
234-
// headers[headersCreated] = new char[len + 1]();
235-
// sprintf(headers[headersCreated], AUTHORIZATION_HEADER, awsKeyID, awsDate,
236-
// awsRegion, awsService, SIGNED_HEADERS, signature);
237-
// headerLens[headersCreated++] = len;
238-
// /*
239-
// len = CONNECTION_HEADER_LEN;
240-
// headers[headersCreated] = new char[len + 1]();
241-
// strcpy(headers[headersCreated], CONNECTION_HEADER);
242-
// headerLens[headersCreated++] = len;
243-
// */
244-
// }
245-
//
246-
// void AWSClient4::createRequestInit(MinimalString &reqPayload) {
247-
// //initialize object-scoped variables
248-
// const char* dateTime = dateTimeProvider->getDateTime();
249-
//
250-
// // @TODO: not sure yet why sprintf doesn't work here
251-
// strncpy(awsDate, dateTime, 8);
252-
// awsDate[9] = '\0';
253-
// strncpy(awsTime, dateTime + 8, 6);
254-
// awsTime[7] = '\0';
255-
//
256-
// Serial.println(awsDate);
257-
// Serial.println(awsTime);
258-
//
259-
// payload = reqPayload;
260-
// headersCreated = 0;
261-
//
262-
// //Create signature and headers
263-
// initSignedHeaders();
264-
// char* toSign = createStringToSign();
265-
// char* signature = createSignature(toSign);
266-
// delete[] toSign;
267-
// initUnsignedHeaders(signature);
268-
// delete[] signature;
269-
// }
270-
//
271-
// void AWSClient4::createRequestCleanup() {
272-
// /* Free each header */
273-
// for (int i = 0; i < headersCreated; i++) {
274-
// delete[] headers[i];
275-
// }
276-
// }
277-
//
278-
// char* AWSClient4::headersToRequest() {
279-
// /* Determine whether to use https or http postLine values. */
280-
// int postLineLen =
281-
// httpS ? HTTPS_REQUEST_POST_LINE_LEN : HTTP_REQUEST_POST_LINE_LEN;
282-
// const char* postLine =
283-
// httpS ? HTTPS_REQUEST_POST_LINE : HTTP_REQUEST_POST_LINE;
284-
//
285-
// /* Calculate length of httpRequest string. */
286-
// char* host = createHostString();
287-
// int httpRequestLen;
288-
//
289-
// // if a path is set, append it to the post header
290-
// if(awsPath[0] != '\0') {
291-
// httpRequestLen = postLineLen + strlen(host) + strlen(awsPath);
292-
// } else {
293-
// httpRequestLen = postLineLen + strlen(host);
294-
// }
295-
//
296-
// for (int i = 0; i < headersCreated; i++) {
297-
// /* +1 for newline. */
298-
// httpRequestLen += *(headerLens + i) + 1;
299-
// }
300-
// /* +1 for newline. */
301-
// httpRequestLen += payload.length() + 1;
302-
//
303-
// /* Create and write to the httpRequest string. */
304-
// char* httpRequest = new char[httpRequestLen + 1]();
305-
// int httpRequestWritten = 0;
306-
//
307-
// // if a path is set, append it to the post header
308-
// if(awsPath[0] != '\0') {
309-
// httpRequestWritten += sprintf(httpRequest + httpRequestWritten, postLine, host, awsPath);
310-
// } else {
311-
// httpRequestWritten += sprintf(httpRequest + httpRequestWritten, postLine, host);
312-
// }
313-
// for (int i = 0; i < headersCreated; i++) {
314-
// httpRequestWritten += sprintf(httpRequest + httpRequestWritten, "%s\n",
315-
// *(headers + i));
316-
// }
317-
// httpRequestWritten += sprintf(httpRequest + httpRequestWritten, "\n%s",
318-
// payload.getCStr());
319-
//
320-
// return httpRequest;
321-
// }
32297

98+
AWSClient4::~AWSClient4() {
99+
if (awsRegion != 0)
100+
delete[] awsRegion;
101+
if (awsEndpoint != 0)
102+
delete[] awsEndpoint;
103+
if (awsSecKey != 0)
104+
delete[] awsSecKey;
105+
if (awsKeyID != 0)
106+
delete[] awsKeyID;
107+
}
108+
109+
char* AWSClient4::createHost() {
110+
// return "example.com";
111+
return awsDomain;
112+
}
113+
114+
char* AWSClient4::createCanonicalHeaders() {
115+
// headers, alphabetically sorted, lowercase, eg: key:value
116+
// content-type:x
117+
// host:host
118+
// x-amz-content-sha256:hash
119+
// x-amz-date:date
120+
char canonical_headers[500] = "";
121+
sprintf(canonical_headers, "%scontent-type:%s\n", canonical_headers, contentType);
122+
sprintf(canonical_headers, "%shost:%s\n", canonical_headers, createHost());
123+
sprintf(canonical_headers, "%sx-amz-content-sha256:%s\n", canonical_headers, payloadHash);
124+
sprintf(canonical_headers, "%sx-amz-date:%sT%sZ\n", canonical_headers, awsDate, awsTime);
125+
return canonical_headers;
126+
}
127+
128+
char* AWSClient4::createRequestHeaders(char* signature) {
129+
char headers[1000] = "";
130+
sprintf(headers, "%sContent-Type: %s\n", headers, contentType);
131+
sprintf(headers, "%sHost: %s\n", headers, createHost());
132+
sprintf(headers, "%sx-amz-content-sha256: %s\n", headers, payloadHash);
133+
sprintf(headers, "%sx-amz-date: %sT%sZ\n", headers, awsDate, awsTime);
134+
sprintf(headers, "%sAuthorization: AWS4-HMAC-SHA256 Credential=%s/%s/%s/%s/aws4_request,SignedHeaders=%s,Signature=%s\n", headers, awsKeyID, awsDate, awsRegion, awsService, signedHeaders, signature);
135+
return headers;
136+
}
137+
138+
char* AWSClient4::createStringToSign(char* canonical_request) {
139+
char string_to_sign[700] = "AWS4-HMAC-SHA256\n";
140+
sprintf(string_to_sign, "%s%sT%sZ\n", canonical_request, awsDate, awsTime);
141+
sprintf(string_to_sign, "%s%s/%s/%s/aws4_request\n", canonical_request, awsDate, awsRegion, awsService);
142+
143+
SHA256* sha256 = new SHA256();
144+
char* hashed = (*sha256)(canonical_request, strlen(canonical_request));
145+
delete sha256;
146+
147+
sprintf(string_to_sign, "%s%s", canonical_request, hashed);
148+
149+
return string_to_sign;
150+
}
151+
152+
char* AWSClient4::createCanonicalRequest() {
153+
char canonical_request[700] = "";
154+
sprintf(canonical_request, "%s%s\n", canonical_request, method); // VERB
155+
sprintf(canonical_request, "%s%s\n", canonical_request, uri); // URI
156+
sprintf(canonical_request, "%s%s\n", canonical_request, queryString); // queryString
323157

158+
char* headers = createCanonicalHeaders();
159+
160+
sprintf(canonical_request, "%s%s", canonical_request, headers); // headers
161+
sprintf(canonical_request, "%s%s\n", canonical_request, signedHeaders); // signed_headers
162+
sprintf(canonical_request, "%s%s\n", canonical_request, payload.getCStr()); // payload
163+
164+
return canonical_request;
165+
}
166+
167+
168+
char* AWSClient4::createSignature(const char* toSign) {
169+
170+
/* Allocate memory for the signature */
171+
char* signature = new char[HASH_HEX_LEN4 + 1]();
172+
173+
/* Create the signature key */
174+
/* + 4 for "AWS4" */
175+
int keyLen = strlen(awsSecKey) + 4;
176+
char* key = new char[keyLen + 1]();
177+
sprintf(key, "AWS4%s", awsSecKey);
178+
179+
/* repeatedly apply hmac with the appropriate values. See
180+
* http://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html
181+
* for algorithm. */
182+
char* k1 = hmacSha256(key, keyLen, awsDate, strlen(awsDate));
183+
delete[] key;
184+
char* k2 = hmacSha256(k1, SHA256_DEC_HASH_LEN, awsRegion,
185+
strlen(awsRegion));
186+
delete[] k1;
187+
char* k3 = hmacSha256(k2, SHA256_DEC_HASH_LEN, awsService,
188+
strlen(awsService));
189+
delete[] k2;
190+
char* k4 = hmacSha256(k3, SHA256_DEC_HASH_LEN, "aws4_request", 12);
191+
delete[] k3;
192+
char* k5 = hmacSha256(k4, SHA256_DEC_HASH_LEN, toSign, strlen(toSign));
193+
delete[] k4;
194+
195+
/* Convert the chars in hash to hex for signature. */
196+
for (int i = 0; i < SHA256_DEC_HASH_LEN; ++i) {
197+
sprintf(signature + 2 * i, "%02lx", 0xff & (unsigned long) k5[i]);
198+
}
199+
delete[] k5;
200+
return signature;
201+
}
324202

325203

326204
char* AWSClient4::createRequest(MinimalString &reqPayload) {
@@ -329,10 +207,31 @@ char* AWSClient4::createRequest(MinimalString &reqPayload) {
329207
|| httpClient == 0 || dateTimeProvider == 0)
330208
return 0;
331209

332-
map<string,string> headers;
333-
headers['host'] = "bar";
210+
// set date and time
211+
// @TODO: find out why sprintf doesn't work
212+
const char* dateTime = dateTimeProvider->getDateTime();
213+
strncpy(awsDate, dateTime, 8);
214+
awsDate[9] = '\0';
215+
strncpy(awsTime, dateTime + 8, 6);
216+
awsTime[7] = '\0';
217+
218+
SHA256* sha256 = new SHA256();
219+
payloadHash = (*sha256)(reqPayload.getCStr(), reqPayload.length());
220+
delete sha256;
221+
222+
payload = reqPayload;
223+
224+
char *canonical_request = createCanonicalRequest();
225+
char *string_to_sign = createStringToSign(canonical_request);
226+
char *signature = createSignature(string_to_sign);
227+
228+
char *headers = createRequestHeaders(signature);
229+
230+
char *host = createHost();
231+
char* request = new char[strlen(method) + strlen(host) + strlen(awsPath) + strlen(headers) + strlen(reqPayload.getCStr()) + 4]();
232+
sprintf(request, "%s %s%s\n%s\n%s", method, createHost(), awsPath, headers, reqPayload.getCStr());
334233

335-
return headers['host'];
234+
return request;
336235

337236
// createRequestInit(reqPayload);
338237
// char* request = headersToRequest();

0 commit comments

Comments
 (0)