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.
Dependencies: FXAS21002 FXOS8700Q
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 Tue Jul 12 2022 20:20:59 by
