use super::*;
impl BucketWarden {
pub fn update_object_encryption(
&mut self,
principal: &str,
request: UpdateObjectEncryptionRequest,
) -> Result<UpdateObjectEncryptionResult, RuntimeError> {
if crate::bucket_basics::is_directory_bucket_name(&request.bucket) {
return Err(RuntimeError::InvalidEncryption(
"UpdateObjectEncryption is not supported for directory buckets".to_string(),
));
}
let resource = object_resource(&request.bucket, &request.key);
self.authorize(principal, S3Action::PutObject, &resource)?;
self.authorize(principal, S3Action::UpdateObjectEncryption, &resource)?;
let target_version_id = if let Some(version_id) = request.version_id.as_deref() {
version_id.to_string()
} else {
self.current_version(&request.bucket, &request.key)?
.version_id
.clone()
};
let current_version = self
.version_by_id(&request.bucket, &request.key, &target_version_id)?
.clone();
if current_version.delete_marker {
return Err(RuntimeError::NoSuchKey(resource));
}
if let Err(error) = current_version
.lock
.assert_deletable(self.clock_epoch_seconds, false)
{
self.audit_denied(
principal,
S3Action::UpdateObjectEncryption,
&resource,
Some(error.to_string()),
);
return Err(RuntimeError::ObjectLocked(error));
}
let current_encryption = current_version.metadata.encryption.clone().ok_or_else(|| {
RuntimeError::InvalidEncryption(
"UpdateObjectEncryption requires an encrypted source object".to_string(),
)
})?;
if current_encryption.algorithm == "aws:kms:dsse" {
return Err(RuntimeError::UnsupportedEncryption(
"UpdateObjectEncryption does not support DSSE-KMS source objects".to_string(),
));
}
let encryption = self.normalize_encryption(request.encryption)?;
if encryption.algorithm != "aws:kms" {
return Err(RuntimeError::InvalidEncryption(
"UpdateObjectEncryption requires SSE-KMS as the requested encryption type"
.to_string(),
));
}
let body = match self.kms.decrypt(¤t_version.ciphertext) {
Ok(body) => body,
Err(error) => {
self.audit_kms_failure(
principal,
"kms:Decrypt",
&resource,
¤t_version.ciphertext.key_id,
&error.to_string(),
);
return Err(RuntimeError::Kms(error));
}
};
let ciphertext = match self.kms.encrypt(&body) {
Ok(ciphertext) => ciphertext,
Err(error) => {
let key_id = self.kms.key_id().to_string();
self.audit_kms_failure(
principal,
"kms:Encrypt",
&resource,
&key_id,
&error.to_string(),
);
return Err(RuntimeError::Kms(error));
}
};
let envelope = self.envelope_metadata(Some(&encryption), &ciphertext, &body);
let version = self.version_by_id_mut(&request.bucket, &request.key, &target_version_id)?;
version.ciphertext = ciphertext;
version.envelope = envelope;
version.metadata.encryption = Some(encryption.clone());
self.audit_allowed(
principal,
S3Action::UpdateObjectEncryption,
&object_resource(&request.bucket, &request.key),
Some(target_version_id.clone()),
);
Ok(UpdateObjectEncryptionResult {
bucket: request.bucket,
key: request.key,
version_id: target_version_id,
encryption,
bucket_key_enabled: request.bucket_key_enabled,
})
}
}