summaryrefslogtreecommitdiff
path: root/src/kms/awskms.rs
diff options
context:
space:
mode:
authorStuart Stock <stuart@int08h.com>2018-10-12 22:39:37 -0500
committerStuart Stock <stuart@int08h.com>2018-10-12 22:39:37 -0500
commitfec19a7d65c9dca293056f40b4a1983b82a0e68d (patch)
tree0e02ecc6174804a5be46f4fba19b7f98be6ab3d2 /src/kms/awskms.rs
parented89d98692ac273ec7dfc39c19008334077779a3 (diff)
downloadroughenough-fec19a7d65c9dca293056f40b4a1983b82a0e68d.zip
Refactor to kms module; add documentation
Diffstat (limited to 'src/kms/awskms.rs')
-rw-r--r--src/kms/awskms.rs128
1 files changed, 128 insertions, 0 deletions
diff --git a/src/kms/awskms.rs b/src/kms/awskms.rs
new file mode 100644
index 0000000..396490f
--- /dev/null
+++ b/src/kms/awskms.rs
@@ -0,0 +1,128 @@
+// Copyright 2017-2018 int08h LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+extern crate hex;
+extern crate log;
+
+#[cfg(feature = "kms")]
+extern crate rusoto_core;
+#[cfg(feature = "kms")]
+extern crate rusoto_kms;
+
+#[cfg(feature = "kms")]
+use self::rusoto_core::Region;
+#[cfg(feature = "kms")]
+use self::rusoto_kms::{DecryptRequest, EncryptRequest, Kms, KmsClient};
+
+use std::default::Default;
+use std::error::Error;
+use std::fmt;
+use std::fmt::Formatter;
+use std::str::FromStr;
+
+use kms::{EncryptedDEK, KmsError, KmsProvider, PlaintextDEK, DEK_SIZE_BYTES};
+
+/// Amazon Key Management Service
+#[cfg(feature = "kms")]
+pub struct AwsKms {
+ kms_client: KmsClient,
+ key_id: String,
+}
+
+#[cfg(feature = "kms")]
+impl AwsKms {
+
+ /// Create a new instance from the ARN of a AWS KMS key.
+ pub fn from_arn(arn: &str) -> Result<Self, KmsError> {
+ let parts: Vec<&str> = arn.split(':').collect();
+
+ if parts.len() != 6 {
+ return Err(KmsError::InvalidConfiguration(format!(
+ "invalid KMS arn: too few parts {}",
+ parts.len()
+ )));
+ }
+
+ let region_part = parts.get(3).expect("region is missing");
+ let region = match Region::from_str(region_part) {
+ Ok(r) => r,
+ Err(e) => return Err(KmsError::InvalidConfiguration(e.description().to_string())),
+ };
+
+ Ok(AwsKms {
+ kms_client: KmsClient::new(region),
+ key_id: arn.to_string(),
+ })
+ }
+}
+
+impl KmsProvider for AwsKms {
+ fn encrypt_dek(&self, plaintext_dek: &PlaintextDEK) -> Result<EncryptedDEK, KmsError> {
+ if plaintext_dek.len() != DEK_SIZE_BYTES {
+ return Err(KmsError::InvalidKey(format!(
+ "provided DEK wrong length: {}",
+ plaintext_dek.len()
+ )));
+ }
+
+ let mut encrypt_req: EncryptRequest = Default::default();
+ encrypt_req.key_id = self.key_id.clone();
+ encrypt_req.plaintext = plaintext_dek.clone();
+
+ match self.kms_client.encrypt(encrypt_req).sync() {
+ Ok(result) => {
+ if let Some(ciphertext) = result.ciphertext_blob {
+ Ok(ciphertext)
+ } else {
+ Err(KmsError::OperationFailed(
+ "no ciphertext despite successful response".to_string(),
+ ))
+ }
+ }
+ Err(e) => Err(KmsError::OperationFailed(e.description().to_string())),
+ }
+ }
+
+ fn decrypt_dek(&self, encrypted_dek: &EncryptedDEK) -> Result<PlaintextDEK, KmsError> {
+ let mut decrypt_req: DecryptRequest = Default::default();
+ decrypt_req.ciphertext_blob = encrypted_dek.clone();
+
+ match self.kms_client.decrypt(decrypt_req).sync() {
+ Ok(result) => {
+ if let Some(plaintext_dek) = result.plaintext {
+ if plaintext_dek.len() == DEK_SIZE_BYTES {
+ Ok(plaintext_dek)
+ } else {
+ Err(KmsError::InvalidKey(format!(
+ "decrypted DEK wrong length: {}",
+ plaintext_dek.len()
+ )))
+ }
+ } else {
+ Err(KmsError::OperationFailed(
+ "decrypted payload is empty".to_string(),
+ ))
+ }
+ }
+ Err(e) => Err(KmsError::OperationFailed(e.description().to_string())),
+ }
+ }
+}
+
+#[cfg(feature = "kms")]
+impl fmt::Display for AwsKms {
+ fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ write!(f, "{}", self.key_id)
+ }
+}