-
Notifications
You must be signed in to change notification settings - Fork 32
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
Attestation report support with openssl #55
base: main
Are you sure you want to change the base?
Conversation
After updating to rustc 1.71, the SVSM build started to fail: $ rm .prereq $ make prereq $ make ... cryptlib.c:(.text.unlikely+0x8): undefined reference to `abort' assert.c:(.text+0x22): undefined reference to `abort' ... The abort function is implemented in Rust and exported for external libraries. The option "-Wl,-u,abort" prevents it from being removed from the svsm.elf. Signed-off-by: Claudio Carvalho <[email protected]>
One of the github tests is failing because it uses the system glibc to build the code. |
@tlendacky @Zildj1an we don't necessarily need to merge this PR into main. If you create a vtpm feature branch we could just merge this PR into it; @dubek could also submit his PR #44 on top of the branch. I have another patch set that adds the vtpm changes, I can submit it once this PR is merged. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just some minor tweaks from my side :)
e8ec243
to
cd01773
Compare
I moved all the openssl calls to a new crate called crypto and marked the crate to be built only when the test feature is not set. With that, all the github tests are passing (including the Tests one). I will update this PR soon. |
There is no need to use the cty package; as of Rust 1.30, the C primitive types are available in either core::ffi or alloc::ffi. The cty package and the ffi crate provide similar functionality. Signed-off-by: Claudio Carvalho <[email protected]>
This removes all the test logic in the wrappers crate and exclude it entirely from tests. The wrappers export C functions that already exist in the glibc. It should not be included in the tests. Signed-off-by: Claudio Carvalho <[email protected]>
Add bindgen to automatically produce Rust FFI (Foreign Functions Interface) bindings out of C headers to be used in other crates. This also renames the target x86_64-unknown-none as bindgen uses it to properly generate bindings. Signed-off-by: Claudio Carvalho <[email protected]>
With the attestation report support, the SnpSecrets is now accessed from multiple places. Signed-off-by: Claudio Carvalho <[email protected]>
When we request an attestation report to the PSP, the guest crashes with the following error due to stack overflow. Launching VM ... /tmp/cmdline.866937 char device redirected to /dev/pts/183 (label compat_monitor0) KVM: entry failed, hardware error 0xffffffff EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000 ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000000 EIP=00000000 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0 ES =0000 00000000 00000000 00000000 CS =0000 00000000 00000000 00000000 SS =0000 00000000 00000000 00000000 DS =0000 00000000 00000000 00000000 FS =0000 00000000 00000000 00000000 GS =0000 00000000 00000000 00000000 LDT=0000 00000000 00000000 00000000 TR =0000 00000000 00000000 00000000 GDT= 0000000000000000 00000000 IDT= 0000000000000000 00000000 CR0=80010033 CR2=0000000000000000 CR3=0000000000000000 CR4=00000668 DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 DR6=00000000ffff0ff0 DR7=0000000000000400 EFER=0000000000001d00 Code=<??> ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? Currently, the SVSM stack size is 4 pages. The same issue happens if we double the stack size. This patch increases the BSP and AP stack size to 16 pages. Signed-off-by: Claudio Carvalho <[email protected]>
Add a generic crypto API required to encrypt and decrypt SNP guest messages. This ensures that the nossl.rs stubs are compiled in when we compile the SVSM with the test feature flag set (e.g. cargo test). This is important because the test binary is meant to run standalone; so, if we try to compile any code that calls the SVSM OpenSSL, that will likely cause compilation conflicts between the libcrt headers and the system glibc. This also adds a placeholder to when the code is compiled without setting the test feature flag (e.g. cargo build). Later we can replace that to point out to a real crypto implementation. Signed-off-by: Claudio Carvalho <[email protected]>
When we compile the code without setting the test feature flag (e.g. cargo build), only the OpenSSL-based implementation is compiled in. Signed-off-by: Claudio Carvalho <[email protected]>
Each SNP guest request command has its own request and response structure definition. However, they are sent and received from the PSP wrapped in the SnpGuestRequestMsg structure. SNP guest request commands are communicated through the hypervisor, so they are expected to be encrypted with a key known only by the guest and the PSP. Signed-off-by: Claudio Carvalho <[email protected]>
This pre-allocates the required SNP_GUEST_REQUEST buffers at boot time to prevent us from having to deal with out-of-memory issues later at boot time or runtime. To send a SNP Guest Request command to the PSP, we need to provide the request and response physical addresses to the PSP; depending on the command we also need to provide the physical address of a data buffer. The size of these buffers are 1, 1 and 4 pages, and they need to be shared with the hypervisor. Access to the buffers are controled through a spinlock. Signed-off-by: Claudio Carvalho <[email protected]>
The function vc_snp_guest_request sends SNP Guest Request messages following the GHCB protocol defined in the Guest Hypervisor Communication Block (GHCB) specification. It supports sending either a extended or non-extended SNP_GUEST_REQUEST message; each one has its own VMGEXIT exit code. Signed-off-by: Claudio Carvalho <[email protected]>
As described in the SNP Firmware ABI specification, SNP_GUEST_REQUEST commands are protected using AES_GCM 256 and a VMPCK key to encrypt/decrypt the message. The firmware generates and provides the VMPCK keys to the guest in a especial secrets page that only the guest and firmware have access to, so the hypervisor cannot alter messages without detection nor read the plaintext of the message. We are limiting the send_request() implementation to encrypt/decrypt messages using the VMPCK0 key only. From guest userspace we can send SNP_GUEST_REQUEST commands using other VMPCK keys. The send_request() also supports sending extended SNP_GUEST_REQUEST commands, where the extended part of it is provided by the hypervisor. For example, in an extended attestation report the PSP firmware provides the attestation report and the hypervisor provides the certificate chain needed to verify the attestation report. If a SNP_GUEST_REQUEST fails, we disable the VMPCK0 to prevent it from being used again to send SNP_GUEST_REQUEST commands to the PSP firmware. The only two exceptions are when the hypervisor returns the error codes below: - BUSY: in this case we re-send the message and if it resturns any error code, we disable the VMPCK0. - INVALID_DATA_BUFFER_LEN: the data buffer provided in the extended SNP_GUEST_REQUEST command is too small. So, we re-send the command, but as non-extended SNP_GUEST_REQUEST in order to protect the IV (sequence number) from replay attacks. If it returns any error code, we disable the VMPCK0. The two cases above could be improved later when, for example, timer support is added to the SVSM. Signed-off-by: Claudio Carvalho <[email protected]>
The guest uses the SnpReportRequest structure to assemble an attestation report request. The PSP uses the SnpReportResponse structure to assemble an attestation report response, which contains the signed attestation report requested. Signed-off-by: Claudio Carvalho <[email protected]>
The get_report() can be used to request an attestation report to the PSP firmware. If the last parameter CertBuf is provided, the certificate chain required to verify the attestation report is saved in the CertBuf.addr provided. If get_report() fails an Err(error_code) is returned. The wrapped error_code is compliant with the Core Protocol error codes defined in the SVSM spec 0.62 (draft). The psp_rc reference provided can be used to further understand the error. Example: let buf: x86_64::addr::VirtAddr = mem::mem_allocate(0x4000).unwrap(); let mut certs: CertsBuf = CertsBuf::new(buf, 0x4000usize); let mut psp_rc: u64 = 0; let mut data: [u8; USER_DATA_SIZE] = [0u8; USER_DATA_SIZE]; data[0] = 0x31; data[1] = 0x32; data[2] = 0x33; data[4] = 0x34; // Test extended attestation report request let result: Result<psp::msg_report::SnpReportResponse, u64> = psp::request::get_report(&data, &mut psp_rc, Some(&mut certs)); if let Ok(resp) = result { prints!("INFO: Report, {} bytes, vmpl {}\n", { resp.get_report_size() }, { resp.get_report().get_vmpl() } ); prints!("INFO: report_id: {:x?}\n", { resp.get_report().get_report_id() }); prints!("INFO: report_data: {:x?}\n", { resp.get_report().get_report_data() }); let sample: *const [u8; 500] = buf.as_ptr() as *const [u8; 500]; prints!("INFO: certs sample {:x?}\n", { unsafe { *sample } }); } Signed-off-by: Claudio Carvalho <[email protected]>
Add the RUST_INSTALLER_ARGS variable to allow passing parameters to the Rust installer in the 'make prereq'. For example: $ make prereq RUST_INSTALLER_ARGS='-y' The cmdline above tells the rust installer that we want to go with the default options without any prompt. It could be useful in the github CI, where tty is not available. If RUST_INSTALLER_ARGS is not set outside the Makefile, the Rust installer is executed without any parameter. All assignments to RUST_INSTALLER_ARGS within the Makefile is ignored, unless the override directive is used. Signed-off-by: Claudio Carvalho <[email protected]>
The test.yml calls the same 'cargo test' command line as defined in the Makefile test target. This updates the test.yml to call 'make test' so that we don't need to maintain the same test in multiple places. Signed-off-by: Claudio Carvalho <[email protected]>
cd01773
to
5ea6ac4
Compare
Updated the test commit link in the PR description. |
Hi Claudio, when I try to build your pull request I'm encountering the following error:
Any idea what I'm doing wrong? Is there another step that I'm missing for building? |
I'm also facing that compilation error. Could you please tell me, @cclaudio what version of libssl-dev are you using? |
I build it on a fresh ubuntu 20.04 image without any issues. Remember to clone the submodules to build the deps. Here are the versions I have,
Can you post the complete build log? |
Thanks @arkivm, we had cloned the submodules and I saw But we should be certain that this is the problem so maybe try replicating from your end. If that turns out to be the issue, we can discuss the best solution. I don't know how hard would it be to update the code so that it works in more recent versions of OpenSSL. We could require specific versions of OpenSSL, we could use conditional compilation depending on the target (e.g. Here's the log:
|
I tried to build a version with OpenSSL v3.1.2 by applying this patch. Seem to compile fine on Ubuntu 20.04 (not run tested). diff --git a/Makefile b/Makefile
index c146791..577ff3e 100644
--- a/Makefile
+++ b/Makefile
@@ -98,7 +98,7 @@ prereq: .prereq
external/openssl/Makefile:
git submodule update --init
- (cd external/openssl && git checkout OpenSSL_1_1_1q && \
+ (cd external/openssl && git checkout openssl-3.1.2 && \
./Configure \
--config=../openssl_svsm.conf \
SVSM \ Since it refuses to find any of the imports under Could you check if you can find these symbols on for i in $(grep -A 5 "bindings" src/crypto/openssl.rs | grep "^\s\+E" | sed 's/\s\+//g' | tr -d '\n' | tr ',' '\n'); do
grep -nw "pub fn $i" bindgen_out.rs;
done script output:
|
Tom suggested to break the PR #35 into two. The first part PR #41 got merged and this is the second part.
The function
get_report()
can be called to request an attestation report; if the last parameterCertBuf
is provided, the certificate chain is stored in theCertBuf.addr
provided.Certificate chain
Make sure the certificate chain is populated in the host, otherwise
get_report()
will return an empty certificate chain. The sev-guest repository explains how to properly set the certificate chain, however, for testing purpose you can just add some random data to the certificates.How to test it
This commit can be applied to test the
get_report()
function.If you build the code with
make FEATURES=verbose
and use thelaunch-qemu.sh
script to launch the guest, you should be able to see messages like this in the console.The test basically requests two attestation reports, where the certificate chain is requested only in the first request. The first 600 bytes of the cert chain is printed.