@@ -2,9 +2,11 @@ use crate::results::UnwrapOrSgxErrorUnexpected;
22
33use core:: mem;
44use core:: ptr:: null;
5+ use log:: * ;
56use log:: { error, info} ;
67use std:: io:: { Read , Write } ;
78use std:: path:: Path ;
9+ use std:: ptr;
810use std:: sgxfs:: SgxFile ;
911use std:: slice;
1012
@@ -71,6 +73,41 @@ pub struct FileMdPlain {
7173
7274const FILE_MD_ENCRYPTED_DATA_SIZE : usize = 3072 ;
7375const FILE_MD_ENCRYPTED_FILENAME_SIZE : usize = 260 ;
76+ const FILE_MD_ENCRYPTED_DATA_NODES : usize = 96 ;
77+
78+ #[ repr( packed) ]
79+ pub struct FileDataKeyAndMac {
80+ pub key : [ u8 ; 16 ] ,
81+ pub gmac : [ u8 ; 16 ] ,
82+ }
83+
84+ impl FileDataKeyAndMac {
85+ unsafe fn decrypt_once (
86+ & self ,
87+ p_src : * const uint8_t ,
88+ src_len : uint32_t ,
89+ p_dst : * mut uint8_t ,
90+ p_iv : & [ u8 ; 12 ] ,
91+ ) -> Result < ( ) , sgx_status_t > {
92+ let res = sgx_rijndael128GCM_decrypt (
93+ & self . key ,
94+ p_src,
95+ src_len,
96+ p_dst,
97+ p_iv. as_ptr ( ) ,
98+ 12 ,
99+ null ( ) ,
100+ 0 ,
101+ & self . gmac ,
102+ ) ;
103+
104+ if sgx_status_t:: SGX_SUCCESS != res {
105+ return Err ( res) ;
106+ }
107+
108+ Ok ( ( ) )
109+ }
110+ }
74111
75112#[ repr( packed) ]
76113pub struct FileMdEncrypted {
@@ -81,8 +118,7 @@ pub struct FileMdEncrypted {
81118 pub mc_uuid : [ u8 ; 16 ] ,
82119 pub mc_value : u32 ,
83120
84- pub mht_key : [ u8 ; 16 ] ,
85- pub mht_gmac : [ u8 ; 16 ] ,
121+ pub root_mht : FileDataKeyAndMac ,
86122
87123 pub data : [ u8 ; FILE_MD_ENCRYPTED_DATA_SIZE ] ,
88124}
@@ -94,29 +130,43 @@ pub struct FileMd {
94130 pub padding : [ u8 ; 610 ] ,
95131}
96132
133+ #[ repr( packed) ]
134+ pub struct FileMhtNode {
135+ pub data : [ FileDataKeyAndMac ; FILE_MD_ENCRYPTED_DATA_NODES ] ,
136+ pub lower_nodes : [ FileDataKeyAndMac ; 32 ] ,
137+ }
138+
97139pub fn unseal_file_from_2_17 (
98140 s_path : & str ,
99141 should_check_fname : bool ,
100142) -> Result < Vec < u8 > , sgx_status_t > {
101143 let mut file = match File :: open ( s_path) {
102144 Ok ( f) => f,
103- Err ( _) => {
104- return Err ( /*e*/ sgx_status_t:: SGX_ERROR_UNEXPECTED ) ;
145+ Err ( e) => {
146+ warn ! ( "Failed to open file: {}" , e) ;
147+ return Err ( sgx_status_t:: SGX_ERROR_UNEXPECTED ) ;
105148 }
106149 } ;
107150
108151 let mut bytes = Vec :: new ( ) ;
109- if file. read_to_end ( & mut bytes) . is_err ( ) {
110- return Err ( /*e*/ sgx_status_t:: SGX_ERROR_UNEXPECTED ) ;
152+ if let Err ( e) = file. read_to_end ( & mut bytes) {
153+ warn ! ( "Failed to read file: {}" , e) ;
154+ return Err ( sgx_status_t:: SGX_ERROR_UNEXPECTED ) ;
111155 }
112156
113157 if bytes. len ( ) < mem:: size_of :: < FileMd > ( ) {
158+ warn ! ( "file too small" ) ;
114159 return Err ( sgx_status_t:: SGX_ERROR_UNEXPECTED ) ;
115160 }
116161
117162 unsafe {
118163 let p_md = bytes. as_mut_ptr ( ) as * const FileMd ;
119164
165+ if ( * p_md) . plain . update_flag > 0 {
166+ warn ! ( "file left in recovery mode, unsupported" ) ;
167+ return Err ( sgx_status_t:: SGX_ERROR_UNEXPECTED ) ; // we don't support recovery
168+ }
169+
120170 let mut key_request = sgx_key_request_t {
121171 key_name : sgx_types:: SGX_KEYSELECT_SEAL ,
122172 key_policy : sgx_types:: SGX_KEYPOLICY_MRSIGNER ,
@@ -131,49 +181,39 @@ pub fn unseal_file_from_2_17(
131181 key_request. cpu_svn . svn = ( * p_md) . plain . cpu_svn ;
132182 key_request. key_id . id = ( * p_md) . plain . key_id ;
133183
134- let mut cur_key: sgx_key_128bit_t = sgx_key_128bit_t:: default ( ) ;
184+ let mut cur_key_mac = FileDataKeyAndMac {
185+ key : sgx_key_128bit_t:: default ( ) ,
186+ gmac : ( * p_md) . plain . meta_data_gmac ,
187+ } ;
135188
136- let mut st = sgx_get_key ( & key_request, & mut cur_key) ;
137- if sgx_status_t:: SGX_SUCCESS != st {
138- return Err ( st) ;
189+ match sgx_get_key ( & key_request, & mut cur_key_mac. key ) {
190+ sgx_status_t:: SGX_SUCCESS => { }
191+ err_code => {
192+ warn ! ( "gen key failed" ) ;
193+ return Err ( err_code) ;
194+ }
139195 }
140196
141197 let /* mut */ md_decr: FileMdEncrypted = FileMdEncrypted {
142198 clean_filename : [ 0 ; FILE_MD_ENCRYPTED_FILENAME_SIZE ] ,
143199 size : 0 ,
144200 mc_uuid : [ 0 ; 16 ] ,
145201 mc_value : 0 ,
146- mht_key : [ 0 ; 16 ] ,
147- mht_gmac : [ 0 ; 16 ] ,
148-
149- data : [ 0 ; 3072 ] ,
202+ root_mht : FileDataKeyAndMac {
203+ key : [ 0 ; 16 ] ,
204+ gmac : [ 0 ; 16 ] ,
205+ } ,
206+ data : [ 0 ; FILE_MD_ENCRYPTED_DATA_SIZE ] ,
150207 } ;
151208
152209 let p_iv: [ u8 ; 12 ] = [ 0 ; 12 ] ;
153210
154- st = sgx_rijndael128GCM_decrypt (
155- & cur_key,
211+ cur_key_mac. decrypt_once (
156212 std:: ptr:: addr_of!( ( * p_md) . encr) as * const u8 ,
157213 mem:: size_of :: < FileMdEncrypted > ( ) as u32 ,
158214 std:: ptr:: addr_of!( md_decr) as * mut uint8_t ,
159- p_iv. as_ptr ( ) as * const u8 ,
160- 12 ,
161- null ( ) ,
162- 0 ,
163- & ( * p_md) . plain . meta_data_gmac ,
164- ) ;
165-
166- if sgx_status_t:: SGX_SUCCESS != st {
167- return Err ( st) ;
168- }
169-
170- let ret_size = std:: ptr:: read_unaligned ( std:: ptr:: addr_of!( md_decr. size) ) as usize ;
171- if ret_size > FILE_MD_ENCRYPTED_DATA_SIZE {
172- return Err ( sgx_status_t:: SGX_ERROR_UNEXPECTED ) ;
173- }
174-
175- bytes. resize ( ret_size, 0 ) ;
176- bytes. copy_from_slice ( slice:: from_raw_parts ( md_decr. data . as_ptr ( ) , ret_size) ) ;
215+ & p_iv,
216+ ) ?;
177217
178218 if should_check_fname {
179219 let raw_path = s_path. as_bytes ( ) ;
@@ -204,6 +244,64 @@ pub fn unseal_file_from_2_17(
204244 return Err ( sgx_status_t:: SGX_ERROR_FILE_NAME_MISMATCH ) ;
205245 }
206246 }
247+
248+ let ret_size = std:: ptr:: read_unaligned ( std:: ptr:: addr_of!( md_decr. size) ) as usize ;
249+
250+ if ret_size <= FILE_MD_ENCRYPTED_DATA_SIZE {
251+ bytes. resize ( ret_size, 0 ) ;
252+ bytes. copy_from_slice ( slice:: from_raw_parts ( md_decr. data . as_ptr ( ) , ret_size) ) ;
253+ } else {
254+ let node_size = mem:: size_of :: < FileMd > ( ) ; // 4K
255+
256+ let num_nodes = ( ret_size - FILE_MD_ENCRYPTED_DATA_SIZE + node_size - 1 ) / node_size;
257+ if num_nodes > FILE_MD_ENCRYPTED_DATA_NODES {
258+ warn ! ( "too many nodes, indirect files not supported" ) ;
259+ return Err ( sgx_status_t:: SGX_ERROR_UNEXPECTED ) ;
260+ }
261+
262+ let size_required = mem:: size_of :: < FileMd > ( ) + node_size * ( num_nodes + 1 ) ;
263+ if bytes. len ( ) < size_required {
264+ warn ! ( "file too short" ) ;
265+ return Err ( sgx_status_t:: SGX_ERROR_UNEXPECTED ) ;
266+ }
267+
268+ let mut bytes_src = bytes;
269+ bytes = Vec :: new ( ) ;
270+ bytes. resize ( FILE_MD_ENCRYPTED_DATA_SIZE + node_size * num_nodes, 7 ) ; // allocate with padding
271+
272+ let mut offs_dst = FILE_MD_ENCRYPTED_DATA_SIZE ;
273+
274+ ptr:: copy_nonoverlapping ( md_decr. data . as_ptr ( ) , bytes. as_mut_ptr ( ) , offs_dst) ;
275+
276+ // Decode mht node
277+ let p_mht_node =
278+ bytes_src. as_mut_ptr ( ) . add ( mem:: size_of :: < FileMd > ( ) ) as * mut FileMhtNode ;
279+
280+ md_decr. root_mht . decrypt_once (
281+ p_mht_node as * const u8 ,
282+ mem:: size_of :: < FileMhtNode > ( ) as u32 ,
283+ p_mht_node as * mut uint8_t ,
284+ & p_iv,
285+ ) ?;
286+
287+ let mut offs_src = mem:: size_of :: < FileMd > ( ) + node_size;
288+
289+ for i_node in 0 ..num_nodes {
290+ let keys = & ( * p_mht_node) . data [ i_node] ;
291+
292+ keys. decrypt_once (
293+ bytes_src. as_ptr ( ) . add ( offs_src) ,
294+ node_size as u32 ,
295+ bytes. as_mut_ptr ( ) . add ( offs_dst) ,
296+ & p_iv,
297+ ) ?;
298+
299+ offs_src += node_size;
300+ offs_dst += node_size;
301+ }
302+
303+ bytes. resize ( ret_size, 0 ) ; // truncate the padding
304+ }
207305 } ;
208306
209307 Ok ( bytes)
@@ -214,26 +312,30 @@ pub fn migrate_file_from_2_17_safe(
214312 should_check_fname : bool ,
215313) -> Result < ( ) , sgx_status_t > {
216314 if Path :: new ( s_path) . exists ( ) {
217- let data = match unseal_file_from_2_17 ( s_path, should_check_fname) {
218- Ok ( x) => x,
219- Err ( e) => {
220- error ! ( "Couldn't unseal file {}, {}" , s_path, e) ;
221- return Err ( e) ;
315+ if SgxFile :: open ( s_path) . is_ok ( ) {
316+ info ! ( "File {} is already converted" , s_path) ;
317+ } else {
318+ let data = match unseal_file_from_2_17 ( s_path, should_check_fname) {
319+ Ok ( x) => x,
320+ Err ( e) => {
321+ error ! ( "Couldn't unseal file {}, {}" , s_path, e) ;
322+ return Err ( e) ;
323+ }
324+ } ;
325+
326+ let s_path_bkp = s_path. to_string ( ) + ".bkp" ;
327+ if let Err ( e) = fs:: copy ( s_path, & s_path_bkp) {
328+ error ! ( "Couldn't backup {} into {}, {}" , s_path, s_path_bkp, e) ;
329+ return Err ( sgx_status_t:: SGX_ERROR_UNEXPECTED ) ;
222330 }
223- } ;
224331
225- let s_path_bkp = s_path. to_string ( ) + ".bkp" ;
226- if let Err ( e) = fs:: copy ( s_path, & s_path_bkp) {
227- error ! ( "Couldn't backup {} into {}, {}" , s_path, s_path_bkp, e) ;
228- return Err ( sgx_status_t:: SGX_ERROR_UNEXPECTED ) ;
229- }
332+ if let Err ( e) = seal ( data. as_slice ( ) , s_path) {
333+ error ! ( "Couldn't RE-seal file {}, {}" , s_path, e) ;
334+ return Err ( e) ;
335+ }
230336
231- if let Err ( e) = seal ( data. as_slice ( ) , s_path) {
232- error ! ( "Couldn't RE-seal file {}, {}" , s_path, e) ;
233- return Err ( e) ;
337+ info ! ( "File {} successfully RE-sealed" , s_path) ;
234338 }
235-
236- info ! ( "File {} successfully RE-sealed" , s_path) ;
237339 } else {
238340 info ! ( "File {} doesn't exist, skipping" , s_path) ;
239341 }
0 commit comments