Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 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
4 changes: 2 additions & 2 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7701,12 +7701,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 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
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub enum AesKeyWrapError {
InvalidKeySize(usize),
/// A backend cryptographic error occurred.
#[error("AES key wrap error")]
#[expect(private_interfaces)] // Will go away after refactoring this algo
#[expect(private_interfaces)]
Backend(#[source] super::BackendError),
}

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() + 24);
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)
}
}
2 changes: 1 addition & 1 deletion support/crypto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

pub mod aes_256_cbc;
pub mod aes_256_gcm;
pub mod aes_key_wrap;
pub mod aes_kwp;
pub mod hmac_sha_256;
pub mod kdf;
pub mod pkcs7;
Expand Down
6 changes: 6 additions & 0 deletions support/crypto/src/rsa/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ impl RsaKeyPair {
pub struct RsaPublicKey(pub(crate) sys::RsaPublicKeyInner);

impl RsaPublicKey {
/// Construct an RSA public key from a big-endian modulus `n` and
/// big-endian public exponent `e`.
pub fn from_components(n: &[u8], e: &[u8]) -> Result<Self, RsaError> {
sys::RsaPublicKeyInner::from_components(n, e).map(Self)
}

/// Encrypt `input` using RSA-OAEP with the specified hash algorithm.
pub fn oaep_encrypt(
&self,
Expand Down
11 changes: 11 additions & 0 deletions support/crypto/src/rsa/ossl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,17 @@ impl RsaKeyPairInner {
pub struct RsaPublicKeyInner(pub(crate) openssl::pkey::PKey<openssl::pkey::Public>);

impl RsaPublicKeyInner {
pub fn from_components(n: &[u8], e: &[u8]) -> Result<Self, RsaError> {
let n = openssl::bn::BigNum::from_slice(n).map_err(|e| err(e, "parsing modulus"))?;
let e =
openssl::bn::BigNum::from_slice(e).map_err(|e| err(e, "parsing public exponent"))?;
let rsa = openssl::rsa::Rsa::from_public_components(n, e)
.map_err(|e| err(e, "constructing RSA public key from components"))?;
let pkey =
openssl::pkey::PKey::from_rsa(rsa).map_err(|e| err(e, "converting RSA to PKey"))?;
Ok(Self(pkey))
}

pub fn oaep_encrypt(
&self,
input: &[u8],
Expand Down
9 changes: 9 additions & 0 deletions support/crypto/src/rsa/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,15 @@ impl RsaKeyPairInner {
pub struct RsaPublicKeyInner(pub(crate) RsaPublicKey);

impl RsaPublicKeyInner {
pub fn from_components(n: &[u8], e: &[u8]) -> Result<Self, RsaError> {
let key = RsaPublicKey::new(
rsa::BoxedUint::from_be_slice_vartime(n),
rsa::BoxedUint::from_be_slice_vartime(e),
)
.map_err(|e| RsaError(e, "constructing RSA public key from components"))?;
Ok(Self(key))
}

pub fn oaep_encrypt(
&self,
input: &[u8],
Expand Down
6 changes: 6 additions & 0 deletions support/crypto/src/rsa/symcrypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ impl RsaKeyPairInner {
pub struct RsaPublicKeyInner(pub(crate) RsaKey);

impl RsaPublicKeyInner {
pub fn from_components(n: &[u8], e: &[u8]) -> Result<Self, RsaError> {
let key = RsaKey::set_public_key(n, e, RsaKeyUsage::SignAndEncrypt)
.map_err(|e| err(e, "constructing RSA public key from components"))?;
Ok(Self(key))
}

pub fn oaep_encrypt(
&self,
input: &[u8],
Expand Down
10 changes: 2 additions & 8 deletions support/crypto/src/x509/symcrypt_rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,6 @@ use der::Encode;
use rsa::sha2;
use x509_cert::Certificate;
Comment thread
smalis-msft marked this conversation as resolved.

#[cfg(symcrypt)]
fn err(err: symcrypt::errors::SymCryptError, op: &'static str) -> X509Error {
X509Error(crate::BackendError::SymCrypt(err, op))
}

#[cfg(symcrypt)]
fn der_err(err: der::Error, op: &'static str) -> X509Error {
X509Error(crate::BackendError::Der(err, op))
Expand Down Expand Up @@ -57,12 +52,11 @@ impl X509CertificateInner {
)
.map_err(|e| der_err(e, "parsing PKCS#1 RSA public key"))?;
#[cfg(symcrypt)]
let key = symcrypt::rsa::RsaKey::set_public_key(
return crate::rsa::RsaPublicKey::from_components(
key.modulus.as_bytes(),
key.public_exponent.as_bytes(),
symcrypt::rsa::RsaKeyUsage::SignAndEncrypt,
)
.map_err(|e| err(e, "constructing RSA public key"))?;
.map_err(|e| X509Error(e.0));
#[cfg(rust)]
let key = key.try_into().unwrap();
Ok(crate::rsa::RsaPublicKey(
Expand Down
4 changes: 2 additions & 2 deletions vm/devices/get/test_igvm_agent_lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ rust-version.workspace = true

[dependencies]
base64.workspace = true
crypto = { workspace = true, features = ["rust"] }
Comment thread
smalis-msft marked this conversation as resolved.
Outdated
getrandom.workspace = true
Comment thread
smalis-msft marked this conversation as resolved.
get_resources.workspace = true
inspect = { workspace = true, features = ["derive"] }
openhcl_attestation_protocol.workspace = true
rsa = { workspace = true, features = ["std", "encoding"] }
serde_json.workspace = true
sha2.workspace = true
thiserror.workspace = true
tracing.workspace = true
zerocopy.workspace = true
Expand Down
Loading
Loading