-
-
Save arkivm/b6867f77501e1647c1cad7896d65fa2a to your computer and use it in GitHub Desktop.
Get attestation report from SVSM VMPL0
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use crate::bios::SnpSecrets; | |
use crate::util::locking::SpinLock; | |
use bindings::*; | |
use core::mem::MaybeUninit; | |
use lazy_static::lazy_static; | |
lazy_static! { | |
static ref SEQ_NUM: SpinLock<u64> = SpinLock::new(0); | |
} | |
pub fn get_attestation_report() { | |
prints!("Trying to get attestation report\n"); | |
let seq_num = match SEQ_NUM.lock().checked_add(1) { | |
Some(n) => n, | |
None => 0, | |
}; | |
let mut req = unsafe { MaybeUninit::<snp_report_req>::zeroed().assume_init() }; | |
let mut msg = unsafe { MaybeUninit::<snp_guest_msg>::zeroed().assume_init() }; | |
let mut msg_resp = unsafe { MaybeUninit::<snp_guest_msg>::zeroed().assume_init() }; | |
// request for VMPL level | |
req.vmpl = 2; | |
let report_req_sz = core::mem::size_of::<snp_report_req>() as u16; | |
let mut hdr: &mut snp_guest_msg_hdr = &mut msg.hdr; | |
// Populate message headers | |
// https://www.amd.com/system/files/TechDocs/56860.pdf - Table. 97 | |
// https://github.com/AMDESE/linux/blob/3f7b2e900f5842ccc42444a5973e00d49dd8fc96/drivers/virt/coco/sevguest/sevguest.c#L287 | |
hdr.algo = aead_algo_SNP_AEAD_AES_256_GCM as u8; | |
hdr.hdr_version = MSG_HDR_VER as u8; | |
hdr.hdr_sz = core::mem::size_of::<snp_guest_msg_hdr>() as u16; | |
hdr.msg_type = msg_type_SNP_MSG_REPORT_REQ as u8; | |
hdr.msg_version = 1; | |
hdr.msg_seqno = seq_num; | |
hdr.msg_vmpck = 0; | |
hdr.msg_sz = report_req_sz; | |
unsafe { | |
let mut enc: Aes = MaybeUninit::zeroed().assume_init(); | |
let mut ret = wc_AesInit(&mut enc, core::ptr::null_mut(), INVALID_DEVID); | |
assert_eq!(ret, 0, "Aes Init failed with ret {}", ret); | |
let svsm_secrets_va = pgtable_pa_to_va(PhysAddr::new(svsm_secrets_page)); | |
let svsm_secrets: *const SnpSecrets = svsm_secrets_va.as_ptr(); | |
let _vmpck0_key = *(&(*svsm_secrets).vmpck0 as *const [u8; 32]); | |
//prints!("{:#?}\n", vmpck0_key); | |
ret = wc_AesGcmSetKey( | |
&mut enc, | |
&(*svsm_secrets).vmpck0 as *const _ as *const u8, | |
32, | |
); | |
assert_eq!(ret, 0, "AesGcmSetKey failed with ret {}", ret); | |
// 16 bytes IV | |
let mut iv = [0u64; 2]; | |
iv[0] = seq_num; | |
let mut auth_tag = [0u8; AES_BLOCK_SIZE as usize]; | |
let mut aad = [0u8; AAD_LEN as usize]; | |
// We authenticate the header from algo | |
// AMD says from 0x20 to 0x5F (https://www.amd.com/system/files/TechDocs/56860.pdf Table 97 | |
// The kernel authenticates from 0x30 to 0x5F | |
// https://github.com/AMDESE/linux/blob/3f7b2e900f5842ccc42444a5973e00d49dd8fc96/drivers/virt/coco/sevguest/sevguest.c#L203 | |
core::ptr::copy_nonoverlapping( | |
&hdr.algo as *const _ as *const u8, | |
&mut aad as *mut _ as *mut u8, | |
AAD_LEN as usize, | |
); | |
//prints!("AAD {:#?}\n", aad); | |
let ret = wc_AesGcmEncrypt( | |
&mut enc, | |
&mut msg.payload as *mut _ as *mut u8, // [out] cipher text | |
&req as *const _ as *const u8, // [in] plain text | |
report_req_sz as u32, // plain text size | |
&mut iv as *mut _ as *mut u8, // iv | |
core::mem::size_of::<[u64; 2]>() as u32, // sizeof(iv) | |
&mut auth_tag as *mut u8, // authtag | |
core::mem::size_of::<[u8; AES_BLOCK_SIZE as usize]>() as u32, // sizeof authtag | |
&mut aad as *const u8, // aad | |
core::mem::size_of::<[u8; AAD_LEN as usize]>() as u32, // sizeof(aad) | |
); | |
assert_eq!(ret, 0, "AesGcmEncrypt failed with {}", ret); | |
// copyt the authtag to header | |
core::ptr::copy_nonoverlapping( | |
&auth_tag as *const _ as *const u8, | |
&mut msg.hdr.authtag as *mut _ as *mut u8, | |
AES_BLOCK_SIZE as usize, | |
); | |
let hdr: &snp_guest_msg_hdr = &msg.hdr; | |
prints!("hdr {:#x?}\n", hdr); | |
let ghcb: *mut Ghcb = vc_get_ghcb(); | |
let req_va: VirtAddr = VirtAddr::from_ptr::<snp_guest_msg>(&msg as *const _); | |
let resp_va: VirtAddr = VirtAddr::from_ptr::<snp_guest_msg>(&msg_resp as *const _); | |
let req_pa: PhysAddr = pgtable_va_to_pa(req_va); | |
let resp_pa: PhysAddr = pgtable_va_to_pa(resp_va); | |
// From §4.1.7, https://developer.amd.com/wp-content/resources/56421.pdf | |
// make both the request and response page as shared | |
pgtable_make_pages_shared(req_va, 4096); | |
pgtable_make_pages_shared(resp_va, 4096); | |
// perform guest request 0x80000011 | |
vc_perform_vmgexit(ghcb, GHCB_GUEST_REQUEST, req_pa.as_u64(), resp_pa.as_u64()); | |
// if sw_exit_info_2 is non-zero, interpret error code from | |
// https://www.amd.com/system/files/TechDocs/56860.pdf Table 100 | |
if !(*ghcb).is_sw_exit_info_2_valid() || (*ghcb).sw_exit_info_2() != 0 { | |
let ret = (*ghcb).sw_exit_info_2(); | |
prints!("Failed! ret code {:x}\n", ret); | |
//prints!("resp {:#x?}\n", msg_resp); | |
//vc_terminate_unhandled_vc(); | |
} | |
// TODO: | |
// - Decrypt the payload | |
// - Parse the attestation report | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment