1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
7 #include "common/armor.h"
8 #include "common/utf8.h"
9 #include "rgw_common.h"
10 #include "rgw_client_io.h"
12 #include "rgw_crypt_sanitize.h"
13 #define dout_context g_ceph_context
14 #define dout_subsys ceph_subsys_rgw
16 static const auto signed_subresources
= {
27 "response-cache-control",
28 "response-content-disposition",
29 "response-content-encoding",
30 "response-content-language",
31 "response-content-type",
45 * ?get the canonical amazon-style header for something?
49 get_canon_amz_hdr(const std::map
<std::string
, std::string
>& meta_map
)
53 for (const auto& kv
: meta_map
) {
54 dest
.append(kv
.first
);
56 dest
.append(kv
.second
);
64 * ?get the canonical representation of the object's location
67 get_canon_resource(const char* const request_uri
,
68 const std::map
<std::string
, std::string
>& sub_resources
)
73 dest
.append(request_uri
);
77 for (const auto& subresource
: signed_subresources
) {
78 const auto iter
= sub_resources
.find(subresource
);
79 if (iter
== std::end(sub_resources
)) {
90 dest
.append(iter
->first
);
91 if (! iter
->second
.empty()) {
93 dest
.append(iter
->second
);
97 dout(10) << "get_canon_resource(): dest=" << dest
<< dendl
;
102 * get the header authentication information required to
103 * compute a request's signature
105 void rgw_create_s3_canonical_header(
106 const char* const method
,
107 const char* const content_md5
,
108 const char* const content_type
,
109 const char* const date
,
110 const std::map
<std::string
, std::string
>& meta_map
,
111 const char* const request_uri
,
112 const std::map
<std::string
, std::string
>& sub_resources
,
113 std::string
& dest_str
)
123 dest
.append(content_md5
);
128 dest
.append(content_type
);
137 dest
.append(get_canon_amz_hdr(meta_map
));
138 dest
.append(get_canon_resource(request_uri
, sub_resources
));
143 int rgw_get_s3_header_digest(const string
& auth_hdr
, const string
& key
, string
& dest
)
148 char hmac_sha1
[CEPH_CRYPTO_HMACSHA1_DIGESTSIZE
];
149 calc_hmac_sha1(key
.c_str(), key
.size(), auth_hdr
.c_str(), auth_hdr
.size(), hmac_sha1
);
151 char b64
[64]; /* 64 is really enough */
152 int ret
= ceph_armor(b64
, b64
+ 64, hmac_sha1
,
153 hmac_sha1
+ CEPH_CRYPTO_HMACSHA1_DIGESTSIZE
);
155 dout(10) << "ceph_armor failed" << dendl
;
165 void rgw_hash_s3_string_sha256(const char *data
, int len
, string
& dest
)
167 calc_hash_sha256(data
, len
, dest
);
170 static inline bool is_base64_for_content_md5(unsigned char c
) {
171 return (isalnum(c
) || isspace(c
) || (c
== '+') || (c
== '/') || (c
== '='));
175 * get the header authentication information required to
176 * compute a request's signature
178 bool rgw_create_s3_canonical_header(const req_info
& info
,
179 utime_t
* const header_time
,
183 const char* const content_md5
= info
.env
->get("HTTP_CONTENT_MD5");
185 for (const char *p
= content_md5
; *p
; p
++) {
186 if (!is_base64_for_content_md5(*p
)) {
187 dout(0) << "NOTICE: bad content-md5 provided (not base64),"
188 << " aborting request p=" << *p
<< " " << (int)*p
<< dendl
;
194 const char *content_type
= info
.env
->get("CONTENT_TYPE");
198 date
= info
.args
.get("Expires");
200 const char *str
= info
.env
->get("HTTP_DATE");
201 const char *req_date
= str
;
205 req_date
= info
.env
->get("HTTP_X_AMZ_DATE");
207 dout(0) << "NOTICE: missing date for auth header" << dendl
;
214 if (!parse_rfc2616(req_date
, &t
)) {
215 dout(0) << "NOTICE: failed to parse date for auth header" << dendl
;
218 if (t
.tm_year
< 70) {
219 dout(0) << "NOTICE: bad date (predates epoch): " << req_date
<< dendl
;
222 *header_time
= utime_t(internal_timegm(&t
), 0);
226 const auto& meta_map
= info
.x_meta_map
;
227 const auto& sub_resources
= info
.args
.get_sub_resources();
229 std::string request_uri
;
230 if (info
.effective_uri
.empty()) {
231 request_uri
= info
.request_uri
;
233 request_uri
= info
.effective_uri
;
236 rgw_create_s3_canonical_header(info
.method
, content_md5
, content_type
,
237 date
.c_str(), meta_map
, request_uri
.c_str(),
238 sub_resources
, dest
);
243 * assemble canonical request for signature version 4
245 void rgw_assemble_s3_v4_canonical_request(const char *method
, const char *canonical_uri
, const char *canonical_qs
,
246 const char *canonical_hdrs
, const char *signed_hdrs
, const char *request_payload_hash
,
256 dest
.append(canonical_uri
);
261 dest
.append(canonical_qs
);
266 dest
.append(canonical_hdrs
);
270 dest
.append(signed_hdrs
);
273 if (request_payload_hash
)
274 dest
.append(request_payload_hash
);
280 * create canonical request for signature version 4
282 void rgw_create_s3_v4_canonical_request(struct req_state
*s
, const string
& canonical_uri
, const string
& canonical_qs
,
283 const string
& canonical_hdrs
, const string
& signed_hdrs
, const string
& request_payload
,
284 bool unsigned_payload
, string
& canonical_req
, string
& canonical_req_hash
)
286 string request_payload_hash
;
288 if (unsigned_payload
) {
289 request_payload_hash
= "UNSIGNED-PAYLOAD";
291 if (s
->aws4_auth_needs_complete
) {
292 request_payload_hash
= AWS_AUTHv4_IO(s
)->grab_aws4_sha256_hash();
294 if (s
->aws4_auth_streaming_mode
) {
295 request_payload_hash
= "STREAMING-AWS4-HMAC-SHA256-PAYLOAD";
297 rgw_hash_s3_string_sha256(request_payload
.c_str(), request_payload
.size(), request_payload_hash
);
302 s
->aws4_auth
->payload_hash
= request_payload_hash
;
304 ldout(s
->cct
, 10) << "payload request hash = " << request_payload_hash
<< dendl
;
306 rgw_assemble_s3_v4_canonical_request(s
->info
.method
, canonical_uri
.c_str(),
307 canonical_qs
.c_str(), canonical_hdrs
.c_str(), signed_hdrs
.c_str(),
308 request_payload_hash
.c_str(), canonical_req
);
310 rgw_hash_s3_string_sha256(canonical_req
.c_str(), canonical_req
.size(), canonical_req_hash
);
312 ldout(s
->cct
, 10) << "canonical request = " << canonical_req
<< dendl
;
313 ldout(s
->cct
, 10) << "canonical request hash = " << canonical_req_hash
<< dendl
;
317 * assemble string to sign for signature version 4
319 void rgw_assemble_s3_v4_string_to_sign(const char *algorithm
, const char *request_date
,
320 const char *credential_scope
, const char *hashed_qr
, string
& dest_str
)
329 dest
.append(request_date
);
332 if (credential_scope
)
333 dest
.append(credential_scope
);
337 dest
.append(hashed_qr
);
343 * create string to sign for signature version 4
345 void rgw_create_s3_v4_string_to_sign(CephContext
*cct
, const string
& algorithm
, const string
& request_date
,
346 const string
& credential_scope
, const string
& hashed_qr
,
347 string
& string_to_sign
) {
349 rgw_assemble_s3_v4_string_to_sign(algorithm
.c_str(), request_date
.c_str(),
350 credential_scope
.c_str(), hashed_qr
.c_str(), string_to_sign
);
352 ldout(cct
, 10) << "string to sign = " << rgw::crypt_sanitize::log_content
{string_to_sign
.c_str()} << dendl
;
356 * calculate the AWS signature version 4
358 int rgw_calculate_s3_v4_aws_signature(struct req_state
*s
,
359 const string
& access_key_id
, const string
&date
, const string
& region
,
360 const string
& service
, const string
& string_to_sign
, string
& signature
) {
362 map
<string
, RGWAccessKey
>::iterator iter
= s
->user
->access_keys
.find(access_key_id
);
363 if (iter
== s
->user
->access_keys
.end()) {
364 ldout(s
->cct
, 10) << "ERROR: access key not encoded in user info" << dendl
;
368 RGWAccessKey
& k
= iter
->second
;
370 string secret_key
= "AWS4" + k
.key
;
372 char secret_k
[secret_key
.size() * MAX_UTF8_SZ
];
376 for (size_t i
= 0; i
< secret_key
.size(); i
++) {
377 n
+= encode_utf8(secret_key
[i
], (unsigned char *) (secret_k
+ n
));
380 string
secret_key_utf8_k(secret_k
, n
);
384 char date_k
[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE
];
385 calc_hmac_sha256(secret_key_utf8_k
.c_str(), secret_key_utf8_k
.size(),
386 date
.c_str(), date
.size(), date_k
);
388 char aux
[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE
* 2 + 1];
389 buf_to_hex((unsigned char *) date_k
, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE
, aux
);
391 ldout(s
->cct
, 10) << "date_k = " << string(aux
) << dendl
;
395 char region_k
[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE
];
396 calc_hmac_sha256(date_k
, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE
, region
.c_str(), region
.size(), region_k
);
398 buf_to_hex((unsigned char *) region_k
, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE
, aux
);
400 ldout(s
->cct
, 10) << "region_k = " << string(aux
) << dendl
;
404 char service_k
[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE
];
405 calc_hmac_sha256(region_k
, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE
, service
.c_str(), service
.size(), service_k
);
407 buf_to_hex((unsigned char *) service_k
, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE
, aux
);
409 ldout(s
->cct
, 10) << "service_k = " << string(aux
) << dendl
;
413 char *signing_k
= s
->aws4_auth
->signing_k
;
415 calc_hmac_sha256(service_k
, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE
, "aws4_request", 12, signing_k
);
417 buf_to_hex((unsigned char *) signing_k
, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE
, aux
);
419 ldout(s
->cct
, 10) << "signing_k = " << string(aux
) << dendl
;
421 s
->aws4_auth
->signing_key
= aux
;
425 char signature_k
[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE
];
426 calc_hmac_sha256(signing_k
, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE
, string_to_sign
.c_str(), string_to_sign
.size(), signature_k
);
428 buf_to_hex((unsigned char *) signature_k
, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE
, aux
);
430 ldout(s
->cct
, 10) << "signature_k = " << string(aux
) << dendl
;
432 signature
= string(aux
);
434 ldout(s
->cct
, 10) << "new signature = " << signature
<< dendl
;