Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wip rgw aws4 #7720

Merged
merged 29 commits into from Feb 20, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
9a0de48
rgw: AWS4 authentication minimal support
jmunhoz Jun 12, 2015
cbfc4af
rgw: handle AWS4 auth case when query string exists
jmunhoz Jun 24, 2015
a15abe4
rgw: add proper AWSv4 and AWSv2 auth detection
jmunhoz Jun 24, 2015
49856eb
rgw: AWS4 auth support when using request params
jmunhoz Jul 3, 2015
483ad81
rgw: avoid re-encoding already encoded query strings in AWS4 auth
jmunhoz Jul 2, 2015
466cb81
rgw: UNSIGNED-PAYLOAD support in AWS4 auth
jmunhoz Sep 14, 2015
3210cd8
rgw: AWS4 auth support for positive content-length
jmunhoz Sep 21, 2015
b7772ca
rgw: initialize aws4_auth_complete
jmunhoz Oct 9, 2015
c32e5ea
rgw: verify Content-MD5 is a valid base64 value
jmunhoz Oct 9, 2015
79b6b4f
rgw: check if x-amz-date has a value
jmunhoz Oct 15, 2015
2de292a
rgw: validate x-amz-sha256
jmunhoz Oct 15, 2015
4da8539
rgw: achieve same error behaviour in S3 and RGW when processing signe…
jmunhoz Oct 23, 2015
52e601b
rgw: multiple fixes and adjustments following aws4 code review
yehudasa Oct 28, 2015
537e549
Revert "rgw: avoid re-encoding already encoded query strings in AWS4 …
jmunhoz Nov 5, 2015
f7f2198
rgw: do not encode key/val when computing canonical qs
jmunhoz Nov 5, 2015
e533917
rgw: verify X-Amz-Date
jmunhoz Nov 13, 2015
5547754
rgw: return -EINVAL on unknow authorization
jmunhoz Nov 13, 2015
e28072e
rgw: add AWS4 completion support for RGW_OP_PUT_OBJ
jmunhoz Jan 13, 2016
8e1048d
rgw: add AWS4 completion support for RGW_OP_PUT_ACLS
jmunhoz Jan 13, 2016
e183009
rgw: raise error on not implemented AWS4 completions
jmunhoz Jan 14, 2016
f851cbc
rgw: implement RGWOp_Metadata_Put::get_type()
yehudasa Jan 15, 2016
b052b0d
rgw: implement missing handlers for aws4 signatures
yehudasa Jan 15, 2016
8a4f8e8
rgw: escape aws4 query string
yehudasa Jan 15, 2016
84bd2af
rgw: add x-amz-expires support
jmunhoz Jan 18, 2016
16646c3
rgw: add aws4 auth grace period
jmunhoz Jan 18, 2016
cc8f31b
rgw: fix bug encoding percentage char in X-Amz-Credential
jmunhoz Jan 23, 2016
e9917a6
rgw: fix host field in canonical headers under qs
jmunhoz Jan 23, 2016
ce42172
rgw: catch up aws4 with the new features
jmunhoz Feb 14, 2016
5527159
Merge remote-tracking branch 'jmunhoz/wip-aws4' into wip-aws4
yehudasa Feb 19, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/common/ceph_crypto.cc
Expand Up @@ -36,6 +36,10 @@ ceph::crypto::HMACSHA1::~HMACSHA1()
{
}

ceph::crypto::HMACSHA256::~HMACSHA256()
{
}

#elif defined(USE_NSS)

// for SECMOD_RestartModules()
Expand Down Expand Up @@ -85,7 +89,7 @@ void ceph::crypto::shutdown()
pthread_mutex_unlock(&crypto_init_mutex);
}

ceph::crypto::HMACSHA1::~HMACSHA1()
ceph::crypto::HMAC::~HMAC()
{
PK11_DestroyContext(ctx, PR_TRUE);
PK11_FreeSymKey(symkey);
Expand Down
38 changes: 30 additions & 8 deletions src/common/ceph_crypto.h
Expand Up @@ -6,6 +6,7 @@
#define CEPH_CRYPTO_MD5_DIGESTSIZE 16
#define CEPH_CRYPTO_HMACSHA1_DIGESTSIZE 20
#define CEPH_CRYPTO_SHA1_DIGESTSIZE 20
#define CEPH_CRYPTO_HMACSHA256_DIGESTSIZE 32
#define CEPH_CRYPTO_SHA256_DIGESTSIZE 32

#ifdef USE_CRYPTOPP
Expand Down Expand Up @@ -36,6 +37,15 @@ namespace ceph {
}
~HMACSHA1();
};

class HMACSHA256: public CryptoPP::HMAC<CryptoPP::SHA256> {
public:
HMACSHA256 (const byte *key, size_t length)
: CryptoPP::HMAC<CryptoPP::SHA256>(key, length)
{
}
~HMACSHA256();
};
}
}
#elif defined(USE_NSS)
Expand Down Expand Up @@ -107,31 +117,33 @@ namespace ceph {
SHA256 () : Digest(SEC_OID_SHA256, CEPH_CRYPTO_SHA256_DIGESTSIZE) { }
};

class HMACSHA1 {
class HMAC {
private:
PK11SlotInfo *slot;
PK11SymKey *symkey;
PK11Context *ctx;
unsigned int digest_size;
public:
HMACSHA1 (const byte *key, size_t length) {
slot = PK11_GetBestSlot(CKM_SHA_1_HMAC, NULL);
HMAC (CK_MECHANISM_TYPE cktype, unsigned int digestsize, const byte *key, size_t length) {
digest_size = digestsize;
slot = PK11_GetBestSlot(cktype, NULL);
assert(slot);
SECItem keyItem;
keyItem.type = siBuffer;
keyItem.data = (unsigned char*)key;
keyItem.len = length;
symkey = PK11_ImportSymKey(slot, CKM_SHA_1_HMAC, PK11_OriginUnwrap,
symkey = PK11_ImportSymKey(slot, cktype, PK11_OriginUnwrap,
CKA_SIGN, &keyItem, NULL);
assert(symkey);
SECItem param;
param.type = siBuffer;
param.data = NULL;
param.len = 0;
ctx = PK11_CreateContextBySymKey(CKM_SHA_1_HMAC, CKA_SIGN, symkey, &param);
ctx = PK11_CreateContextBySymKey(cktype, CKA_SIGN, symkey, &param);
assert(ctx);
Restart();
}
~HMACSHA1 ();
~HMAC ();
void Restart() {
SECStatus s;
s = PK11_DigestBegin(ctx);
Expand All @@ -145,12 +157,22 @@ namespace ceph {
void Final (byte *digest) {
SECStatus s;
unsigned int dummy;
s = PK11_DigestFinal(ctx, digest, &dummy, CEPH_CRYPTO_HMACSHA1_DIGESTSIZE);
s = PK11_DigestFinal(ctx, digest, &dummy, digest_size);
assert(s == SECSuccess);
assert(dummy == CEPH_CRYPTO_HMACSHA1_DIGESTSIZE);
assert(dummy == digest_size);
Restart();
}
};

class HMACSHA1 : public HMAC {
public:
HMACSHA1 (const byte *key, size_t length) : HMAC(CKM_SHA_1_HMAC, CEPH_CRYPTO_HMACSHA1_DIGESTSIZE, key, length) { }
};

class HMACSHA256 : public HMAC {
public:
HMACSHA256 (const byte *key, size_t length) : HMAC(CKM_SHA256_HMAC, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, key, length) { }
};
}
}

Expand Down
3 changes: 0 additions & 3 deletions src/common/utf8.c
Expand Up @@ -16,9 +16,6 @@
#include <stdio.h>
#include <string.h>

#define MAX_UTF8_SZ 6
#define INVALID_UTF8_CHAR 0xfffffffful

static int high_bits_set(int c)
{
int ret = 0;
Expand Down
3 changes: 3 additions & 0 deletions src/common/utf8.h
Expand Up @@ -15,6 +15,9 @@
#ifndef CEPH_COMMON_UTF8_H
#define CEPH_COMMON_UTF8_H

#define MAX_UTF8_SZ 6
#define INVALID_UTF8_CHAR 0xfffffffful

#ifdef __cplusplus
extern "C" {
#endif
Expand Down
198 changes: 198 additions & 0 deletions src/rgw/rgw_auth_s3.cc
Expand Up @@ -2,7 +2,10 @@
// vim: ts=8 sw=2 smarttab

#include "common/armor.h"
#include "common/utf8.h"
#include "rgw_common.h"
#include "rgw_client_io.h"
#include "rgw_rest.h"

#define dout_subsys ceph_subsys_rgw

Expand Down Expand Up @@ -147,6 +150,11 @@ int rgw_get_s3_header_digest(const string& auth_hdr, const string& key, string&
return 0;
}

void rgw_hash_s3_string_sha256(const char *data, int len, string& dest)
{
calc_hash_sha256(data, len, dest);
}

static inline bool is_base64_for_content_md5(unsigned char c) {
return (isalnum(c) || isspace(c) || (c == '+') || (c == '/') || (c == '='));
}
Expand Down Expand Up @@ -214,3 +222,193 @@ bool rgw_create_s3_canonical_header(req_info& info, utime_t *header_time, string

return true;
}

/*
* assemble canonical request for signature version 4
*/
void rgw_assemble_s3_v4_canonical_request(const char *method, const char *canonical_uri, const char *canonical_qs,
const char *canonical_hdrs, const char *signed_hdrs, const char *request_payload_hash,
string& dest_str)
{
string dest;

if (method)
dest = method;
dest.append("\n");

if (canonical_uri) {
dest.append(canonical_uri);
}
dest.append("\n");

if (canonical_qs) {
dest.append(canonical_qs);
}
dest.append("\n");

if (canonical_hdrs)
dest.append(canonical_hdrs);
dest.append("\n");

if (signed_hdrs)
dest.append(signed_hdrs);
dest.append("\n");

if (request_payload_hash)
dest.append(request_payload_hash);

dest_str = dest;
}

/*
* create canonical request for signature version 4
*/
void rgw_create_s3_v4_canonical_request(struct req_state *s, const string& canonical_uri, const string& canonical_qs,
const string& canonical_hdrs, const string& signed_hdrs, const string& request_payload,
bool unsigned_payload, string& canonical_req, string& canonical_req_hash)
{
string request_payload_hash;

if (unsigned_payload) {
request_payload_hash = "UNSIGNED-PAYLOAD";
} else {
if (s->aws4_auth_needs_complete) {
request_payload_hash = STREAM_IO(s)->grab_aws4_sha256_hash();
} else {
rgw_hash_s3_string_sha256(request_payload.c_str(), request_payload.size(), request_payload_hash);
}
}

s->aws4_auth->payload_hash = request_payload_hash;

ldout(s->cct, 10) << "payload request hash = " << request_payload_hash << dendl;

rgw_assemble_s3_v4_canonical_request(s->info.method, canonical_uri.c_str(),
canonical_qs.c_str(), canonical_hdrs.c_str(), signed_hdrs.c_str(),
request_payload_hash.c_str(), canonical_req);

rgw_hash_s3_string_sha256(canonical_req.c_str(), canonical_req.size(), canonical_req_hash);

ldout(s->cct, 10) << "canonical request = " << canonical_req << dendl;
ldout(s->cct, 10) << "canonical request hash = " << canonical_req_hash << dendl;
}

/*
* assemble string to sign for signature version 4
*/
void rgw_assemble_s3_v4_string_to_sign(const char *algorithm, const char *request_date,
const char *credential_scope, const char *hashed_qr, string& dest_str)
{
string dest;

if (algorithm)
dest = algorithm;
dest.append("\n");

if (request_date)
dest.append(request_date);
dest.append("\n");

if (credential_scope)
dest.append(credential_scope);
dest.append("\n");

if (hashed_qr)
dest.append(hashed_qr);

dest_str = dest;
}

/*
* create string to sign for signature version 4
*/
void rgw_create_s3_v4_string_to_sign(CephContext *cct, const string& algorithm, const string& request_date,
const string& credential_scope, const string& hashed_qr,
string& string_to_sign) {

rgw_assemble_s3_v4_string_to_sign(algorithm.c_str(), request_date.c_str(),
credential_scope.c_str(), hashed_qr.c_str(), string_to_sign);

ldout(cct, 10) << "string to sign = " << string_to_sign << dendl;
}

/*
* calculate the AWS signature version 4
*/
int rgw_calculate_s3_v4_aws_signature(struct req_state *s,
const string& access_key_id, const string &date, const string& region,
const string& service, const string& string_to_sign, string& signature) {

map<string, RGWAccessKey>::iterator iter = s->user->access_keys.find(access_key_id);
if (iter == s->user->access_keys.end()) {
ldout(s->cct, 10) << "ERROR: access key not encoded in user info" << dendl;
return -EPERM;
}

RGWAccessKey& k = iter->second;

string secret_key = "AWS4" + k.key;

char secret_k[secret_key.size() * MAX_UTF8_SZ];

size_t n = 0;

for (size_t i = 0; i < secret_key.size(); i++) {
n += encode_utf8(secret_key[i], (unsigned char *) (secret_k + n));
}

string secret_key_utf8_k(secret_k, n);

/* date */

char date_k[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE];
calc_hmac_sha256(secret_key_utf8_k.c_str(), secret_key_utf8_k.size(),
date.c_str(), date.size(), date_k);

char aux[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE * 2 + 1];
buf_to_hex((unsigned char *) date_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, aux);

ldout(s->cct, 10) << "date_k = " << string(aux) << dendl;

/* region */

char region_k[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE];
calc_hmac_sha256(date_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, region.c_str(), region.size(), region_k);

buf_to_hex((unsigned char *) region_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, aux);

ldout(s->cct, 10) << "region_k = " << string(aux) << dendl;

/* service */

char service_k[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE];
calc_hmac_sha256(region_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, service.c_str(), service.size(), service_k);

buf_to_hex((unsigned char *) service_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, aux);

ldout(s->cct, 10) << "service_k = " << string(aux) << dendl;

/* aws4_request */

char signing_k[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE];
calc_hmac_sha256(service_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, "aws4_request", 12, signing_k);

buf_to_hex((unsigned char *) signing_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, aux);

ldout(s->cct, 10) << "signing_k = " << string(aux) << dendl;

/* new signature */

char signature_k[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE];
calc_hmac_sha256(signing_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, string_to_sign.c_str(), string_to_sign.size(), signature_k);

buf_to_hex((unsigned char *) signature_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, aux);

ldout(s->cct, 10) << "signature_k = " << string(aux) << dendl;

signature = string(aux);

ldout(s->cct, 10) << "new signature = " << signature << dendl;

return 0;
}
15 changes: 15 additions & 0 deletions src/rgw/rgw_auth_s3.h
Expand Up @@ -18,5 +18,20 @@ bool rgw_create_s3_canonical_header(req_info& info, utime_t *header_time,
string& dest, bool qsr);
int rgw_get_s3_header_digest(const string& auth_hdr, const string& key,
string& dest);
int rgw_get_s3_header_digest(const string& auth_hdr, const string& key, string& dest);

void rgw_hash_s3_string_sha256(const char *data, int len, string& dest);
void rgw_create_s3_v4_canonical_request(struct req_state *s, const string& canonical_uri,
const string& canonical_qs, const string& canonical_hdrs,
const string& signed_hdrs, const string& request_payload,
bool unsigned_payload,
string& canonical_req, string& canonical_req_hash);
void rgw_create_s3_v4_string_to_sign(CephContext *cct, const string& algorithm,
const string& request_date, const string& credential_scope,
const string& hashed_qr, string& string_to_sign);
int rgw_calculate_s3_v4_aws_signature(struct req_state *s, const string& access_key_id,
const string &date, const string& region,
const string& service, const string& string_to_sign,
string& signature);

#endif
14 changes: 13 additions & 1 deletion src/rgw/rgw_client_io.cc
Expand Up @@ -69,7 +69,7 @@ int RGWStreamIO::write(const char *buf, int len)
return 0;
}

int RGWStreamIO::read(char *buf, int max, int *actual)
int RGWStreamIO::read(char *buf, int max, int *actual, bool hash /* = false */)
{
int ret = read_data(buf, max);
if (ret < 0)
Expand All @@ -79,5 +79,17 @@ int RGWStreamIO::read(char *buf, int max, int *actual)

bytes_received += *actual;

if (hash) {
if (!sha256_hash) {
sha256_hash = calc_hash_sha256_open_stream();
}
calc_hash_sha256_update_stream(sha256_hash, buf, *actual);
}

return 0;
}

string RGWStreamIO::grab_aws4_sha256_hash()
{
return calc_hash_sha256_close_stream(&sha256_hash);
}