@@ -16,7 +16,7 @@ use core::panic::PanicInfo;
1616use core:: ptr:: NonNull ;
1717use svsm:: address:: { Address , PhysAddr , VirtAddr } ;
1818#[ cfg( feature = "attest" ) ]
19- use svsm:: attest:: AttestationDriver ;
19+ use svsm:: attest:: { AttestationDriver , SecretRequest } ;
2020use svsm:: boot_params:: BootParamBox ;
2121use svsm:: boot_params:: BootParams ;
2222use svsm:: console:: install_console_logger;
@@ -77,6 +77,7 @@ use svsm::virtio::probe_mmio_slots;
7777use svsm:: vtpm:: vtpm_init;
7878
7979use alloc:: string:: String ;
80+ use alloc:: vec:: Vec ;
8081use release:: COCONUT_VERSION ;
8182
8283#[ cfg( feature = "attest" ) ]
@@ -466,6 +467,133 @@ fn free_init_bsp_stack() {
466467 free_multiple_pages ( stack_base, stack_pages) ;
467468}
468469
470+ fn load_vtpm_wrapped_key ( ) -> Option < Vec < u8 > > {
471+ use alloc:: vec;
472+ use svsm:: block:: BLOCK_DEVICE ;
473+ use virtio_drivers:: device:: blk:: SECTOR_SIZE ;
474+
475+ let blk_guard = BLOCK_DEVICE . try_get_inner ( ) . ok ( ) ?;
476+ log:: info!( "SVSM: Loading wrapped KEK from block device" ) ;
477+
478+ let disk_size = blk_guard. size ( ) ;
479+ if disk_size < SECTOR_SIZE {
480+ return None ;
481+ }
482+
483+ let mut header_buf = vec ! [ 0u8 ; SECTOR_SIZE ] ;
484+ if let Err ( e) = blk_guard. read_blocks ( 0 , & mut header_buf) {
485+ log:: error!( "Failed to read header block for wrapped key: {e:?}" ) ;
486+ return None ;
487+ }
488+
489+ if & header_buf[ 0 ..8 ] != b"SVSMvTPM" {
490+ log:: info!( "SVSM: block device does not contain a valid SVSMvTPM header" ) ;
491+ return None ;
492+ }
493+
494+ // Read the wrapped key from sector 0
495+ let wrapped_key_offset = 64 ;
496+ let wrapped_key_len = 256 ;
497+ let wrapped_key = header_buf[ wrapped_key_offset..wrapped_key_offset + wrapped_key_len] . to_vec ( ) ;
498+
499+ log:: info!(
500+ "SVSM: Successfully loaded wrapped KEK from block device (len={})" ,
501+ wrapped_key. len( )
502+ ) ;
503+ Some ( wrapped_key)
504+ }
505+
506+ fn load_vtpm_state_poc ( kbs_key : & [ u8 ] ) -> Option < Vec < u8 > > {
507+ use aes_gcm:: { AeadInPlace , Aes256Gcm , KeyInit , Nonce , aead:: generic_array:: GenericArray } ;
508+ use alloc:: vec;
509+ use svsm:: block:: BLOCK_DEVICE ;
510+ use virtio_drivers:: device:: blk:: SECTOR_SIZE ;
511+
512+ let blk_guard = BLOCK_DEVICE . try_get_inner ( ) . ok ( ) ?;
513+ log:: info!( "Loading encrypted vTPM state from block device..." ) ;
514+ let disk_size = blk_guard. size ( ) ;
515+ if disk_size < SECTOR_SIZE {
516+ return None ;
517+ }
518+
519+ let mut header_buf = vec ! [ 0u8 ; SECTOR_SIZE ] ;
520+ if let Err ( e) = blk_guard. read_blocks ( 0 , & mut header_buf) {
521+ log:: error!( "Failed to read header block: {e:?}" ) ;
522+ return None ;
523+ }
524+
525+ if & header_buf[ 0 ..8 ] != b"SVSMvTPM" {
526+ log:: info!( "Block device does not contain a valid SVSMvTPM header" ) ;
527+ return None ;
528+ }
529+
530+ let version = u16:: from_le_bytes ( header_buf[ 8 ..10 ] . try_into ( ) . unwrap ( ) ) ;
531+ let cipher_id = u16:: from_le_bytes ( header_buf[ 10 ..12 ] . try_into ( ) . unwrap ( ) ) ;
532+ let payload_size = u32:: from_le_bytes ( header_buf[ 12 ..16 ] . try_into ( ) . unwrap ( ) ) as usize ;
533+
534+ let mut iv = [ 0u8 ; 12 ] ;
535+ iv. copy_from_slice ( & header_buf[ 16 ..28 ] ) ;
536+
537+ let mut tag = [ 0u8 ; 16 ] ;
538+ tag. copy_from_slice ( & header_buf[ 28 ..44 ] ) ;
539+
540+ log:: info!(
541+ "Found vTPM header: v{}, cipher={}, size={}, secretlen={}" ,
542+ version,
543+ cipher_id,
544+ payload_size,
545+ kbs_key. len( )
546+ ) ;
547+
548+ if cipher_id != 1 || kbs_key. len ( ) != 32 {
549+ log:: error!(
550+ "Unsupported cipher ID ({}) or invalid kbs key length (expected 32, got {})" ,
551+ cipher_id,
552+ kbs_key. len( )
553+ ) ;
554+ }
555+
556+ let payload_offset = 320 ; // After 64 header + 256 wrapped key
557+ let total_bytes_to_read = payload_offset + payload_size;
558+
559+ if disk_size < total_bytes_to_read {
560+ log:: error!( "Disk size smaller than declared payload" ) ;
561+ }
562+
563+ // Read the entire payload (rounding up to sector size)
564+ let total_sectors = total_bytes_to_read. div_ceil ( SECTOR_SIZE ) ;
565+ let mut disk_buf = vec ! [ 0u8 ; total_sectors * SECTOR_SIZE ] ;
566+
567+ for pos in 0 ..total_sectors {
568+ let start = pos * SECTOR_SIZE ;
569+ let end = start + SECTOR_SIZE ;
570+ if let Err ( e) = blk_guard. read_blocks ( pos, & mut disk_buf[ start..end] ) {
571+ log:: error!( "Failed to read payload block {pos}: {e:?}" ) ;
572+ return None ;
573+ }
574+ }
575+
576+ let ciphertext = & mut disk_buf[ payload_offset..payload_offset + payload_size] ;
577+ let cipher = Aes256Gcm :: new ( GenericArray :: from_slice ( kbs_key) ) ;
578+ match cipher. decrypt_in_place_detached (
579+ Nonce :: from_slice ( & iv) ,
580+ b"" ,
581+ ciphertext,
582+ GenericArray :: from_slice ( & tag) ,
583+ ) {
584+ Ok ( _) => {
585+ log:: info!( "Successfully decrypted vTPM state" ) ;
586+ let mut final_state = vec ! [ 0u8 ; payload_size] ;
587+ final_state. copy_from_slice ( ciphertext) ;
588+ Some ( final_state)
589+ }
590+ Err ( e) => {
591+ log:: error!( "Failed to decrypt vTPM state: {e:?}" ) ;
592+ None
593+ }
594+ }
595+ }
596+
469597fn svsm_init ( launch_info : & KernelLaunchInfo ) {
470598 // If required, the GDB stub can be started earlier, just after the console
471599 // is initialised in svsm_start() above.
@@ -547,16 +675,38 @@ fn svsm_init(launch_info: &KernelLaunchInfo) {
547675 initialize_virtio_mmio ( & boot_params) . expect ( "Failed to initialize virtio-mmio drivers" ) ;
548676
549677 #[ cfg( feature = "attest" ) ]
550- {
551- let mut proxy = AttestationDriver :: try_from ( Tee :: Snp ) . unwrap ( ) ;
552- let _data = proxy. attest ( ) . unwrap ( ) ;
678+ let kbs_secret = {
679+ let wrapped_key = load_vtpm_wrapped_key ( ) . expect (
680+ "SVSM: Cryptographic header or wrapped key is missing from block device! Boot aborted" ,
681+ ) ;
553682
554- // Nothing to do with data at the moment, simply print a success message.
555- log:: info!( "attestation successful" ) ;
556- }
683+ let mut proxy =
684+ AttestationDriver :: try_from ( Tee :: Snp ) . expect ( "Failed to initialize Attestation Driver" ) ;
685+
686+ log:: info!( "SVSM: Initiating HSM wrap-key attestation" ) ;
687+ let secret_request = SecretRequest :: Pkcs11Unwrap { wrapped_key } ;
688+ let decryption_key = proxy
689+ . attest ( Some ( secret_request) )
690+ . expect ( "Attestation failed: could not retrieve key from KBS HSM" ) ;
691+
692+ Some ( decryption_key)
693+ } ;
694+
695+ #[ cfg( not( feature = "attest" ) ) ]
696+ let kbs_secret: Option < Vec < u8 > > = None ;
557697
558698 #[ cfg( all( feature = "vtpm" , not( test) ) ) ]
559- vtpm_init ( None , None ) . expect ( "vTPM failed to initialize" ) ;
699+ {
700+ let mut vtpm_state: Option < Vec < u8 > > = None ;
701+
702+ #[ cfg( all( feature = "attest" , feature = "block" ) ) ]
703+ {
704+ if let Some ( secret) = & kbs_secret {
705+ vtpm_state = load_vtpm_state_poc ( secret) ;
706+ }
707+ }
708+ vtpm_init ( vtpm_state, kbs_secret. as_deref ( ) ) . expect ( "vTPM failed to initialize" ) ;
709+ }
560710
561711 #[ cfg( all( feature = "uefivars" , not( test) ) ) ]
562712 uefi_mm_protocol_init ( ) . expect ( "uefi mm protocol failed to initialize" ) ;
0 commit comments