From 909ac90eb9ae908968b717c4ecbea4ab65f0cdfa Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Fri, 15 Nov 2024 01:44:21 +0800 Subject: [PATCH] feat: datakey decrypt fails when not exportable --- README.md | 2 +- src/jose.rs | 17 +++++++---------- src/serve_datakey.rs | 20 ++++++++++---------- src/serve_encrypt_decrypt.rs | 35 +++++++++++++++++++---------------- 4 files changed, 37 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index c22572b..f60afa1 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ Generate data key: ```shell curl -X POST http://127.0.0.1:5567/datakey \ -H "Content-Type: application/json" \ - -d '{"key_type":"aes", "key_spec":"256", "return_plaintext": true}' + -d '{"type":"aes", "spec":"256", "exportable": true, "return_plaintext": true}' ``` Upgrade to v3.2 diff --git a/src/jose.rs b/src/jose.rs index bb7ac2a..8f0cb6c 100644 --- a/src/jose.rs +++ b/src/jose.rs @@ -50,7 +50,7 @@ pub fn rsa_key_to_pem(rsa_private_key: &RsaPrivateKey) -> XResult { } pub fn jwk_to_rsa_pubic_key(rsa_jwk: &str) -> XResult { - let rsa: Rsa = opt_result!(serde_json::from_str(&rsa_jwk), "Bad RSA JWK: {}, error: {}", rsa_jwk); + let rsa: Rsa = opt_result!(serde_json::from_str(rsa_jwk), "Bad RSA JWK: {}, error: {}", rsa_jwk); let rsa_public_key = opt_result!(RsaPublicKey::try_from(rsa), "Bad RSA JWK: {}, error: {:?}", rsa_jwk); Ok(rsa_public_key) } @@ -73,7 +73,7 @@ pub fn deserialize_jwe_rsa(jwe: &str, rsa: &RsaPrivateKey) -> XResult<(Vec, if alg != JWE_ALG_RSA_OAEP { return simple_error!("Invalid JWE header alg: {}", alg); } - Ok(opt_result!(rsa.decrypt(Oaep::new::(), &key_wrap), "Unwrap key failed: {}")) + Ok(opt_result!(rsa.decrypt(Oaep::new::(), key_wrap), "Unwrap key failed: {}")) }) } @@ -82,7 +82,7 @@ pub fn serialize_jwe_aes(payload: &[u8], key: &[u8]) -> XResult { } 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)?) + serialize_jwe_aes_32(Some(data_type.to_string()), iff!(exportable, None, Some(false)), payload, to_bytes32(key)?) } pub fn serialize_jwe_aes_32(data_type: Option, exportable: Option, payload: &[u8], key: [u8; 32]) -> XResult { @@ -93,11 +93,10 @@ pub fn serialize_jwe_aes_32(data_type: Option, exportable: Option, 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); - Ok(opt_result!(kek.wrap_vec(&data_key[..]), "Wrap key failed: {}")) + Ok(opt_result!(kek.wrap_vec(data_key), "Wrap key failed: {}")) }) } @@ -111,7 +110,7 @@ pub fn deserialize_jwe_aes_32(jwe: &str, key: [u8; 32]) -> XResult<(Vec, Jwe return simple_error!("Invalid JWE header alg: {}", alg); } let kek = Kek::from(key); - Ok(opt_result!(kek.unwrap_vec(&key_wrap), "Unwrap key failed: {}")) + Ok(opt_result!(kek.unwrap_vec(key_wrap), "Unwrap key failed: {}")) }) } @@ -137,7 +136,7 @@ where LOCAL_KMS_PREFIX, header_b64, URL_SAFE_NO_PAD.encode(&cek), - URL_SAFE_NO_PAD.encode(&iv), + URL_SAFE_NO_PAD.encode(iv), URL_SAFE_NO_PAD.encode(&ciphertext), URL_SAFE_NO_PAD.encode(&tag) )) @@ -187,9 +186,7 @@ fn to_bytes32(bytes: &[u8]) -> XResult<[u8; 32]> { return simple_error!("Not valid 32 bytes"); } let mut ret = [0; 32]; - for i in 0..32 { - ret[i] = bytes[i]; - } + ret.copy_from_slice(&bytes[..32]); Ok(ret) } diff --git a/src/serve_datakey.rs b/src/serve_datakey.rs index bc6ccb7..98f5b2d 100644 --- a/src/serve_datakey.rs +++ b/src/serve_datakey.rs @@ -17,9 +17,9 @@ use serde_json::{Map, Value}; // type:ec, spec:p256,p384,p521,ed25519,cv25519 #[derive(Serialize, Deserialize)] struct DataKeyRequest { - key_type: String, - key_spec: String, - key_name: Option, + r#type: String, + spec: String, + name: Option, exportable: Option, return_plaintext: Option, } @@ -32,15 +32,15 @@ async fn inner_generate(req: Request) -> XResult<(StatusCode, Value)> { let whole_body = hyper::body::aggregate(req).await?; let request: DataKeyRequest = serde_json::from_reader(whole_body.reader())?; - debugging!("Generate data key: {} {}", &request.key_type, &request.key_spec); + debugging!("Generate data key: {} {}", &request.r#type, &request.spec); let key = match get_master_key() { None => return serve_common::error("status_not_ready"), Some(key) => key, }; let exportable = request.exportable.unwrap_or(true); - let ret_key_plaintext = iff!(exportable, false, request.return_plaintext.unwrap_or(false)); + 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()) { + let response_result = match (request.r#type.as_str(), request.spec.as_str()) { ("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), @@ -53,16 +53,16 @@ async fn inner_generate(req: Request) -> XResult<(StatusCode, Value)> { Err(e) => serve_common::error(&format!("internal error: {}", e)), Ok((key_plaintext, key_ciphertext)) => { let mut map = Map::new(); - map.insert("key_type".to_string(), Value::String(request.key_type)); - map.insert("key_spec".to_string(), Value::String(request.key_spec)); + map.insert("key_type".to_string(), Value::String(request.r#type)); + map.insert("key_spec".to_string(), Value::String(request.spec)); if let Some(key_plaintext) = key_plaintext { map.insert("key_plaintext".to_string(), Value::String(STANDARD.encode(&key_plaintext))); } map.insert("key_ciphertext".to_string(), Value::String(key_ciphertext)); - if let Some(_key_name) = &request.key_name { + if let Some(_name) = &request.name { // TODO write datakey to db - // TODO let data_key_name = format!("datakey:{}", key_name); + // TODO let data_key_name = format!("datakey:{}", name); } Ok((StatusCode::OK, Value::Object(map))) diff --git a/src/serve_encrypt_decrypt.rs b/src/serve_encrypt_decrypt.rs index b6d9b83..5712780 100644 --- a/src/serve_encrypt_decrypt.rs +++ b/src/serve_encrypt_decrypt.rs @@ -28,23 +28,26 @@ async fn inner_decrypt(req: Request) -> XResult<(StatusCode, Value)> { }; let decrypted_value = jose::deserialize_jwe_aes(&data.encrypted_value, &key.read()); drop(key); + let (data, header) = decrypted_value?; - decrypted_value.map(|(data, header)| { - let mut map = byte_to_multi_view_map(&data, true); - let mut header_map = Map::new(); - header_map.insert("enc".to_string(), Value::String(header.enc.clone())); - header_map.insert("alg".to_string(), Value::String(header.alg.clone())); - if let Some(version) = &header.version { - header_map.insert("version".to_string(), Value::String(version.to_string())); - } - if let Some(data_type) = &header.data_type { - header_map.insert("data_type".to_string(), Value::String(data_type.to_string())); - } - if !header_map.is_empty() { - map.insert("header".to_string(), Value::Object(header_map)); - } - (StatusCode::OK, Value::Object(map)) - }) + if let Some(false) = header.exportable { + return serve_common::error("data_not_exportable"); + } + + let mut map = byte_to_multi_view_map(&data, true); + let mut header_map = Map::new(); + header_map.insert("enc".to_string(), Value::String(header.enc.clone())); + header_map.insert("alg".to_string(), Value::String(header.alg.clone())); + if let Some(version) = &header.version { + header_map.insert("version".to_string(), Value::String(version.to_string())); + } + if let Some(data_type) = &header.data_type { + header_map.insert("data_type".to_string(), Value::String(data_type.to_string())); + } + if !header_map.is_empty() { + map.insert("header".to_string(), Value::Object(header_map)); + } + Ok((StatusCode::OK, Value::Object(map))) } pub async fn encrypt(req: Request) -> Result> {