Skip to content

Commit 5ffc9b9

Browse files
committed
Attesting data
1 parent 3c3158a commit 5ffc9b9

File tree

10 files changed

+227
-14
lines changed

10 files changed

+227
-14
lines changed

Cargo.lock

Lines changed: 56 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ members = [
44
"fortanix-vme/eif-tools",
55
"fortanix-vme/fortanix-vme-abi",
66
"fortanix-vme/fortanix-vme-runner",
7+
"fortanix-vme/nsm",
78
"fortanix-vme/nitro-attestation-verify",
89
"fortanix-vme/tests/hello_world",
910
"fortanix-vme/tests/outgoing_connection",
1011
"fortanix-vme/tests/incoming_connection",
1112
"fortanix-vme/tests/iron",
13+
"fortanix-vme/tests/nsm-test",
1214
"intel-sgx/aesm-client",
1315
"intel-sgx/dcap-provider",
1416
"intel-sgx/dcap-ql-sys",
@@ -34,6 +36,7 @@ exclude = ["examples"]
3436
[patch.crates-io]
3537
libc = { git = "https://github.com/fortanix/libc.git", branch = "fortanixvme" }
3638
mbedtls = { git = "https://github.com/fortanix/rust-mbedtls", branch = "master" }
39+
nix = { git = "https://github.com/fortanix/nix.git", branch = "raoul/fortanixvme_r0.20.2" }
3740
serde = { git = "https://github.com/fortanix/serde.git", branch = "master" }
3841
vsock = { git = "https://github.com/fortanix/vsock-rs.git", branch = "fortanixvme" }
3942
rustc-serialize = { git = "https://github.com/jethrogb/rustc-serialize.git", branch = "portability" }

fortanix-vme/ci-common.sh

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -108,18 +108,20 @@ function cargo_test {
108108
scp ./test_interaction.sh ubuntu@${AWS_VM}:/home/ubuntu/ci-fortanixvme/${name}/
109109
fi
110110
fi
111-
RUST_BACKTRACE=full ${elf} -- --nocapture > ${out} 2> ${err}
111+
if [ ! -f ./skip_on_dev_platform ]; then
112+
RUST_BACKTRACE=full ${elf} -- --nocapture > ${out} 2> ${err}
112113

113-
out=$(cat ${out} | grep -v "^#" || true)
114-
expected=$(cat ./out.expected)
114+
out=$(cat ${out} | grep -v "^#" || true)
115+
expected=$(cat ./out.expected)
115116

116-
if [ "${out}" == "${expected}" ]; then
117-
echo "Test ${name}: Success"
118-
else
119-
echo "Test ${name}: Failed"
120-
echo "Got: ${out}"
121-
echo "Expected: ${expected}"
122-
exit -1
117+
if [ "${out}" == "${expected}" ]; then
118+
echo "Test ${name}: Success"
119+
else
120+
echo "Test ${name}: Failed"
121+
echo "Got: ${out}"
122+
echo "Expected: ${expected}"
123+
exit -1
124+
fi
123125
fi
124126
fi
125127

fortanix-vme/ci-fortanixvme.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ run_tests\
7070
hello_world \
7171
outgoing_connection \
7272
incoming_connection \
73-
iron
73+
iron \
74+
nsm-test
7475

7576
echo "********************************"
7677
echo "** All tests succeeded! **"

fortanix-vme/nsm/Cargo.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = "nsm"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
nitro-attestation-verify = { path = "../nitro-attestation-verify" }
10+
nsm-driver = { git = "https://github.com/aws/aws-nitro-enclaves-nsm-api" }
11+
nsm-io = { git = "https://github.com/aws/aws-nitro-enclaves-nsm-api" }
12+
serde_bytes = "0.11"

fortanix-vme/nsm/src/lib.rs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
pub use nitro_attestation_verify::{AttestationDocument, Unverified, NitroError as AttestationError};
2+
use nsm_io::{ErrorCode, Response, Request};
3+
pub use serde_bytes::ByteBuf;
4+
5+
pub struct Nsm(i32);
6+
7+
#[derive(Debug)]
8+
pub enum Error {
9+
AttestationError(AttestationError),
10+
BufferTooSmall,
11+
CannotOpenDriver,
12+
InputTooLarge,
13+
InternalError,
14+
InvalidArgument,
15+
InvalidOperation,
16+
InvalidPcrIndex,
17+
InvalidResponse,
18+
ReadOnlyPcrIndex,
19+
}
20+
21+
impl std::fmt::Display for Error {
22+
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
23+
match self {
24+
Error::AttestationError(ref msg) => write!(fmt, "Attestation error: {}", msg),
25+
Error::BufferTooSmall => write!(fmt, "Buffer too small"),
26+
Error::CannotOpenDriver => write!(fmt, "CannotOpenDriver"),
27+
Error::InputTooLarge => write!(fmt, "InputTooLarge"),
28+
Error::InternalError => write!(fmt, "InternalError"),
29+
Error::InvalidArgument => write!(fmt, "InvalidArgument"),
30+
Error::InvalidOperation => write!(fmt, "InvalidOperation"),
31+
Error::InvalidPcrIndex => write!(fmt, "InvalidPcrIndex"),
32+
Error::InvalidResponse => write!(fmt, "InvalidResponse"),
33+
Error::ReadOnlyPcrIndex => write!(fmt, "ReadOnlyPcrIndex"),
34+
}
35+
}
36+
}
37+
38+
impl std::error::Error for Error {
39+
fn description(&self) -> &str {
40+
match self {
41+
Error::AttestationError(_e) => "Attestation error",
42+
Error::BufferTooSmall => "Provided output buffer too small",
43+
Error::CannotOpenDriver => "Failed to open driver",
44+
Error::InputTooLarge => "User-provided input is too large",
45+
Error::InternalError => "NitroSecureModule cannot fulfill request due to internal error",
46+
Error::InvalidArgument => "Invalid input argument",
47+
Error::InvalidOperation => "Request cannot be fulfilled due to missing capabilities",
48+
Error::InvalidPcrIndex => "Platform Configuration Register index out of bounds",
49+
Error::InvalidResponse => "The received response does not correspond to the earlier request",
50+
Error::ReadOnlyPcrIndex => "Platform Configuration Register is in read-only mode and the operation attempted to modify it",
51+
}
52+
}
53+
}
54+
55+
impl From<AttestationError> for Error {
56+
fn from(e: AttestationError) -> Self {
57+
Error::AttestationError(e)
58+
}
59+
}
60+
61+
impl From<ErrorCode> for Error {
62+
fn from(e: ErrorCode) -> Self {
63+
match e {
64+
ErrorCode::InvalidArgument => Error::InvalidArgument,
65+
ErrorCode::InvalidIndex => Error::InvalidPcrIndex,
66+
ErrorCode::InvalidResponse => Error::InvalidResponse,
67+
ErrorCode::ReadOnlyIndex => Error::ReadOnlyPcrIndex,
68+
ErrorCode::InvalidOperation => Error::InvalidOperation,
69+
ErrorCode::BufferTooSmall => Error::BufferTooSmall,
70+
ErrorCode::InputTooLarge => Error::InputTooLarge,
71+
ErrorCode::InternalError => Error::InternalError,
72+
ErrorCode::Success => Error::InvalidResponse,
73+
}
74+
}
75+
}
76+
77+
impl Nsm {
78+
pub fn new() -> Result<Self, Error> {
79+
let fd = nsm_driver::nsm_init();
80+
81+
if fd < 0 {
82+
Err(Error::CannotOpenDriver)
83+
} else {
84+
Ok(Nsm(fd))
85+
}
86+
}
87+
88+
pub fn attest(&mut self, user_data: Option<ByteBuf>, nonce: Option<ByteBuf>, public_key: Option<ByteBuf>) -> Result<AttestationDocument<Unverified>, Error> {
89+
let req = Request::Attestation {
90+
user_data,
91+
nonce,
92+
public_key,
93+
};
94+
match nsm_driver::nsm_process_request(self.0, req) {
95+
Response::Attestation { document } => Ok(AttestationDocument::from_slice(document.as_slice())?),
96+
Response::Error(code) => Err(code.into()),
97+
_ => Err(Error::InvalidResponse),
98+
}
99+
}
100+
}
101+
102+
impl Drop for Nsm {
103+
fn drop(&mut self) {
104+
nsm_driver::nsm_exit(self.0);
105+
}
106+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[package]
2+
name = "nsm-test"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
nsm = { path = "../../nsm" }
10+
pkix = { version = "0.1" }
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Hello, world!
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Yes, this test only makes sense running as an AWS Nitro enclave
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use nsm::{ByteBuf, Nsm};
2+
3+
fn main() {
4+
let mut nsm = Nsm::new().unwrap();
5+
let user_data = ByteBuf::from(vec![0, 1, 2]);
6+
let nonce = ByteBuf::from(vec![3, 4, 5]);
7+
let pub_key = ByteBuf::from(vec![6, 7, 8]);
8+
let doc = nsm.attest(Some(user_data.clone()), Some(nonce.clone()), Some(pub_key.clone())).unwrap();
9+
println!("#module_id: {}", doc.module_id);
10+
println!("#timestamp: {}", doc.timestamp);
11+
println!("digest: {}", doc.digest);
12+
assert_eq!(doc.digest, "SHA384");
13+
for (idx, val) in doc.pcrs.iter() {
14+
println!("# pcr{} = {:?}", idx, val);
15+
}
16+
println!("#certificate: {}", pkix::pem::der_to_pem(&doc.certificate, pkix::pem::PEM_CERTIFICATE));
17+
println!("#cabundle: {:?}", doc.cabundle.iter().map(|cert| pkix::pem::der_to_pem(cert, pkix::pem::PEM_CERTIFICATE)).collect::<Vec::<String>>());
18+
println!("public_key: {:?}", pkix::pem::der_to_pem(doc.public_key.as_ref().unwrap(), pkix::pem::PEM_CERTIFICATE));
19+
assert_eq!(doc.public_key.unwrap(), pub_key);
20+
println!("user_data: {:?}", doc.user_data);
21+
assert_eq!(doc.user_data.unwrap(), user_data);
22+
println!("nonce: {:?}", doc.nonce);
23+
assert_eq!(doc.nonce.unwrap(), nonce);
24+
}

0 commit comments

Comments
 (0)