1
1
// Copyright 2020 Contributors to the Parsec project.
2
2
// SPDX-License-Identifier: Apache-2.0
3
3
4
- use std:: convert:: TryFrom ;
4
+ use std:: { convert:: TryFrom , io :: Read } ;
5
5
6
6
use crate :: {
7
7
constants:: { tss:: * , CapabilityType , PropertyTag } ,
8
8
handles:: { NvIndexHandle , NvIndexTpmHandle , TpmHandle } ,
9
9
interface_types:: resource_handles:: NvAuth ,
10
- structures:: { CapabilityData , Name , NvPublic } ,
10
+ structures:: { CapabilityData , MaxNvBuffer , Name , NvPublic } ,
11
11
Context , Error , Result , WrapperErrorKind ,
12
12
} ;
13
13
@@ -17,27 +17,19 @@ pub fn read_full(
17
17
auth_handle : NvAuth ,
18
18
nv_index_handle : NvIndexTpmHandle ,
19
19
) -> Result < Vec < u8 > > {
20
- let maxsize = context
21
- . get_tpm_property ( PropertyTag :: NvBufferMax ) ?
22
- . unwrap_or ( 512 ) as usize ;
20
+ let mut rw = NvOpenOptions :: new ( ) . open ( context, auth_handle, nv_index_handle) ?;
21
+ let mut result = Vec :: with_capacity ( rw. size ( ) ) ;
23
22
24
- let nv_idx = TpmHandle :: NvIndex ( nv_index_handle) ;
25
- let nv_idx = context. execute_without_session ( |ctx| ctx. tr_from_tpm_public ( nv_idx) ) ?;
26
- let nv_idx: NvIndexHandle = nv_idx. into ( ) ;
27
-
28
- let ( nvpub, _) = context. execute_without_session ( |ctx| ctx. nv_read_public ( nv_idx) ) ?;
29
- let nvsize = nvpub. data_size ( ) ;
30
-
31
- let mut result = Vec :: new ( ) ;
32
- result. reserve_exact ( nvsize) ;
33
-
34
- for offset in ( 0 ..nvsize) . step_by ( maxsize) {
35
- let size: u16 = std:: cmp:: min ( maxsize, nvsize - offset) as u16 ;
36
-
37
- let res = context. nv_read ( auth_handle, nv_idx, size, offset as u16 ) ?;
38
- result. extend_from_slice ( & res) ;
39
- }
40
- context. execute_without_session ( |ctx| ctx. tr_close ( & mut nv_idx. into ( ) ) ) ?;
23
+ let _ = rw. read_to_end ( & mut result) . map_err ( |e| {
24
+ // Try to convert the error back into a tss-esapi::Error if it was one originally
25
+ match e. into_inner ( ) {
26
+ None => Error :: WrapperError ( WrapperErrorKind :: InvalidParam ) ,
27
+ Some ( e) => match e. downcast :: < Error > ( ) {
28
+ Ok ( e) => * e,
29
+ Err ( _) => Error :: WrapperError ( WrapperErrorKind :: InvalidParam ) ,
30
+ } ,
31
+ }
32
+ } ) ?;
41
33
42
34
Ok ( result)
43
35
}
@@ -83,3 +75,104 @@ pub fn list(context: &mut Context) -> Result<Vec<(NvPublic, Name)>> {
83
75
} )
84
76
} )
85
77
}
78
+
79
+ /// Options and flags which can be used to determine how a non-volatile storage index is opened.
80
+ ///
81
+ /// This builder exposes the ability to determine how a [`NvReaderWriter`] is opened, and is typically used by
82
+ /// calling [`NvOpenOptions::new`], chaining method calls to set each option and then calling [`NvOpenOptions::open`].
83
+ #[ derive( Debug , Clone , Default ) ]
84
+ // The type is going to get more complex in the future
85
+ #[ allow( missing_copy_implementations) ]
86
+ pub struct NvOpenOptions { }
87
+
88
+ impl NvOpenOptions {
89
+ /// Creates a new blank set of options for opening a non-volatile storage index
90
+ ///
91
+ /// All options are initially set to `false`/`None`.
92
+ pub fn new ( ) -> Self {
93
+ Self { }
94
+ }
95
+
96
+ /// Opens a non-volatile storage index using the options specified by `self`
97
+ ///
98
+ /// The non-volatile storage index may be used for reading or writing or both.
99
+ pub fn open < ' a > (
100
+ & self ,
101
+ context : & ' a mut Context ,
102
+ auth_handle : NvAuth ,
103
+ nv_index_handle : NvIndexTpmHandle ,
104
+ ) -> Result < NvReaderWriter < ' a > > {
105
+ let buffer_size = context
106
+ . get_tpm_property ( PropertyTag :: NvBufferMax ) ?
107
+ . unwrap_or ( MaxNvBuffer :: MAX_SIZE as u32 ) as usize ;
108
+
109
+ let nv_idx = TpmHandle :: NvIndex ( nv_index_handle) ;
110
+ let nv_idx = context
111
+ . execute_without_session ( |ctx| ctx. tr_from_tpm_public ( nv_idx) ) ?
112
+ . into ( ) ;
113
+ let data_size = context
114
+ . execute_without_session ( |ctx| ctx. nv_read_public ( nv_idx) )
115
+ . map ( |( nvpub, _) | nvpub. data_size ( ) ) ?;
116
+
117
+ Ok ( NvReaderWriter {
118
+ context,
119
+ auth_handle,
120
+ buffer_size,
121
+ nv_idx,
122
+ data_size,
123
+ offset : 0 ,
124
+ } )
125
+ }
126
+ }
127
+
128
+ /// Non-volatile storage index reader/writer
129
+ ///
130
+ /// Provides methods and trait implementations to interact with a non-volatile storage index that has been opened.
131
+ ///
132
+ /// Use [`NvOpenOptions::open`] to obtain an [`NvReaderWriter`] object.
133
+ #[ derive( Debug ) ]
134
+ pub struct NvReaderWriter < ' a > {
135
+ context : & ' a mut Context ,
136
+ auth_handle : NvAuth ,
137
+
138
+ buffer_size : usize ,
139
+ nv_idx : NvIndexHandle ,
140
+ data_size : usize ,
141
+ offset : usize ,
142
+ }
143
+
144
+ impl NvReaderWriter < ' _ > {
145
+ /// The size of the data in the non-volatile storage index
146
+ pub fn size ( & self ) -> usize {
147
+ self . data_size
148
+ }
149
+ }
150
+
151
+ impl Read for NvReaderWriter < ' _ > {
152
+ fn read ( & mut self , buf : & mut [ u8 ] ) -> std:: io:: Result < usize > {
153
+ if self . data_size <= self . offset {
154
+ return Ok ( 0 ) ;
155
+ }
156
+
157
+ let desired_size = std:: cmp:: min ( buf. len ( ) , self . data_size - self . offset ) ;
158
+ let size: u16 = std:: cmp:: min ( self . buffer_size , desired_size) as u16 ;
159
+
160
+ let res = self
161
+ . context
162
+ . nv_read ( self . auth_handle , self . nv_idx , size, self . offset as u16 )
163
+ . map_err ( |e| std:: io:: Error :: new ( std:: io:: ErrorKind :: Other , e) ) ?;
164
+ buf[ 0 ..size as usize ] . copy_from_slice ( & res) ;
165
+ self . offset += size as usize ;
166
+
167
+ Ok ( size. into ( ) )
168
+ }
169
+ }
170
+
171
+ impl Drop for NvReaderWriter < ' _ > {
172
+ fn drop ( & mut self ) {
173
+ let mut obj_handle = self . nv_idx . into ( ) ;
174
+ let _ = self
175
+ . context
176
+ . execute_without_session ( |ctx| ctx. tr_close ( & mut obj_handle) ) ;
177
+ }
178
+ }
0 commit comments