diff options
Diffstat (limited to 'src/api/s3/encryption.rs')
-rw-r--r-- | src/api/s3/encryption.rs | 64 |
1 files changed, 42 insertions, 22 deletions
diff --git a/src/api/s3/encryption.rs b/src/api/s3/encryption.rs index 17974df1..723aeb07 100644 --- a/src/api/s3/encryption.rs +++ b/src/api/s3/encryption.rs @@ -46,7 +46,7 @@ const X_AMZ_COPY_SOURCE_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY: HeaderName = const X_AMZ_COPY_SOURCE_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5: HeaderName = HeaderName::from_static("x-amz-copy-source-server-side-encryption-customer-key-md5"); -const CUSTOMER_ALGORITHM_AES256: HeaderValue = HeaderValue::from_static("AES256"); +const CUSTOMER_ALGORITHM_AES256: &[u8] = b"AES256"; type StreamNonceSize = aes_gcm::aead::stream::NonceSize<Aes256Gcm, StreamLE31<Aes256Gcm>>; @@ -86,7 +86,7 @@ impl EncryptionParams { } } - pub fn check_decrypt_for_get<'a>( + pub fn check_decrypt<'a>( garage: &Garage, req: &Request<impl Body>, obj_enc: &'a ObjectVersionEncryption, @@ -97,7 +97,7 @@ impl EncryptionParams { &X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY, &X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5, )?; - Self::check_decrypt(garage, key, obj_enc) + Self::check_decrypt_common(garage, key, obj_enc) } pub fn check_decrypt_for_copy_source<'a>( @@ -111,10 +111,10 @@ impl EncryptionParams { &X_AMZ_COPY_SOURCE_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY, &X_AMZ_COPY_SOURCE_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5, )?; - Self::check_decrypt(garage, key, obj_enc) + Self::check_decrypt_common(garage, key, obj_enc) } - fn check_decrypt<'a>( + fn check_decrypt_common<'a>( garage: &Garage, key: Option<Key<Aes256Gcm>>, obj_enc: &'a ObjectVersionEncryption, @@ -294,34 +294,46 @@ fn parse_request_headers( key_header: &HeaderName, md5_header: &HeaderName, ) -> Result<Option<Key<Aes256Gcm>>, Error> { - match req.headers().get(alg_header) { - Some(alg) if *alg == CUSTOMER_ALGORITHM_AES256 => { + parse_encryption_params( + req.headers().get(alg_header).map(HeaderValue::as_bytes), + req.headers().get(key_header).map(HeaderValue::as_bytes), + req.headers().get(md5_header).map(HeaderValue::as_bytes), + ) +} + +fn parse_encryption_params( + alg: Option<&[u8]>, + key: Option<&[u8]>, + md5: Option<&[u8]>, +) -> Result<Option<Key<Aes256Gcm>>, Error> { + match alg { + Some(CUSTOMER_ALGORITHM_AES256) => { use md5::{Digest, Md5}; - let key_b64 = req - .headers() - .get(key_header) - .ok_or_bad_request(format!("Missing {} header", key_header))?; + let key_b64 = + key.ok_or_bad_request("Missing server-side-encryption-customer-key header")?; let key_bytes: [u8; 32] = BASE64_STANDARD .decode(&key_b64) - .ok_or_bad_request(format!("Invalid {} header", key_header))? + .ok_or_bad_request( + "Invalid server-side-encryption-customer-key header: invalid base64", + )? .try_into() .ok() - .ok_or_bad_request(format!("Invalid {} header", key_header))?; + .ok_or_bad_request( + "Invalid server-side-encryption-customer-key header: invalid length", + )?; - let md5_b64 = req - .headers() - .get(md5_header) - .ok_or_bad_request(format!("Missing {} header", md5_header))?; - let md5_bytes = BASE64_STANDARD - .decode(&md5_b64) - .ok_or_bad_request(format!("Invalid {} header", md5_header))?; + let md5_b64 = + md5.ok_or_bad_request("Missing server-side-encryption-customer-key-md5 header")?; + let md5_bytes = BASE64_STANDARD.decode(&md5_b64).ok_or_bad_request( + "Invalid server-side-encryption-customer-key-md5 header: invalid bass64", + )?; let mut hasher = Md5::new(); hasher.update(&key_bytes[..]); if hasher.finalize().as_slice() != md5_bytes.as_slice() { return Err(Error::bad_request( - "Encryption key MD5 checksum does not match", + "Server-side encryption client key MD5 checksum does not match", )); } @@ -330,7 +342,15 @@ fn parse_request_headers( Some(alg) => Err(Error::InvalidEncryptionAlgorithm( alg.to_str().unwrap_or("??").to_string(), )), - None => Ok(None), + None => { + if key.is_some() || md5.is_some() { + Err(Error::bad_request( + "Unexpected server-side-encryption-customer-key{,-md5} header(s)", + )) + } else { + Ok(None) + } + } } } |