aboutsummaryrefslogtreecommitdiff
path: root/src/api/signature.rs
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2020-07-15 15:31:13 +0200
committerAlex Auvolat <alex@adnab.me>2020-07-15 15:31:13 +0200
commit1c70552f959229195cba250039900fddd77284f3 (patch)
tree321ba3583cdd4d0fe6e3465cdca5170ad8e93e83 /src/api/signature.rs
parent6c7f9704eabad3f19e426371b21f174f7e1dc2cf (diff)
downloadgarage-1c70552f959229195cba250039900fddd77284f3.tar.gz
garage-1c70552f959229195cba250039900fddd77284f3.zip
Validate content MD5 and SHA256 sums for PutObject and UploadPart
Diffstat (limited to 'src/api/signature.rs')
-rw-r--r--src/api/signature.rs28
1 files changed, 25 insertions, 3 deletions
diff --git a/src/api/signature.rs b/src/api/signature.rs
index 798ba7fb..6e23afda 100644
--- a/src/api/signature.rs
+++ b/src/api/signature.rs
@@ -6,6 +6,7 @@ use hyper::{Body, Method, Request};
use sha2::{Digest, Sha256};
use garage_table::*;
+use garage_util::data::Hash;
use garage_util::error::Error;
use garage_model::garage::Garage;
@@ -18,7 +19,10 @@ const LONG_DATETIME: &str = "%Y%m%dT%H%M%SZ";
type HmacSha256 = Hmac<Sha256>;
-pub async fn check_signature(garage: &Garage, request: &Request<Body>) -> Result<Key, Error> {
+pub async fn check_signature(
+ garage: &Garage,
+ request: &Request<Body>,
+) -> Result<(Key, Option<Hash>), Error> {
let mut headers = HashMap::new();
for (key, val) in request.headers() {
headers.insert(key.to_string(), val.to_str()?.to_string());
@@ -97,7 +101,21 @@ pub async fn check_signature(garage: &Garage, request: &Request<Body>) -> Result
return Err(Error::Forbidden(format!("Invalid signature")));
}
- Ok(key)
+ let content_sha256 = if authorization.content_sha256 == "UNSIGNED-PAYLOAD" {
+ None
+ } else {
+ let bytes = hex::decode(authorization.content_sha256).or(Err(Error::BadRequest(
+ format!("Invalid content sha256 hash"),
+ )))?;
+ let mut hash = [0u8; 32];
+ if bytes.len() != 32 {
+ return Err(Error::BadRequest(format!("Invalid content sha256 hash")));
+ }
+ hash.copy_from_slice(&bytes[..]);
+ Some(Hash::from(hash))
+ };
+
+ Ok((key, content_sha256))
}
struct Authorization {
@@ -193,13 +211,17 @@ fn parse_query_authorization(headers: &HashMap<String, String>) -> Result<Author
.ok_or(Error::BadRequest(format!(
"X-Amz-Signature not found in query parameters"
)))?;
+ let content_sha256 = headers
+ .get("x-amz-content-sha256")
+ .map(|x| x.as_str())
+ .unwrap_or("UNSIGNED-PAYLOAD");
Ok(Authorization {
key_id,
scope,
signed_headers: signed_headers.to_string(),
signature: signature.to_string(),
- content_sha256: "UNSIGNED-PAYLOAD".to_string(),
+ content_sha256: content_sha256.to_string(),
})
}