summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorStuart Stock <stuart@int08h.com>2018-10-09 20:54:49 -0500
committerStuart Stock <stuart@int08h.com>2018-10-09 20:54:49 -0500
commitc66513b606f6aacf61bab1434c1f512c24981b2b (patch)
tree8f5374f9163366bfd845cd796c087f68f9f9baf2 /src
parentbab728c1c5eea847e06e13400dc40a522f2b4d25 (diff)
downloadroughenough-c66513b606f6aacf61bab1434c1f512c24981b2b.zip
continue work on kms
Diffstat (limited to 'src')
-rw-r--r--src/bin/roughenough-kms.rs59
-rw-r--r--src/config/environment.rs14
-rw-r--r--src/key/envelope.rs41
-rw-r--r--src/key/mod.rs22
4 files changed, 74 insertions, 62 deletions
diff --git a/src/bin/roughenough-kms.rs b/src/bin/roughenough-kms.rs
index bc749bb..b660488 100644
--- a/src/bin/roughenough-kms.rs
+++ b/src/bin/roughenough-kms.rs
@@ -16,7 +16,6 @@
//! Work with Roughenough long-term key
//!
-#[macro_use]
extern crate clap;
#[macro_use]
extern crate log;
@@ -26,31 +25,21 @@ extern crate roughenough;
extern crate simple_logger;
extern crate untrusted;
-use std::default::Default;
-
use clap::{App, Arg};
-use roughenough::key::{EnvelopeEncryption, KmsProvider};
use roughenough::VERSION;
+use roughenough::key::EnvelopeEncryption;
#[cfg(feature = "kms")]
use roughenough::key::awskms::AwsKms;
#[cfg(feature = "kms")]
-fn aws_kms() {
- let client = AwsKms::from_arn(
- "arn:aws:kms:us-east-2:927891522318:key/1c96fb2c-d417-48f4-bf24-8e7173a587f5",
- ).unwrap();
+fn aws_kms(kms_key: &str, plaintext_seed: &[u8]) {
+ let client = AwsKms::from_arn(kms_key).unwrap();
- let plaintext_seed = [b'a'; 32];
match EnvelopeEncryption::encrypt_seed(&client, &plaintext_seed) {
- Ok(bundle) => {
- info!("Bundle len={}", bundle.len());
- info!("{}", hex::encode(&bundle));
-
- match EnvelopeEncryption::decrypt_seed(&client, &bundle) {
- Ok(plaintext) => info!("Result is {}", hex::encode(plaintext)),
- Err(e) => error!("Nope, {:?}", e),
- };
+ Ok(encrypted_blob) => {
+ println!("key_protection: \"{}\"", kms_key);
+ println!("seed: {}", hex::encode(&encrypted_blob));
}
Err(e) => {
error!("Error: {:?}", e);
@@ -65,22 +54,34 @@ pub fn main() {
let matches = App::new("Roughenough key management")
.version(VERSION)
- .arg(
- Arg::with_name("operation")
- .required(true)
- .help("The operation to perform")
- .takes_value(true),
- ).get_matches();
+ .arg(Arg::with_name("kms-key")
+ .short("k")
+ .long("kms-key")
+ .takes_value(true)
+ .required(true)
+ .help("Identity of the KMS key to be used"))
+ .arg(Arg::with_name("seed")
+ .short("s")
+ .long("seed")
+ .takes_value(true)
+ .required(true)
+ .help("Seed for the server's long-term identity"))
+ .get_matches();
+
+ let kms_key = matches.value_of("kms-key").unwrap();
+ let plaintext_seed = matches.value_of("seed")
+ .map(|seed| hex::decode(seed).expect("Error parsing seed value"))
+ .unwrap();
+
+ if plaintext_seed.len() != 32 {
+ error!("Seed must be 32 bytes long; provided seed is {}", plaintext_seed.len());
+ return;
+ }
if cfg!(feature = "kms") {
- info!("KMS feature enabled");
#[cfg(feature = "kms")]
- {
- aws_kms();
- }
+ aws_kms(kms_key, &plaintext_seed);
} else {
warn!("KMS not enabled, nothing to do");
}
-
- info!("Done");
}
diff --git a/src/config/environment.rs b/src/config/environment.rs
index 8f91f0c..a4cb528 100644
--- a/src/config/environment.rs
+++ b/src/config/environment.rs
@@ -74,12 +74,8 @@ impl EnvironmentConfig {
};
if let Ok(seed) = env::var(ROUGHENOUGH_SEED) {
- cfg.seed = hex::decode(&seed).expect(
- format!(
- "invalid seed value: {}\n'seed' should be 32 byte hex value",
- seed
- ).as_ref(),
- );
+ cfg.seed = hex::decode(&seed)
+ .expect("invalid seed value; 'seed' should be a hex value");
};
if let Ok(batch_size) = env::var(ROUGHENOUGH_BATCH_SIZE) {
@@ -96,6 +92,12 @@ impl EnvironmentConfig {
cfg.status_interval = Duration::from_secs(val as u64);
};
+ if let Ok(key_protection) = env::var(ROUGHENOUGH_KEY_PROTECTION) {
+ cfg.key_protection = key_protection
+ .parse()
+ .expect(format!("invalid key_protection value: {}", key_protection).as_ref());
+ }
+
Ok(cfg)
}
}
diff --git a/src/key/envelope.rs b/src/key/envelope.rs
index bb3560f..5128b76 100644
--- a/src/key/envelope.rs
+++ b/src/key/envelope.rs
@@ -39,11 +39,14 @@ const MIN_PAYLOAD_SIZE: usize = DEK_LEN_FIELD
+ MIN_SEED_LENGTH as usize
+ TAG_SIZE_BYTES;
-// Domain separation in case KMS key is reused
+// No input prefix to skip, consume entire buffer
+const IN_PREFIX_LEN: usize = 0;
+
+// Trivial domain separation to guard KMS key reuse
static AD: &[u8; 11] = b"roughenough";
// Convenience function to create zero-filled Vec of given size
-fn zero_filled(len: usize) -> Vec<u8> {
+fn vec_zero_filled(len: usize) -> Vec<u8> {
let mut v = Vec::with_capacity(len);
for _ in 0..len {
v.push(0);
@@ -63,31 +66,30 @@ impl EnvelopeEncryption {
)));
}
- info!("--- decrypt ---");
- info!("blob {}", hex::encode(ciphertext_blob));
let mut tmp = Cursor::new(ciphertext_blob);
+
+ // Read the lengths of the wrapped DEK and of the nonce
let dek_len = tmp.read_u16::<LittleEndian>()?;
let nonce_len = tmp.read_u16::<LittleEndian>()?;
- let mut encrypted_dek = zero_filled(dek_len as usize);
+ // Consume the wrapped DEK
+ let mut encrypted_dek = vec_zero_filled(dek_len as usize);
tmp.read_exact(&mut encrypted_dek)?;
- let mut nonce = zero_filled(nonce_len as usize);
+ // Consume the nonce
+ let mut nonce = vec_zero_filled(nonce_len as usize);
tmp.read_exact(&mut nonce)?;
+ // Consume the encrypted seed + tag
let mut encrypted_seed = Vec::new();
tmp.read_to_end(&mut encrypted_seed)?;
- info!("dek len {}", dek_len);
- info!("nonce len {}", nonce_len);
- info!("enc dec {}", hex::encode(&encrypted_dek));
- info!("nonce {}", hex::encode(&nonce));
- info!("blob {}", hex::encode(&encrypted_seed));
-
+ // Invoke KMS to decrypt the DEK
let dek = kms.decrypt_dek(&encrypted_dek)?;
- let dek_open_key = OpeningKey::new(&AES_256_GCM, &dek)?;
- match open_in_place(&dek_open_key, &nonce, AD, 0, &mut encrypted_seed) {
+ // Decrypt the seed value using the DEK
+ let dek_open_key = OpeningKey::new(&AES_256_GCM, &dek)?;
+ match open_in_place(&dek_open_key, &nonce, AD, IN_PREFIX_LEN, &mut encrypted_seed) {
Ok(plaintext_seed) => Ok(plaintext_seed.to_vec()),
Err(e) => Err(KmsError::OperationFailed(
"failed to decrypt plaintext seed".to_string(),
@@ -112,7 +114,7 @@ impl EnvelopeEncryption {
plaintext_buf.push(0);
}
- // Encrypt the plaintext seed
+ // Encrypt the plaintext seed using the DEK
let dek_seal_key = SealingKey::new(&AES_256_GCM, &dek)?;
let encrypted_seed = match seal_in_place(
&dek_seal_key,
@@ -129,7 +131,7 @@ impl EnvelopeEncryption {
}
};
- // Wrap the DEK
+ // Use the KMS to wrap the DEK
let wrapped_dek = kms.encrypt_dek(&dek.to_vec())?;
// And coalesce everything together
@@ -140,13 +142,6 @@ impl EnvelopeEncryption {
output.write_all(&nonce)?;
output.write_all(&encrypted_seed)?;
- info!("--- encrypt ---");
- info!("seed {}", hex::encode(plaintext_seed));
- info!("dek {}", hex::encode(&dek));
- info!("enc dek {}", hex::encode(&wrapped_dek));
- info!("nonce {}", hex::encode(&nonce));
- info!("blob {}", hex::encode(&encrypted_seed));
-
Ok(output)
}
}
diff --git a/src/key/mod.rs b/src/key/mod.rs
index 62c37a9..7ae2198 100644
--- a/src/key/mod.rs
+++ b/src/key/mod.rs
@@ -26,6 +26,7 @@ mod longterm;
mod online;
use std::error::Error;
+use std::str::FromStr;
pub use self::envelope::EnvelopeEncryption;
pub use self::longterm::LongTermKey;
@@ -39,11 +40,24 @@ pub enum KeyProtection {
/// No protection, seed is in plaintext
Plaintext,
- /// Envelope encryption with Key-Encrypting-Key (KEK) from AWS Key Management Service
- AwsKmsEnvelope,
+ /// Envelope encryption using AWS Key Management Service
+ AwsKmsEnvelope(String),
- /// Envelope encryption with Key-Encrypting-Key (KEK) from Google Cloud Key Management Service
- GoogleKmsEnvelope,
+ /// Envelope encryption using Google Cloud Key Management Service
+ GoogleKmsEnvelope(String),
+}
+
+impl FromStr for KeyProtection {
+ type Err = ();
+
+ fn from_str(s: &str) -> Result<KeyProtection, ()> {
+ match s {
+ "plaintext" => Ok(KeyProtection::Plaintext),
+ s if s.starts_with("arn") => Ok(KeyProtection::AwsKmsEnvelope(s.to_string())),
+ s if s.starts_with("gcp") => Ok(KeyProtection::GoogleKmsEnvelope(s.to_string())),
+ _ => Err(())
+ }
+ }
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Hash, Clone)]