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.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
FileSecurityDb.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2018 ARM Limited 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may 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, 00012 * WITHOUT 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 #include "FileSecurityDb.h" 00018 00019 namespace ble { 00020 namespace generic { 00021 00022 const uint16_t DB_VERSION = 1; 00023 00024 #define DB_STORE_OFFSET_FLAGS (0) 00025 #define DB_STORE_OFFSET_LOCAL_KEYS (DB_STORE_OFFSET_FLAGS + sizeof(SecurityDistributionFlags_t)) 00026 #define DB_STORE_OFFSET_PEER_KEYS (DB_STORE_OFFSET_LOCAL_KEYS + sizeof(SecurityEntryKeys_t)) 00027 #define DB_STORE_OFFSET_PEER_IDENTITY (DB_STORE_OFFSET_PEER_KEYS + sizeof(SecurityEntryKeys_t)) 00028 #define DB_STORE_OFFSET_PEER_SIGNING (DB_STORE_OFFSET_PEER_IDENTITY + sizeof(SecurityEntryIdentity_t)) 00029 00030 #define DB_STORE_OFFSET_LOCAL_KEYS_LTK (DB_STORE_OFFSET_LOCAL_KEYS) 00031 #define DB_STORE_OFFSET_LOCAL_KEYS_EDIV (DB_STORE_OFFSET_LOCAL_KEYS_LTK + sizeof(ltk_t)) 00032 #define DB_STORE_OFFSET_LOCAL_KEYS_RAND (DB_STORE_OFFSET_LOCAL_KEYS_EDIV + sizeof(ediv_t)) 00033 00034 #define DB_STORE_OFFSET_PEER_KEYS_LTK (DB_STORE_OFFSET_PEER_KEYS) 00035 #define DB_STORE_OFFSET_PEER_KEYS_EDIV (DB_STORE_OFFSET_PEER_KEYS_LTK + sizeof(ltk_t)) 00036 #define DB_STORE_OFFSET_PEER_KEYS_RAND (DB_STORE_OFFSET_PEER_KEYS_EDIV + sizeof(ediv_t)) 00037 00038 #define DB_STORE_OFFSET_PEER_IDENTITY_ADDRESS (DB_STORE_OFFSET_PEER_IDENTITY) 00039 #define DB_STORE_OFFSET_PEER_IDENTITY_IRK (DB_STORE_OFFSET_PEER_IDENTITY + sizeof(address_t)) 00040 #define DB_STORE_OFFSET_PEER_IDENTITY_ADDRESS_IS_PUBLIC (DB_STORE_OFFSET_PEER_IDENTITY_IRK + sizeof(irk_t)) 00041 00042 #define DB_STORE_OFFSET_PEER_SIGNING_COUNT (DB_STORE_OFFSET_PEER_SIGNING + sizeof(csrk_t)) 00043 00044 /* make size multiple of 4 */ 00045 #define PAD4(value) ((((value - 1) / 4) * 4) + 4) 00046 00047 #define DB_SIZE_STORE \ 00048 PAD4( \ 00049 sizeof(SecurityDistributionFlags_t) + \ 00050 sizeof(SecurityEntryKeys_t) + \ 00051 sizeof(SecurityEntryKeys_t) + \ 00052 sizeof(SecurityEntryIdentity_t) + \ 00053 sizeof(SecurityEntrySigning_t) \ 00054 ) 00055 00056 #define DB_SIZE_STORES \ 00057 (FileSecurityDb::MAX_ENTRIES * DB_SIZE_STORE) 00058 00059 #define DB_OFFSET_VERSION (0) 00060 #define DB_OFFSET_RESTORE (DB_OFFSET_VERSION + sizeof(DB_VERSION)) 00061 #define DB_OFFSET_LOCAL_IDENTITY (DB_OFFSET_RESTORE + sizeof(bool)) 00062 #define DB_OFFSET_LOCAL_CSRK (DB_OFFSET_LOCAL_IDENTITY + sizeof(SecurityEntryIdentity_t)) 00063 #define DB_OFFSET_LOCAL_SIGN_COUNT (DB_OFFSET_LOCAL_CSRK + sizeof(csrk_t)) 00064 #define DB_OFFSET_STORES (DB_OFFSET_LOCAL_SIGN_COUNT + sizeof(sign_count_t)) 00065 #define DB_OFFSET_MAX (DB_OFFSET_STORES + DB_SIZE_STORES) 00066 #define DB_SIZE PAD4(DB_OFFSET_MAX) 00067 00068 typedef SecurityDb::entry_handle_t entry_handle_t; 00069 00070 FileSecurityDb::FileSecurityDb(FILE *db_file) 00071 : SecurityDb(), 00072 _db_file(db_file) { 00073 /* init the offset in entries so they point to file positions */ 00074 for (size_t i = 0; i < get_entry_count(); i++) { 00075 _entries[i].file_offset = DB_OFFSET_STORES + i * DB_SIZE_STORE; 00076 } 00077 } 00078 00079 FileSecurityDb::~FileSecurityDb() { 00080 fclose(_db_file); 00081 } 00082 00083 FILE* FileSecurityDb::open_db_file(const char *db_path) { 00084 if (!db_path) { 00085 return NULL; 00086 } 00087 00088 /* try to open an existing file */ 00089 FILE *db_file = fopen(db_path, "rb+"); 00090 00091 if (!db_file) { 00092 /* file doesn't exist, create it */ 00093 db_file = fopen(db_path, "wb+"); 00094 } 00095 00096 if (!db_file) { 00097 /* failed to create a file, abort */ 00098 return NULL; 00099 } 00100 00101 /* we will check the db file and if the version or size doesn't match 00102 * what we expect we will blank it */ 00103 bool init = false; 00104 uint16_t version; 00105 00106 fseek(db_file, DB_OFFSET_VERSION, SEEK_SET); 00107 00108 if ((fread(&version, sizeof(version), 1, db_file) == 1) && 00109 (version == DB_VERSION)) { 00110 /* if file size differs from database size init the file */ 00111 fseek(db_file, 0, SEEK_END); 00112 if (ftell(db_file) != DB_SIZE) { 00113 init = true; 00114 } 00115 } else { 00116 init = true; 00117 } 00118 00119 if (init) { 00120 return erase_db_file(db_file); 00121 } 00122 00123 return db_file; 00124 } 00125 00126 FILE* FileSecurityDb::erase_db_file(FILE* db_file) { 00127 fseek(db_file, 0, SEEK_SET); 00128 00129 /* zero the file */ 00130 const uint32_t zero = 0; 00131 size_t count = DB_SIZE / 4; 00132 while (count--) { 00133 if (fwrite(&zero, sizeof(zero), 1, db_file) != 1) { 00134 fclose(db_file); 00135 return NULL; 00136 } 00137 } 00138 00139 if (fflush(db_file)) { 00140 fclose(db_file); 00141 return NULL; 00142 } 00143 00144 return db_file; 00145 } 00146 00147 SecurityDistributionFlags_t* FileSecurityDb::get_distribution_flags( 00148 entry_handle_t db_handle 00149 ) { 00150 return reinterpret_cast<SecurityDistributionFlags_t*>(db_handle); 00151 } 00152 00153 /* local keys */ 00154 00155 /* set */ 00156 void FileSecurityDb::set_entry_local_ltk( 00157 entry_handle_t db_handle, 00158 const ltk_t <k 00159 ) { 00160 entry_t *entry = as_entry(db_handle); 00161 if (!entry) { 00162 return; 00163 } 00164 00165 entry->flags.ltk_sent = true; 00166 00167 db_write(<k, entry->file_offset + DB_STORE_OFFSET_LOCAL_KEYS_LTK); 00168 } 00169 00170 void FileSecurityDb::set_entry_local_ediv_rand( 00171 entry_handle_t db_handle, 00172 const ediv_t &ediv, 00173 const rand_t &rand 00174 ) { 00175 entry_t *entry = as_entry(db_handle); 00176 if (!entry) { 00177 return; 00178 } 00179 00180 db_write(&ediv, entry->file_offset + DB_STORE_OFFSET_LOCAL_KEYS_EDIV); 00181 db_write(&rand, entry->file_offset + DB_STORE_OFFSET_LOCAL_KEYS_RAND); 00182 } 00183 00184 /* peer's keys */ 00185 00186 /* set */ 00187 00188 void FileSecurityDb::set_entry_peer_ltk( 00189 entry_handle_t db_handle, 00190 const ltk_t <k 00191 ) { 00192 entry_t *entry = as_entry(db_handle); 00193 if (!entry) { 00194 return; 00195 } 00196 00197 entry->flags.ltk_stored = true; 00198 00199 db_write(<k, entry->file_offset + DB_STORE_OFFSET_PEER_KEYS_LTK); 00200 } 00201 00202 void FileSecurityDb::set_entry_peer_ediv_rand( 00203 entry_handle_t db_handle, 00204 const ediv_t &ediv, 00205 const rand_t &rand 00206 ) { 00207 entry_t *entry = as_entry(db_handle); 00208 if (!entry) { 00209 return; 00210 } 00211 00212 db_write(&ediv, entry->file_offset + DB_STORE_OFFSET_PEER_KEYS_EDIV); 00213 db_write(&rand, entry->file_offset + DB_STORE_OFFSET_PEER_KEYS_RAND); 00214 } 00215 00216 void FileSecurityDb::set_entry_peer_irk( 00217 entry_handle_t db_handle, 00218 const irk_t &irk 00219 ) { 00220 entry_t *entry = as_entry(db_handle); 00221 if (!entry) { 00222 return; 00223 } 00224 00225 entry->flags.irk_stored = true; 00226 00227 db_write(&irk, entry->file_offset + DB_STORE_OFFSET_PEER_IDENTITY_IRK); 00228 } 00229 00230 void FileSecurityDb::set_entry_peer_bdaddr( 00231 entry_handle_t db_handle, 00232 bool address_is_public, 00233 const address_t &peer_address 00234 ) { 00235 entry_t *entry = as_entry(db_handle); 00236 if (!entry) { 00237 return; 00238 } 00239 00240 db_write(&peer_address, entry->file_offset + DB_STORE_OFFSET_PEER_IDENTITY_ADDRESS); 00241 db_write(&address_is_public, entry->file_offset + DB_STORE_OFFSET_PEER_IDENTITY_ADDRESS_IS_PUBLIC); 00242 } 00243 00244 void FileSecurityDb::set_entry_peer_csrk( 00245 entry_handle_t db_handle, 00246 const csrk_t &csrk 00247 ) { 00248 entry_t *entry = as_entry(db_handle); 00249 if (!entry) { 00250 return; 00251 } 00252 00253 entry->flags.csrk_stored = true; 00254 00255 db_write(&csrk, entry->file_offset + DB_STORE_OFFSET_PEER_SIGNING); 00256 } 00257 00258 void FileSecurityDb::set_entry_peer_sign_counter( 00259 entry_handle_t db_handle, 00260 sign_count_t sign_counter 00261 ) { 00262 entry_t *entry = as_entry(db_handle); 00263 if (entry) { 00264 entry->peer_sign_counter = sign_counter; 00265 } 00266 } 00267 00268 /* saving and loading from nvm */ 00269 00270 void FileSecurityDb::restore() { 00271 /* restore if requested */ 00272 bool restore_toggle = false; 00273 db_read(&restore_toggle, DB_OFFSET_RESTORE); 00274 00275 if (!restore_toggle) { 00276 erase_db_file(_db_file); 00277 00278 db_write(&DB_VERSION, DB_OFFSET_VERSION); 00279 return; 00280 } 00281 00282 db_read(&_local_identity, DB_OFFSET_LOCAL_IDENTITY); 00283 db_read(&_local_csrk, DB_OFFSET_LOCAL_CSRK); 00284 db_read(&_local_sign_counter, DB_OFFSET_LOCAL_SIGN_COUNT); 00285 00286 /* read flags and sign counters */ 00287 for (size_t i = 0; i < get_entry_count(); i++) { 00288 db_read(&_entries[i].flags, _entries[i].file_offset + DB_STORE_OFFSET_FLAGS); 00289 db_read(&_entries[i].peer_sign_counter, _entries[i].file_offset + DB_STORE_OFFSET_PEER_SIGNING_COUNT); 00290 } 00291 00292 } 00293 00294 void FileSecurityDb::sync(entry_handle_t db_handle) { 00295 entry_t *entry = as_entry(db_handle); 00296 if (!entry) { 00297 return; 00298 } 00299 00300 db_write(&entry->peer_sign_counter, entry->file_offset + DB_STORE_OFFSET_PEER_SIGNING_COUNT); 00301 db_write(&entry->flags, entry->file_offset + DB_STORE_OFFSET_FLAGS); 00302 } 00303 00304 void FileSecurityDb::set_restore(bool reload) { 00305 db_write(&reload, DB_OFFSET_RESTORE); 00306 } 00307 00308 /* helper functions */ 00309 00310 uint8_t FileSecurityDb::get_entry_count() { 00311 return MAX_ENTRIES; 00312 } 00313 00314 SecurityDistributionFlags_t* FileSecurityDb::get_entry_handle_by_index(uint8_t index) { 00315 if (index < MAX_ENTRIES) { 00316 return &_entries[index].flags; 00317 } else { 00318 return NULL; 00319 } 00320 } 00321 00322 void FileSecurityDb::reset_entry(entry_handle_t db_entry) { 00323 entry_t *entry = as_entry(db_entry); 00324 if (!entry) { 00325 return; 00326 } 00327 00328 fseek(_db_file, entry->file_offset, SEEK_SET); 00329 const uint32_t zero = 0; 00330 size_t count = DB_SIZE_STORE / 4; 00331 while (count--) { 00332 fwrite(&zero, sizeof(zero), 1, _db_file); 00333 } 00334 00335 entry->flags = SecurityDistributionFlags_t(); 00336 entry->peer_sign_counter = 0; 00337 } 00338 00339 SecurityEntryIdentity_t* FileSecurityDb::read_in_entry_peer_identity(entry_handle_t db_entry) { 00340 entry_t *entry = as_entry(db_entry); 00341 if (!entry) { 00342 return NULL; 00343 } 00344 00345 SecurityEntryIdentity_t* identity = reinterpret_cast<SecurityEntryIdentity_t*>(_buffer); 00346 db_read(identity, entry->file_offset + DB_STORE_OFFSET_PEER_IDENTITY); 00347 00348 return identity; 00349 }; 00350 00351 SecurityEntryKeys_t* FileSecurityDb::read_in_entry_peer_keys(entry_handle_t db_entry) { 00352 entry_t *entry = as_entry(db_entry); 00353 if (!entry) { 00354 return NULL; 00355 } 00356 00357 SecurityEntryKeys_t* keys = reinterpret_cast<SecurityEntryKeys_t*>(_buffer); 00358 db_read(keys, entry->file_offset + DB_STORE_OFFSET_PEER_KEYS); 00359 00360 return keys; 00361 }; 00362 00363 SecurityEntryKeys_t* FileSecurityDb::read_in_entry_local_keys(entry_handle_t db_entry) { 00364 entry_t *entry = as_entry(db_entry); 00365 if (!entry) { 00366 return NULL; 00367 } 00368 00369 SecurityEntryKeys_t* keys = reinterpret_cast<SecurityEntryKeys_t*>(_buffer); 00370 db_read(keys, entry->file_offset + DB_STORE_OFFSET_LOCAL_KEYS); 00371 00372 return keys; 00373 }; 00374 00375 SecurityEntrySigning_t* FileSecurityDb::read_in_entry_peer_signing(entry_handle_t db_entry) { 00376 entry_t *entry = as_entry(db_entry); 00377 if (!entry) { 00378 return NULL; 00379 } 00380 00381 /* only read in the csrk */ 00382 csrk_t* csrk = reinterpret_cast<csrk_t*>(_buffer); 00383 db_read(csrk, entry->file_offset + DB_STORE_OFFSET_PEER_SIGNING); 00384 00385 00386 /* use the counter held in memory */ 00387 SecurityEntrySigning_t* signing = reinterpret_cast<SecurityEntrySigning_t*>(_buffer); 00388 signing->counter = entry->peer_sign_counter; 00389 00390 return signing; 00391 }; 00392 00393 } /* namespace pal */ 00394 } /* namespace ble */
Generated on Tue Jul 12 2022 13:54:21 by
