Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
esfs.c
00001 /* 00002 * Copyright (c) 2016 ARM Limited. All rights reserved. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * Licensed under the Apache License, Version 2.0 (the License); you may 00005 * not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an AS IS BASIS, WITHOUT 00012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 00018 00019 // ----------------------------------------------------------- Includes ----------------------------------------------------------- 00020 00021 #ifdef MBED_CLOUD_CLIENT_USER_CONFIG_FILE 00022 #include MBED_CLOUD_CLIENT_USER_CONFIG_FILE 00023 #endif 00024 00025 00026 #include "pal.h" 00027 #include "esfs.h" 00028 #include "esfs_file_name.h" 00029 00030 #include "mbed-trace/mbed_trace.h" 00031 00032 00033 #include <string.h> // For memcmp and strncat 00034 00035 00036 00037 // --------------------------------------------------------- Definitions ---------------------------------------------------------- 00038 00039 00040 #define TRACE_GROUP "esfs" // Maximum 4 characters 00041 00042 // We do not really know what other uses (if any) the file system card will have. 00043 // We will assume that it may contain other files and we will keep all ESFS files in one directory. 00044 // A future enhancement could be to put files that are not to be removed at factory reset in a separate directory. 00045 #if !defined(ESFS_WORKING_DIRECTORY) 00046 #define ESFS_WORKING_DIRECTORY "WORKING" 00047 #endif 00048 00049 #if !defined(ESFS_BACKUP_DIRECTORY) 00050 #define ESFS_BACKUP_DIRECTORY "BACKUP" 00051 #endif 00052 00053 #define FACTORY_RESET_DIR "FR" 00054 #define FACTORY_RESET_FILE "fr_on" 00055 00056 // We choose a size that does not take up too much stack, but minimizes the number of reads. 00057 #define ESFS_READ_CHUNK_SIZE_IN_BYTES (64) 00058 00059 #define ESFS_BITS_IN_BYTE (8) 00060 #define ESFS_AES_BLOCK_SIZE_BYTES (16) 00061 #define ESFS_AES_IV_SIZE_BYTES (16) 00062 #define ESFS_AES_COUNTER_INDEX_IN_IV ESFS_AES_NONCE_SIZE_BYTES 00063 #define ESFS_AES_COUNTER_SIZE_BYTES (8) 00064 #define ESFS_AES_KEY_SIZE_BYTES (16) 00065 #define ESFS_AES_KEY_SIZE_BITS (ESFS_AES_KEY_SIZE_BYTES * ESFS_BITS_IN_BYTE) 00066 00067 // Defines the size in bytes of buffers for AES encryption / decryption. 00068 // In case we have to encrypt / decrypt a bigger amount of bytes, we loop over the buffer 00069 // and encrypt / decrypt up to ESFS_AES_BUF_SIZE_BYTES bytes on each step 00070 #define ESFS_AES_BUF_SIZE_BYTES (256) 00071 00072 // This should be incremented when the file format changes 00073 #define ESFS_FILE_FORMAT_VERSION (1) 00074 00075 #define ESFS_FILE_COPY_CHUNK_SIZE (256) 00076 00077 #define MAX_FULL_PATH_SIZE (PAL_MAX_FOLDER_DEPTH_CHAR + \ 00078 1 + \ 00079 PAL_MAX(sizeof(ESFS_BACKUP_DIRECTORY), sizeof(ESFS_WORKING_DIRECTORY)) + \ 00080 PAL_MAX(sizeof(FACTORY_RESET_DIR) + sizeof(FACTORY_RESET_FILE), ESFS_QUALIFIED_FILE_NAME_LENGTH)) 00081 00082 static bool esfs_initialize = false; 00083 00084 00085 00086 // -------------------------------------------------- Functions Implementation ---------------------------------------------------- 00087 00088 00089 // --------------------------------------------------------------- 00090 // Helper Functions 00091 // --------------------------------------------------------------- 00092 00093 00094 esfs_result_e esfs_init(void) 00095 { 00096 esfs_result_e result = ESFS_SUCCESS; 00097 tr_info("esfs_init - enter"); 00098 if (!esfs_initialize) 00099 { 00100 palStatus_t pal_result = PAL_SUCCESS; 00101 esfs_file_t file_handle = {0}; 00102 char dir_path[MAX_FULL_PATH_SIZE] = { 0 }; 00103 00104 pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, dir_path); 00105 if (pal_result != PAL_SUCCESS) 00106 { 00107 tr_err("esfs_init() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)pal_result); 00108 result = ESFS_ERROR; 00109 goto errorExit; 00110 } 00111 00112 strncat(dir_path, "/" ESFS_WORKING_DIRECTORY, sizeof(ESFS_WORKING_DIRECTORY)); 00113 00114 //Looping on first file system operation to work around IOTMORF-914 - sd-driver initialization 00115 for(int i=0 ; i<100; i++) 00116 { 00117 // Create the esfs subfolder working 00118 pal_result = pal_fsMkDir(dir_path); 00119 if ((pal_result == PAL_SUCCESS) || (pal_result == PAL_ERR_FS_NAME_ALREADY_EXIST)) 00120 { 00121 break; 00122 } 00123 tr_err("esfs_init() %d", i); 00124 pal_osDelay(50); 00125 00126 } 00127 00128 if ((pal_result != PAL_SUCCESS) && (pal_result != PAL_ERR_FS_NAME_ALREADY_EXIST)) 00129 { 00130 tr_err("esfs_init() - pal_fsMkDir() for working directory failed with pal_status = 0x%x", (unsigned int)pal_result); 00131 result = ESFS_ERROR; 00132 goto errorExit; 00133 } 00134 00135 pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, dir_path); 00136 if (pal_result != PAL_SUCCESS) 00137 { 00138 00139 tr_err("esfs_init() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)pal_result); 00140 result = ESFS_ERROR; 00141 goto errorExit; 00142 } 00143 00144 strncat(dir_path, "/" ESFS_BACKUP_DIRECTORY, sizeof(ESFS_BACKUP_DIRECTORY)); 00145 00146 // Create the directory ESFS_BACKUP_DIRECTORY 00147 pal_result = pal_fsMkDir(dir_path); 00148 if (pal_result != PAL_SUCCESS) 00149 { 00150 // Any error apart from file exist returns error. 00151 if (pal_result != PAL_ERR_FS_NAME_ALREADY_EXIST) 00152 { 00153 tr_err("esfs_init() - pal_fsMkDir() for backup directory failed with pal_status = 0x%x", (unsigned int)pal_result); 00154 result = ESFS_ERROR; 00155 goto errorExit; 00156 } 00157 } 00158 00159 // create the correct path for factory reset file fr_on 00160 strncat(dir_path, "/" FACTORY_RESET_DIR "/" FACTORY_RESET_FILE, sizeof(FACTORY_RESET_DIR) + sizeof(FACTORY_RESET_FILE)); 00161 pal_result = pal_fsFopen(dir_path, PAL_FS_FLAG_READONLY, &(file_handle.file)); 00162 // (res == PAL_SUCCESS) : flag file can be opened for reading --> file \FR\fr_on found 00163 // previous factory reset failed during execution 00164 // (res == PAL_ERR_FS_NO_FILE) : flag file was not found --> good scenario 00165 // (res != PAL_ERR_FS_NO_FILE) : file system problem 00166 if (pal_result == PAL_SUCCESS) 00167 { 00168 // Close the file before factory reset 00169 pal_result = pal_fsFclose(&(file_handle.file)); 00170 if (pal_result != PAL_SUCCESS) 00171 { 00172 tr_err("esfs_init() - unexpected filesystem behavior pal_fsFclose() failed with pal_status = 0x%x", (unsigned int)pal_result); 00173 result = ESFS_ERROR; 00174 goto errorExit; 00175 } 00176 // previous factory reset failed during execution - therefore we call this factory_reset again 00177 result = esfs_factory_reset(); 00178 if (result != ESFS_SUCCESS) 00179 { 00180 tr_err("esfs_init() - esfs_factory_reset() failed with esfs_result_e = 0x%x", result); 00181 result = ESFS_ERROR; 00182 goto errorExit; 00183 } 00184 } else if (pal_result != PAL_ERR_FS_NO_FILE) 00185 { 00186 tr_err("esfs_init() - unexpected filesystem behavior pal_fsFopen() failed with pal_status = 0x%x", (unsigned int)pal_result); 00187 result = ESFS_ERROR; 00188 goto errorExit; 00189 } 00190 00191 esfs_initialize = true; 00192 } 00193 return ESFS_SUCCESS; 00194 00195 errorExit: 00196 return result; 00197 00198 } 00199 00200 esfs_result_e esfs_finalize(void) 00201 { 00202 esfs_initialize = false; 00203 tr_info("esfs_finalize - enter"); 00204 return ESFS_SUCCESS; 00205 } 00206 00207 // Validate that a file handle has been initialized by create or open. 00208 // Parameters : file_handle - [IN] A pointer to a file handle for which we calculate the size. 00209 // Return : ESFS_SUCCESS on success. Error code otherwise 00210 static esfs_result_e esfs_validate(esfs_file_t *file_handle) 00211 { 00212 if(file_handle && file_handle->blob_name_length > 0) 00213 { 00214 return ESFS_SUCCESS; 00215 } 00216 else 00217 { 00218 return ESFS_ERROR; 00219 } 00220 } 00221 00222 00223 //Function : esfs_not_encrypted_file_header_size 00224 // 00225 //Description: This function returns the size in bytes of the file header without the metadata values part. 00226 // This is actually the non-encrypted part of the file header. 00227 // It is useful for calculation the file pointer position for AES encryption / decryption which starts only from the 00228 // encrypted part of the file. 00229 // 00230 //Parameters : file_handle - [IN] A pointer to a file handle for which we calculate the size. 00231 // 00232 //Return : The size in bytes of the non-encrypted part of the file header 00233 static size_t esfs_not_encrypted_file_header_size(esfs_file_t *file_handle) 00234 { 00235 esfs_tlv_properties_t *tlv_properties = &(file_handle->tlv_properties); 00236 00237 return ( file_handle->blob_name_length + // Name length field 00238 sizeof(file_handle->blob_name_length) + // Name field 00239 sizeof(uint16_t) + // Version field 00240 sizeof(uint16_t) + // Mode field 00241 (((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) ? ESFS_AES_NONCE_SIZE_BYTES : 0) + // Nonce field [non mandatory field] 00242 sizeof(tlv_properties->number_of_items) + // Metadata number of elements field 00243 (tlv_properties->number_of_items * sizeof(tlv_properties->tlv_items[0])) // Metadata tlv headers 00244 ); 00245 } 00246 00247 // Returns the size in bytes of the file header. 00248 // This can only be called after the header has been read. 00249 // Parameters : 00250 // file_handle - [IN] A pointer to a file handle for which we calculate the size. 00251 static size_t esfs_file_header_size(esfs_file_t *file_handle) 00252 { 00253 size_t metadata_size = 0; 00254 esfs_tlv_properties_t *tlv_properties = &file_handle->tlv_properties; 00255 00256 for(int i = 0; i < tlv_properties->number_of_items; i++) 00257 { 00258 metadata_size += tlv_properties->tlv_items[i].length_in_bytes; 00259 } 00260 00261 return esfs_not_encrypted_file_header_size(file_handle) + metadata_size; 00262 } 00263 00264 // Helper function to calculate the cmac on data that is written. 00265 // Parameters : 00266 // pbuf - [IN] A pointer to a buffer 00267 // num_bytes - [IN] number of bytes that we request to write. 00268 // file_handle - [IN] A pointer to a file handle for which we calculate the size. 00269 // Return : ESFS_SUCCESS on success. Error code otherwise 00270 static esfs_result_e esfs_fwrite_and_calc_cmac(const void *pbuf, size_t num_bytes, esfs_file_t *file_handle) 00271 { 00272 palStatus_t res = pal_CMACUpdate(file_handle->signature_ctx, pbuf, num_bytes); 00273 if(res != PAL_SUCCESS) 00274 { 00275 tr_err("esfs_fwrite_and_calc_cmac() - pal_CMACUpdate failed with result = 0x%x", (unsigned int)res); 00276 return ESFS_ERROR; 00277 } 00278 00279 size_t num_bytes_written; 00280 res = pal_fsFwrite(&file_handle->file, pbuf, num_bytes, &num_bytes_written); 00281 if(res != PAL_SUCCESS || num_bytes != num_bytes_written) 00282 { 00283 tr_err("esfs_fwrite_and_calc_cmac() - pal_fsFwrite failed, status = 0x%x, written bytes = %zu, expected = %zu", 00284 (unsigned int)res, num_bytes_written, num_bytes); 00285 return ESFS_ERROR; 00286 } 00287 00288 return ESFS_SUCCESS; 00289 } 00290 00291 00292 // Helper function to start a cmac run. 00293 // Moves the file position to the start of the file. 00294 // Parameters : 00295 // file_handle - [IN] A pointer to a file handle. 00296 // If successful it creates a cmac context which must be destroyed with a call to esfs_cmac_finish 00297 // Return : ESFS_SUCCESS on success. Error code otherwise. 00298 static esfs_result_e esfs_cmac_start(esfs_file_t *file_handle) 00299 { 00300 unsigned char key[ESFS_CMAC_SIZE_IN_BYTES]; 00301 00302 // Get CMAC key from PAL 00303 palStatus_t res = pal_osGetDeviceKey(palOsStorageSignatureKey128Bit , &key[0], ESFS_CMAC_SIZE_IN_BYTES); 00304 if(res != PAL_SUCCESS) 00305 { 00306 tr_err("esfs_start_cmac() - pal_osGetDeviceKey() failed with pal_status = 0x%x", (unsigned int)res); 00307 return ESFS_ERROR; 00308 } 00309 00310 // Start CMAC with the key. Initializes signature_ctx 00311 res = pal_CMACStart(&file_handle->signature_ctx, &key[0], 128, PAL_CIPHER_ID_AES); 00312 if(res != PAL_SUCCESS) 00313 { 00314 tr_err("esfs_start_cmac() - pal_CMACStart() failed with pal_status = 0x%x", (unsigned int)res); 00315 return ESFS_ERROR; 00316 } 00317 00318 // Seek to the start of the file 00319 res = pal_fsFseek(&file_handle->file, 0, PAL_FS_OFFSET_SEEKSET); 00320 if(res != PAL_SUCCESS) 00321 { 00322 tr_err("esfs_start_cmac() - pal_fsFseek() failed with pal status 0x%x", (unsigned int)res); 00323 00324 // Clean up the cmac context 00325 size_t num_bytes; 00326 // Ignore error. Sets file_handle->signature_ctx to 0 on success 00327 (void)pal_CMACFinish(&file_handle->signature_ctx, &key[0], &num_bytes); 00328 return ESFS_ERROR; 00329 } 00330 00331 return ESFS_SUCCESS; 00332 } 00333 00334 // Helper function to read and calculate the cmac on data that is read. 00335 // The function will not update the cmac if there is no CMAC context in the file handle. 00336 // Updates the file position. 00337 // Parameters : 00338 // file_handle - [IN] A pointer to a file handle for which we calculate the cmac. 00339 // pbuf - [OUT] A pointer to a buffer containing the data that is read. 00340 // num_bytes - [IN] number of bytes that we request to read. 00341 // num_bytes_read - [OUT] A pointer to a location in which will be written the number of bytes actually read. 00342 // Return : ESFS_SUCCESS on success. Error code otherwise 00343 static esfs_result_e esfs_cmac_read(esfs_file_t *file_handle, void *pbuf, size_t num_bytes, size_t *num_bytes_read) 00344 { 00345 palStatus_t res = pal_fsFread(&file_handle->file, pbuf, num_bytes, num_bytes_read); 00346 if(res != PAL_SUCCESS) 00347 { 00348 tr_err("esfs_cmac_read() - pal_fsFread failed with status = 0x%x", (unsigned int)res); 00349 return ESFS_ERROR; 00350 } 00351 00352 // Update the CMAC only if there is a context. (It is allowed to read the file without calculating CMAC if 00353 // it does not need to checked.) 00354 if(file_handle->signature_ctx) 00355 { 00356 res = pal_CMACUpdate(file_handle->signature_ctx, pbuf, *num_bytes_read); 00357 if(res != PAL_SUCCESS) 00358 { 00359 tr_err("esfs_cmac_read() - pal_CMACUpdate failed with status = 0x%x", (unsigned int)res); 00360 return ESFS_ERROR; 00361 } 00362 } 00363 00364 return ESFS_SUCCESS; 00365 } 00366 00367 00368 // Helper function to skip past a part of the file while calculating the cmac on the skipped data. 00369 // Updates the file position. 00370 // Parameters : 00371 // file_handle - [IN] A pointer to a file handle. 00372 // to - [IN] The absolute position from the start of the file to which skip. 00373 // It must be greater than the current position and no longer that the file size. 00374 // Return : ESFS_SUCCESS on success. Error code otherwise. 00375 static esfs_result_e esfs_cmac_skip_to(esfs_file_t *file_handle, int32_t to) 00376 { 00377 // Get current position 00378 int32_t current_pos; 00379 palStatus_t res = pal_fsFtell(&file_handle->file, ¤t_pos); 00380 if (res != PAL_SUCCESS) 00381 { 00382 tr_err("esfs_cmac_skip_to() - pal_fsFtell() failed with pal_status = 0x%x", (unsigned int)res); 00383 return ESFS_ERROR; 00384 } 00385 00386 // Iterate over the rest of file in chunks to calculate the cmac 00387 // buffer will contain only data read form the file 00388 for (int32_t i = to - current_pos; i > 0; i -= ESFS_READ_CHUNK_SIZE_IN_BYTES) 00389 { 00390 // Read a chunk 00391 // Here we read the file as is - plain text or encrypted 00392 uint8_t buffer[ESFS_READ_CHUNK_SIZE_IN_BYTES]; 00393 size_t num_bytes; 00394 esfs_result_e res = esfs_cmac_read(file_handle, buffer, PAL_MIN(i, ESFS_READ_CHUNK_SIZE_IN_BYTES), &num_bytes); 00395 if (res != ESFS_SUCCESS || num_bytes == 0) 00396 { 00397 tr_err("esfs_cmac_skip_to() failed num_bytes bytes = %zu", num_bytes); 00398 return ESFS_ERROR; 00399 } 00400 } 00401 return ESFS_SUCCESS; 00402 } 00403 00404 // Helper function to terminate a cmac run and return the resulting cmac. 00405 // Parameters : 00406 // file_handle - [IN] A pointer to a file handle for which we calculate the cmac. 00407 // pcmac - [OUT] A pointer to a buffer into which the cmac will be written. It must be at least ESFS_CMAC_SIZE_IN_BYTES. 00408 // Return : ESFS_SUCCESS on success. Error code otherwise 00409 static esfs_result_e esfs_cmac_finish(esfs_file_t *file_handle, unsigned char *pcmac) 00410 { 00411 size_t num_bytes; 00412 00413 // Sets file_handle->signature_ctx to 0 on success 00414 palStatus_t res = pal_CMACFinish(&file_handle->signature_ctx, pcmac, &num_bytes); 00415 if(res != PAL_SUCCESS) 00416 { 00417 tr_err("esfs_finish_cmac() - pal_CMACFinish() failed with pal_status = 0x%x", (unsigned int)res); 00418 return ESFS_ERROR; 00419 } 00420 return ESFS_SUCCESS; 00421 } 00422 00423 // Helper function to compare the passed cmac against the one in the file and to the one in the file descriptor 00424 // and then return the file position in the passed value. 00425 // Updates the file position. 00426 // Parameters : 00427 // file_handle - [IN] A pointer to a file handle for which we check the cmac. 00428 // pcmac - [IN] A pointer to a buffer containing the cmac that will be compared. It must be at least ESFS_CMAC_SIZE_IN_BYTES. 00429 // position - [IN] The absolute position from the start of the file to which we restore the file position. 00430 // Return : ESFS_SUCCESS on success. Error code otherwise. 00431 static esfs_result_e esfs_cmac_check_and_restore(esfs_file_t *file_handle, unsigned char *pcmac, int32_t position) 00432 { 00433 // Read the signature from the file 00434 unsigned char file_cmac[ESFS_CMAC_SIZE_IN_BYTES]; 00435 size_t num_bytes; 00436 palStatus_t res = pal_fsFread(&file_handle->file, &file_cmac[0], ESFS_CMAC_SIZE_IN_BYTES, &num_bytes); 00437 if (res != PAL_SUCCESS || num_bytes != ESFS_CMAC_SIZE_IN_BYTES) 00438 { 00439 tr_err("esfs_cmac_check_and_restore() - pal_fsFread() failed with pal result = 0x%x and num_bytes bytes = %zu", (unsigned int)res, num_bytes); 00440 return ESFS_ERROR; 00441 } 00442 // Compare the cmac that we read from the file with the one that is passed and check it against 00443 // the one recorded in esfs_open in order to verify that the file is the same as the one that was opened. 00444 if(memcmp(&file_cmac[0], pcmac, ESFS_CMAC_SIZE_IN_BYTES) != 0 || 00445 memcmp(&file_cmac[0], &file_handle->cmac[0], ESFS_CMAC_SIZE_IN_BYTES) != 0) 00446 { 00447 tr_err("esfs_cmac_check_and_restore() - cmac that we read from the file does not match the one that we calculated"); 00448 return ESFS_CMAC_DOES_NOT_MATCH; 00449 } 00450 00451 // Set the file position to the byte indicated by position. 00452 res = pal_fsFseek(&file_handle->file, position, PAL_FS_OFFSET_SEEKSET); 00453 if(res != PAL_SUCCESS) 00454 { 00455 tr_err("esfs_cmac_check_and_restore() - pal_fsFseek() failed with pal status 0x%x", (unsigned int)res); 00456 return ESFS_ERROR; 00457 } 00458 00459 return ESFS_SUCCESS; 00460 } 00461 00462 //Function : esfs_memcpy_reverse 00463 // 00464 //Description: This function copies the first <len_bytes> bytes from input buffer <src_ptr> to output buffer <dest_ptr> in 00465 // reversed order (e.g. '1' '2' '3' data array will be copied as '3' '2' '1'). 00466 // Note: The function assumes that the memory areas of the input buffers src_ptr and dest_ptr do not overlap. 00467 // 00468 //Parameters : dest_ptr - [IN / OUT] A pointer to the destination buffer to which bytes will be copied. 00469 // src_ptr - [IN] A pointer to the source buffer from which bytes will be copied. 00470 // len_bytes - [IN] Number of bytes to be copied. 00471 // 00472 //Return : A pointer to the output buffer <dest_ptr> 00473 static void *esfs_memcpy_reverse(void *dest_ptr, const void *src_ptr, uint32_t len_bytes) 00474 { 00475 uint8_t *tmp_dest_ptr = (uint8_t *)dest_ptr; 00476 const uint8_t *tmp_src_ptr = (const uint8_t *)src_ptr; 00477 00478 00479 // Make the reverse copy 00480 while(len_bytes > 0) 00481 { 00482 *(tmp_dest_ptr++) = *(tmp_src_ptr + len_bytes - 1); 00483 len_bytes--; 00484 } 00485 00486 return dest_ptr; 00487 } 00488 00489 //Function : esfs_calc_file_pos_for_aes 00490 // 00491 //Description: This function calculates the file position for the purpose of AES encrypt / decrypt: 00492 // The returned position is relative to the beginning of the encrypted data. 00493 // The file is encrypted starting from the meta data part (the meta data values). 00494 // 00495 //Parameters : file_handle - [IN] A pointer to a file handle on which we calculate the position. 00496 // position - [OUT] A pointer to size_t to be filled in with the returned position. 00497 // 00498 //Return : ESFS_SUCCESS on success. Error code otherwise 00499 static esfs_result_e esfs_calc_file_pos_for_aes(esfs_file_t *file_handle, size_t *position) 00500 { 00501 palStatus_t pal_status = PAL_SUCCESS; 00502 00503 size_t non_encrypt_size = 0; 00504 00505 00506 *position = 0; 00507 00508 // Get current position inside the file 00509 pal_status = pal_fsFtell( &(file_handle->file), (int32_t *)position ); 00510 00511 if(pal_status != PAL_SUCCESS) 00512 { 00513 tr_err("esfs_calc_file_pos_for_aes() - pal_fsFtell() failed with pal_status = 0x%x", (unsigned int)pal_status); 00514 return ESFS_ERROR; 00515 } 00516 00517 // Calculate non_encrypt_size to be subtracted from position 00518 non_encrypt_size = esfs_not_encrypted_file_header_size(file_handle); 00519 00520 if(*position < non_encrypt_size) 00521 { 00522 tr_err("esfs_calc_file_pos_for_aes() - Error. Position is in non encrypted part."); 00523 return ESFS_ERROR; 00524 } 00525 00526 00527 *position -= non_encrypt_size; 00528 00529 00530 return ESFS_SUCCESS; 00531 } 00532 00533 00534 //Function : esfs_set_counter_in_iv_by_file_pos 00535 // 00536 //Description: This function fills in the last 8 bytes of the IV [iv128_arr] with the counter calculated according to 00537 // the input position. 00538 // 00539 //Parameters : position - [IN] The position in the file when count starts from the encrypted data part (the meta data values). 00540 // iv128_arr - [IN/OUT] A 16 bytes buffer holding the IV. 00541 // First 8 bytes contain the NONCE, and last 8 bytes will be filled in with the counter. 00542 // 00543 //Return : ESFS_SUCCESS on success. Error code otherwise 00544 static void esfs_set_counter_in_iv_by_file_pos(size_t position, uint8_t *iv128_arr) 00545 { 00546 uint64_t counter = 0; 00547 00548 00549 // Calculate counter part of IV 00550 counter = (uint64_t)(position / ESFS_AES_BLOCK_SIZE_BYTES); 00551 00552 00553 // Copy the counter part to the IV 00554 #if BIG__ENDIAN == 1 00555 memcpy(iv128_arr + ESFS_AES_COUNTER_INDEX_IN_IV, &counter, ESFS_AES_COUNTER_SIZE_BYTES); 00556 #else 00557 esfs_memcpy_reverse(iv128_arr + ESFS_AES_COUNTER_INDEX_IN_IV, &counter, ESFS_AES_COUNTER_SIZE_BYTES); 00558 #endif 00559 } 00560 00561 00562 //Function : esfs_aes_enc_dec_by_file_pos 00563 // 00564 //Description: This function encrypts / decrypts data using AES-CTR. 00565 // This is the basic function used for AES encrypt / decrypt. 00566 // Due to the nature of AES-CTR which works on blocks, special handling is required in case the data in the file is not 00567 // on block boundaries. In this case we encrypt / decrypt this "partial block data" in a temporal buffer after copying 00568 // the data to the corresponding index inside this buffer. The rest of the data is being encrypted / decrypted normally. 00569 // 00570 //Parameters : aes_ctx - [IN] The per-initiated AES context. 00571 // buf_in - [IN] A buffer containing to data to be encrypted / decrypted. 00572 // buf_out - [OUT] A buffer to be filled in with the encrypted / decrypted data. 00573 // len_bytes - [IN] Number of bytes to encrypt / decrypt. 00574 // position - [IN] The position in the file when count starts from the encrypted data part (the meta data values). 00575 // nonce64_ptr - [IN] An 8 bytes buffer holding the NONCE part of the IV. 00576 // 00577 //Return : ESFS_SUCCESS on success. Error code otherwise 00578 static esfs_result_e esfs_aes_enc_dec_by_file_pos( palAesHandle_t aes_ctx, 00579 const uint8_t *buf_in, 00580 uint8_t *buf_out, 00581 size_t len_bytes, 00582 size_t position, 00583 uint8_t *nonce64_ptr 00584 ) 00585 { 00586 palStatus_t pal_status = PAL_SUCCESS; 00587 00588 uint8_t prev_remainder = 0; // Size in bytes of partial block PREVIOUSLY encrypted / decrypted 00589 uint8_t partial_block_size = 0; // Size in bytes of partial block for NEXT encrypt / decrypt 00590 00591 uint8_t partial_block_size_temp = 0; 00592 00593 uint8_t partial_block_in[ESFS_AES_BLOCK_SIZE_BYTES] = {0}; // Will contain data for next partial encrypt / decrypt 00594 uint8_t partial_block_out[ESFS_AES_BLOCK_SIZE_BYTES] = {0}; 00595 00596 uint8_t iv_arr[ESFS_AES_IV_SIZE_BYTES] = {0}; // Will contain nonce [bytes 0 - 7] and counter [bytes 8 - 15] 00597 00598 00599 // -------- partial_block_in: Size = block_size [16 bytes] 00600 // | 00601 // | 00602 // \|/ 00603 // 00604 // ----------------------------------------------------------------------------------------- 00605 // | | | | 00606 // | 0 ... 0 | Data copied form buf_in | 0 ... 0 | 00607 // | | | | 00608 // ----------------------------------------------------------------------------------------- 00609 // ^ ^ ^ 00610 // | | | 00611 // | | | 00612 // | | | 00613 // Size: prev_remainder | Size: might be 0 00614 // | 00615 // | 00616 // Size: partial_block_size 00617 // (might consume the buffer till its end) 00618 00619 00620 prev_remainder = (position % ESFS_AES_BLOCK_SIZE_BYTES); 00621 00622 partial_block_size_temp = ESFS_AES_BLOCK_SIZE_BYTES - prev_remainder; 00623 partial_block_size = PAL_MIN(partial_block_size_temp, len_bytes); 00624 00625 // Prepare partial_block_in: Copy data for next encrypt / decrypt from buf_in to partial_block_in 00626 memcpy(partial_block_in + prev_remainder, buf_in, partial_block_size); 00627 00628 // Prepare iv_arr: Copy nonce into bytes [0 - 7] of IV buffer 00629 memcpy(iv_arr, nonce64_ptr, ESFS_AES_NONCE_SIZE_BYTES); 00630 00631 // Prepare iv_arr: Set counter in bytes [8 - 15] of IV buffer 00632 esfs_set_counter_in_iv_by_file_pos(position, iv_arr); 00633 00634 00635 // Encrypt / decrypt partial block [run on entire block, and copy later only desired part) 00636 pal_status = pal_aesCTRWithZeroOffset(aes_ctx, partial_block_in, partial_block_out, ESFS_AES_BLOCK_SIZE_BYTES, iv_arr); 00637 00638 if(pal_status != PAL_SUCCESS) 00639 { 00640 tr_err("esfs_aes_enc_dec_by_file_pos() - pal_aesCTRWithZeroOffset() failed with pal_status = 0x%x", (unsigned int)pal_status); 00641 return ESFS_ERROR; 00642 } 00643 00644 // Copy partial_block_out to buf_out 00645 memcpy(buf_out, partial_block_out + prev_remainder, partial_block_size); 00646 00647 00648 // Encrypt / decrypt the rest of the data 00649 if(len_bytes > partial_block_size) 00650 { 00651 // Set updated counter in bytes [8 - 15] of IV buffer 00652 esfs_set_counter_in_iv_by_file_pos(position + partial_block_size, iv_arr); 00653 00654 pal_status = pal_aesCTRWithZeroOffset(aes_ctx, buf_in + partial_block_size, buf_out + partial_block_size, len_bytes - partial_block_size, iv_arr); 00655 00656 if(pal_status != PAL_SUCCESS) 00657 { 00658 tr_err("esfs_aes_enc_dec_by_file_pos() - pal_aesCTRWithZeroOffset() failed with pal_status = 0x%x", (unsigned int)pal_status); 00659 return ESFS_ERROR; 00660 } 00661 } 00662 00663 00664 return ESFS_SUCCESS; 00665 } 00666 00667 00668 //Function : esfs_read_and_decrypt 00669 // 00670 //Description: This function reads encrypted data from a file, decrypts it, and writes it into a buffer. 00671 // 00672 //Parameters : file_handle - [IN] A pointer to a file handle from which we read data. 00673 // buffer - [IN] The buffer to fill in with decrypted file data. 00674 // bytes_to_read - [IN] Number of bytes to read from the file. 00675 // read_bytes_ptr - [OUT] A pointer to size_t to be filled in with number of bytes actually read from the file. 00676 // 00677 //Return : ESFS_SUCCESS on success. Error code otherwise 00678 static esfs_result_e esfs_read_and_decrypt(esfs_file_t *file_handle, void *buffer, size_t bytes_to_read, size_t *read_bytes_ptr) 00679 { 00680 esfs_result_e result = ESFS_SUCCESS; 00681 00682 size_t position = 0; 00683 00684 00685 // Get file pointer position for AES - Must be done before calling pal_fsFread() which modifies the file pointer position 00686 result = esfs_calc_file_pos_for_aes(file_handle, &position); 00687 00688 if(result != ESFS_SUCCESS) 00689 { 00690 tr_err("esfs_read_and_decrypt() - esfs_calc_file_pos_for_aes() failed with status = 0x%x", result); 00691 return result; 00692 } 00693 00694 00695 // Read file's encrypted data into buffer 00696 result = esfs_cmac_read(file_handle, buffer, bytes_to_read, read_bytes_ptr ); 00697 00698 if((result != ESFS_SUCCESS) || (*read_bytes_ptr != bytes_to_read)) 00699 { 00700 tr_err("esfs_read_and_decrypt() - esfs_cmac_read() failed with ESFS_status = 0x%x", (unsigned int)result); 00701 return ESFS_ERROR; 00702 } 00703 00704 00705 // AES decrypt in-place - decrypt the encrypted data inside buffer, into buffer [out parameter] 00706 result = esfs_aes_enc_dec_by_file_pos(file_handle->aes_ctx, buffer, buffer, bytes_to_read, position, file_handle->nonce); 00707 00708 if(result != ESFS_SUCCESS) 00709 { 00710 tr_err("esfs_read_and_decrypt() - esfs_aes_enc_dec_by_file_pos() failed with status = 0x%x", (unsigned int)result); 00711 return result; 00712 } 00713 00714 00715 return ESFS_SUCCESS; 00716 } 00717 00718 00719 //Function : esfs_encrypt_fwrite_and_calc_cmac 00720 // 00721 //Description: This function takes a plain text buffer, encrypts it, writes the encrypted data to a file, and updates the 00722 // CMAC signature. 00723 // 00724 // Since we cannot modify the data of the input buffer (const), this operation cannot be done in-place, so we need 00725 // to use another buffer for the encryption result. In order to avoid dynamically allocation, we use a buffer 00726 // of size ESFS_AES_BUF_SIZE_BYTES statically allocated on the stack. This forces us to encrypt and write in a loop - 00727 // each iteration encrypts and writes maximum size of ESFS_AES_BUF_SIZE_BYTES bytes. 00728 // 00729 //Parameters : buffer - [IN] The buffer to encrypt and write to the file. 00730 // bytes_to_write - [IN] The number of bytes to write. 00731 // file_handle - [IN] A pointer to a file handle to which we write the data. 00732 // 00733 //Return : ESFS_SUCCESS on success. Error code otherwise 00734 static esfs_result_e esfs_encrypt_fwrite_and_calc_cmac(const void *buffer, size_t bytes_to_write, esfs_file_t *file_handle) 00735 { 00736 esfs_result_e result = ESFS_SUCCESS; 00737 00738 size_t position = 0; 00739 size_t remaining_bytes_to_write = bytes_to_write; 00740 00741 const uint8_t *buffer_tmp_ptr = (uint8_t *)buffer; // Will point to the next reading point in buffer as we read it 00742 00743 uint8_t encrypted_data[ESFS_AES_BUF_SIZE_BYTES] = {0}; // Will hold encrypted data to be written to the file 00744 00745 00746 if(buffer == NULL) 00747 { 00748 tr_err("esfs_encrypt_fwrite_and_calc_cmac() - Bad arguments error. Input buffer is NULL."); 00749 return ESFS_ERROR; 00750 } 00751 00752 00753 // Get file pointer position for AES - Must be done before calling esfs_fwrite_and_calc_cmac() which modifies the file pointer position 00754 result = esfs_calc_file_pos_for_aes(file_handle, &position); 00755 00756 if(result != ESFS_SUCCESS) 00757 { 00758 tr_err("esfs_encrypt_fwrite_and_calc_cmac() - esfs_calc_file_pos_for_aes failed with result=0x%x", result); 00759 return result; 00760 } 00761 00762 00763 // On every iteration in the loop, encrypt ESFS_AES_BUF_SIZE_BYTES bytes, and write them to the file 00764 while(remaining_bytes_to_write >= ESFS_AES_BUF_SIZE_BYTES) 00765 { 00766 // AES encrypt into encrypted_data 00767 result = esfs_aes_enc_dec_by_file_pos(file_handle->aes_ctx, buffer_tmp_ptr, encrypted_data, ESFS_AES_BUF_SIZE_BYTES, position, file_handle->nonce); 00768 00769 if(result != ESFS_SUCCESS) 00770 { 00771 tr_err("esfs_encrypt_fwrite_and_calc_cmac() - esfs_aes_enc_dec_by_file_pos failed with result=0x%x", result); 00772 return result; 00773 } 00774 00775 // Write the encrypted data to the file 00776 result = esfs_fwrite_and_calc_cmac(encrypted_data, ESFS_AES_BUF_SIZE_BYTES, file_handle); 00777 00778 if((result != ESFS_SUCCESS)) 00779 { 00780 tr_err("esfs_encrypt_fwrite_and_calc_cmac() - esfs_fwrite_and_calc_cmac() status = 0x%x", (unsigned int)result); 00781 00782 // esfs_fwrite_and_calc_cmac() failed so we cannot be sure of the state of the file - mark the file as invalid 00783 file_handle->file_invalid = 1; 00784 00785 return ESFS_ERROR; 00786 } 00787 00788 position += ESFS_AES_BUF_SIZE_BYTES; 00789 buffer_tmp_ptr += ESFS_AES_BUF_SIZE_BYTES; 00790 00791 remaining_bytes_to_write -= ESFS_AES_BUF_SIZE_BYTES; 00792 } 00793 00794 00795 // AES encrypt the leftover of buffer 00796 if(remaining_bytes_to_write > 0) 00797 { 00798 // AES encrypt into encrypted_data 00799 result = esfs_aes_enc_dec_by_file_pos(file_handle->aes_ctx, buffer_tmp_ptr, encrypted_data, remaining_bytes_to_write, position, file_handle->nonce); 00800 00801 if(result != ESFS_SUCCESS) 00802 { 00803 tr_err("esfs_encrypt_fwrite_and_calc_cmac() - esfs_aes_enc_dec_by_file_pos failed with result=0x%x", result); 00804 return result; 00805 } 00806 00807 00808 // Write the encrypted data to the file 00809 result = esfs_fwrite_and_calc_cmac(encrypted_data, remaining_bytes_to_write, file_handle); 00810 00811 if((result != ESFS_SUCCESS)) 00812 { 00813 tr_err("esfs_encrypt_fwrite_and_calc_cmac() - esfs_fwrite_and_calc_cmac() status = 0x%x", (unsigned int)result); 00814 00815 // esfs_fwrite_and_calc_cmac() failed so we cannot be sure of the state of the file - mark the file as invalid 00816 file_handle->file_invalid = 1; 00817 00818 return ESFS_ERROR; 00819 } 00820 } 00821 00822 return ESFS_SUCCESS; 00823 } 00824 00825 00826 esfs_result_e esfs_reset(void) 00827 { 00828 esfs_result_e result = ESFS_SUCCESS; 00829 palStatus_t pal_result = PAL_SUCCESS; 00830 char dir_path[MAX_FULL_PATH_SIZE] = { 0 }; 00831 tr_info("esfs_reset - enter"); 00832 pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, dir_path); 00833 if (pal_result != PAL_SUCCESS) 00834 { 00835 tr_err("esfs_reset() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)pal_result); 00836 result = ESFS_ERROR; 00837 goto errorExit; 00838 } 00839 00840 strncat(dir_path, "/" ESFS_WORKING_DIRECTORY, sizeof(ESFS_WORKING_DIRECTORY)); 00841 00842 // delete the files in working dir 00843 pal_result = pal_fsRmFiles(dir_path); 00844 // the use case is that esfs folder may not exist 00845 if ((pal_result != PAL_SUCCESS) && (pal_result != PAL_ERR_FS_NO_FILE) && (pal_result != PAL_ERR_FS_NO_PATH)) 00846 { 00847 tr_err("esfs_reset() - pal_fsRmFiles(ESFS_WORKING_DIRECTORY) failed with pal_status = 0x%x", (unsigned int)pal_result); 00848 result = ESFS_ERROR; 00849 goto errorExit; 00850 } 00851 00852 // delete working directory 00853 pal_result = pal_fsRmDir(dir_path); 00854 if (pal_result != PAL_SUCCESS) 00855 { 00856 // Any error apart from dir not exist returns error. 00857 if ((pal_result != PAL_ERR_FS_NO_FILE) && (pal_result != PAL_ERR_FS_NO_PATH)) 00858 { 00859 tr_err("esfs_reset() - pal_fsRmDir(ESFS_WORKING_DIRECTORY) failed with pal_status = 0x%x", (unsigned int)pal_result); 00860 result = ESFS_ERROR; 00861 goto errorExit; 00862 } 00863 } 00864 00865 pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, dir_path); 00866 if (pal_result != PAL_SUCCESS) 00867 { 00868 00869 tr_err("esfs_reset() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)pal_result); 00870 result = ESFS_ERROR; 00871 goto errorExit; 00872 } 00873 00874 strncat(dir_path, "/" ESFS_BACKUP_DIRECTORY, sizeof(ESFS_BACKUP_DIRECTORY)); 00875 00876 // delete the files in backup dir 00877 pal_result = pal_fsRmFiles(dir_path); 00878 // the use case is that esfs folder may not exist 00879 if ((pal_result != PAL_SUCCESS) && (pal_result != PAL_ERR_FS_NO_FILE) && (pal_result != PAL_ERR_FS_NO_PATH)) 00880 { 00881 tr_err("esfs_reset() - pal_fsRmFiles(ESFS_BACKUP_DIRECTORY) failed with pal_status = 0x%x", (unsigned int)pal_result); 00882 result = ESFS_ERROR; 00883 goto errorExit; 00884 } 00885 00886 pal_result = pal_fsRmDir(dir_path); 00887 if (pal_result != PAL_SUCCESS) 00888 { 00889 // Any error apart from dir not exist returns error. 00890 if ((pal_result != PAL_ERR_FS_NO_FILE) && (pal_result != PAL_ERR_FS_NO_PATH)) 00891 { 00892 tr_err("esfs_reset() - pal_fsRmDir(ESFS_BACKUP_DIRECTORY) failed with pal_status = 0x%x", (unsigned int)pal_result); 00893 result = ESFS_ERROR; 00894 goto errorExit; 00895 } 00896 } 00897 00898 if (esfs_finalize() != ESFS_SUCCESS) 00899 { 00900 tr_err("esfs_reset() - esfs_finalize() failed"); 00901 result = ESFS_ERROR; 00902 goto errorExit; 00903 } 00904 00905 if (esfs_init() != ESFS_SUCCESS) 00906 { 00907 tr_err("esfs_reset() - esfs_init() failed"); 00908 result = ESFS_ERROR; 00909 goto errorExit; 00910 } 00911 00912 return ESFS_SUCCESS; 00913 00914 errorExit: 00915 return result; 00916 } 00917 00918 00919 esfs_result_e esfs_factory_reset(void) { 00920 palStatus_t pal_result = PAL_SUCCESS; 00921 esfs_result_e result = ESFS_SUCCESS; 00922 esfs_file_t file_handle = { 0 }; 00923 char working_dir_path[MAX_FULL_PATH_SIZE] = { 0 }; 00924 char full_path_backup_dir[MAX_FULL_PATH_SIZE] = { 0 }; 00925 bool is_single_partition = true; 00926 00927 tr_info("esfs_factory_reset - enter"); 00928 pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, full_path_backup_dir); 00929 if (pal_result != PAL_SUCCESS) 00930 { 00931 tr_err("esfs_factory_reset() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)pal_result); 00932 return ESFS_ERROR; 00933 } 00934 00935 strncat(full_path_backup_dir, "/" ESFS_BACKUP_DIRECTORY "/" FACTORY_RESET_DIR, sizeof(ESFS_BACKUP_DIRECTORY) + sizeof(FACTORY_RESET_DIR)); 00936 // Create the factory reset subfolder - FR 00937 pal_result = pal_fsMkDir(full_path_backup_dir); 00938 if (pal_result != PAL_SUCCESS) 00939 { 00940 // Any error apart from file exist returns error. 00941 if (pal_result != PAL_ERR_FS_NAME_ALREADY_EXIST) 00942 { 00943 tr_err("esfs_factory_reset() - pal_fsMkDir(ESFS_BACKUP_DIRECTORY/FACTORY_RESET_DIR) failed with pal_status = 0x%x", (unsigned int)pal_result); 00944 result = ESFS_ERROR; 00945 goto errorExit; 00946 } 00947 } 00948 00949 strncat(full_path_backup_dir, "/" FACTORY_RESET_FILE, sizeof(FACTORY_RESET_FILE)); 00950 // Create the fr_on flag file 00951 pal_result = pal_fsFopen(full_path_backup_dir, PAL_FS_FLAG_READWRITEEXCLUSIVE, &(file_handle.file)); 00952 00953 // (res == PAL_SUCCESS) : factory reset is called on the first time 00954 // (res == PAL_ERR_FS_NAME_ALREADY_EXIST) : factory reset is called again after it was failed 00955 // on the first time and therefore the file exists 00956 if ((pal_result != PAL_SUCCESS) && (pal_result != PAL_ERR_FS_NAME_ALREADY_EXIST)) 00957 { 00958 tr_err("esfs_factory_reset() - unexpected filesystem behavior pal_fsFopen() failed with pal_status = 0x%x", (unsigned int)pal_result); 00959 result = ESFS_ERROR; 00960 goto errorExit; 00961 } 00962 00963 // close the file only if we opened it 00964 if (pal_result == PAL_SUCCESS) 00965 { 00966 pal_result = pal_fsFclose(&(file_handle.file)); 00967 if (pal_result != PAL_SUCCESS) 00968 { 00969 tr_err("esfs_factory_reset() - unexpected filesystem behavior pal_fsFclose() failed with pal_status = 0x%x", (unsigned int)pal_result); 00970 result = ESFS_ERROR; 00971 goto errorExit; 00972 } 00973 } 00974 00975 pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, working_dir_path); 00976 if (pal_result != PAL_SUCCESS) 00977 { 00978 tr_err("esfs_factory_reset() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)pal_result); 00979 result = ESFS_ERROR; 00980 goto errorExit; 00981 } 00982 00983 // Check if there is a single partition by comparing the primary and secondary mount points. 00984 // This is the only reliable way to do it, since the logic that determines the number of partitions is 00985 // hidden behind the PAL API. 00986 pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, full_path_backup_dir); 00987 if (pal_result != PAL_SUCCESS) 00988 { 00989 tr_err("esfs_factory_reset() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)pal_result); 00990 result = ESFS_ERROR; 00991 goto errorExit; 00992 } 00993 is_single_partition = (strcmp(working_dir_path,full_path_backup_dir) == 0); 00994 00995 strncat(working_dir_path, "/" ESFS_WORKING_DIRECTORY, sizeof(ESFS_WORKING_DIRECTORY)); 00996 00997 // We can only format the working folder if it is dedicated for exclusive use of esfs and 00998 // it is not the only partition that exists. The assumption here is that if it is the only partition, 00999 // then the backup folder is also on that partition. In that case, formatting would remove the backup partition, 01000 // which we do not want to do! 01001 if (pal_fsIsPrivatePartition(PAL_FS_PARTITION_PRIMARY) && !is_single_partition) 01002 { 01003 pal_result = pal_fsFormat(PAL_FS_PARTITION_PRIMARY); 01004 if (pal_result != PAL_SUCCESS) 01005 { 01006 tr_err("esfs_factory_reset() - pal_fsFormat() for working directory failed with pal_status = 0x%x", (unsigned int)pal_result); 01007 result = ESFS_ERROR; 01008 goto errorExit; 01009 } 01010 pal_result = pal_fsMkDir(working_dir_path); 01011 if (pal_result != PAL_SUCCESS) 01012 { 01013 tr_err("esfs_factory_reset() - pal_fsMkDir(ESFS_WORKING_DIRECTORY) failed with pal_status = 0x%x", (unsigned int)pal_result); 01014 result = ESFS_ERROR; 01015 goto errorExit; 01016 } 01017 } 01018 else 01019 { 01020 // delete the files in working dir 01021 pal_result = pal_fsRmFiles(working_dir_path); 01022 // the use case is that esfs folder may not exist 01023 if ((pal_result != PAL_SUCCESS) && (pal_result != PAL_ERR_FS_NO_FILE) && (pal_result != PAL_ERR_FS_NO_PATH)) 01024 { 01025 tr_err("esfs_factory_reset() - pal_fsRmFiles(ESFS_WORKING_DIRECTORY) failed with pal_status = 0x%x", (unsigned int)pal_result); 01026 result = ESFS_ERROR; 01027 goto errorExit; 01028 } 01029 } 01030 01031 pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, full_path_backup_dir); 01032 if (pal_result != PAL_SUCCESS) 01033 { 01034 tr_err("esfs_factory_reset() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)pal_result); 01035 return ESFS_ERROR; 01036 } 01037 strncat(full_path_backup_dir, "/" ESFS_BACKUP_DIRECTORY, sizeof(ESFS_BACKUP_DIRECTORY)); 01038 01039 pal_result = pal_fsCpFolder(full_path_backup_dir, working_dir_path); 01040 01041 if ((pal_result != PAL_SUCCESS) && (pal_result != PAL_ERR_FS_NO_FILE)) 01042 { 01043 tr_err("esfs_factory_reset() - pal_fsCpFolder() from backup to working failed with pal_status = 0x%x", (unsigned int)pal_result); 01044 result = ESFS_ERROR; 01045 goto errorExit; 01046 } 01047 01048 strncat(full_path_backup_dir, "/" FACTORY_RESET_DIR "/" FACTORY_RESET_FILE, sizeof(FACTORY_RESET_DIR) + sizeof(FACTORY_RESET_FILE)); 01049 // delete the flag file because factory reset flow ended successfully 01050 pal_result = pal_fsUnlink(full_path_backup_dir); 01051 if (pal_result != PAL_SUCCESS) 01052 { 01053 tr_err("esfs_factory_reset() - pal_fsUnlink(ESFS_BACKUP_DIRECTORY/FACTORY_RESET_DIR/FACTORY_RESET_FILE) failed with pal_status = 0x%x", (unsigned int)pal_result); 01054 result = ESFS_ERROR; 01055 goto errorExit; 01056 } 01057 01058 return ESFS_SUCCESS; 01059 01060 errorExit: 01061 return result; 01062 } 01063 01064 // Internal function to read header information and check its' validity. 01065 // Checks the name given against the name written in the file. 01066 // Checks the version. 01067 // Initializes some fields of file_handle: blob_name_length, esf_mode 01068 // Assumes that the read position is at the start of the file. 01069 // CMAC is calculated. 01070 // Parameters : 01071 // name [IN] A pointer to an array of binary data that uniquely identifies the file. 01072 // name_length [IN] size in bytes of the name. The minimum is 1 and the maximum is ESFS_MAX_NAME_LENGTH. 01073 // file_handle [IN] A pointer to a file handle on which we calculate the position. 01074 // return esf_success - name matches; 01075 // ESFS_HASH_CONFLICT - name does not match 01076 // ESFS_WRONG_FILE_VERSION - version does not match 01077 // ESFS_ERROR - other problem 01078 // On ESFS_SUCCESS or ESFS_HASH_CONFLICT the read position is set after the name. 01079 // On failure the position is undefined. 01080 static esfs_result_e esfs_check_file_validity(const uint8_t* name, size_t name_length, esfs_file_t *file_handle) 01081 { 01082 esfs_result_e result = ESFS_ERROR; 01083 01084 // Read the version 01085 uint16_t version; 01086 size_t num_bytes; 01087 result = esfs_cmac_read(file_handle, &version , sizeof(version), &num_bytes); 01088 if (result != ESFS_SUCCESS || num_bytes != sizeof(version)) 01089 { 01090 tr_err("esfs_check_file_validity() - esfs_cmac_read() failed with ESFS result = 0x%x and num_bytes bytes = %zu", 01091 (unsigned int)result, num_bytes); 01092 goto errorExit; 01093 } 01094 // Check that the files version is the same as the source code version. 01095 if(version != ESFS_FILE_FORMAT_VERSION) 01096 { 01097 tr_err("esfs_check_file_validity() - invalid version: failed with version = %u instead of %u", (unsigned int)version, (unsigned int)ESFS_FILE_FORMAT_VERSION); 01098 result = ESFS_INVALID_FILE_VERSION; 01099 goto errorExit; 01100 } 01101 01102 // Read the mode 01103 result = esfs_cmac_read(file_handle, (void *)( &file_handle->esfs_mode ), sizeof(file_handle->esfs_mode), &num_bytes); 01104 if (result != ESFS_SUCCESS || num_bytes != sizeof(file_handle->esfs_mode)) 01105 { 01106 tr_err("esfs_check_file_validity() mode - failed num_bytes bytes = %zu", num_bytes); 01107 goto errorExit; 01108 } 01109 // The mode is not used further in the opening process, so no further checks need be performed as cmac check will detect any 01110 // tampering. 01111 01112 // Read the name length 01113 result = esfs_cmac_read(file_handle, (void *)( &file_handle->blob_name_length ), sizeof(file_handle->blob_name_length), &num_bytes); 01114 if (result != ESFS_SUCCESS || num_bytes != sizeof(file_handle->blob_name_length)) 01115 { 01116 tr_err("esfs_check_file_validity() name length- esfs_cmac_read() failed with result = 0x%x and num_bytes bytes = %zu", 01117 (unsigned int)result, num_bytes); 01118 goto errorExit; 01119 } 01120 // Check that the name in the file is the same length as the one given. It cannot be greater than ESFS_MAX_NAME_LENGTH 01121 // because that is checked on entry to the function. 01122 if (name_length != file_handle->blob_name_length) 01123 { 01124 tr_err("esfs_check_file_validity() - name length conflict"); 01125 // The hash of the name conflicts with the hash of another name. 01126 result = ESFS_HASH_CONFLICT; 01127 goto errorExit; 01128 } 01129 // Check the name chunk by chunk 01130 for (int i = name_length; i > 0; i -= ESFS_READ_CHUNK_SIZE_IN_BYTES) 01131 { 01132 // Read a chunk 01133 char buffer[ESFS_READ_CHUNK_SIZE_IN_BYTES]; 01134 result = esfs_cmac_read(file_handle, (void *)buffer, PAL_MIN(i, ESFS_READ_CHUNK_SIZE_IN_BYTES), &num_bytes); 01135 if (result != ESFS_SUCCESS || num_bytes == 0) 01136 { 01137 tr_err("esfs_check_file_validity() - read name failed with ESFS result = 0x%x and num_bytes bytes = %zu", 01138 (unsigned int)result, num_bytes); 01139 goto errorExit; 01140 } 01141 // Check that the chunk matches 01142 //tr_info("Comparing %s (%d bytes) name_length=%d", name, (int )num_bytes,(int )name_length); 01143 if (memcmp(buffer, name, num_bytes) != 0) 01144 { 01145 tr_err("esfs_check_file_validity() - esfs hash conflict : The hash of the name conflicts with the hash of another name"); 01146 // The hash of the name conflicts with the hash of another name. 01147 result = ESFS_HASH_CONFLICT; 01148 goto errorExit; 01149 } 01150 // Advance past what we just checked. 01151 name += num_bytes; 01152 } 01153 return ESFS_SUCCESS; 01154 errorExit: 01155 return result; 01156 } 01157 01158 // Internal function to check the name against the name written in the file. 01159 // Assume that the read position is set to before the name length. 01160 // Parameters : 01161 // fd - [IN] A pointer to a file descriptor. 01162 // file_size [OUT] A pointer to a value into which the file size is returned. 01163 // return esf_success - name matches; 01164 // ESFS_HASH_CONFLICT - name does not match ; 01165 // ESFS_ERROR - other problem 01166 // On ESFS_SUCCESS or ESFS_HASH_CONFLICT the read position is set after the name. 01167 // On failure the position is undefined. 01168 01169 // Helper function 01170 // Restores current position unless it fails. 01171 // On failure the position is undefined. 01172 static palStatus_t esfs_get_physical_file_size(palFileDescriptor_t* fd, int32_t *file_size) 01173 { 01174 palStatus_t res; 01175 01176 // Get current position 01177 int32_t current_pos; 01178 res = pal_fsFtell(fd, ¤t_pos); 01179 if (res != PAL_SUCCESS) 01180 { 01181 tr_err("esfs_get_physical_file_size() - pal_fsFtell() failed with pal_status = 0x%x", (unsigned int)res); 01182 goto errorExit; 01183 } 01184 // Seek to end of file 01185 res = pal_fsFseek(fd, 0, PAL_FS_OFFSET_SEEKEND); 01186 if (res != PAL_SUCCESS) 01187 { 01188 tr_err("esfs_get_physical_file_size() - pal_fsFseek() failed with pal_status = 0x%x", (unsigned int)res); 01189 goto errorExit; 01190 } 01191 // Get new position 01192 res = pal_fsFtell(fd, file_size); 01193 if (res != PAL_SUCCESS) 01194 { 01195 tr_err("esfs_get_physical_file_size() - pal_fsFtell() failed with pal_status = 0x%x", (unsigned int)res); 01196 goto errorExit; 01197 } 01198 // Restore old position 01199 res = pal_fsFseek(fd, current_pos, PAL_FS_OFFSET_SEEKSET); 01200 if (res != PAL_SUCCESS) 01201 { 01202 tr_err("esfs_get_physical_file_size() - pal_fsFseek() failed with pal_status = 0x%x", (unsigned int)res); 01203 goto errorExit; 01204 } 01205 01206 errorExit: 01207 return res; 01208 } 01209 01210 // Copy one file to another. 01211 // Parameters : 01212 // src_file - [IN] A pointer to a string containing the source file name. 01213 // src_file - [IN] A pointer to a string containing the destination file name. 01214 // Return : ESFS_SUCCESS on success. Error code otherwise 01215 static esfs_result_e esfs_copy_file(const char *src_file, const char *dst_file) 01216 { 01217 bool is_src_file_opened = false; 01218 bool is_dst_file_opened = false; 01219 esfs_file_t file_handle = { 0 }; 01220 esfs_file_t file_handle_copy = { 0 }; 01221 esfs_result_e result = ESFS_ERROR; 01222 palStatus_t res = PAL_SUCCESS; 01223 size_t bytes_to_read = ESFS_FILE_COPY_CHUNK_SIZE; 01224 size_t num_bytes_read = 0; 01225 size_t num_bytes_write = 0; 01226 uint8_t buffer[ESFS_FILE_COPY_CHUNK_SIZE] = {0}; 01227 int32_t file_size = 0; 01228 int32_t copied_bytes = 0; 01229 // Open src file read only mode 01230 res = pal_fsFopen(src_file, PAL_FS_FLAG_READONLY, &(file_handle.file)); 01231 if (res != PAL_SUCCESS) 01232 { 01233 // File cannot be opened so return an error 01234 tr_err("esfs_copy_file() - pal_fsFopen() src file failed with pal_status = 0x%x", (unsigned int)res); 01235 result = ESFS_NOT_EXISTS; 01236 goto errorExit; 01237 } 01238 is_src_file_opened = true; 01239 // Open for reading and writing exclusively, If the file already exists, trunced file 01240 res = pal_fsFopen(dst_file, PAL_FS_FLAG_READWRITETRUNC, &(file_handle_copy.file)); 01241 if (res != PAL_SUCCESS) 01242 { 01243 // File cannot be opened so return an error 01244 tr_err("esfs_copy_file() - pal_fsFopen() dst file failed with pal_status = 0x%x", (unsigned int)res); 01245 result = ESFS_ERROR; 01246 goto errorExit; 01247 } 01248 is_dst_file_opened = true; 01249 01250 res = esfs_get_physical_file_size(&(file_handle.file), &file_size); 01251 if (res != PAL_SUCCESS) 01252 { 01253 tr_err("esfs_copy_file() - esfs_get_physical_file_size() failed with pal_status = 0x%x", (unsigned int)res); 01254 result = ESFS_ERROR; 01255 goto errorExit; 01256 } 01257 while (copied_bytes < file_size) 01258 { 01259 if (copied_bytes + (int32_t)bytes_to_read > file_size) 01260 { 01261 bytes_to_read = file_size - copied_bytes; 01262 } 01263 res = pal_fsFread(&(file_handle.file), buffer, bytes_to_read, &num_bytes_read); 01264 if (res != PAL_SUCCESS) 01265 { 01266 tr_err("esfs_copy_file() - pal_fsFread() failed with pal_status = 0x%x", (unsigned int)res); 01267 result = ESFS_ERROR; 01268 goto errorExit; 01269 } 01270 01271 res = pal_fsFwrite(&(file_handle_copy.file), buffer, bytes_to_read, &num_bytes_write); 01272 if ((res != PAL_SUCCESS) || (num_bytes_write != bytes_to_read)) 01273 { 01274 tr_err("esfs_copy_file() - pal_fsFwrite() failed with pal result = 0x%x and num_bytes_write bytes = %zu", 01275 (unsigned int)res, num_bytes_write); 01276 result = ESFS_ERROR; 01277 goto errorExit; 01278 } 01279 01280 copied_bytes += bytes_to_read; 01281 01282 } 01283 01284 01285 res = pal_fsFclose(&(file_handle.file)); 01286 if (res != PAL_SUCCESS) 01287 { 01288 tr_err("esfs_copy_file() - pal_fsFclose() for src file failed with pal_status = 0x%x", (unsigned int)res); 01289 result = ESFS_ERROR; 01290 goto errorExit; 01291 } 01292 res = pal_fsFclose(&(file_handle_copy.file)); 01293 if (res != PAL_SUCCESS) 01294 { 01295 tr_err("esfs_copy_file() - pal_fsFclose() for dst file failed with pal_status = 0x%x", (unsigned int)res); 01296 result = ESFS_ERROR; 01297 goto errorExit; 01298 } 01299 return ESFS_SUCCESS; 01300 01301 errorExit: 01302 if (is_src_file_opened) 01303 { 01304 // we will not delete the src file 01305 pal_fsFclose(&(file_handle.file)); 01306 } 01307 01308 if (is_dst_file_opened) 01309 { 01310 pal_fsFclose(&(file_handle_copy.file)); 01311 // Clean up if possible. Ignore return value. 01312 (void)pal_fsUnlink(dst_file); 01313 } 01314 return result; 01315 } 01316 01317 01318 01319 01320 // Internal function to create a new file and open it for writing. 01321 // Does not return error if file exists. 01322 // Keep all the conditions that allow the file creation in a single function, esfs_create, while the 01323 // esfs_create_internal will concentrate on file creation mechanics. 01324 // Parameters: 01325 // name - [IN] A pointer to an array of binary data that uniquely identifies the file. 01326 // name_length - [IN] size in bytes of the name. The minimum is 1 and the maximum is ESFS_MAX_NAME_LENGTH. 01327 // meta_data - [IN] A pointer to an array of TLVs structures with meta_data_qty members 01328 // meta_data_qty - [IN] number of tlvs in the array pointed by meta_data parameter. Minimum is 0 maximum is ESFS_MAX_TYPE_LENGTH_VALUES 01329 // esfs_mode - [IN] a bit map combination of values from enum EsfsMode. 01330 // file_handle - [IN/OUT] Pointer to the handle data structure into which to write the new handle. 01331 // returns ESFS_SUCCESS The file handle can be used in other esfs functions. It must be closed to release it. 01332 // ESFS_ERROR - other problem 01333 static esfs_result_e esfs_create_internal( const uint8_t *name, 01334 size_t name_length, 01335 const esfs_tlv_item_t *meta_data, 01336 size_t meta_data_qty, 01337 uint16_t esfs_mode, 01338 esfs_file_t *file_handle, 01339 const char* full_path_to_create 01340 ) 01341 { 01342 esfs_result_e result = ESFS_ERROR; 01343 01344 int32_t position = 0; 01345 size_t i; 01346 uint16_t file_created = 0; 01347 uint16_t cmac_created = 0; 01348 uint16_t u16 = ESFS_FILE_FORMAT_VERSION; 01349 01350 01351 // Create the file. 01352 // Note that we always overwrite any previous file. 01353 palStatus_t res = pal_fsFopen(full_path_to_create, PAL_FS_FLAG_READWRITETRUNC, &file_handle->file); 01354 if(res != PAL_SUCCESS) 01355 { 01356 // more informative message will be written after hash conflict will be implemented 01357 tr_err("esfs_create_internal() - pal_fsFopen() failed with status 0x%x", (unsigned int)res); 01358 goto errorExit; 01359 } 01360 file_created = 1; 01361 01362 if(esfs_cmac_start(file_handle) != ESFS_SUCCESS) 01363 { 01364 goto errorExit; 01365 } 01366 cmac_created = 1; 01367 01368 // Write the version 01369 if(esfs_fwrite_and_calc_cmac(&u16, sizeof(u16), file_handle) != ESFS_SUCCESS) 01370 { 01371 tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for esfs version failed"); 01372 result = ESFS_ERROR; 01373 goto errorExit; 01374 } 01375 01376 // Write the mode 01377 if(esfs_fwrite_and_calc_cmac(&esfs_mode, sizeof(esfs_mode), file_handle) != ESFS_SUCCESS) 01378 { 01379 tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for esfs_mode failed"); 01380 result = ESFS_ERROR; 01381 goto errorExit; 01382 } 01383 01384 // Header 01385 // Write the name length 01386 u16 = (uint16_t)name_length; 01387 if(esfs_fwrite_and_calc_cmac(&u16, sizeof(u16), file_handle) != ESFS_SUCCESS) 01388 { 01389 tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for name_length failed"); 01390 result = ESFS_ERROR; 01391 goto errorExit; 01392 } 01393 01394 // Write the name 01395 if(esfs_fwrite_and_calc_cmac(name, name_length, file_handle) != ESFS_SUCCESS) 01396 { 01397 tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for name failed."); 01398 result = ESFS_ERROR; 01399 goto errorExit; 01400 } 01401 01402 // Write the AES nonce, whether the file is encrypted or not. This ensures that the file format is the same 01403 // whether encrypted or not. 01404 if ((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) 01405 { 01406 if(esfs_fwrite_and_calc_cmac((void *)(file_handle->nonce), ESFS_AES_NONCE_SIZE_BYTES, file_handle) != ESFS_SUCCESS) 01407 { 01408 tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for AES nonce failed"); 01409 result = ESFS_ERROR; 01410 goto errorExit; 01411 } 01412 } 01413 01414 // Write the Metadata header 01415 // Write the number of items of meta data 01416 u16 = (uint16_t)meta_data_qty; 01417 if(esfs_fwrite_and_calc_cmac(&u16,sizeof(u16), file_handle) != ESFS_SUCCESS) 01418 { 01419 tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for number of items of meta data failed"); 01420 result = ESFS_ERROR; 01421 goto errorExit; 01422 } 01423 01424 // If there is meta data 01425 if(meta_data_qty != 0) 01426 { 01427 res = pal_fsFtell(&file_handle->file, &position); 01428 if(res != PAL_SUCCESS) 01429 { 01430 tr_err("esfs_create_internal() - pal_fsFtell() failed with pal_status = 0x%x", (unsigned int)res); 01431 result = ESFS_ERROR; 01432 goto errorExit; 01433 } 01434 position += (sizeof(file_handle->tlv_properties.tlv_items[0]) * meta_data_qty); 01435 for(i = 0; i < meta_data_qty; i++ ) 01436 { 01437 file_handle->tlv_properties.tlv_items[i].type = meta_data[i].type; 01438 file_handle->tlv_properties.tlv_items[i].length_in_bytes = meta_data[i].length_in_bytes; 01439 file_handle->tlv_properties.tlv_items[i].position = (uint16_t)position; 01440 // Increment position for next iteration 01441 position += meta_data[i].length_in_bytes; 01442 } 01443 01444 // Write the metadata items 01445 result = esfs_fwrite_and_calc_cmac(&file_handle->tlv_properties.tlv_items[0], sizeof(file_handle->tlv_properties.tlv_items[0])*meta_data_qty, file_handle); 01446 if(result != ESFS_SUCCESS) 01447 { 01448 tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for meta data items failed with esfs result = 0x%x", result); 01449 result = ESFS_ERROR; 01450 goto errorExit; 01451 } 01452 01453 // Set the number_of_items field here since it is in use later in this function 01454 // when we calculate the file header size 01455 file_handle->tlv_properties.number_of_items = meta_data_qty; 01456 01457 // Write the Metadata data values 01458 // If encrypted esfs is requested (by the esfs_mode argument), then this part should be encrypted 01459 for(i = 0; i < meta_data_qty; i++ ) 01460 { 01461 if((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) 01462 { 01463 result = esfs_encrypt_fwrite_and_calc_cmac(meta_data[i].value, meta_data[i].length_in_bytes, file_handle); 01464 } 01465 else 01466 { 01467 result = esfs_fwrite_and_calc_cmac(meta_data[i].value, meta_data[i].length_in_bytes, file_handle); 01468 } 01469 01470 if(result != ESFS_SUCCESS) 01471 { 01472 tr_err("esfs_create_internal() - esfs_fwrite_and_calc_cmac() for meta data item values failed with esfs result = 0x%x", result); 01473 result = ESFS_ERROR; 01474 goto errorExit; 01475 } 01476 } 01477 } 01478 01479 file_handle->file_flag = ESFS_WRITE; 01480 01481 return ESFS_SUCCESS; 01482 01483 errorExit: 01484 01485 if(file_created) 01486 { 01487 pal_fsFclose(&file_handle->file); 01488 // Clean up if possible. Ignore return value. 01489 (void)pal_fsUnlink(full_path_to_create); 01490 } 01491 if(cmac_created) 01492 { 01493 uint8_t key[ESFS_CMAC_SIZE_IN_BYTES]; 01494 // Clean up cmac. Ignore error. 01495 (void)esfs_cmac_finish(file_handle, &key[0]); 01496 } 01497 01498 return result; 01499 } 01500 01501 // --------------------------------------------------------------- 01502 // API Functions 01503 // --------------------------------------------------------------- 01504 01505 01506 esfs_result_e esfs_create(const uint8_t *name, size_t name_length, const esfs_tlv_item_t *meta_data, size_t meta_data_qty, uint16_t esfs_mode, esfs_file_t *file_handle) 01507 { 01508 01509 palStatus_t res = PAL_SUCCESS; 01510 esfs_result_e result = ESFS_ERROR; 01511 01512 bool is_aes_ctx_created = false; 01513 01514 01515 // Verify that the structure is always packed to six bytes, since we read and write it as a whole. 01516 PAL_ASSERT_STATIC(sizeof(esfs_tlvItem_t) == 6); 01517 01518 // Verify that the array is always packed without padding, since we read and write it as a whole. 01519 PAL_ASSERT_STATIC(sizeof(esfs_tlvItem_t[ESFS_MAX_TYPE_LENGTH_VALUES]) == ESFS_MAX_TYPE_LENGTH_VALUES * sizeof(esfs_tlvItem_t)); 01520 01521 tr_info("esfs_create - enter"); 01522 01523 // Check parameters 01524 if (!file_handle || !name || name_length == 0 || name_length > ESFS_MAX_NAME_LENGTH || meta_data_qty > ESFS_MAX_TYPE_LENGTH_VALUES) 01525 { 01526 tr_err("esfs_create() failed with bad parameters"); 01527 result = ESFS_INVALID_PARAMETER; 01528 goto errorExit; 01529 } 01530 01531 // Check the metadata parameter 01532 for(size_t meta_data_index = 0; meta_data_index < meta_data_qty; meta_data_index++ ) 01533 { 01534 if ((!meta_data[meta_data_index].value) || (meta_data[meta_data_index].length_in_bytes == 0)) 01535 { 01536 tr_err("esfs_create() failed with bad parameters for metadata"); 01537 result = ESFS_INVALID_PARAMETER; 01538 goto errorExit; 01539 } 01540 } 01541 01542 // If esfs is in encryption mode, make the required initializations 01543 if((esfs_mode & ESFS_ENCRYPTED) != 0) 01544 { 01545 // ** Create AES context for AES encryption 01546 res = pal_initAes( &(file_handle->aes_ctx) ); 01547 01548 if(res != PAL_SUCCESS) 01549 { 01550 tr_err("esfs_create() - pal_initAes() failed with pal status 0x%x", (unsigned int)res); 01551 result = ESFS_ERROR ; 01552 goto errorExit; 01553 } 01554 01555 is_aes_ctx_created = true; 01556 01557 // ** Get AES key from PAL 01558 // Note: On each call, PAL should return the same 128 bits key 01559 uint8_t aes_key[ESFS_AES_KEY_SIZE_BYTES]; // For AES encryption 01560 res = pal_osGetDeviceKey(palOsStorageEncryptionKey128Bit, aes_key, ESFS_AES_KEY_SIZE_BYTES); 01561 01562 if(res != PAL_SUCCESS) 01563 { 01564 tr_err("esfs_create() - pal_osGetDeviceKey() failed with pal status 0x%x", (unsigned int)res); 01565 result = ESFS_ERROR ; 01566 goto errorExit; 01567 } 01568 01569 // ** Assign generated AES key to AES context 01570 res = pal_setAesKey( file_handle->aes_ctx, 01571 aes_key, 01572 ESFS_AES_KEY_SIZE_BITS, 01573 PAL_KEY_TARGET_ENCRYPTION 01574 ); 01575 01576 if(res != PAL_SUCCESS) 01577 { 01578 tr_err("esfs_create() - pal_setAesKey() failed with pal status 0x%x", (unsigned int)res); 01579 result = ESFS_ERROR ; 01580 goto errorExit; 01581 } 01582 01583 // ** Generate the AES nonce for AES usage 01584 res = pal_osRandomBuffer(file_handle->nonce, ESFS_AES_NONCE_SIZE_BYTES); 01585 01586 if(res != PAL_SUCCESS) 01587 { 01588 tr_err("esfs_create() - pal_osRandomBuffer() failed with pal status 0x%x", (unsigned int)res); 01589 result = ESFS_ERROR ; 01590 goto errorExit; 01591 } 01592 } 01593 01594 // We set the blob_name_length field here because it is in use later in this function when we calculate the file header size. 01595 // Since this field is also used to check the file handle validity [ esfs_validate() ] we set it to zero on an error exit. 01596 file_handle->blob_name_length = name_length; 01597 01598 file_handle->esfs_mode = esfs_mode; 01599 01600 file_handle->file_invalid = 0; 01601 01602 file_handle->tlv_properties.number_of_items = 0; 01603 01604 // Indicate that there is not a signature context yet. 01605 file_handle->signature_ctx = 0; 01606 01607 file_handle->data_size = 0; 01608 01609 if (esfs_get_name_from_blob(name, name_length, file_handle->short_file_name, ESFS_FILE_NAME_LENGTH) != ESFS_SUCCESS) 01610 { 01611 tr_err("esfs_create() - esfs_get_name_from_blob() failed"); 01612 goto errorExit; 01613 } 01614 01615 // Put working file name in file_full_path 01616 char file_full_path[MAX_FULL_PATH_SIZE]; 01617 res = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, file_full_path); 01618 if (res != PAL_SUCCESS) 01619 { 01620 tr_err("esfs_create() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)res); 01621 result = ESFS_ERROR; 01622 goto errorExit; 01623 } 01624 strncat(file_full_path, "/" ESFS_WORKING_DIRECTORY "/", sizeof(ESFS_WORKING_DIRECTORY) + 1); 01625 strncat(file_full_path, file_handle->short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1); 01626 01627 01628 // Check if the file exists in the working directory (not acceptable) 01629 // Note that this is just a check. We will only actually open the file later (in esfs_create_internal()). 01630 res = pal_fsFopen(file_full_path, PAL_FS_FLAG_READONLY, &file_handle->file); 01631 if (res == PAL_SUCCESS) 01632 { 01633 result = ESFS_EXISTS; 01634 file_handle->esfs_mode = 0; 01635 // result can be ESFS_HASH_CONFLICT or ESFS_WRONG_FILE_VERSION 01636 // Check if there is a different name in the file 01637 // Check that the name written inside the file is the same as that given. If not 01638 // you should choose a different name. 01639 esfs_result_e check_result = esfs_check_file_validity(name, name_length, file_handle); 01640 if (check_result == ESFS_HASH_CONFLICT || check_result == ESFS_INVALID_FILE_VERSION) 01641 { 01642 result = check_result; 01643 } 01644 pal_fsFclose(&file_handle->file); 01645 tr_err("esfs_create() - pal_fsFopen() for working dir file failed"); 01646 goto errorExit; 01647 } 01648 01649 // If factory reset file then we make some checks 01650 if (esfs_mode & (uint16_t)ESFS_FACTORY_VAL) 01651 { 01652 // Put backup folder name in file_full_path 01653 res = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, file_full_path); 01654 if (res != PAL_SUCCESS) 01655 { 01656 tr_err("esfs_create() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)res); 01657 result = ESFS_ERROR; 01658 goto errorExit; 01659 } 01660 strncat(file_full_path, "/" ESFS_BACKUP_DIRECTORY, sizeof(ESFS_BACKUP_DIRECTORY)); 01661 01662 // Create the esfs subfolder for backup 01663 res = pal_fsMkDir(file_full_path); 01664 if (res != PAL_SUCCESS) 01665 { 01666 // Any error apart from file exist returns error. 01667 if (res != PAL_ERR_FS_NAME_ALREADY_EXIST) 01668 { 01669 tr_err("esfs_create() - pal_fsMkDir() for backup dir failed with pal status 0x%x", (unsigned int)res); 01670 goto errorExit; 01671 } 01672 } 01673 01674 // Put backup file name in file_full_path 01675 strcat(file_full_path, "/"); 01676 strncat(file_full_path, file_handle->short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1); 01677 01678 // Check if the file exists in esfs backup directory (acceptable unless there is a hash conflict for the name) 01679 res = pal_fsFopen(file_full_path, PAL_FS_FLAG_READONLY, &file_handle->file); 01680 if (res == PAL_SUCCESS) 01681 { 01682 file_handle->esfs_mode = 0; 01683 // result can be ESFS_HASH_CONFLICT or ESFS_WRONG_FILE_VERSION 01684 // Check if there is a different name in the file 01685 // Check that the name written inside the file is the same as that given. If not 01686 // you should choose a different name. 01687 esfs_result_e check_result = esfs_check_file_validity(name, name_length, file_handle); 01688 01689 // Close the file. 01690 pal_fsFclose(&file_handle->file); 01691 01692 if (check_result == ESFS_HASH_CONFLICT || check_result == ESFS_INVALID_FILE_VERSION) 01693 { 01694 tr_err("esfs_create() - esfs_check_file_validity() failed with status 0x%x", check_result); 01695 result = check_result; 01696 goto errorExit; 01697 } 01698 // It is OK for it to exist, so continue. 01699 } 01700 } 01701 01702 // Now we actually create the new file. 01703 // file_full_path contains the correct location (working/backup) 01704 result = esfs_create_internal( 01705 name, 01706 name_length, 01707 meta_data, 01708 meta_data_qty, 01709 esfs_mode, 01710 file_handle, 01711 // Working or backup 01712 file_full_path 01713 ); 01714 if(result != ESFS_SUCCESS) 01715 { 01716 goto errorExit; 01717 } 01718 01719 return ESFS_SUCCESS; 01720 01721 errorExit: 01722 01723 // Invalidate blob_name_length filed since it is used to check the file handle validity [ esfs_validate() ] 01724 if(file_handle != NULL) 01725 { 01726 file_handle->blob_name_length = 0; 01727 } 01728 01729 if(is_aes_ctx_created) 01730 { 01731 pal_freeAes( &(file_handle->aes_ctx) ); 01732 } 01733 return result; 01734 } 01735 01736 esfs_result_e esfs_open(const uint8_t *name, size_t name_length, uint16_t *esfs_mode, esfs_file_t *file_handle) 01737 { 01738 esfs_result_e result = ESFS_ERROR; 01739 uint16_t file_opened = 0; 01740 uint16_t cmac_created = 0; 01741 bool is_aes_ctx_created = false; 01742 palStatus_t res = PAL_SUCCESS; 01743 01744 tr_info("esfs_open - enter"); 01745 // Check parameters 01746 if(!file_handle || !name || name_length == 0 || name_length > ESFS_MAX_NAME_LENGTH) 01747 { 01748 tr_err("esfs_open() failed with bad parameters"); 01749 result = ESFS_INVALID_PARAMETER; 01750 goto errorExit; 01751 } 01752 01753 char working_dir_path[MAX_FULL_PATH_SIZE]; 01754 res = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, working_dir_path); 01755 if (res != PAL_SUCCESS) 01756 { 01757 tr_err("esfs_open() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)res); 01758 return ESFS_ERROR; 01759 } 01760 01761 strncat(working_dir_path, "/" ESFS_WORKING_DIRECTORY "/", sizeof(ESFS_WORKING_DIRECTORY) + 1); 01762 01763 // This is used to esfs_validate the file handle so we set it to zero here and only when open 01764 // succeeds to the real value. 01765 file_handle->blob_name_length = 0; 01766 01767 file_handle->file_invalid = 0; 01768 01769 memset(&file_handle->cmac[0], 0, sizeof(file_handle->cmac)); 01770 01771 if(esfs_get_name_from_blob(name, name_length, file_handle->short_file_name, ESFS_FILE_NAME_LENGTH) != ESFS_SUCCESS) 01772 { 01773 tr_err("esfs_open() - esfs_get_name_from_blob() failed"); 01774 result = ESFS_ERROR; 01775 goto errorExit; 01776 } 01777 01778 strncat(working_dir_path, file_handle->short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1); 01779 01780 // Open the file read only 01781 res = pal_fsFopen(working_dir_path, PAL_FS_FLAG_READONLY, &file_handle->file); 01782 if(res != PAL_SUCCESS) 01783 { 01784 // tr_err("esfs_open() - pal_fsFopen() for working dir file failed with pal_status = 0x%x", (unsigned int)res); 01785 // File cannot be opened so return an error 01786 result = ESFS_NOT_EXISTS; 01787 goto errorExit; 01788 } 01789 01790 file_opened = 1; 01791 01792 if(esfs_cmac_start(file_handle) != ESFS_SUCCESS) 01793 { 01794 goto errorExit; 01795 } 01796 cmac_created = 1; 01797 01798 // Check that the name written inside the file is the same as that given 01799 // Note: After this call, the read position will be set to the point after the "Name Blob" 01800 result = esfs_check_file_validity(name, name_length, file_handle); 01801 if(result != ESFS_SUCCESS) 01802 { 01803 // the requested file not exists, but exists file with the same short name 01804 if (result == ESFS_HASH_CONFLICT) 01805 { 01806 result = ESFS_NOT_EXISTS; 01807 } 01808 tr_err("esfs_open() - esfs_check_file_validity() failed with status = 0x%x", result); 01809 // File cannot be opened so return an error 01810 goto errorExit; 01811 } 01812 01813 if (esfs_mode) 01814 { 01815 *esfs_mode = file_handle->esfs_mode; // file_handle->esfs_mode was set by esfs_check_file_validity() 01816 } 01817 01818 // If esfs is in encryption mode, make the required initializations 01819 if((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) 01820 { 01821 // ** Create AES context for AES decryption 01822 res = pal_initAes( &(file_handle->aes_ctx) ); 01823 01824 if(res != PAL_SUCCESS) 01825 { 01826 tr_err("esfs_open() - pal_initAes() failed with status 0x%x", (unsigned int)res); 01827 result = ESFS_ERROR ; 01828 goto errorExit; 01829 } 01830 01831 is_aes_ctx_created = true; 01832 01833 // ** Get AES key from PAL 01834 // Note: On each call, PAL should return the same 128 bits key 01835 uint8_t aes_key[ESFS_AES_KEY_SIZE_BYTES]; 01836 res = pal_osGetDeviceKey(palOsStorageEncryptionKey128Bit, aes_key, ESFS_AES_KEY_SIZE_BYTES); 01837 01838 if(res != PAL_SUCCESS) 01839 { 01840 tr_err("esfs_open() - pal_osGetDeviceKey() failed with status 0x%x", (unsigned int)res); 01841 result = ESFS_ERROR ; 01842 goto errorExit; 01843 } 01844 01845 // ** Assign generated AES key to AES context 01846 res = pal_setAesKey( file_handle->aes_ctx, 01847 aes_key, 01848 ESFS_AES_KEY_SIZE_BITS, 01849 PAL_KEY_TARGET_ENCRYPTION 01850 ); 01851 01852 if(res != PAL_SUCCESS) 01853 { 01854 tr_err("esfs_open() - pal_setAesKey() failed with status 0x%x", (unsigned int)res); 01855 result = ESFS_ERROR; 01856 goto errorExit; 01857 } 01858 01859 } 01860 01861 size_t num_bytes; 01862 01863 // ** Read the AES nonce into file_handle->nonce 01864 if ((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) 01865 { 01866 result = esfs_cmac_read(file_handle, &file_handle->nonce[0], ESFS_AES_NONCE_SIZE_BYTES, &num_bytes); 01867 if((result != ESFS_SUCCESS) || (num_bytes != ESFS_AES_NONCE_SIZE_BYTES)) 01868 { 01869 tr_err("esfs_open() - esfs_cmac_read() (AES nonce) failed with ESFS result = 0x%x and num_bytes bytes = %zu", 01870 (unsigned int)result, num_bytes); 01871 result = ESFS_ERROR; 01872 goto errorExit; 01873 } 01874 } 01875 01876 file_handle->tlv_properties.number_of_items = 0; 01877 01878 // Read the number of items of meta data 01879 uint16_t meta_data_qty; 01880 result = esfs_cmac_read(file_handle, (void *)( &meta_data_qty ), sizeof(meta_data_qty), &num_bytes); 01881 if(result != ESFS_SUCCESS || num_bytes != sizeof(meta_data_qty) || meta_data_qty > ESFS_MAX_TYPE_LENGTH_VALUES) 01882 { 01883 tr_err("esfs_open() - esfs_cmac_read() (number of items of meta data) failed with ESFS result = 0x%x and num_bytes bytes = %zu", 01884 (unsigned int)result, num_bytes); 01885 result = ESFS_ERROR; 01886 goto errorExit; 01887 } 01888 01889 // Read the metadata properties if there are any 01890 if(meta_data_qty != 0) 01891 { 01892 result = esfs_cmac_read( file_handle, 01893 (void *) ( &(file_handle->tlv_properties.tlv_items[0]) ), 01894 (sizeof(file_handle->tlv_properties.tlv_items[0]) * meta_data_qty), 01895 &num_bytes 01896 ); 01897 01898 if(result != ESFS_SUCCESS || num_bytes != sizeof(file_handle->tlv_properties.tlv_items[0])*meta_data_qty) 01899 { 01900 tr_err("esfs_open() - esfs_cmac_read() (metadata properties) failed with ESFS result = 0x%x and num_bytes bytes = %zu", 01901 (unsigned int)result, num_bytes); 01902 goto errorExit; 01903 } 01904 01905 // Skip to the start of the data by calculating the last metadata position plus its length 01906 esfs_tlvItem_t *ptypeLengthValueItem = &file_handle->tlv_properties.tlv_items[meta_data_qty - 1]; 01907 01908 if(esfs_cmac_skip_to(file_handle, ptypeLengthValueItem->position + ptypeLengthValueItem->length_in_bytes) != ESFS_SUCCESS) 01909 { 01910 tr_err("esfs_open() - esfs_cmac_skip_to() failed."); 01911 result = ESFS_ERROR; 01912 goto errorExit; 01913 } 01914 } 01915 01916 file_handle->tlv_properties.number_of_items = meta_data_qty; 01917 01918 // We are at the start of the data section 01919 file_handle->current_read_pos = 0; 01920 01921 // Get current position 01922 int32_t current_pos; 01923 res = pal_fsFtell(&file_handle->file, ¤t_pos); 01924 if (res != PAL_SUCCESS) 01925 { 01926 tr_err("esfs_open() - pal_fsFtell() failed with pal_status = 0x%x", (unsigned int)res); 01927 goto errorExit; 01928 } 01929 01930 // get the whole file size and store it in the handle 01931 res = esfs_get_physical_file_size(&file_handle->file, &file_handle->file_size); 01932 if (res != PAL_SUCCESS) 01933 { 01934 tr_err("esfs_open() - esfs_open() failed with status 0x%x", (unsigned int)res); 01935 result = ESFS_ERROR; 01936 goto errorExit; 01937 } 01938 01939 // Skip to the end of the file while calculating the cmac 01940 if(esfs_cmac_skip_to(file_handle, file_handle->file_size - ESFS_CMAC_SIZE_IN_BYTES) != ESFS_SUCCESS) 01941 { 01942 tr_err("esfs_open() - esfs_cmac_skip_to() failed."); 01943 result = ESFS_ERROR; 01944 goto errorExit; 01945 } 01946 01947 // Terminate cmac calculation and get it. 01948 unsigned char cmac[ESFS_CMAC_SIZE_IN_BYTES]; 01949 if(esfs_cmac_finish(file_handle, &cmac[0]) != ESFS_SUCCESS) 01950 { 01951 tr_err("esfs_open() - esfs_finish_cmac() failed"); 01952 goto errorExit; 01953 } 01954 cmac_created = 0; 01955 01956 // save the CMAC in the file descriptor. We will use this to check that the file has not 01957 // changed when esfs_read() or read_meta_data() is called. 01958 memcpy(&file_handle->cmac[0],&cmac[0],sizeof(file_handle->cmac)); 01959 01960 // Check the cmac and set the file position to the start of the data 01961 if(esfs_cmac_check_and_restore(file_handle, &cmac[0], current_pos) != ESFS_SUCCESS) 01962 { 01963 tr_err("esfs_open() - cmac that we read from the file does not match the one that we calculated"); 01964 result = ESFS_CMAC_DOES_NOT_MATCH; 01965 goto errorExit; 01966 } 01967 01968 // Calculate the size of the data only, by getting the file size and deducting the header and cmac 01969 file_handle->data_size = file_handle->file_size - esfs_file_header_size(file_handle); 01970 01971 // We deduct the cmac bytes at the end of the file since they are not part of the data 01972 file_handle->data_size -= ESFS_CMAC_SIZE_IN_BYTES; 01973 01974 file_handle->file_flag = ESFS_READ; 01975 file_handle->blob_name_length = name_length; 01976 01977 return ESFS_SUCCESS; 01978 01979 errorExit: 01980 if(file_opened) 01981 { 01982 pal_fsFclose(&file_handle->file); 01983 } 01984 if(is_aes_ctx_created) 01985 { 01986 pal_freeAes( &(file_handle->aes_ctx) ); 01987 } 01988 if(cmac_created) 01989 { 01990 // Clean up cmac. Ignore error. 01991 (void)esfs_cmac_finish(file_handle, &cmac[0]); 01992 } 01993 01994 return result; 01995 } 01996 01997 esfs_result_e esfs_write(esfs_file_t *file_handle, const void *buffer, size_t bytes_to_write) 01998 { 01999 esfs_result_e result = ESFS_ERROR; 02000 02001 tr_info("esfs_write - enter"); 02002 if((esfs_validate(file_handle) != ESFS_SUCCESS) || (!buffer) || (bytes_to_write == 0)) 02003 { 02004 tr_err("esfs_write() failed with bad parameters"); 02005 return ESFS_INVALID_PARAMETER; 02006 } 02007 02008 if(file_handle->file_flag == ESFS_READ) 02009 { 02010 tr_err("esfs_write() write failed - file is opened for read only"); 02011 result = ESFS_FILE_OPEN_FOR_READ; 02012 goto errorExit; 02013 } 02014 else 02015 { 02016 // Write data 02017 // If encrypted esfs is requested (file_handle->esfs_mode), then this part should be encrypted 02018 02019 // The data should be encrypted if the encrypted esfs is requested by the esfs_mode argument 02020 if((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) 02021 { 02022 result = esfs_encrypt_fwrite_and_calc_cmac(buffer, bytes_to_write, file_handle); 02023 } 02024 else 02025 { 02026 result = esfs_fwrite_and_calc_cmac(buffer, bytes_to_write, file_handle); 02027 } 02028 02029 if(result != ESFS_SUCCESS) 02030 { 02031 tr_err("esfs_write() - esfs_fwrite_and_calc_cmac()/esfs_encrypt_fwrite_and_calc_cmac() for data failed with esfs result = 0x%x", result); 02032 // Since the write failed, we cannot be sure of the state of the file, so we mark it as invalid. 02033 file_handle->file_invalid = 1; 02034 result = ESFS_ERROR; 02035 goto errorExit; 02036 } 02037 } 02038 02039 file_handle->data_size += bytes_to_write; 02040 02041 return ESFS_SUCCESS; 02042 02043 errorExit: 02044 return result; 02045 } 02046 02047 esfs_result_e esfs_read(esfs_file_t *file_handle, void *buffer, size_t bytes_to_read, size_t *read_bytes) 02048 { 02049 esfs_result_e result = ESFS_ERROR; 02050 uint16_t cmac_created = 0; 02051 size_t remaining_bytes = 0; 02052 palStatus_t res = PAL_SUCCESS; 02053 02054 tr_info("esfs_read - enter"); 02055 if(esfs_validate(file_handle) != ESFS_SUCCESS || read_bytes == NULL || !buffer) 02056 { 02057 result = ESFS_INVALID_PARAMETER; 02058 goto errorExit; 02059 } 02060 02061 if(file_handle->file_flag != ESFS_READ) 02062 { 02063 result = ESFS_FILE_OPEN_FOR_WRITE; 02064 goto errorExit; 02065 } 02066 // Save file position 02067 int32_t position; 02068 res = pal_fsFtell(&file_handle->file, &position); 02069 if(res != PAL_SUCCESS) 02070 { 02071 tr_err("esfs_read() - pal_fsFtell() failed with pal status 0x%x", (unsigned int)res); 02072 goto errorExit; 02073 } 02074 02075 // Limit how many bytes we can actually read depending on the size of the data section. 02076 remaining_bytes = file_handle->data_size - file_handle->current_read_pos; 02077 bytes_to_read = PAL_MIN(remaining_bytes, bytes_to_read); 02078 02079 if(esfs_cmac_start(file_handle) != ESFS_SUCCESS) 02080 { 02081 goto errorExit; 02082 } 02083 cmac_created = 1; 02084 02085 if(esfs_cmac_skip_to(file_handle, position) != ESFS_SUCCESS) 02086 { 02087 goto errorExit; 02088 } 02089 02090 // Read data 02091 // If required according to esfs_mode, the read data will be decrypted 02092 size_t num_bytes; 02093 if((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) 02094 { 02095 if(esfs_read_and_decrypt(file_handle, buffer, bytes_to_read, &num_bytes) != ESFS_SUCCESS) 02096 { 02097 goto errorExit; 02098 } 02099 } 02100 else 02101 { 02102 if(esfs_cmac_read(file_handle, buffer, bytes_to_read, &num_bytes ) != ESFS_SUCCESS) 02103 { 02104 goto errorExit; 02105 } 02106 } 02107 02108 *read_bytes = num_bytes; 02109 02110 if(esfs_cmac_skip_to(file_handle ,file_handle->file_size - ESFS_CMAC_SIZE_IN_BYTES) != ESFS_SUCCESS) 02111 { 02112 goto errorExit; 02113 } 02114 02115 unsigned char cmac[ESFS_CMAC_SIZE_IN_BYTES]; 02116 if(esfs_cmac_finish(file_handle, &cmac[0]) != ESFS_SUCCESS) 02117 { 02118 tr_err("esfs_read() - esfs_finish_cmac() failed"); 02119 goto errorExit; 02120 } 02121 cmac_created = 0; 02122 02123 // Check the cmac and set to the byte after the end of the data being read. 02124 if(esfs_cmac_check_and_restore(file_handle, &cmac[0], position + num_bytes) != ESFS_SUCCESS) 02125 { 02126 tr_err("esfs_read() - cmac that we read from the file does not match the one that we calculated"); 02127 result = ESFS_CMAC_DOES_NOT_MATCH; 02128 goto errorExit; 02129 } 02130 02131 // Update the current position 02132 file_handle->current_read_pos += num_bytes; 02133 02134 return ESFS_SUCCESS; 02135 02136 errorExit: 02137 tr_err("esfs_read errorExit result=0x%x", result); 02138 if(cmac_created) 02139 { 02140 // Clean up cmac. Ignore error and resulting cmac. 02141 (void)esfs_cmac_finish(file_handle, &cmac[0]); 02142 } 02143 02144 return result; 02145 } 02146 02147 esfs_result_e esfs_seek(esfs_file_t *file_handle, int32_t offset, esfs_seek_origin_e whence, uint32_t *position) 02148 { 02149 esfs_result_e result = ESFS_ERROR; 02150 palStatus_t res = PAL_SUCCESS; 02151 tr_info("esfs_seek - enter"); 02152 if(esfs_validate(file_handle) != ESFS_SUCCESS) 02153 { 02154 tr_err("esfs_seek() failed with bad parameters"); 02155 return ESFS_INVALID_PARAMETER; 02156 } 02157 02158 if(file_handle->file_flag != ESFS_READ) 02159 { 02160 tr_err("esfs_seek() seek failed - file is opened for write only"); 02161 result = ESFS_FILE_OPEN_FOR_WRITE; 02162 goto errorExit; 02163 } 02164 pal_fsOffset_t pal_whence; 02165 // ESFS whence enum values are in sync with those of pal 02166 if(whence == ESFS_SEEK_SET) 02167 { 02168 if(offset > (int32_t)file_handle->data_size || offset < 0) 02169 { 02170 tr_err("esfs_seek() failed with bad parameters in offset calculation : ESFS_SEEK_SET"); 02171 result = ESFS_INVALID_PARAMETER; 02172 goto errorExit; 02173 } 02174 // Add the offset to the start of the data 02175 offset += esfs_file_header_size(file_handle); 02176 pal_whence = PAL_FS_OFFSET_SEEKSET; 02177 } 02178 else if(whence == ESFS_SEEK_END) 02179 { 02180 if(offset < -(int32_t)file_handle->data_size || offset > 0) 02181 { 02182 tr_err("esfs_seek() failed with bad parameters in offset calculation : ESFS_SEEK_END"); 02183 result = ESFS_INVALID_PARAMETER; 02184 goto errorExit; 02185 } 02186 // Deduct the cmac size from the offset because it is located after the data section. 02187 offset -= ESFS_CMAC_SIZE_IN_BYTES; 02188 pal_whence = PAL_FS_OFFSET_SEEKEND; 02189 } 02190 else if(whence == ESFS_SEEK_CUR) 02191 { 02192 if(offset + file_handle->current_read_pos > (int32_t)file_handle->data_size || offset + (int32_t)file_handle->current_read_pos < 0) 02193 { 02194 tr_err("esfs_seek() failed with bad parameters in offset calculation : ESFS_SEEK_CUR"); 02195 result = ESFS_INVALID_PARAMETER; 02196 goto errorExit; 02197 } 02198 pal_whence = PAL_FS_OFFSET_SEEKCUR; 02199 } 02200 else 02201 { 02202 tr_err("esfs_seek() failed with bad parameters - wrong whence"); 02203 result = ESFS_INVALID_PARAMETER; 02204 goto errorExit; 02205 } 02206 res = pal_fsFseek(&file_handle->file, offset, pal_whence); 02207 if(res != PAL_SUCCESS) 02208 { 02209 tr_err("esfs_seek() - pal_fsFseek() failed with pal status 0x%x", (unsigned int)res); 02210 goto errorExit; 02211 } 02212 // Get current position if position is not NULL 02213 if(position) 02214 { 02215 res = pal_fsFtell(&file_handle->file, (int32_t *)position); 02216 if(res != PAL_SUCCESS) 02217 { 02218 tr_err("esfs_seek() - pal_fsFtell() failed with pal status 0x%x", (unsigned int)res); 02219 goto errorExit; 02220 } 02221 02222 // Ignore the file header data 02223 *position -= esfs_file_header_size(file_handle); 02224 02225 // Update the current position 02226 file_handle->current_read_pos = *position; 02227 } 02228 02229 return ESFS_SUCCESS; 02230 02231 errorExit: 02232 return result; 02233 } 02234 02235 02236 esfs_result_e esfs_file_size(esfs_file_t *file_handle, size_t *size_in_bytes) 02237 { 02238 esfs_result_e result = ESFS_ERROR; 02239 02240 tr_info("esfs_file_size - enter"); 02241 if((esfs_validate(file_handle) != ESFS_SUCCESS) || (!size_in_bytes)) 02242 { 02243 tr_err("esfs_file_size() failed with bad parameters"); 02244 result = ESFS_INVALID_PARAMETER; 02245 goto errorExit; 02246 } 02247 02248 *size_in_bytes = file_handle->data_size; 02249 02250 return ESFS_SUCCESS; 02251 02252 errorExit: 02253 return result; 02254 } 02255 02256 esfs_result_e esfs_close(esfs_file_t *file_handle) 02257 { 02258 uint16_t failed_to_write_CMAC = 0; 02259 uint16_t file_esfs_mode = 0; 02260 esfs_file_flag_e esfs_file_flag; 02261 char esfs_short_file_name[ESFS_QUALIFIED_FILE_NAME_LENGTH] = {0}; 02262 esfs_result_e result = ESFS_ERROR; 02263 char full_path_working_dir[MAX_FULL_PATH_SIZE]; 02264 palStatus_t res = PAL_SUCCESS; 02265 02266 tr_info("esfs_close - enter"); 02267 if(esfs_validate(file_handle) != ESFS_SUCCESS) 02268 { 02269 tr_err("esfs_close() failed with bad parameters"); 02270 result = ESFS_INVALID_PARAMETER; 02271 goto errorExit; 02272 } 02273 02274 res = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, full_path_working_dir); 02275 if (res != PAL_SUCCESS) 02276 { 02277 tr_err("esfs_close() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)res); 02278 result = ESFS_ERROR; 02279 goto errorExit; 02280 } 02281 02282 strncat(full_path_working_dir, "/" ESFS_WORKING_DIRECTORY "/", sizeof(ESFS_WORKING_DIRECTORY) + 1); 02283 02284 02285 // Close AES context if needed 02286 if((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) 02287 { 02288 pal_freeAes( &(file_handle->aes_ctx) ); 02289 } 02290 02291 esfs_file_flag = file_handle->file_flag; 02292 file_esfs_mode = file_handle->esfs_mode; 02293 strncpy(esfs_short_file_name, file_handle->short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1); 02294 02295 if(file_handle->file_flag == ESFS_WRITE) 02296 { 02297 unsigned char cmac[ESFS_CMAC_SIZE_IN_BYTES]; 02298 // Finish signature calculation 02299 if(esfs_cmac_finish(file_handle, &cmac[0]) != ESFS_SUCCESS) 02300 { 02301 tr_err("esfs_close() - esfs_cmac_finish() failed"); 02302 goto errorExit; 02303 } 02304 // Write signature 02305 size_t bytes_written; 02306 res = pal_fsFwrite(&file_handle->file, &cmac[0], sizeof(cmac), &bytes_written); 02307 if(res != PAL_SUCCESS || sizeof(cmac) != bytes_written) 02308 { 02309 tr_err("esfs_close() - pal_fsFwrite() (signature) failed with pal result = 0x%x and bytes_written bytes = %zu", 02310 (unsigned int)res, bytes_written); 02311 // mark the file invalid on a failed write 02312 file_handle->file_invalid = 1; 02313 // Continue so that we delete the file, but we should return failure later 02314 failed_to_write_CMAC = 1; 02315 } 02316 } 02317 02318 res = pal_fsFclose(&file_handle->file); 02319 if(res == PAL_SUCCESS) 02320 { 02321 // Remove a file that is invalid. It may have become invalid due to a failed write. 02322 if(file_handle->file_invalid) 02323 { 02324 strncat(full_path_working_dir,file_handle->short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1); 02325 02326 res = pal_fsUnlink(full_path_working_dir); 02327 if(res != PAL_SUCCESS) 02328 { 02329 tr_err("esfs_close() - pal_fsUnlink() failed with pal status 0x%x", (unsigned int)res); 02330 goto errorExit; 02331 } 02332 } 02333 } 02334 else 02335 { 02336 tr_err("esfs_close() - pal_fsFclose() failed with pal status 0x%x", (unsigned int)res); 02337 goto errorExit; 02338 } 02339 02340 if(failed_to_write_CMAC) 02341 { 02342 goto errorExit; 02343 } 02344 02345 02346 if ((file_esfs_mode & ESFS_FACTORY_VAL) && (esfs_file_flag == ESFS_WRITE) && !(file_handle->file_invalid)) 02347 { 02348 char full_path_backup_dir[MAX_FULL_PATH_SIZE] = { 0 }; 02349 02350 res = pal_fsGetMountPoint(PAL_FS_PARTITION_SECONDARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, full_path_backup_dir); 02351 if (res != PAL_SUCCESS) 02352 { 02353 tr_err("esfs_close() - pal_fsGetMountPoint() for backup directory failed with pal_status = 0x%x", (unsigned int)res); 02354 result = ESFS_ERROR; 02355 goto errorExit; 02356 } 02357 02358 strncat(full_path_backup_dir, "/" ESFS_BACKUP_DIRECTORY "/", sizeof(ESFS_BACKUP_DIRECTORY) + 1); 02359 02360 strncat(full_path_working_dir, esfs_short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH -1); 02361 strncat(full_path_backup_dir, esfs_short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1); 02362 02363 if (esfs_copy_file(full_path_backup_dir, full_path_working_dir) != ESFS_SUCCESS) 02364 { 02365 tr_err("esfs_close() - esfs_copy_file() failed"); 02366 goto errorExit; 02367 } 02368 } 02369 02370 return ESFS_SUCCESS; 02371 errorExit: 02372 return result; 02373 } 02374 02375 esfs_result_e esfs_delete(const uint8_t *name, size_t name_length) 02376 { 02377 02378 palStatus_t pal_result = PAL_SUCCESS; 02379 char working_dir_path[MAX_FULL_PATH_SIZE] = { 0 }; 02380 char short_file_name[ESFS_QUALIFIED_FILE_NAME_LENGTH]; 02381 esfs_result_e result = ESFS_ERROR; 02382 02383 tr_info("esfs_delete - enter"); 02384 // Check parameters 02385 if(!name || name_length == 0) 02386 { 02387 tr_err("esfs_delete() failed with bad parameters"); 02388 result = ESFS_INVALID_PARAMETER; 02389 goto errorExit; 02390 } 02391 if(esfs_get_name_from_blob(name, name_length, short_file_name, ESFS_FILE_NAME_LENGTH ) != ESFS_SUCCESS) 02392 { 02393 tr_err("esfs_delete() - esfs_get_name_from_blob() failed"); 02394 goto errorExit; 02395 } 02396 tr_info("esfs_delete %s", short_file_name); 02397 02398 pal_result = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, PAL_MAX_FOLDER_DEPTH_CHAR + 1, working_dir_path); 02399 if (pal_result != PAL_SUCCESS) 02400 { 02401 tr_err("esfs_delete() - pal_fsGetMountPoint() for working directory failed with pal_status = 0x%x", (unsigned int)pal_result); 02402 result = ESFS_ERROR; 02403 goto errorExit; 02404 } 02405 02406 strncat(working_dir_path, "/" ESFS_WORKING_DIRECTORY "/", sizeof(ESFS_WORKING_DIRECTORY) + 1); 02407 02408 // We do not verify that name is the actual name in the file because currently we do not allow the situation of hash 02409 // clash to arise. 02410 02411 strncat(working_dir_path,short_file_name, ESFS_QUALIFIED_FILE_NAME_LENGTH - 1); 02412 02413 tr_info("esfs_delete %s", working_dir_path); 02414 pal_result = pal_fsUnlink(working_dir_path); 02415 02416 if ((pal_result == PAL_ERR_FS_NO_FILE) || (pal_result == PAL_ERR_FS_NO_PATH)) 02417 { 02418 tr_err("esfs_delete() - pal_fsUnlink() failed with pal status 0x%x", (unsigned int)pal_result); 02419 result = ESFS_NOT_EXISTS; 02420 goto errorExit; 02421 } 02422 else if (pal_result != PAL_SUCCESS) 02423 { 02424 tr_err("esfs_delete() - pal_fsUnlink() failed with pal status 0x%x", (unsigned int)pal_result); 02425 goto errorExit; 02426 } 02427 02428 return ESFS_SUCCESS; 02429 errorExit: 02430 return result; 02431 } 02432 02433 esfs_result_e esfs_get_meta_data_properties(esfs_file_t *file_handle, esfs_tlv_properties_t **meta_data_properties) 02434 { 02435 esfs_result_e result = ESFS_ERROR; 02436 tr_info("esfs_get_meta_data_properties - enter"); 02437 if((esfs_validate(file_handle) != ESFS_SUCCESS) || (!meta_data_properties)) 02438 { 02439 tr_err("esfs_get_meta_data_properties() failed with bad parameters"); 02440 result = ESFS_INVALID_PARAMETER; 02441 goto errorExit; 02442 } 02443 02444 if (file_handle->file_flag != ESFS_READ) 02445 { 02446 tr_err("esfs_get_meta_data_properties() failed - file is opened for write only"); 02447 result = ESFS_FILE_OPEN_FOR_WRITE; 02448 goto errorExit; 02449 } 02450 02451 *meta_data_properties = &file_handle->tlv_properties; 02452 return ESFS_SUCCESS; 02453 errorExit: 02454 return result; 02455 } 02456 02457 02458 esfs_result_e esfs_read_meta_data(esfs_file_t *file_handle, uint32_t index, esfs_tlv_item_t *meta_data) 02459 { 02460 esfs_result_e result = ESFS_ERROR; 02461 bool is_read_error = false; 02462 uint16_t cmac_created = 0; 02463 int32_t offset_to_restore = 0; 02464 palStatus_t res = PAL_SUCCESS; 02465 02466 tr_info("esfs_read_meta_data - enter"); 02467 if(esfs_validate(file_handle) != ESFS_SUCCESS || index >= ESFS_MAX_TYPE_LENGTH_VALUES || !meta_data || (file_handle->tlv_properties.tlv_items[index].length_in_bytes == 0)) 02468 { 02469 tr_err("esfs_read_meta_data() failed with bad parameters"); 02470 result = ESFS_INVALID_PARAMETER; 02471 goto errorExit; 02472 } 02473 02474 if(file_handle->file_flag != ESFS_READ) 02475 { 02476 tr_err("esfs_read_meta_data() failed - file is opened for write only"); 02477 result = ESFS_FILE_OPEN_FOR_WRITE; 02478 goto errorExit; 02479 } 02480 // Get current file position 02481 int32_t current_pos; 02482 res = pal_fsFtell(&file_handle->file, ¤t_pos); 02483 if(res != PAL_SUCCESS) 02484 { 02485 tr_err("esfs_read_meta_data() - pal_fsFtell() failed with pal status 0x%x", (unsigned int)res); 02486 goto errorExit; 02487 } 02488 02489 // Start the cmac calculation and position to the start of the file 02490 if(esfs_cmac_start(file_handle) != ESFS_SUCCESS) 02491 { 02492 goto errorExit; 02493 } 02494 cmac_created = 1; 02495 02496 // Skip to the meta-data position while calculating the cmac 02497 if(esfs_cmac_skip_to(file_handle, file_handle->tlv_properties.tlv_items[index].position) != ESFS_SUCCESS) 02498 { 02499 tr_err("esfs_read_meta_data() - pal_fsFseek() failed with pal status 0x%x", (unsigned int)res); 02500 goto errorExit; 02501 } 02502 02503 // Read data 02504 // If required according to esfs_mode, the read data will be decrypted 02505 size_t num_bytes; 02506 if((file_handle->esfs_mode & ESFS_ENCRYPTED) != 0) 02507 { 02508 if(esfs_read_and_decrypt( file_handle, 02509 meta_data->value, 02510 file_handle->tlv_properties.tlv_items[index].length_in_bytes, 02511 &num_bytes 02512 ) != ESFS_SUCCESS) 02513 { 02514 is_read_error = true; 02515 } 02516 } 02517 else 02518 { 02519 if(esfs_cmac_read(file_handle, meta_data->value, file_handle->tlv_properties.tlv_items[index].length_in_bytes, &num_bytes ) != ESFS_SUCCESS) 02520 { 02521 is_read_error = true; 02522 } 02523 } 02524 02525 if(is_read_error || (num_bytes != file_handle->tlv_properties.tlv_items[index].length_in_bytes)) 02526 { 02527 tr_err("esfs_read_meta_data() - read data failed is_read_error = %s and num_bytes = %zu", 02528 is_read_error ? "true" : "false", num_bytes); 02529 goto errorExit; 02530 } 02531 02532 // Skip to the end of the data section of the file. 02533 if(esfs_cmac_skip_to(file_handle ,file_handle->file_size - ESFS_CMAC_SIZE_IN_BYTES) != ESFS_SUCCESS) 02534 { 02535 goto errorExit; 02536 } 02537 02538 // Return the cmac 02539 unsigned char cmac[ESFS_CMAC_SIZE_IN_BYTES]; 02540 if(esfs_cmac_finish(file_handle, &cmac[0]) != ESFS_SUCCESS) 02541 { 02542 tr_err("esfs_read() - esfs_finish_cmac() failed"); 02543 goto errorExit; 02544 } 02545 cmac_created = 0; 02546 02547 // Before restoring old position, make sure offset_to_restore is not a negative number 02548 offset_to_restore = current_pos; 02549 if(offset_to_restore < 0) 02550 { 02551 tr_err("esfs_read_meta_data() failed - current_pos is negative"); 02552 goto errorExit; 02553 } 02554 02555 // Check the cmac and restore the file position to the saved position 02556 if(esfs_cmac_check_and_restore(file_handle, &cmac[0], offset_to_restore) != ESFS_SUCCESS) 02557 { 02558 tr_err("esfs_read_meta_data() - cmac that we read from the file does not match the one that we calculated"); 02559 result = ESFS_CMAC_DOES_NOT_MATCH; 02560 goto errorExit; 02561 } 02562 02563 // Update meta_data fields 02564 meta_data->type = file_handle->tlv_properties.tlv_items[index].type; 02565 meta_data->length_in_bytes = file_handle->tlv_properties.tlv_items[index].length_in_bytes; 02566 02567 return ESFS_SUCCESS; 02568 02569 errorExit: 02570 if(cmac_created) 02571 { 02572 // Clean up cmac. Ignore error. 02573 (void)esfs_cmac_finish(file_handle, &cmac[0]); 02574 } 02575 return result; 02576 }
Generated on Mon Aug 29 2022 19:53:39 by
