]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: get_v4_canonical_request_hash doesn't depend on req_state anymore.
authorRadoslaw Zarzynski <rzarzynski@mirantis.com>
Thu, 13 Apr 2017 15:12:43 +0000 (17:12 +0200)
committerRadoslaw Zarzynski <rzarzynski@mirantis.com>
Wed, 7 Jun 2017 10:43:15 +0000 (12:43 +0200)
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 <rzarzynski@mirantis.com>
src/rgw/rgw_auth_s3.cc
src/rgw/rgw_auth_s3.h
src/rgw/rgw_rest_s3.cc

index 785d2ce560f87c6e08f37eb98cf4b684f4074fad..2b5c32741cdd64f0e1a3ecec35fcb0e71a7ac993 100644 (file)
@@ -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;
 }
index 5c1f8b0481a9823c8b48a23e05be6c6d53329c45..b4a85c016dbc2fd7872ae1c09685d42b8d157976 100644 (file)
@@ -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,
index 925717ce5b405264290be988b49cd9bf3ff7534f..77d8d00a4d80333efaffd6c25e65b926167a2fb0 100644 (file)
@@ -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());