diff --git a/Cargo.lock b/Cargo.lock index 6a2e125cb..e78ea89b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2653,7 +2653,7 @@ dependencies = [ "serde", "serde_json", "thiserror", - "yasna", + "yasna 0.4.0", "zeroize", ] @@ -2813,6 +2813,7 @@ dependencies = [ "lazy_static", "log", "openssl", + "p12", "prost 0.11.9", "reqwest", "resource_uri", @@ -2828,6 +2829,7 @@ dependencies = [ "tonic", "tonic-build", "uuid", + "yasna 0.5.2", "zeroize", ] @@ -3582,6 +3584,23 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "p12" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4873306de53fe82e7e484df31e1e947d61514b6ea2ed6cd7b45d63006fd9224" +dependencies = [ + "cbc", + "cipher", + "des", + "getrandom 0.2.10", + "hmac", + "lazy_static", + "rc2", + "sha1", + "yasna 0.5.2", +] + [[package]] name = "p256" version = "0.12.0" @@ -4398,6 +4417,15 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "rc2" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62c64daa8e9438b84aaae55010a93f396f8e60e3911590fcba770d04643fc1dd" +dependencies = [ + "cipher", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -5200,6 +5228,17 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + [[package]] name = "sha1collisiondetection" version = "0.2.7" @@ -6669,6 +6708,12 @@ dependencies = [ "num-bigint", ] +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" + [[package]] name = "zeroize" version = "1.6.0" diff --git a/confidential-data-hub/kms/Cargo.toml b/confidential-data-hub/kms/Cargo.toml index 899c8dc68..aa3ea99f8 100644 --- a/confidential-data-hub/kms/Cargo.toml +++ b/confidential-data-hub/kms/Cargo.toml @@ -18,6 +18,7 @@ kbs_protocol = { path = "../../attestation-agent/kbs_protocol", default-features lazy_static.workspace = true log.workspace = true openssl = { workspace = true, optional = true } +p12 = { version = "0.6.3", optional = true } prost = { workspace = true, optional = true } resource_uri = { path = "../../attestation-agent/deps/resource_uri" } sha2 = { workspace = true, optional = true } @@ -31,6 +32,7 @@ tokio = { workspace = true, features = ["fs"] } toml.workspace = true tonic = { workspace = true, optional = true } uuid = { workspace = true, features = ["serde", "v4"], optional = true } +yasna = { version = "0.5.2", optional = true } zeroize = { workspace = true, optional = true } [dev-dependencies] @@ -44,6 +46,6 @@ tonic-build.workspace = true [features] default = ["aliyun", "kbs"] -aliyun = ["chrono", "hex", "openssl", "prost", "reqwest", "sha2", "tonic"] +aliyun = ["chrono", "hex", "openssl", "p12", "prost", "reqwest", "sha2", "tonic", "yasna"] kbs = ["kbs_protocol"] sev = ["bincode", "crypto", "dep:sev", "prost", "tonic", "uuid", "zeroize"] diff --git a/confidential-data-hub/kms/src/plugins/aliyun/credential.rs b/confidential-data-hub/kms/src/plugins/aliyun/credential.rs index 57493b678..36dd90536 100644 --- a/confidential-data-hub/kms/src/plugins/aliyun/credential.rs +++ b/confidential-data-hub/kms/src/plugins/aliyun/credential.rs @@ -7,12 +7,14 @@ use anyhow::*; use base64::{engine::general_purpose::STANDARD, Engine}; +use log::debug; use openssl::{ - pkcs12::Pkcs12, pkey::{PKey, Private}, sign::Signer, }; +use p12::{CertBag, ContentInfo, MacData, SafeBagKind, PFX}; use serde::Deserialize; +use yasna::ASN1Result; #[derive(Clone, Debug)] pub(crate) struct Credential { @@ -39,13 +41,10 @@ impl Credential { let password: Password = serde_json::from_str(pswd)?; - let private_key_der = STANDARD.decode(ck.private_key_data.as_bytes())?; - let pkcs12 = Pkcs12::from_der(&private_key_der)?; - let parsed = pkcs12.parse2(&password.client_key_password)?; - let private_key = parsed - .pkey - .ok_or_else(|| anyhow!("no private key included in pkcs12"))?; + let private_key = + Self::parse_private_key(ck.private_key_data, password.client_key_password)?; + let private_key = PKey::private_key_from_der(&private_key)?; let credential = Credential { client_key_id: ck.key_id.clone(), private_key, @@ -61,4 +60,56 @@ impl Credential { Ok(format!("Bearer {}", STANDARD.encode(signature))) } + + pub(crate) fn parse_private_key(private_key_data: String, password: String) -> Result> { + let private_key_der = STANDARD.decode(private_key_data.as_bytes())?; + let pfx = yasna::parse_der(&private_key_der, |r| -> ASN1Result { + r.read_sequence(|r| { + let version = r.next().read_u8()?; + let auth_safe = ContentInfo::parse(r.next())?; + let mac_data = r.read_optional(MacData::parse).ok().flatten(); + std::result::Result::Ok(PFX { + version, + auth_safe, + mac_data, + }) + }) + })?; + + let bags = pfx.bags(&password)?; + for bag in &bags { + match &bag.bag { + SafeBagKind::Pkcs8ShroudedKeyBag(k) => { + let pass = Self::bmp_string(&password); + let private_key = k + .encryption_algorithm + .decrypt_pbe(&k.encrypted_data, &pass) + .ok_or(anyhow!("decrypt pbe failed"))?; + return Ok(private_key); + } + SafeBagKind::CertBag(e) => match e { + CertBag::X509(x) => { + debug!("parse aliyun pkcs12 credential X509: {}", hex::encode(x)) + } + CertBag::SDSI(s) => debug!("parse aliyun pkcs12 credential SDSI: {:?}", s), + }, + _ => continue, + } + } + + Err(anyhow!("no private key found!")) + } + + fn bmp_string(s: &str) -> Vec { + let utf16: Vec = s.encode_utf16().collect(); + + let mut bytes = Vec::with_capacity(utf16.len() * 2 + 2); + for c in utf16 { + bytes.push((c / 256) as u8); + bytes.push((c % 256) as u8); + } + bytes.push(0x00); + bytes.push(0x00); + bytes + } }