From 4362d05346ee17d6fee8b31dc68ac74e76ff3d4b Mon Sep 17 00:00:00 2001 From: Larry Dewey Date: Fri, 2 Aug 2024 14:16:11 -0500 Subject: [PATCH] rand: Removing use of openssl rand for crypto According to the documentation, openssl's `rand_bytes(...)` function will be seeded with `/dev/urandom`, which is not sound for cryptographic application. We will be switching to using the `rdrand` crate which will utilize the X86_64 microcode call to `RDRAND`, instead. All X86_64 instructions are protected by the Guest Hypervisor Communication Block (GHCB), and may thus be presumed secure for cryptographic practices in the context of confidential compute. Signed-off-by: Larry Dewey --- Cargo.lock | 10 ++++++++++ Cargo.toml | 2 ++ src/error.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ src/session/key.rs | 18 ++++++++++++++++-- src/session/mod.rs | 39 +++++++++++++++++++++++++++++---------- 5 files changed, 103 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ee3bab6d..674c3d30 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -702,6 +702,15 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rdrand" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d92195228612ac8eed47adbc2ed0f04e513a4ccb98175b6f2bd04d963b533655" +dependencies = [ + "rand_core", +] + [[package]] name = "redox_syscall" version = "0.5.1" @@ -869,6 +878,7 @@ dependencies = [ "libc", "openssl", "p384", + "rdrand", "rsa", "serde", "serde-big-array", diff --git a/Cargo.toml b/Cargo.toml index 622ebd14..3996afda 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,7 @@ doc = false [features] default = ["sev", "snp"] +openssl = ["dep:openssl", "rdrand"] hw_tests = [] dangerous_hw_tests = ["hw_tests"] sev = [] @@ -68,6 +69,7 @@ sha2 = { version = "0.10.8", optional = true } x509-cert = { version = "0.2.5", optional = true } byteorder = "1.4.3" base64 = "0.22.1" +rdrand = { version = "^0.8", optional = true } [target.'cfg(target_os = "linux")'.dev-dependencies] kvm-ioctls = ">=0.16" diff --git a/src/error.rs b/src/error.rs index 735603d2..896b3f2d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,6 +1,8 @@ // SPDX-License-Identifier: Apache-2.0 use bincode; +#[cfg(feature = "openssl")] +use openssl::error::ErrorStack; use std::{ array::TryFromSliceError, convert::From, @@ -9,6 +11,9 @@ use std::{ io, }; +#[cfg(feature = "openssl")] +use rdrand::ErrorCode; + use std::os::raw::c_int; #[cfg(feature = "openssl")] @@ -159,6 +164,13 @@ pub enum Indeterminate { Unknown, } +impl From for Indeterminate { + /// Creates an easy + fn from(value: T) -> Self { + Self::Known(value) + } +} + #[derive(Debug)] /// Wrapper Error for Firmware or User API Errors pub enum UserApiError { @@ -1048,3 +1060,37 @@ impl std::convert::From for MeasurementError { Self::LargeArrayError(value) } } + +#[cfg(feature = "openssl")] +/// Used to describe errors related to SEV-ES "Sessions". +pub enum SessionError { + /// Errors which occur from using the rdrand crate. + RandError(ErrorCode), + + /// OpenSSL Error Stack + OpenSSLStack(ErrorStack), + + /// Errors occuring from IO operations. + IOError(std::io::Error), +} + +#[cfg(feature = "openssl")] +impl From for SessionError { + fn from(value: ErrorCode) -> Self { + Self::RandError(value) + } +} + +#[cfg(feature = "openssl")] +impl From for SessionError { + fn from(value: std::io::Error) -> Self { + Self::IOError(value) + } +} + +#[cfg(feature = "openssl")] +impl From for SessionError { + fn from(value: ErrorStack) -> Self { + Self::OpenSSLStack(value) + } +} diff --git a/src/session/key.rs b/src/session/key.rs index 3a1cf49f..d046b93e 100644 --- a/src/session/key.rs +++ b/src/session/key.rs @@ -8,6 +8,8 @@ use std::{ ptr::write_volatile, }; +use rdrand::{ErrorCode, RdRand}; + use openssl::*; #[repr(transparent)] @@ -55,9 +57,21 @@ impl Key { Key(vec![0u8; size]) } - pub fn random(size: usize) -> Result { + /// Will attempt to create a random Key derived from the CPU RDRAND instruction. + pub fn random(size: usize) -> std::result::Result { + // Create a new empty key to store the pseudo-random bytes in. let mut key = Key::zeroed(size); - rand::rand_bytes(&mut key)?; + + // Instantiate a pseudo-random number generator instance to pull + // random data from the CPU RDRAND instruction set. + let mut rng = RdRand::new()?; + + // Attempt to generate N-number of bytes specified by the `size` + // parameter, storing the bytes inside they key generated at the + // start of the method. + rng.try_fill_bytes(&mut key)?; + + // Return the key when successful. Ok(key) } } diff --git a/src/session/mod.rs b/src/session/mod.rs index 09b30885..83327d00 100644 --- a/src/session/mod.rs +++ b/src/session/mod.rs @@ -5,10 +5,14 @@ mod key; +use crate::error::SessionError; + use super::*; use std::io::{Error, ErrorKind, Result}; +use rdrand::{ErrorCode, RdRand}; + use openssl::*; /// Represents a brand-new secure channel with the AMD SP. @@ -43,9 +47,9 @@ impl launch::sev::Policy { } impl std::convert::TryFrom for Session { - type Error = std::io::Error; + type Error = ErrorCode; - fn try_from(value: launch::sev::Policy) -> Result { + fn try_from(value: launch::sev::Policy) -> std::result::Result { Ok(Self { tek: key::Key::random(16)?, tik: key::Key::random(16)?, @@ -88,7 +92,10 @@ impl Session { } /// Produces data needed to initiate the SEV launch sequence. - pub fn start(&self, chain: certs::sev::Chain) -> Result { + pub fn start( + &self, + chain: certs::sev::Chain, + ) -> std::result::Result { use certs::sev::*; let pdh = chain.verify()?; @@ -97,8 +104,11 @@ impl Session { let z = key::Key::new(prv.derive(pdh)?); let mut nonce = [0u8; 16]; let mut iv = [0u8; 16]; - rand::rand_bytes(&mut nonce)?; - rand::rand_bytes(&mut iv)?; + + let mut rng: RdRand = RdRand::new()?; + + rng.try_fill_bytes(&mut nonce)?; + rng.try_fill_bytes(&mut iv)?; Ok(launch::sev::Start { policy: self.policy, @@ -109,14 +119,20 @@ impl Session { /// Like the above start function, yet takes PDH as input instead of deriving it from a /// certificate chain. - pub fn start_pdh(&self, pdh: certs::sev::sev::Certificate) -> Result { + pub fn start_pdh( + &self, + pdh: certs::sev::sev::Certificate, + ) -> std::result::Result { let (crt, prv) = sev::Certificate::generate(sev::Usage::PDH)?; let z = key::Key::new(prv.derive(&pdh)?); let mut nonce = [0u8; 16]; let mut iv = [0u8; 16]; - rand::rand_bytes(&mut nonce)?; - rand::rand_bytes(&mut iv)?; + + let mut rng: RdRand = RdRand::new()?; + + rng.try_fill_bytes(&mut nonce)?; + rng.try_fill_bytes(&mut iv)?; Ok(launch::sev::Start { policy: self.policy, @@ -232,9 +248,12 @@ impl Session { &self, flags: launch::sev::HeaderFlags, data: &[u8], - ) -> Result { + ) -> std::result::Result { let mut iv = [0u8; 16]; - rand::rand_bytes(&mut iv)?; + + let mut rng: RdRand = RdRand::new()?; + + rng.try_fill_bytes(&mut iv)?; let ciphertext = symm::encrypt(symm::Cipher::aes_128_ctr(), &self.tek, Some(&iv), data)?;