/* This file is part of Eclat. Copyright (C) 2012, 2013 Sergey Poznyakoff. Eclat is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. Eclat is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Eclat. If not, see . */ #include #include #include #include "libeclat.h" #include "sha256.h" #include "grecs.h" struct pname { size_t i; char **a; }; static int get_param_name(void *sym, void *data) { struct grecs_syment *se = sym; struct pname *pn = data; pn->a[pn->i++] = se->name; return 0; } static int compnames(const void *a, const void *b) { char * const *ac = a; char * const *bc = b; return strcmp(*ac, *bc); } static void querysign2(struct ec2_query *req, char *secret) { char **pnames; size_t i, n; struct grecs_txtacc *acc; struct pname pn; char *str; char digest[SHA256_DIGEST_SIZE]; size_t siglen; const char *verb; char tsbuf[22]; time_t t; acc = grecs_txtacc_create(); /* Add default parameters */ eclat_query_add_param(req, "SignatureMethod", "HmacSHA256"); eclat_query_add_param(req, "SignatureVersion", "2"); time(&t); strftime(tsbuf, sizeof(tsbuf), "%Y-%m-%dT%H:%M:%SZ", gmtime(&t)); eclat_query_add_param(req, "Timestamp", tsbuf); eclat_query_encode(req); /* Collect and sort parameter names */ n = grecs_symtab_count_entries(req->params); pnames = grecs_calloc(n, sizeof(pnames[0])); pn.i = 0; pn.a = pnames; grecs_symtab_enumerate(req->params, get_param_name, &pn); qsort(pnames, n, sizeof(pnames[0]), compnames); verb = (req->flags & EC2_QF_POST) ? "POST" : "GET"; grecs_txtacc_grow(acc, verb, strlen(verb)); grecs_txtacc_grow_char(acc, '\n'); grecs_txtacc_grow(acc, req->endpoint, strlen(req->endpoint)); grecs_txtacc_grow_char(acc, '\n'); grecs_txtacc_grow(acc, req->uri, strlen(req->uri)); grecs_txtacc_grow_char(acc, '\n'); /* Append a canonicalized query string */ for (i = 0; i < n; i++) { struct ec2_param *p, key; key.name = pnames[i]; p = grecs_symtab_lookup_or_install(req->params, &key, NULL); if (!p) abort(); if (i != 0) grecs_txtacc_grow_char(acc, '&'); grecs_txtacc_grow(acc, p->name, strlen(p->name)); if (p->value) { grecs_txtacc_grow_char(acc, '='); grecs_txtacc_grow(acc, p->value, strlen(p->value)); } } grecs_txtacc_grow_char(acc, 0); str = grecs_txtacc_finish(acc, 0); hmac_sha256(str, strlen(str), secret, strlen(secret), digest); eclat_base64_encode((unsigned char *)digest, sizeof(digest), (unsigned char**) &req->signature, &siglen); grecs_txtacc_free(acc); free(pnames); /*FIXME t += req->ttl; strftime(tsbuf, sizeof(tsbuf), "%Y-%m-%dT%H:%M:%SZ", gmtime(&t)); eclat_query_add_param(req, "Expires", tsbuf); */ } static void querysign4(struct ec2_query *req, char *secret) { abort(); } struct qsimpl { char *qs_version; void (*qs_fun)(struct ec2_query *, char *); }; static struct qsimpl qstab[] = { { "2", querysign2 }, { "4", querysign4 }, { NULL } }; void eclat_query_sign(struct ec2_query *req, char *secret, char *version) { struct qsimpl *qs; for (qs = qstab; qs->qs_version && strcmp(qs->qs_version, version); qs++) ; if (qs->qs_version) qs->qs_fun(req, secret); else { err("INTERNAL ERROR: unsupported version %s", version); abort(); } }