@@ -5,22 +5,21 @@ use std::path::PathBuf;
55use anyhow:: Context ;
66use clap:: Parser ;
77use log:: info;
8- use tss_esapi:: structures:: Signature ;
8+ use tss_esapi:: constants:: SessionType ;
9+ use tss_esapi:: handles:: { ObjectHandle , SessionHandle } ;
10+ use tss_esapi:: structures:: { Digest , Nonce , Signature } ;
911use tss_esapi:: traits:: UnMarshall ;
10- use tss_esapi:: tss2_esys:: * ;
12+ use tss_esapi:: tss2_esys:: TPMT_TK_AUTH ;
1113
1214use crate :: cli:: GlobalOpts ;
13- use crate :: parse:: { self , parse_context_source} ;
14- use crate :: raw_esys:: RawEsysContext ;
15+ use crate :: context:: create_context;
16+ use crate :: handle:: { ContextSource , load_object_from_source} ;
17+ use crate :: parse:: parse_context_source;
18+ use crate :: session:: load_session_from_file;
1519
16- use crate :: handle:: ContextSource ;
17-
18- /// Extend a policy with PolicySigned.
20+ /// Authorize a policy with a signed authorization.
1921///
20- /// Wraps TPM2_PolicySigned (raw FFI). PolicySigned uses no
21- /// authorization sessions because the command has no authIndex.
22- /// Instead, the TPM validates the provided signature against
23- /// authObject's public key as part of the policy assertion.
22+ /// Wraps TPM2_PolicySigned.
2423#[ derive( Parser ) ]
2524pub struct PolicySignedCmd {
2625 /// Policy session file
@@ -44,8 +43,8 @@ pub struct PolicySignedCmd {
4443 pub cphash_input : Option < PathBuf > ,
4544
4645 /// Policy reference (digest) (hex:<hex_bytes> or file:<path>)
47- #[ arg( short = 'q' , long = "qualification" , value_parser = parse:: parse_qualification) ]
48- pub qualification : Option < parse:: Qualification > ,
46+ #[ arg( short = 'q' , long = "qualification" , value_parser = crate :: parse:: parse_qualification) ]
47+ pub qualification : Option < crate :: parse:: Qualification > ,
4948
5049 /// Output file for the timeout
5150 #[ arg( short = 't' , long = "timeout" ) ]
@@ -62,160 +61,84 @@ pub struct PolicySignedCmd {
6261
6362impl PolicySignedCmd {
6463 pub fn execute ( & self , global : & GlobalOpts ) -> anyhow:: Result < ( ) > {
65- let mut raw = RawEsysContext :: new ( global. tcti . as_deref ( ) ) ?;
64+ let mut ctx = create_context ( global. tcti . as_deref ( ) ) ?;
6665
67- let session_handle = raw. context_load (
68- self . session
69- . to_str ( )
70- . ok_or_else ( || anyhow:: anyhow!( "invalid session path" ) ) ?,
71- ) ?;
66+ let session = load_session_from_file ( & mut ctx, & self . session , SessionType :: Policy ) ?;
67+ let policy_session = session
68+ . try_into ( )
69+ . map_err ( |_| anyhow:: anyhow!( "expected a policy session" ) ) ?;
7270
73- let auth_object = raw . resolve_handle_from_source ( & self . key_context ) ?;
71+ let auth_object = load_object_from_source ( & mut ctx , & self . key_context ) ?;
7472
7573 let sig_data = std:: fs:: read ( & self . signature )
7674 . with_context ( || format ! ( "reading signature from {}" , self . signature. display( ) ) ) ?;
7775 let signature = Signature :: unmarshall ( & sig_data)
7876 . map_err ( |e| anyhow:: anyhow!( "invalid signature: {e}" ) ) ?;
79- let tpmt_sig: TPMT_SIGNATURE = signature
80- . try_into ( )
81- . map_err ( |e| anyhow:: anyhow!( "signature conversion: {e:?}" ) ) ?;
82-
83- let nonce_tpm = TPM2B_NONCE :: default ( ) ;
8477
8578 let cp_hash = match & self . cphash_input {
8679 Some ( path) => {
8780 let data = std:: fs:: read ( path) ?;
88- let mut buf = TPM2B_DIGEST :: default ( ) ;
89- if data. len ( ) > buf. buffer . len ( ) {
90- anyhow:: bail!(
91- "cpHash from {} is too large: {} bytes (maximum {} bytes)" ,
92- path. display( ) ,
93- data. len( ) ,
94- buf. buffer. len( )
95- ) ;
96- }
97- buf. size = data. len ( ) as u16 ;
98- buf. buffer [ ..data. len ( ) ] . copy_from_slice ( & data) ;
99- buf
81+ Digest :: try_from ( data) . map_err ( |e| anyhow:: anyhow!( "invalid cpHash: {e}" ) ) ?
10082 }
101- None => TPM2B_DIGEST :: default ( ) ,
83+ None => Digest :: default ( ) ,
10284 } ;
10385
10486 let policy_ref = match & self . qualification {
105- Some ( q) => {
106- let data = q. as_slice ( ) ;
107- let mut buf = TPM2B_NONCE :: default ( ) ;
108- if data. len ( ) > buf. buffer . len ( ) {
109- anyhow:: bail!(
110- "qualification is too large: {} bytes (maximum {} bytes)" ,
111- data. len( ) ,
112- buf. buffer. len( )
113- ) ;
114- }
115- buf. size = data. len ( ) as u16 ;
116- buf. buffer [ ..data. len ( ) ] . copy_from_slice ( data) ;
117- buf
118- }
119- None => TPM2B_NONCE :: default ( ) ,
87+ Some ( bytes) => Nonce :: try_from ( bytes. as_slice ( ) . to_vec ( ) )
88+ . map_err ( |e| anyhow:: anyhow!( "qualifying data: {e}" ) ) ?,
89+ None => Nonce :: default ( ) ,
12090 } ;
12191
122- // Extract data from ESYS-allocated pointers immediately, then free
123- // them before performing any I/O that could fail and leak memory.
124- let ( timeout_data , ticket_data ) = unsafe {
125- let mut timeout_ptr : * mut TPM2B_TIMEOUT = std:: ptr :: null_mut ( ) ;
126- let mut ticket_ptr : * mut TPMT_TK_AUTH = std :: ptr :: null_mut ( ) ;
92+ let expiration = if self . expiration == 0 {
93+ None
94+ } else {
95+ Some ( std:: time :: Duration :: from_secs ( self . expiration as u64 ) )
96+ } ;
12797
128- // PolicySigned has Auth Index: None for both handles,
129- // so all session handles are ESYS_TR_NONE.
130- let rc = Esys_PolicySigned (
131- raw. ptr ( ) ,
98+ let ( timeout, ticket) = ctx
99+ . policy_signed (
100+ policy_session,
132101 auth_object,
133- session_handle,
134- ESYS_TR_NONE ,
135- ESYS_TR_NONE ,
136- ESYS_TR_NONE ,
137- & nonce_tpm,
138- & cp_hash,
139- & policy_ref,
140- self . expiration ,
141- & tpmt_sig,
142- & mut timeout_ptr,
143- & mut ticket_ptr,
144- ) ;
145- if rc != 0 {
146- anyhow:: bail!( "Esys_PolicySigned failed: 0x{rc:08x}" ) ;
147- }
148-
149- let timeout_data = if !timeout_ptr. is_null ( ) {
150- let t = & * timeout_ptr;
151- Some ( t. buffer [ ..t. size as usize ] . to_vec ( ) )
152- } else {
153- None
154- } ;
155-
156- let ticket_data = if !ticket_ptr. is_null ( ) {
157- let ticket = & * ticket_ptr;
158- let bytes = std:: slice:: from_raw_parts (
159- ticket as * const TPMT_TK_AUTH as * const u8 ,
160- std:: mem:: size_of :: < TPMT_TK_AUTH > ( ) ,
161- ) ;
162- Some ( bytes. to_vec ( ) )
163- } else {
164- None
165- } ;
102+ Nonce :: default ( ) , // nonce_tpm
103+ cp_hash,
104+ policy_ref,
105+ expiration,
106+ signature,
107+ )
108+ . context ( "TPM2_PolicySigned failed" ) ?;
166109
167- if !timeout_ptr. is_null ( ) {
168- Esys_Free ( timeout_ptr as * mut _ ) ;
169- }
170- if !ticket_ptr. is_null ( ) {
171- Esys_Free ( ticket_ptr as * mut _ ) ;
172- }
173-
174- ( timeout_data, ticket_data)
175- } ;
110+ info ! ( "policy signed succeeded" ) ;
176111
177- if let ( Some ( path) , Some ( data ) ) = ( & self . timeout_out , & timeout_data ) {
178- std:: fs:: write ( path, data )
112+ if let Some ( ref path) = self . timeout_out {
113+ std:: fs:: write ( path, timeout . as_bytes ( ) )
179114 . with_context ( || format ! ( "writing timeout to {}" , path. display( ) ) ) ?;
180115 }
181116
182- if let ( Some ( path) , Some ( data) ) = ( & self . ticket_out , & ticket_data) {
183- std:: fs:: write ( path, data)
117+ if let Some ( ref path) = self . ticket_out {
118+ let tss_ticket: TPMT_TK_AUTH = ticket
119+ . try_into ( )
120+ . map_err ( |e| anyhow:: anyhow!( "failed to convert ticket: {e:?}" ) ) ?;
121+ let bytes = unsafe {
122+ std:: slice:: from_raw_parts (
123+ & tss_ticket as * const TPMT_TK_AUTH as * const u8 ,
124+ std:: mem:: size_of :: < TPMT_TK_AUTH > ( ) ,
125+ )
126+ } ;
127+ std:: fs:: write ( path, bytes)
184128 . with_context ( || format ! ( "writing ticket to {}" , path. display( ) ) ) ?;
185129 }
186130
187131 if let Some ( ref path) = self . policy {
188- let digest_data = unsafe {
189- let mut digest_ptr: * mut TPM2B_DIGEST = std:: ptr:: null_mut ( ) ;
190- let rc = Esys_PolicyGetDigest (
191- raw. ptr ( ) ,
192- session_handle,
193- ESYS_TR_NONE ,
194- ESYS_TR_NONE ,
195- ESYS_TR_NONE ,
196- & mut digest_ptr,
197- ) ;
198- if rc != 0 {
199- anyhow:: bail!( "Esys_PolicyGetDigest failed: 0x{rc:08x}" ) ;
200- }
201-
202- if !digest_ptr. is_null ( ) {
203- let d = & * digest_ptr;
204- let v = d. buffer [ ..d. size as usize ] . to_vec ( ) ;
205- Esys_Free ( digest_ptr as * mut _ ) ;
206- Some ( v)
207- } else {
208- None
209- }
210- } ;
211- if let Some ( ref data) = digest_data {
212- std:: fs:: write ( path, data)
213- . with_context ( || format ! ( "writing policy digest to {}" , path. display( ) ) ) ?;
214- }
132+ let digest = ctx
133+ . policy_get_digest ( policy_session)
134+ . context ( "TPM2_PolicyGetDigest failed" ) ?;
135+ std:: fs:: write ( path, digest. as_bytes ( ) )
136+ . with_context ( || format ! ( "writing policy digest to {}" , path. display( ) ) ) ?;
215137 }
216138
217- raw. context_save_to_file ( session_handle, & self . session ) ?;
218- info ! ( "policy signed succeeded" ) ;
139+ let handle: ObjectHandle = SessionHandle :: from ( policy_session) . into ( ) ;
140+ crate :: session:: save_session_and_forget ( ctx, handle, & self . session ) ?;
141+
219142 Ok ( ( ) )
220143 }
221144}
0 commit comments