Skip to content

Commit 70090fe

Browse files
committed
fix(s3s/sigv4): reorder header-auth checks, use s3_error! macro, add TODO
- Move x-amz-date extraction, credential-date validation, and clock-skew check before the secret key lookup in v4_check_header_auth so stale requests are rejected before I/O. - Replace remaining S3Error::new + set_message patterns in the new credential-date checks with the s3_error! macro for consistency. - Add TODO in v4_check_post_signature noting the double policy parse (signature verification + later prepare stage) as an optimization target.
1 parent 43e4f3b commit 70090fe

1 file changed

Lines changed: 18 additions & 21 deletions

File tree

crates/s3s/src/ops/signature.rs

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,7 @@ fn extract_amz_content_sha256<'a>(hs: &'_ OrderedHeaders<'a>) -> S3Result<Option
3737
Ok(x) => Ok(Some(x)),
3838
Err(e) => {
3939
// https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv-troubleshooting.html
40-
let mut err = S3Error::new(S3ErrorCode::SignatureDoesNotMatch);
41-
err.set_message("invalid header: x-amz-content-sha256");
42-
err.set_source(Box::new(e));
43-
Err(err)
40+
Err(s3_error!(e, SignatureDoesNotMatch, "invalid header: x-amz-content-sha256"))
4441
}
4542
}
4643
}
@@ -271,6 +268,11 @@ impl SignatureContext<'_> {
271268
// Per AWS SigV4 spec, the signed POST policy must contain eq conditions
272269
// for x-amz-date, x-amz-credential, and x-amz-algorithm that match the
273270
// submitted form fields exactly.
271+
//
272+
// TODO: the policy is parsed again later in `prepare` via
273+
// `PostPolicy::from_base64` + `validate_conditions_only`. Consider
274+
// caching the parsed `PostPolicy` here and reusing it downstream to
275+
// avoid the double base64-decode + JSON-parse.
274276
{
275277
let policy = PostPolicy::from_base64(info.policy).map_err(|e| s3_error!(e, InvalidPolicyDocument))?;
276278

@@ -292,9 +294,7 @@ impl SignatureContext<'_> {
292294

293295
// Per AWS SigV4 spec, the credential scope date must match the x-amz-date date.
294296
if credential.date != amz_date.fmt_date().as_str() {
295-
let mut err = S3Error::new(S3ErrorCode::SignatureDoesNotMatch);
296-
err.set_message("credential scope date does not match x-amz-date");
297-
return Err(err);
297+
return Err(s3_error!(SignatureDoesNotMatch, "credential scope date does not match x-amz-date"));
298298
}
299299

300300
validate_sig_v4_clock_skew(&amz_date, time::OffsetDateTime::now_utc(), &self.config.snapshot())?;
@@ -348,9 +348,7 @@ impl SignatureContext<'_> {
348348

349349
// Per AWS SigV4 spec, the credential scope date must match the x-amz-date date.
350350
if presigned_url.credential.date != presigned_url.amz_date.fmt_date().as_str() {
351-
let mut err = S3Error::new(S3ErrorCode::SignatureDoesNotMatch);
352-
err.set_message("credential scope date does not match x-amz-date");
353-
return Err(err);
351+
return Err(s3_error!(SignatureDoesNotMatch, "credential scope date does not match x-amz-date"));
354352
}
355353

356354
// ASK: how to use it?
@@ -456,6 +454,16 @@ impl SignatureContext<'_> {
456454

457455
let auth = require_auth(self.auth)?;
458456

457+
// Reject stale requests before doing I/O work (secret key lookup).
458+
let amz_date = extract_amz_date(&self.hs)?.ok_or_else(|| invalid_request!("missing header: x-amz-date"))?;
459+
460+
// Per AWS SigV4 spec, the credential scope date must match the x-amz-date date.
461+
if authorization.credential.date != amz_date.fmt_date().as_str() {
462+
return Err(s3_error!(SignatureDoesNotMatch, "credential scope date does not match x-amz-date"));
463+
}
464+
465+
validate_sig_v4_clock_skew(&amz_date, time::OffsetDateTime::now_utc(), &self.config.snapshot())?;
466+
459467
let amz_content_sha256 = extract_amz_content_sha256(&self.hs)?;
460468

461469
if service == "s3" && amz_content_sha256.is_none() {
@@ -465,17 +473,6 @@ impl SignatureContext<'_> {
465473
let access_key = authorization.credential.access_key_id;
466474
let secret_key = auth.get_secret_key(access_key).await?;
467475

468-
let amz_date = extract_amz_date(&self.hs)?.ok_or_else(|| invalid_request!("missing header: x-amz-date"))?;
469-
470-
// Per AWS SigV4 spec, the credential scope date must match the x-amz-date date.
471-
if authorization.credential.date != amz_date.fmt_date().as_str() {
472-
let mut err = S3Error::new(S3ErrorCode::SignatureDoesNotMatch);
473-
err.set_message("credential scope date does not match x-amz-date");
474-
return Err(err);
475-
}
476-
477-
validate_sig_v4_clock_skew(&amz_date, time::OffsetDateTime::now_utc(), &self.config.snapshot())?;
478-
479476
let is_stream = amz_content_sha256.is_some_and(|v| v.is_streaming());
480477

481478
let expected_signature = authorization.signature;

0 commit comments

Comments
 (0)