Skip to content

Make remote_attestation crate no_std compatible #2556

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 24, 2022
Merged
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
16 changes: 2 additions & 14 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions grpc_attestation/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ oak_remote_attestation = { path = "../remote_attestation/rust/" }
oak_functions_abi = { path = "../oak_functions/abi/" }
prost = "*"
prost-types = "*"
serde = { version = "*", features = ["derive"] }
tokio = { version = "*", features = [
"fs",
"macros",
Expand Down
80 changes: 2 additions & 78 deletions oak_functions/loader/fuzz/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 7 additions & 6 deletions remote_attestation/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ authors = ["Ivan Petrov <[email protected]>"]
edition = "2021"
license = "Apache-2.0"

[features]
default = []
std = ["anyhow/std", "prost/std"]

[dependencies]
anyhow = "*"
bincode = "*"
anyhow = { version = "*", default-features = false }
bytes = { version = "*", default-features = false }
log = "*"
prost = "*"
prost = { version = "*", default-features = false, features = ["prost-derive"] }
Copy link
Contributor

Choose a reason for hiding this comment

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

Since we are not restricting versions, is it possible that the future versions of our dependencies will become std instead of no_std?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, it is possible. I am not sure whether there is a good way to detect that automatically.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Wouldn't this crate fail to compile in that case (at least with the defaul features, i.e. alloc instead of std)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

If prost removes no_std compatibility and removes the std feature so that it always pulls in std I think it will still compile. std reexports the core and alloc types, so the types will still be compatible.

Copy link
Contributor

Choose a reason for hiding this comment

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

Drive-by: the best way I've found to check no_std compatibility is to have a CI step that cross-compiles for a target with no std available.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thanks. At the moment the build requires a target OS because that is required by ring. We should be able to build it for a UEFI target once briansmith/ring#1406 has been merged.

ring = "*"
serde = { version = "*", features = ["derive"] }
serde-big-array = { version = "*", features = ["const-generics"] }
sha2 = "*"

[build-dependencies]
prost-build = "*"
Expand Down
3 changes: 1 addition & 2 deletions remote_attestation/rust/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@
// limitations under the License.
//

fn main() -> Result<(), Box<dyn std::error::Error>> {
fn main() {
prost_build::compile_protos(
&["remote_attestation/proto/remote_attestation.proto"],
&["../.."],
)
.expect("Proto compilation failed");
Ok(())
}
13 changes: 6 additions & 7 deletions remote_attestation/rust/src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,17 @@
// protocol.

use crate::message::EncryptedData;
use alloc::{format, vec, vec::Vec};
use anyhow::{anyhow, Context};
use core::convert::TryInto;
use ring::{
aead::{self, BoundKey},
agreement,
digest::{digest, SHA256},
hkdf::{Salt, HKDF_SHA256},
rand::{SecureRandom, SystemRandom},
signature::{EcdsaKeyPair, EcdsaSigningAlgorithm, EcdsaVerificationAlgorithm, KeyPair},
};
use sha2::{digest::Digest, Sha256};
Copy link
Contributor

Choose a reason for hiding this comment

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

Did sha2 require std?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No, but ring already provides the ability to generate sha256 hashes, so I removed sha2 to reduce the dependencies.

use std::convert::TryInto;

/// Length of the encryption nonce.
/// `ring::aead` uses 96-bit (12-byte) nonces.
Expand Down Expand Up @@ -339,6 +340,7 @@ pub struct Signer {

impl Signer {
pub fn create() -> anyhow::Result<Self> {
// TODO(#2557): Ensure SystemRandom work when building for x86_64 UEFI targets.
let rng = ring::rand::SystemRandom::new();
let key_pair_pkcs8 = EcdsaKeyPair::generate_pkcs8(SIGNING_ALGORITHM, &rng)
.map_err(|error| anyhow!("Couldn't generate PKCS#8 key pair: {:?}", error))?;
Expand Down Expand Up @@ -397,11 +399,8 @@ impl SignatureVerifier {

/// Computes a SHA-256 digest of `input` and returns it in a form of raw bytes.
pub fn get_sha256(input: &[u8]) -> [u8; SHA256_HASH_LENGTH] {
let mut hasher = Sha256::new();
hasher.update(&input);
hasher
.finalize()
.as_slice()
digest(&SHA256, input)
.as_ref()
.try_into()
.expect("Incorrect SHA-256 hash length")
}
Expand Down
19 changes: 11 additions & 8 deletions remote_attestation/rust/src/handshaker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use crate::{
},
proto::{AttestationInfo, AttestationReport},
};
use alloc::{boxed::Box, vec, vec::Vec};
use anyhow::{anyhow, Context};
use prost::Message;

Expand All @@ -54,8 +55,8 @@ impl Default for ClientHandshakerState {
}
}

impl std::fmt::Debug for ClientHandshakerState {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
impl core::fmt::Debug for ClientHandshakerState {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match self {
Self::Initializing => write!(f, "Initializing"),
Self::ExpectingServerIdentity(_) => write!(f, "ExpectingServerIdentity"),
Expand All @@ -81,8 +82,8 @@ impl Default for ServerHandshakerState {
}
}

impl std::fmt::Debug for ServerHandshakerState {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
impl core::fmt::Debug for ServerHandshakerState {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match self {
Self::ExpectingClientHello => write!(f, "ExpectingClientHello"),
Self::ExpectingClientIdentity(_) => write!(f, "ExpectingClientIdentity"),
Expand Down Expand Up @@ -131,7 +132,7 @@ impl ClientHandshaker {
deserialize_message(message).context("Couldn't deserialize message")?;
match deserialized_message {
MessageWrapper::ServerIdentity(server_identity) => {
match std::mem::take(&mut self.state) {
match core::mem::take(&mut self.state) {
ClientHandshakerState::ExpectingServerIdentity(key_negotiator) => {
let client_identity = self
.process_server_identity(server_identity, key_negotiator)
Expand Down Expand Up @@ -380,7 +381,7 @@ impl ServerHandshaker {
)),
},
MessageWrapper::ClientIdentity(client_identity) => {
match std::mem::take(&mut self.state) {
match core::mem::take(&mut self.state) {
ServerHandshakerState::ExpectingClientIdentity(key_negotiator) => {
self.process_client_identity(client_identity, key_negotiator)
.context("Couldn't process client identity message")?;
Expand Down Expand Up @@ -602,8 +603,8 @@ pub struct AttestationBehavior {
signer: Option<Signer>,
}

impl std::fmt::Debug for AttestationBehavior {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
impl core::fmt::Debug for AttestationBehavior {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match (
self.contains_peer_attestation(),
self.contains_self_attestation(),
Expand Down Expand Up @@ -732,6 +733,7 @@ pub fn verify_attestation_info(
expected_tee_measurement: &[u8],
) -> anyhow::Result<()> {
let attestation_info = AttestationInfo::decode(attestation_info_bytes)
.map_err(anyhow::Error::msg)
.context("Couldn't decode attestation info Protobuf message")?;

// TODO(#1867): Add remote attestation support, use real TEE reports and check that
Expand Down Expand Up @@ -760,6 +762,7 @@ pub fn serialize_protobuf<M: prost::Message>(message: &M) -> anyhow::Result<Vec<
let mut message_bytes = Vec::new();
message
.encode(&mut message_bytes)
.map_err(anyhow::Error::msg)
.context("Couldn't serialize Protobuf message to bytes")?;
Ok(message_bytes)
}
4 changes: 4 additions & 0 deletions remote_attestation/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
// limitations under the License.
//

#![no_std]

extern crate alloc;

pub mod proto {
#![allow(clippy::return_self_not_must_use)]
include!(concat!(env!("OUT_DIR"), "/oak.remote_attestation.rs"));
Expand Down
Loading