Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 44 additions & 2 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,27 @@ version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"

[[package]]
name = "aes"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66bd29a732b644c0431c6140f370d097879203d79b80c94a6747ba0872adaef8"
dependencies = [
"cipher",
"cpubits",
"cpufeatures",
]

[[package]]
name = "aes-kw"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40e4645e6ea320665abf87e13821f9a37ab204b34bcb18e34e7d1dcf2366516e"
dependencies = [
"aes",
"const-oid",
]

[[package]]
name = "aho-corasick"
version = "1.1.3"
Expand Down Expand Up @@ -730,6 +751,16 @@ dependencies = [
"half",
]

[[package]]
name = "cipher"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e34d8227fe1ba289043aeb13792056ff80fd6de1a9f49137a5f499de8e8c78ea"
dependencies = [
"crypto-common",
"inout",
]

[[package]]
name = "clap"
version = "4.5.46"
Expand Down Expand Up @@ -1039,6 +1070,7 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
name = "crypto"
version = "0.0.0"
dependencies = [
"aes-kw",
"anyhow",
"der",
"getrandom 0.4.2",
Expand Down Expand Up @@ -3653,6 +3685,15 @@ dependencies = [
"serde",
]

[[package]]
name = "inout"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7"
dependencies = [
"hybrid-array",
]

[[package]]
name = "input_core"
version = "0.0.0"
Expand Down Expand Up @@ -7701,12 +7742,12 @@ name = "test_igvm_agent_lib"
version = "0.0.0"
dependencies = [
"base64 0.22.1",
"crypto",
"get_resources",
"getrandom 0.4.2",
"inspect",
"openhcl_attestation_protocol",
"rsa",
"serde_json",
"sha2",
"thiserror 2.0.16",
"tracing",
"zerocopy",
Expand All @@ -7719,6 +7760,7 @@ dependencies = [
"cc",
"cfg-if",
"clap",
"crypto",
"get_resources",
"guid",
"parking_lot",
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,7 @@ crc32fast = { version = "1.3.2", default-features = false }
flate2 = "1.1"

# --- Cryptography & secure computing ---
aes-kw = "0.3.0"
constant_time_eq = "0.5"
der = "0.8"
getrandom = "0.4"
Expand Down
33 changes: 15 additions & 18 deletions openhcl/underhill_attestation/src/key_protector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ pub(crate) enum GetKeysFromKeyProtectorError {
#[error("failed to unwrap the ingress DEK entry with RSA-OAEP in KeyProtector")]
IngressDekRsaUnwrap(#[source] crypto::rsa::RsaError),
#[error("failed to unwrap the ingress DEK entry with AES-WRAP-WITH-PADDING in KeyProtector")]
IngressDekAesUnwrap(#[source] crypto::aes_key_wrap::AesKeyWrapError),
IngressDekAesUnwrap(#[source] crypto::aes_kwp::AesKeyWrapError),
#[error("failed to unwrap the egress DEK entry with RSA-OAEP in KeyProtector")]
EgressDekRsaUnwrap(#[source] crypto::rsa::RsaError),
#[error("failed to unwrap the egress DEK entry with AES-WRAP-WITH-PADDING in KeyProtector")]
EgressDekAesUnwrap(#[source] crypto::aes_key_wrap::AesKeyWrapError),
EgressDekAesUnwrap(#[source] crypto::aes_kwp::AesKeyWrapError),
#[error("failed to wrap the egress key with RSA-OAEP")]
EgressKeyRsaWrap(#[source] crypto::rsa::RsaError),
#[error("failed to wrap the egress key with AES-WRAP-WITH-PADDING")]
EgressKeyAesWrap(#[source] crypto::aes_key_wrap::AesKeyWrapError),
EgressKeyAesWrap(#[source] crypto::aes_kwp::AesKeyWrapError),
}

/// AES-Wrapped AES key size (32-byte with 8-byte padding)
Expand Down Expand Up @@ -163,13 +163,12 @@ impl KeyProtectorExt for KeyProtector {

// The DEK buffer should contain an AES-wrapped key.
let dek_buffer = &self.dek[ingress_idx].dek_buffer;
let aes_unwrapped_key =
crypto::aes_key_wrap::AesKeyWrap::new(&rsa_unwrapped_key)
.and_then(|kw| {
kw.unwrapper()?
.unwrap(&dek_buffer[..AES_WRAPPED_AES_KEY_LENGTH])
})
.map_err(GetKeysFromKeyProtectorError::IngressDekAesUnwrap)?;
let aes_unwrapped_key = crypto::aes_kwp::AesKeyWrap::new(&rsa_unwrapped_key)
.and_then(|kw| {
kw.unwrapper()?
.unwrap(&dek_buffer[..AES_WRAPPED_AES_KEY_LENGTH])
})
.map_err(GetKeysFromKeyProtectorError::IngressDekAesUnwrap)?;

if aes_unwrapped_key.len() != AES_GCM_KEY_LENGTH {
Err(GetKeysFromKeyProtectorError::InvalidAesUnwrapOutputSize {
Expand Down Expand Up @@ -208,7 +207,7 @@ impl KeyProtectorExt for KeyProtector {
let dek_buffer = self.dek[egress_idx].dek_buffer;
let old_egress_key = if let Some(unwrapping_key) = &des_key {
// The DEK buffer should contain an AES-wrapped key.
crypto::aes_key_wrap::AesKeyWrap::new(unwrapping_key)
crypto::aes_kwp::AesKeyWrap::new(unwrapping_key)
.and_then(|kw| {
kw.unwrapper()?
.unwrap(&dek_buffer[..AES_WRAPPED_AES_KEY_LENGTH])
Expand All @@ -235,7 +234,7 @@ impl KeyProtectorExt for KeyProtector {

let new_egress_key = if let Some(wrapping_key) = des_key {
// Create an AES wrapped key
crypto::aes_key_wrap::AesKeyWrap::new(&wrapping_key)
crypto::aes_kwp::AesKeyWrap::new(&wrapping_key)
.and_then(|kw| kw.wrapper()?.wrap(&encrypt_egress_key))
.map_err(GetKeysFromKeyProtectorError::EgressKeyAesWrap)?
} else {
Expand Down Expand Up @@ -396,8 +395,7 @@ mod tests {

// Test DEK wrapped by the test DES key (AES-256)
let des = generate_aes_256();
let result =
crypto::aes_key_wrap::AesKeyWrap::new(&des).and_then(|kw| kw.wrapper()?.wrap(&dek));
let result = crypto::aes_kwp::AesKeyWrap::new(&des).and_then(|kw| kw.wrapper()?.wrap(&dek));
assert!(result.is_ok());
let aes_wrapped_dek = result.unwrap();

Expand Down Expand Up @@ -461,7 +459,7 @@ mod tests {
assert!(result.is_ok());
let des_key = result.unwrap();

let result = crypto::aes_key_wrap::AesKeyWrap::new(&des_key).and_then(|kw| {
let result = crypto::aes_kwp::AesKeyWrap::new(&des_key).and_then(|kw| {
kw.unwrapper()?
.unwrap(&key_protector.dek[egress_index].dek_buffer[..AES_WRAPPED_AES_KEY_LENGTH])
});
Expand Down Expand Up @@ -503,7 +501,7 @@ mod tests {
assert!(result.is_ok());
let des_key = result.unwrap();

let result = crypto::aes_key_wrap::AesKeyWrap::new(&des_key).and_then(|kw| {
let result = crypto::aes_kwp::AesKeyWrap::new(&des_key).and_then(|kw| {
kw.unwrapper()?
.unwrap(&key_protector.dek[egress_index].dek_buffer[..AES_WRAPPED_AES_KEY_LENGTH])
});
Expand All @@ -522,8 +520,7 @@ mod tests {

// Test DEK wrapped by the test DES key (AES-256)
let des = generate_aes_256();
let result =
crypto::aes_key_wrap::AesKeyWrap::new(&des).and_then(|kw| kw.wrapper()?.wrap(&dek));
let result = crypto::aes_kwp::AesKeyWrap::new(&des).and_then(|kw| kw.wrapper()?.wrap(&dek));
assert!(result.is_ok());
let mut aes_wrapped_dek = result.unwrap();

Expand Down
6 changes: 3 additions & 3 deletions openhcl/underhill_attestation/src/secure_key_release.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ pub(crate) enum Pkcs11RsaAesKeyUnwrapError {
#[error("RSA unwrap failed")]
RsaUnwrap(#[source] crypto::rsa::RsaError),
#[error("AES unwrap failed")]
AesUnwrap(#[source] crypto::aes_key_wrap::AesKeyWrapError),
AesUnwrap(#[source] crypto::aes_kwp::AesKeyWrapError),
#[error("failed to parse PKCS#8 DER as RSA key")]
ParsePkcs8Der(#[source] crypto::rsa::RsaError),
}
Expand Down Expand Up @@ -94,7 +94,7 @@ fn pkcs11_rsa_aes_key_unwrap(
let unwrapped_aes_key = unwrapping_rsa_key
.oaep_decrypt(wrapped_aes_key, HashAlgorithm::Sha1)
.map_err(Pkcs11RsaAesKeyUnwrapError::RsaUnwrap)?;
let unwrapped_rsa_key = crypto::aes_key_wrap::AesKeyWrap::new(&unwrapped_aes_key)
let unwrapped_rsa_key = crypto::aes_kwp::AesKeyWrap::new(&unwrapped_aes_key)
.and_then(|kw| kw.unwrapper()?.unwrap(wrapped_rsa_key))
.map_err(Pkcs11RsaAesKeyUnwrapError::AesUnwrap)?;
let unwrapped_rsa_key = RsaKeyPair::from_pkcs8_der(&unwrapped_rsa_key)
Expand Down Expand Up @@ -421,7 +421,7 @@ mod tests {
let wrapped_aes_key = wrapping_rsa_key
.oaep_encrypt(&wrapping_aes_key, crypto::rsa::HashAlgorithm::Sha1)
.unwrap();
let wrapped_target_key = crypto::aes_key_wrap::AesKeyWrap::new(&wrapping_aes_key)
let wrapped_target_key = crypto::aes_kwp::AesKeyWrap::new(&wrapping_aes_key)
.unwrap()
.wrapper()
.unwrap()
Expand Down
3 changes: 2 additions & 1 deletion openvmm/openvmm_entry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ unicycle.workspace = true
net_tap.workspace = true

[target.'cfg(windows)'.dependencies]
crypto = { workspace = true, optional = true, features = ["rust"] }
vmswitch.workspace = true
virt_whp.workspace = true
vmbus_proxy.workspace = true
Expand All @@ -123,5 +124,5 @@ build_rs_guest_arch.workspace = true
workspace = true

[package.metadata.xtask.unused-deps]
# keep the crypto dep so we can specify the vendored feature
# keep the crypto dep so we can specify vendored and backend features
ignored = ["crypto"]
2 changes: 2 additions & 0 deletions support/crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ symcrypt = [
# Note that some of these crates have known security issues.
# This backend should not be used in production scenarios.
rust = [
"dep:aes-kw",
"dep:der",
"dep:getrandom",
"dep:pkcs1",
Expand All @@ -49,6 +50,7 @@ openssl = { workspace = true, optional = true }

symcrypt = { workspace = true, optional = true }

aes-kw = { workspace = true, optional = true }
der = { workspace = true, optional = true }
getrandom = { workspace = true, optional = true, features = ["sys_rng"] }
pkcs1 = { workspace = true, optional = true }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@

//! AES key wrap with padding (RFC 5649).

#![cfg(openssl)]
#![cfg(any(openssl, rust))]

#[cfg(openssl)]
mod ossl;
#[cfg(openssl)]
use ossl as sys;

#[cfg(rust)]
mod rust;
#[cfg(rust)]
use rust as sys;

use thiserror::Error;

/// An error for AES key wrap operations.
Expand All @@ -19,9 +24,14 @@ pub enum AesKeyWrapError {
#[error("invalid wrapping key size {0}")]
InvalidKeySize(usize),
/// A backend cryptographic error occurred.
#[cfg(not(rust))]
#[error("AES key wrap error")]
#[expect(private_interfaces)] // Will go away after refactoring this algo
#[expect(private_interfaces)]
Backend(#[source] super::BackendError),
/// A backend cryptographic error occurred.
#[cfg(rust)]
#[error("AES key wrap error during {1}: {0}")]
Backend(String, &'static str),
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note to self: hide variants

}

/// AES key wrap with padding (RFC 5649).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,29 +60,26 @@ impl AesKeyWrapInner {

impl AesKeyWrapCtxInner<'_> {
pub fn wrap(&mut self, payload: &[u8]) -> Result<Vec<u8>, AesKeyWrapError> {
let padding = 8 - payload.len() % 8;
let mut output = vec![0; payload.len() + padding + 16];
let count = self
.ctx
.cipher_update(payload, Some(&mut output))
let mut output = Vec::with_capacity(payload.len() + 16);
self.ctx
.cipher_update_vec(payload, &mut output)
.map_err(|e| err(e, "wrapping key"))?;
// DEVNOTE: Skip the `cipher_final()`, which is effectively a no-op for this operation
// according to OpenSSL implementation.
output.truncate(count);
self.ctx
.cipher_final_vec(&mut output)
.map_err(|e| err(e, "finalizing key wrap"))?;
Ok(output)
}
}

impl AesKeyUnwrapCtxInner<'_> {
pub fn unwrap(&mut self, wrapped_payload: &[u8]) -> Result<Vec<u8>, AesKeyWrapError> {
let mut output = vec![0; wrapped_payload.len() + 16];
let count = self
.ctx
.cipher_update(wrapped_payload, Some(&mut output))
let mut output = Vec::with_capacity(wrapped_payload.len() + 16);
self.ctx
.cipher_update_vec(wrapped_payload, &mut output)
.map_err(|e| err(e, "unwrapping key"))?;
// DEVNOTE: Skip the `cipher_final()`, which is effectively a no-op for this operation
// according to OpenSSL implementation.
output.truncate(count);
self.ctx
.cipher_final_vec(&mut output)
.map_err(|e| err(e, "finalizing key unwrap"))?;
Ok(output)
}
}
Loading
Loading