feat: datakey decrypt fails when not exportable

This commit is contained in:
2024-11-15 01:44:21 +08:00
parent 655f9f5ede
commit 909ac90eb9
4 changed files with 37 additions and 37 deletions

View File

@@ -84,7 +84,7 @@ Generate data key:
```shell ```shell
curl -X POST http://127.0.0.1:5567/datakey \ curl -X POST http://127.0.0.1:5567/datakey \
-H "Content-Type: application/json" \ -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 Upgrade to v3.2

View File

@@ -50,7 +50,7 @@ pub fn rsa_key_to_pem(rsa_private_key: &RsaPrivateKey) -> XResult<String> {
} }
pub fn jwk_to_rsa_pubic_key(rsa_jwk: &str) -> XResult<RsaPublicKey> { pub fn jwk_to_rsa_pubic_key(rsa_jwk: &str) -> XResult<RsaPublicKey> {
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); let rsa_public_key = opt_result!(RsaPublicKey::try_from(rsa), "Bad RSA JWK: {}, error: {:?}", rsa_jwk);
Ok(rsa_public_key) Ok(rsa_public_key)
} }
@@ -73,7 +73,7 @@ pub fn deserialize_jwe_rsa(jwe: &str, rsa: &RsaPrivateKey) -> XResult<(Vec<u8>,
if alg != JWE_ALG_RSA_OAEP { if alg != JWE_ALG_RSA_OAEP {
return simple_error!("Invalid JWE header alg: {}", alg); return simple_error!("Invalid JWE header alg: {}", alg);
} }
Ok(opt_result!(rsa.decrypt(Oaep::new::<Sha1>(), &key_wrap), "Unwrap key failed: {}")) Ok(opt_result!(rsa.decrypt(Oaep::new::<Sha1>(), key_wrap), "Unwrap key failed: {}"))
}) })
} }
@@ -82,7 +82,7 @@ pub fn serialize_jwe_aes(payload: &[u8], key: &[u8]) -> XResult<String> {
} }
pub fn serialize_jwe_aes_with_data_type(data_type: &str, exportable: bool, payload: &[u8], key: &[u8]) -> XResult<String> { pub fn serialize_jwe_aes_with_data_type(data_type: &str, exportable: bool, payload: &[u8], key: &[u8]) -> XResult<String> {
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<String>, exportable: Option<bool>, payload: &[u8], key: [u8; 32]) -> XResult<String> { pub fn serialize_jwe_aes_32(data_type: Option<String>, exportable: Option<bool>, payload: &[u8], key: [u8; 32]) -> XResult<String> {
@@ -93,11 +93,10 @@ pub fn serialize_jwe_aes_32(data_type: Option<String>, exportable: Option<bool>,
version: Some(get_master_key_checksum(&key)), version: Some(get_master_key_checksum(&key)),
data_type, data_type,
exportable, exportable,
..Default::default()
}; };
serialize_jwe_fn(&header, payload, |data_key| -> XResult<Vec<u8>> { serialize_jwe_fn(&header, payload, |data_key| -> XResult<Vec<u8>> {
let kek = Kek::from(key); 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<u8>, Jwe
return simple_error!("Invalid JWE header alg: {}", alg); return simple_error!("Invalid JWE header alg: {}", alg);
} }
let kek = Kek::from(key); 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, LOCAL_KMS_PREFIX,
header_b64, header_b64,
URL_SAFE_NO_PAD.encode(&cek), 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(&ciphertext),
URL_SAFE_NO_PAD.encode(&tag) 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"); return simple_error!("Not valid 32 bytes");
} }
let mut ret = [0; 32]; let mut ret = [0; 32];
for i in 0..32 { ret.copy_from_slice(&bytes[..32]);
ret[i] = bytes[i];
}
Ok(ret) Ok(ret)
} }

View File

@@ -17,9 +17,9 @@ use serde_json::{Map, Value};
// type:ec, spec:p256,p384,p521,ed25519,cv25519 // type:ec, spec:p256,p384,p521,ed25519,cv25519
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct DataKeyRequest { struct DataKeyRequest {
key_type: String, r#type: String,
key_spec: String, spec: String,
key_name: Option<String>, name: Option<String>,
exportable: Option<bool>, exportable: Option<bool>,
return_plaintext: Option<bool>, return_plaintext: Option<bool>,
} }
@@ -32,15 +32,15 @@ async fn inner_generate(req: Request<Body>) -> XResult<(StatusCode, Value)> {
let whole_body = hyper::body::aggregate(req).await?; let whole_body = hyper::body::aggregate(req).await?;
let request: DataKeyRequest = serde_json::from_reader(whole_body.reader())?; 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() { let key = match get_master_key() {
None => return serve_common::error("status_not_ready"), None => return serve_common::error("status_not_ready"),
Some(key) => key, Some(key) => key,
}; };
let exportable = request.exportable.unwrap_or(true); 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", "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", "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), ("aes", "256") => generate_aes("datakey:aes-256", exportable, key, 32, ret_key_plaintext),
@@ -53,16 +53,16 @@ async fn inner_generate(req: Request<Body>) -> XResult<(StatusCode, Value)> {
Err(e) => serve_common::error(&format!("internal error: {}", e)), Err(e) => serve_common::error(&format!("internal error: {}", e)),
Ok((key_plaintext, key_ciphertext)) => { Ok((key_plaintext, key_ciphertext)) => {
let mut map = Map::new(); let mut map = Map::new();
map.insert("key_type".to_string(), Value::String(request.key_type)); map.insert("key_type".to_string(), Value::String(request.r#type));
map.insert("key_spec".to_string(), Value::String(request.key_spec)); map.insert("key_spec".to_string(), Value::String(request.spec));
if let Some(key_plaintext) = key_plaintext { if let Some(key_plaintext) = key_plaintext {
map.insert("key_plaintext".to_string(), Value::String(STANDARD.encode(&key_plaintext))); map.insert("key_plaintext".to_string(), Value::String(STANDARD.encode(&key_plaintext)));
} }
map.insert("key_ciphertext".to_string(), Value::String(key_ciphertext)); 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 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))) Ok((StatusCode::OK, Value::Object(map)))

View File

@@ -28,8 +28,12 @@ async fn inner_decrypt(req: Request<Body>) -> XResult<(StatusCode, Value)> {
}; };
let decrypted_value = jose::deserialize_jwe_aes(&data.encrypted_value, &key.read()); let decrypted_value = jose::deserialize_jwe_aes(&data.encrypted_value, &key.read());
drop(key); drop(key);
let (data, header) = decrypted_value?;
if let Some(false) = header.exportable {
return serve_common::error("data_not_exportable");
}
decrypted_value.map(|(data, header)| {
let mut map = byte_to_multi_view_map(&data, true); let mut map = byte_to_multi_view_map(&data, true);
let mut header_map = Map::new(); let mut header_map = Map::new();
header_map.insert("enc".to_string(), Value::String(header.enc.clone())); header_map.insert("enc".to_string(), Value::String(header.enc.clone()));
@@ -43,8 +47,7 @@ async fn inner_decrypt(req: Request<Body>) -> XResult<(StatusCode, Value)> {
if !header_map.is_empty() { if !header_map.is_empty() {
map.insert("header".to_string(), Value::Object(header_map)); map.insert("header".to_string(), Value::Object(header_map));
} }
(StatusCode::OK, Value::Object(map)) Ok((StatusCode::OK, Value::Object(map)))
})
} }
pub async fn encrypt(req: Request<Body>) -> Result<Response<Body>> { pub async fn encrypt(req: Request<Body>) -> Result<Response<Body>> {