diff --git a/src/jose.rs b/src/jose.rs index dd255b9..bb7ac2a 100644 --- a/src/jose.rs +++ b/src/jose.rs @@ -7,7 +7,7 @@ use rand::{random, thread_rng}; use rsa::pkcs1::LineEnding; use rsa::pkcs8::EncodePublicKey; use rsa::{Oaep, RsaPrivateKey, RsaPublicKey}; -use rust_util::{opt_result, simple_error, XResult}; +use rust_util::{iff, opt_result, simple_error, XResult}; use serde_derive::{Deserialize, Serialize}; use sha1::Sha1; use sha2::{Digest, Sha256}; @@ -18,7 +18,7 @@ const JWE_ALG_A256KW: &str = "A256KW"; const JWE_ALG_RSA_OAEP: &str = "RSA-OAEP"; const JWE_DOT: &str = "."; -#[derive(Debug, Serialize, Deserialize)] +#[derive(Default, Debug, Serialize, Deserialize)] pub struct JweHeader { pub enc: String, pub alg: String, @@ -27,6 +27,8 @@ pub struct JweHeader { pub version: Option, #[serde(skip_serializing_if = "Option::is_none")] pub data_type: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub exportable: Option, } pub fn generate_rsa_key(bits: u32) -> XResult { @@ -58,8 +60,7 @@ pub fn serialize_jwe_rsa(payload: &[u8], rsa_public_key: &RsaPublicKey) -> XResu enc: JWE_ENC_A256GCM.to_string(), alg: JWE_ALG_RSA_OAEP.to_string(), vendor: "local-mini-kms".to_string(), - version: None, - data_type: None, + ..Default::default() }; serialize_jwe_fn(&header, payload, |data_key| -> XResult> { let mut r = thread_rng(); @@ -77,20 +78,22 @@ pub fn deserialize_jwe_rsa(jwe: &str, rsa: &RsaPrivateKey) -> XResult<(Vec, } pub fn serialize_jwe_aes(payload: &[u8], key: &[u8]) -> XResult { - serialize_jwe_aes_32(None, payload, to_bytes32(key)?) + serialize_jwe_aes_32(None, None, payload, to_bytes32(key)?) } -pub fn serialize_jwe_aes_with_data_type(data_type: &str, payload: &[u8], key: &[u8]) -> XResult { - serialize_jwe_aes_32(Some(data_type.to_string()), payload, to_bytes32(key)?) +pub fn serialize_jwe_aes_with_data_type(data_type: &str, exportable: bool, payload: &[u8], key: &[u8]) -> XResult { + serialize_jwe_aes_32(Some(data_type.to_string()), iff!(exportable, Some(false), None), payload, to_bytes32(key)?) } -pub fn serialize_jwe_aes_32(data_type: Option, payload: &[u8], key: [u8; 32]) -> XResult { +pub fn serialize_jwe_aes_32(data_type: Option, exportable: Option, payload: &[u8], key: [u8; 32]) -> XResult { let header = JweHeader { enc: JWE_ENC_A256GCM.to_string(), alg: JWE_ALG_A256KW.to_string(), vendor: "local-mini-kms".to_string(), version: Some(get_master_key_checksum(&key)), data_type, + exportable, + ..Default::default() }; serialize_jwe_fn(&header, payload, |data_key| -> XResult> { let kek = Kek::from(key); diff --git a/src/serve_datakey.rs b/src/serve_datakey.rs index 56c24d3..bc6ccb7 100644 --- a/src/serve_datakey.rs +++ b/src/serve_datakey.rs @@ -20,6 +20,7 @@ struct DataKeyRequest { key_type: String, key_spec: String, key_name: Option, + exportable: Option, return_plaintext: Option, } @@ -36,12 +37,13 @@ async fn inner_generate(req: Request) -> XResult<(StatusCode, Value)> { None => return serve_common::error("status_not_ready"), Some(key) => key, }; - let ret_key_plaintext = request.return_plaintext.unwrap_or(false); + let exportable = request.exportable.unwrap_or(true); + let ret_key_plaintext = iff!(exportable, false, request.return_plaintext.unwrap_or(false)); let response_result = match (request.key_type.as_str(), request.key_spec.as_str()) { - ("aes", "128") => generate_aes("datakey:aes-128", key, 16, ret_key_plaintext), - ("aes", "192") => generate_aes("datakey:aes-192", key, 24, ret_key_plaintext), - ("aes", "256") => generate_aes("datakey:aes-256", key, 32, ret_key_plaintext), + ("aes", "128") => generate_aes("datakey:aes-128", exportable, key, 16, ret_key_plaintext), + ("aes", "192") => generate_aes("datakey:aes-192", exportable, key, 24, ret_key_plaintext), + ("aes", "256") => generate_aes("datakey:aes-256", exportable, key, 32, ret_key_plaintext), // TODO rsa 2048, rsa 3072, rsa 4096 // TODO ec p256, p384, p521, ed25519, cv25519 _ => return serve_common::error("invalid key_type or key_spec"), @@ -68,10 +70,10 @@ async fn inner_generate(req: Request) -> XResult<(StatusCode, Value)> { } } -fn generate_aes(data_key_type: &str, key: SecBytes, len: i32, ret_key_plaintext: bool) -> XResult<(Option>, String)> { +fn generate_aes(data_key_type: &str, exportable: bool, key: SecBytes, len: i32, ret_key_plaintext: bool) -> XResult<(Option>, String)> { let bytes: [u8; 32] = random(); let value = &bytes[0..len as usize]; let key_plaintext = iff!(ret_key_plaintext, Some(value.to_vec()), None); - let key_ciphertext = jose::serialize_jwe_aes_with_data_type(data_key_type, value, &key.read())?; + let key_ciphertext = jose::serialize_jwe_aes_with_data_type(data_key_type, exportable, value, &key.read())?; Ok((key_plaintext, key_ciphertext)) }