From: Radoslaw Zarzynski Date: Thu, 13 Apr 2017 15:12:43 +0000 (+0200) Subject: rgw: get_v4_canonical_request_hash doesn't depend on req_state anymore. X-Git-Tag: v12.1.0~155^2~66 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=c9afd24940dfefa19f94c8983045e1c3b032d45d;p=ceph.git rgw: get_v4_canonical_request_hash doesn't depend on req_state anymore. In AWSv4 the hash of real, transfered payload IS NOT necessary to form a Canonical Request, and thus verify a Signature. x-amz-content-sha256 header lets get the information very early -- before seeing first byte of HTTP body. As a consequence, we can decouple Signature verification from payload's fingerprint check. Although RadosGW doesn't do that for now, the situation will definitely change in the future. Signed-off-by: Radoslaw Zarzynski --- diff --git a/src/rgw/rgw_auth_s3.cc b/src/rgw/rgw_auth_s3.cc index 785d2ce560f8..2b5c32741cdd 100644 --- a/src/rgw/rgw_auth_s3.cc +++ b/src/rgw/rgw_auth_s3.cc @@ -290,37 +290,18 @@ static std::string assemble_v4_canonical_request( /* * create canonical request for signature version 4 */ -std::string get_v4_canonical_request_hash(struct req_state* const s, +std::string get_v4_canonical_request_hash(CephContext* cct, + const std::string& http_verb, const std::string& canonical_uri, const std::string& canonical_qs, const std::string& canonical_hdrs, const std::string& signed_hdrs, - const std::string& request_payload, - const bool unsigned_payload) + const std::string& request_payload_hash) { - string request_payload_hash; - - if (unsigned_payload) { - request_payload_hash = "UNSIGNED-PAYLOAD"; - } else { - if (s->aws4_auth_needs_complete) { - request_payload_hash = AWS_AUTHv4_IO(s)->grab_aws4_sha256_hash(); - } else { - if (s->aws4_auth_streaming_mode) { - request_payload_hash = "STREAMING-AWS4-HMAC-SHA256-PAYLOAD"; - } else { - request_payload_hash = \ - hash_string_sha256(request_payload.c_str(), request_payload.size()); - } - } - } - - s->aws4_auth->payload_hash = request_payload_hash; - - ldout(s->cct, 10) << "payload request hash = " << request_payload_hash << dendl; + ldout(cct, 10) << "payload request hash = " << request_payload_hash << dendl; std::string canonical_req = \ - assemble_v4_canonical_request(s->info.method, + assemble_v4_canonical_request(http_verb.c_str(), canonical_uri.c_str(), canonical_qs.c_str(), canonical_hdrs.c_str(), @@ -330,8 +311,8 @@ std::string get_v4_canonical_request_hash(struct req_state* const s, std::string canonical_req_hash = \ hash_string_sha256(canonical_req.c_str(), canonical_req.size()); - ldout(s->cct, 10) << "canonical request = " << canonical_req << dendl; - ldout(s->cct, 10) << "canonical request hash = " << canonical_req_hash << dendl; + ldout(cct, 10) << "canonical request = " << canonical_req << dendl; + ldout(cct, 10) << "canonical request hash = " << canonical_req_hash << dendl; return canonical_req_hash; } diff --git a/src/rgw/rgw_auth_s3.h b/src/rgw/rgw_auth_s3.h index 5c1f8b0481a9..b4a85c016dbc 100644 --- a/src/rgw/rgw_auth_s3.h +++ b/src/rgw/rgw_auth_s3.h @@ -161,13 +161,13 @@ namespace s3 { std::string hash_string_sha256(const char* data, int len); -std::string get_v4_canonical_request_hash(struct req_state* s, +std::string get_v4_canonical_request_hash(CephContext* cct, + const std::string& http_verb, const std::string& canonical_uri, const std::string& canonical_qs, const std::string& canonical_hdrs, const std::string& signed_hdrs, - const std::string& request_payload, - bool unsigned_payload); + const std::string& request_payload_hash); std::string get_v4_string_to_sign(CephContext* cct, const std::string& algorithm, diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index 925717ce5b40..77d8d00a4d80 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -3420,22 +3420,50 @@ int RGW_Auth_S3::authorize_aws4_auth_complete(RGWRados *store, struct req_state int RGW_Auth_S3::authorize_v4_complete(RGWRados *store, struct req_state *s, const string& request_payload, bool unsigned_payload) { - size_t pos; + const char *expected_request_payload_hash = s->info.env->get("HTTP_X_AMZ_CONTENT_SHA256"); + if (!expected_request_payload_hash) { + /* In AWSv4 the hash of real, transfered payload IS NOT necessary to form + * a Canonical Request, and thus verify a Signature. x-amz-content-sha256 + * header lets get the information very early -- before seeing first byte + * of HTTP body. As a consequence, we can decouple Signature verification + * from payload's fingerprint check. Although RadosGW doesn't do that for + * now, the situation will definitely change in the future. + * + * An HTTP client MUST send x-amz-content-sha256. AFAIK the single exception + * to that is the case of using Query Parameters for doing the auth In such + * scenario, the "UNSIGNED-PAYLOAD" literals are used instead. */ + expected_request_payload_hash = "UNSIGNED-PAYLOAD"; + } /* craft canonical request */ - string canonical_req_hash = \ - rgw::auth::s3::get_v4_canonical_request_hash(s, s->aws4_auth->canonical_uri, + std::string canonical_req_hash = \ + rgw::auth::s3::get_v4_canonical_request_hash(s->cct, + s->info.method, + s->aws4_auth->canonical_uri, s->aws4_auth->canonical_qs, s->aws4_auth->canonical_hdrs, s->aws4_auth->signed_hdrs, - request_payload, unsigned_payload); + expected_request_payload_hash); - /* Validate x-amz-sha256 */ + if (unsigned_payload) { + s->aws4_auth->payload_hash = "UNSIGNED-PAYLOAD"; + } else { + if (s->aws4_auth_needs_complete) { + s->aws4_auth->payload_hash = AWS_AUTHv4_IO(s)->grab_aws4_sha256_hash(); + } else { + if (s->aws4_auth_streaming_mode) { + s->aws4_auth->payload_hash = "STREAMING-AWS4-HMAC-SHA256-PAYLOAD"; + } else { + s->aws4_auth->payload_hash = \ + rgw::auth::s3::hash_string_sha256(request_payload.c_str(), + request_payload.size()); + } + } + } + /* Validate x-amz-sha256 */ if (s->aws4_auth_needs_complete) { - const char *expected_request_payload_hash = s->info.env->get("HTTP_X_AMZ_CONTENT_SHA256"); - if (expected_request_payload_hash && - s->aws4_auth->payload_hash.compare(expected_request_payload_hash) != 0) { + if (s->aws4_auth->payload_hash.compare(expected_request_payload_hash) != 0) { ldout(s->cct, 10) << "ERROR: x-amz-content-sha256 does not match" << dendl; return -ERR_AMZ_CONTENT_SHA256_MISMATCH; } @@ -3462,7 +3490,7 @@ int RGW_Auth_S3::authorize_v4_complete(RGWRados *store, struct req_state *s, con string cs_aux = s->aws4_auth->credential_scope; string date_cs = cs_aux; - pos = date_cs.find("/"); + size_t pos = date_cs.find("/"); date_cs = date_cs.substr(0, pos); cs_aux = cs_aux.substr(pos + 1, cs_aux.length());