]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: optimize and clean-up the AWSv4 signature processing.
authorRadoslaw Zarzynski <rzarzynski@mirantis.com>
Wed, 10 May 2017 19:51:13 +0000 (21:51 +0200)
committerRadoslaw Zarzynski <rzarzynski@mirantis.com>
Wed, 7 Jun 2017 10:43:19 +0000 (12:43 +0200)
Signed-off-by: Radoslaw Zarzynski <rzarzynski@mirantis.com>
src/rgw/rgw_auth_s3.cc
src/rgw/rgw_auth_s3.h
src/rgw/rgw_common.cc
src/rgw/rgw_common.h
src/rgw/rgw_rest_s3.cc

index 50169f83f09f61b3991bac5a80f5c8e55f81e41d..c02fb550218217a2c8480952fbec40bd9f469d88 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <map>
 #include <string>
+#include <vector>
 
 #include "common/armor.h"
 #include "common/utf8.h"
@@ -587,136 +588,69 @@ get_v4_canonical_headers(const req_info& info,
   return canonical_hdrs;
 }
 
-std::string hash_string_sha256(const char* const data, const int len)
-{
-  std::string dest;
-  calc_hash_sha256(data, len, dest);
-  return dest;
-}
-
-/*
- * assemble canonical request for signature version 4
- */
-static std::string assemble_v4_canonical_request(
-  const char* const method,
-  const char* const canonical_uri,
-  const char* const canonical_qs,
-  const char* const canonical_hdrs,
-  const char* const signed_hdrs,
-  const char* const request_payload_hash)
-{
-  std::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);
-
-  return dest;
-}
-
 /*
  * create canonical request for signature version 4
  *
  * http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
  */
-std::string get_v4_canon_req_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_hash)
+sha256_digest_t
+get_v4_canon_req_hash(CephContext* cct,
+                      const boost::string_ref& http_verb,
+                      const std::string& canonical_uri,
+                      const std::string& canonical_qs,
+                      const std::string& canonical_hdrs,
+                      const std::string& signed_hdrs,
+                      const boost::string_ref& request_payload_hash)
 {
   ldout(cct, 10) << "payload request hash = " << request_payload_hash << dendl;
 
-  std::string canonical_req = \
-    assemble_v4_canonical_request(http_verb.c_str(),
-                                  canonical_uri.c_str(),
-                                  canonical_qs.c_str(),
-                                  canonical_hdrs.c_str(),
-                                  signed_hdrs.c_str(),
-                                  request_payload_hash.c_str());
-
-  std::string canonical_req_hash = \
-    hash_string_sha256(canonical_req.c_str(), canonical_req.size());
+  const auto canonical_req = std::string()
+    .append(http_verb.data(), http_verb.length())
+    .append("\n")
+    .append(canonical_uri)
+    .append("\n")
+    .append(canonical_qs)
+    .append("\n")
+    .append(canonical_hdrs)
+    .append("\n")
+    .append(signed_hdrs)
+    .append("\n")
+    .append(request_payload_hash.data(), request_payload_hash.length());
+
+  const auto canonical_req_hash = calc_hash_sha256(canonical_req);
 
   ldout(cct, 10) << "canonical request = " << canonical_req << dendl;
-  ldout(cct, 10) << "canonical request hash = " << canonical_req_hash << dendl;
+  ldout(cct, 10) << "canonical request hash = "
+                 << buf_to_hex(canonical_req_hash).data() << dendl;
 
   return canonical_req_hash;
 }
 
-/*
- * assemble string to sign for signature version 4
- */
-static std::string rgw_assemble_s3_v4_string_to_sign(
-  const char* const algorithm,
-  const char* const request_date,
-  const char* const credential_scope,
-  const char* const hashed_qr
-) {
-  std::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);
-
-  return dest;
-}
-
 /*
  * create string to sign for signature version 4
  *
  * http://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html
  */
 std::string get_v4_string_to_sign(CephContext* const cct,
-                                  const std::string& algorithm,
-                                  const std::string& request_date,
-                                  const std::string& credential_scope,
-                                  const std::string& hashed_qr)
+                                  const boost::string_ref& algorithm,
+                                  const boost::string_ref& request_date,
+                                  const boost::string_ref& credential_scope,
+                                  const sha256_digest_t& canonreq_hash)
 {
-  const auto 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());
+  const auto hexed_cr_hash = buf_to_hex(canonreq_hash);
+  const auto string_to_sign = std::string()
+    .append(algorithm.data(), algorithm.length())
+    .append("\n")
+    .append(request_date.data(), request_date.length())
+    .append("\n")
+    .append(credential_scope.data(), credential_scope.length())
+    .append("\n")
+    .append(hexed_cr_hash.data(), hexed_cr_hash.size() - 1);
 
   ldout(cct, 10) << "string to sign = "
                  << rgw::crypt_sanitize::log_content{string_to_sign.c_str()}
                  << dendl;
+
   return string_to_sign;
 }
 
@@ -743,31 +677,40 @@ parse_cred_scope(boost::string_ref credential_scope)
   return std::make_tuple(date_cs, region_cs, service_cs);
 }
 
-/*
- * calculate the SigningKey of AWS auth version 4
- */
-std::array<unsigned char, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE>
-get_v4_signing_key(CephContext* const cct,
-                   const std::string& credential_scope,
-                   const std::string& access_key_secret)
+static inline std::vector<unsigned char>
+transform_secret_key(const boost::string_ref& secret_access_key)
 {
-  std::string secret_key = "AWS4" + access_key_secret;
-  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));
+  /* TODO(rzarzynski): switch to constexpr when C++14 becomes available. */
+  static const std::initializer_list<unsigned char> AWS4 { 'A', 'W', 'S', '4' };
+
+  /* boost::container::small_vector might be used here if someone wants to
+   * optimize out even more dynamic allocations. */
+  std::vector<unsigned char> secret_key_utf8;
+  secret_key_utf8.reserve(AWS4.size() + secret_access_key.size());
+  secret_key_utf8.assign(AWS4);
+
+  for (const auto c : secret_access_key) {
+    std::array<unsigned char, MAX_UTF8_SZ> buf;
+    const size_t n = encode_utf8(c, buf.data());
+    secret_key_utf8.insert(std::end(secret_key_utf8),
+                           std::begin(buf), std::begin(buf) + n);
   }
 
-  string secret_key_utf8_k(secret_k, n);
+  return secret_key_utf8;
+}
 
+/*
+ * calculate the SigningKey of AWS auth version 4
+ */
+sha256_digest_t get_v4_signing_key(CephContext* const cct,
+                                   const boost::string_ref& credential_scope,
+                                   const boost::string_ref& secret_access_key)
+{
   boost::string_ref date, region, service;
   std::tie(date, region, service) = parse_cred_scope(credential_scope);
 
-  const auto date_k = calc_hmac_sha256(secret_key_utf8_k.c_str(),
-                                       secret_key_utf8_k.size(),
-                                       date.data(), date.size());
+  const auto utfed_sec_key = transform_secret_key(secret_access_key);
+  const auto date_k = calc_hmac_sha256(utfed_sec_key, date);
   const auto region_k = calc_hmac_sha256(date_k, region);
   const auto service_k = calc_hmac_sha256(region_k, service);
 
@@ -788,20 +731,17 @@ get_v4_signing_key(CephContext* const cct,
 
  * http://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html
  */
-std::string get_v4_signature(CephContext* const cct,
-                             const std::array<unsigned char, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE>& signing_key,
-                             const std::string& string_to_sign)
+std::array<char, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE * 2 + 1>
+get_v4_signature(CephContext* const cct,
+                 const sha256_digest_t& signing_key,
+                 const boost::string_ref& string_to_sign)
 {
   /* The server-side generated signature for comparison. */
-  const auto signature_k = \
+  const auto signature = \
     buf_to_hex(calc_hmac_sha256(signing_key, string_to_sign));
 
-  /* FIXME(rzarzynski): we might want to switch the return type from
-   * std::string to std::array<char, N>. */
-  const std::string signature = \
-    std::string(signature_k.data(), signature_k.size() - 1);
+  ldout(cct, 10) << "generated signature = " << signature.data() << dendl;
 
-  ldout(cct, 10) << "generated signature = " << signature << dendl;
   return signature;
 }
 
index 6b3b33bf2a57a6d5710499fbece144eaf18a0170..0d2a9608933281a5675f4acccf0d82e3ce1732d5 100644 (file)
@@ -10,6 +10,7 @@
 #include <tuple>
 
 #include <boost/container/static_vector.hpp>
+#include <boost/utility/string_ref.hpp>
 
 #include "rgw_common.h"
 #include "rgw_rest_s3.h"
@@ -397,30 +398,30 @@ boost::optional<std::string> get_v4_canonical_headers(const req_info& info,
                                                       bool using_qs,
                                                       bool force_boto2_compat);
 
-std::string hash_string_sha256(const char* data, int len);
-
-std::string get_v4_canon_req_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_hash);
+extern sha256_digest_t
+get_v4_canon_req_hash(CephContext* cct,
+                      const boost::string_ref& http_verb,
+                      const std::string& canonical_uri,
+                      const std::string& canonical_qs,
+                      const std::string& canonical_hdrs,
+                      const std::string& signed_hdrs,
+                      const boost::string_ref& request_payload_hash);
 
 std::string get_v4_string_to_sign(CephContext* cct,
-                                  const std::string& algorithm,
-                                  const std::string& request_date,
-                                  const std::string& credential_scope,
-                                  const std::string& hashed_qr);
+                                  const boost::string_ref& algorithm,
+                                  const boost::string_ref& request_date,
+                                  const boost::string_ref& credential_scope,
+                                  const sha256_digest_t& canonreq_hash);
 
-std::array<unsigned char, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE>
+extern sha256_digest_t
 get_v4_signing_key(CephContext* const cct,
-                   const std::string& credential_scope,
-                   const std::string& access_key_secret);
+                   const boost::string_ref& credential_scope,
+                   const boost::string_ref& access_key_secret);
 
-std::string get_v4_signature(CephContext* cct,
-                             const std::array<unsigned char, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE>& signing_key,
-                             const std::string& string_to_sign);
+extern std::array<char, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE * 2 + 1>
+get_v4_signature(CephContext* cct,
+                 const sha256_digest_t& signing_key,
+                 const boost::string_ref& string_to_sign);
 
 static inline
 std::string get_v2_signature(CephContext*,
index 7874fd1f2e6ae8452452c2da1852549aeb3993f8..97cee5e69814779114e2c996d4da7378dee02691 100644 (file)
@@ -675,25 +675,22 @@ void calc_hmac_sha256(const char *key, int key_len,
   memcpy(dest, hash_sha256, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE);
 }
 
+using ceph::crypto::SHA256;
+
 /*
  * calculate the sha256 hash value of a given msg
  */
-void calc_hash_sha256(const char *msg, int len, string& dest)
+sha256_digest_t calc_hash_sha256(const boost::string_ref& msg)
 {
-  char hash_sha256[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE];
+  std::array<unsigned char, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE> hash;
 
-  SHA256 hash;
-  hash.Update((const unsigned char *)msg, len);
-  hash.Final((unsigned char *)hash_sha256);
+  SHA256 hasher;
+  hasher.Update(reinterpret_cast<const unsigned char*>(msg.data()), msg.size());
+  hasher.Final(hash.data());
 
-  char hex_str[(CEPH_CRYPTO_SHA256_DIGESTSIZE * 2) + 1];
-  buf_to_hex((unsigned char *)hash_sha256, CEPH_CRYPTO_SHA256_DIGESTSIZE, hex_str);
-
-  dest = std::string(hex_str);
+  return hash;
 }
 
-using ceph::crypto::SHA256;
-
 SHA256* calc_hash_sha256_open_stream()
 {
   return new SHA256;
index b7efddfd674bebeb708a66e11495111dd107c03c..fc246db6c9373622735e3517f982a2db5ed6d953 100644 (file)
@@ -2215,10 +2215,14 @@ extern std::string url_encode(const std::string& src);
 extern void calc_hmac_sha1(const char *key, int key_len,
                           const char *msg, int msg_len, char *dest);
 /* destination should be CEPH_CRYPTO_HMACSHA256_DIGESTSIZE bytes long */
-extern void calc_hmac_sha256(const char *key, int key_len, const char *msg, int msg_len, char *dest);
+extern void calc_hmac_sha256(const char *key, int key_len,
+                             const char *msg, int msg_len,
+                             char *dest);
 
-static inline std::array<unsigned char,
-                         CEPH_CRYPTO_HMACSHA256_DIGESTSIZE>
+using sha256_digest_t = \
+  std::array<unsigned char, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE>;
+
+static inline sha256_digest_t
 calc_hmac_sha256(const char *key, const int key_len,
                  const char *msg, const int msg_len) {
   std::array<unsigned char, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE> dest;
@@ -2227,9 +2231,27 @@ calc_hmac_sha256(const char *key, const int key_len,
   return dest;
 }
 
+static inline sha256_digest_t
+calc_hmac_sha256(const boost::string_ref& key, const boost::string_ref& msg) {
+  std::array<unsigned char, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE> dest;
+  calc_hmac_sha256(key.data(), key.size(),
+                   msg.data(), msg.size(),
+                   reinterpret_cast<char*>(dest.data()));
+  return dest;
+}
+
+static inline sha256_digest_t
+calc_hmac_sha256(const std::vector<unsigned char>& key,
+                 const boost::string_ref& msg) {
+  std::array<unsigned char, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE> dest;
+  calc_hmac_sha256(reinterpret_cast<const char*>(key.data()), key.size(),
+                   msg.data(), msg.size(),
+                   reinterpret_cast<char*>(dest.data()));
+  return dest;
+}
+
 template<size_t KeyLenN>
-static inline std::array<unsigned char,
-                         CEPH_CRYPTO_HMACSHA256_DIGESTSIZE>
+static inline sha256_digest_t
 calc_hmac_sha256(const std::array<unsigned char, KeyLenN>& key,
                  const boost::string_ref& msg) {
   std::array<unsigned char, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE> dest;
@@ -2239,8 +2261,7 @@ calc_hmac_sha256(const std::array<unsigned char, KeyLenN>& key,
   return dest;
 }
 
-extern void calc_hash_sha256(const char *msg, int len, string& dest);
-extern void calc_hash_sha256(const string& msg, string& dest);
+extern sha256_digest_t calc_hash_sha256(const boost::string_ref& msg);
 
 using ceph::crypto::SHA256;
 extern SHA256* calc_hash_sha256_open_stream();
index afddb5f48cfc67f5eae8e3f815bc87b6079bf265..06c0417cc2815c58223732ab3fbf45306c41ca2d 100644 (file)
@@ -3566,8 +3566,8 @@ static inline
 std::string v4_signature(const std::string& credential_scope,
 
                          CephContext* const cct,
-                         const std::string& secret_key,
-                         const std::string& string_to_sign)
+                         const boost::string_ref& secret_key,
+                         const boost::string_ref& string_to_sign)
 {
   auto signing_key = \
     rgw::auth::s3::get_v4_signing_key(cct, credential_scope, secret_key);
@@ -3576,13 +3576,7 @@ std::string v4_signature(const std::string& credential_scope,
     rgw::auth::s3::get_v4_signature(cct, std::move(signing_key),
                                     string_to_sign);
 
-
-  ldout(cct, 10) << "-----------------------------" << dendl;
-  ldout(cct, 10) << "Server Signature = " << server_signature
-                 << dendl;
-  ldout(cct, 10) << "-----------------------------" << dendl;
-
-  return server_signature;
+  return std::string(server_signature.data(), server_signature.size() - 1);
 }
 
 std::tuple<AWSVerAbstractor::access_key_id_t,