Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers FileSecurityDb.cpp Source File

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  &ltk
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(&ltk, 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  &ltk
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(&ltk, 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 */