Browse Source

Add platformIO files and adapt file structure

pull/3/head
Patrick Rathje 10 months ago
parent
commit
760ceca785
  1. 46
      .gitignore
  2. 13
      CMakeLists.txt
  3. 0
      include/tls_config/user-tls.conf
  4. 46
      lib/README
  5. 52
      lib/exposure-notification/examples/tracking.c
  6. 0
      lib/exposure-notification/include/exposure-notification.h
  7. 14
      lib/exposure-notification/library.json
  8. 15
      lib/exposure-notification/src/exposure-notification.c
  9. 36
      platformio.ini
  10. 11
      test/README
  11. 222
      test/test_common/test_common.cpp
  12. 6
      zephyr/CMakeLists.txt
  13. 2
      zephyr/prj.conf

46
.gitignore

@ -1 +1,47 @@
build/
# Random seed file created by test scripts and sample programs
seedfile
# CMake build artifacts:
CMakeCache.txt
CMakeFiles
CTestTestfile.cmake
cmake_install.cmake
Testing
# CMake generates *.dir/ folders for in-tree builds (used by MSVC projects), ignore all of those:
*.dir/
# MSVC files generated by CMake:
/*.sln
/*.vcxproj
/*.filters
# Test coverage build artifacts:
Coverage
*.gcno
*.gcda
# generated by scripts/memory.sh
massif-*
# MSVC build artifacts:
*.exe
*.pdb
*.ilk
*.lib
# Python build artifacts:
*.pyc
# Generated documentation:
/apidoc
# Editor navigation files:
/GPATH
/GRTAGS
/GSYMS
/GTAGS
/TAGS
/tags
.pio
.vscode

13
CMakeLists.txt

@ -1,13 +0,0 @@
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.13.1)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(bluecovid)
target_sources(app PRIVATE src/main.c src/contacts.c src/exposure-notification.c src/gatt-service.c src/covid.c)
zephyr_include_directories(${APPLICATION_SOURCE_DIR}/src/tls_config)
#use for testing only, will update keys every X seconds, default is 600
#add_definitions(-DEN_INTERVAL_LENGTH=11)
#add_definitions(-DEN_INTERVAL_LENGTH=1)

0
src/tls_config/user-tls.conf → include/tls_config/user-tls.conf

46
lib/README

@ -0,0 +1,46 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in a an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

52
lib/exposure-notification/examples/tracking.c

@ -0,0 +1,52 @@
#include "exposure-notification.h"
#include "time.h"
int main(int argc, char **argv) {
// first init everything
// TODO: More randomization, we init with NULL to let en init mbdet entropy for us
en_init(NULL);
// get the currentTime
time_t currentTime = time(NULL);
// The periodKey changes each EN_TEK_ROLLING_PERIOD intervals
ENIntervalNumber periodInterval = en_get_interval_number_at_period_start(currentTime);
ENPeriodKey periodKey;
ENPeriodIdentifierKey periodIdentifierKey;
ENPeriodMetadataEncryptionKey periodMetadaEncryptionKey;
// setup period keys at the beginning
// in theory you could let them generate automatically setting periodInterval to 0
en_generate_and_derive_period_keys(&periodKey, &periodIdentifierKey, &periodMetadaEncryptionKey);
char metadata[128] = "";
while(1) {
// we check the current time to know if we actually need to regenerate anything
currentTime = time(NULL);
ENIntervalNumber currentInterval = en_get_interval_number(currentTime);
// we check if we need to generate new keys
if (currentInterval - periodInterval >= EN_TEK_ROLLING_PERIOD) {
periodInterval = en_get_interval_number_at_period_start(currentTime);
en_generate_and_derive_period_keys(&periodKey, &periodIdentifierKey, &periodMetadaEncryptionKey);
// TODO: Store new periodKey with periodInterval
}
// we now generate the new interval identifier and re-encrypt the metadata
ENIntervalIdentifier intervalIdentifier;
en_derive_interval_identifier(&intervalIdentifier, &periodIdentifierKey, currentInterval);
char encryptedMetadata[sizeof(metadata)];
en_encrypt_interval_metadata(&periodMetadaEncryptionKey, &intervalIdentifier, metadata, encryptedMetadata, sizeof(metadata));
// broadcast intervalIdentifier plus encryptedMetada according to specs
// TODO: receive packets and store them
// repeat for 10-20 minutes
}
return 0;
}

0
src/exposure-notification.h → lib/exposure-notification/include/exposure-notification.h

14
lib/exposure-notification/library.json

@ -0,0 +1,14 @@
{
"description": "exposure-notification",
"frameworks": "*",
"keywords": "exposure, notification, contact, tracking, tracing",
"name": "exposure-notification",
"platforms": "*",
"version": "0.1",
"dependencies": [
{
"name": "mbedtls",
"version": "^2.16.4"
}
]
}

15
src/exposure-notification.c → lib/exposure-notification/src/exposure-notification.c

@ -4,22 +4,27 @@
* SPDX-License-Identifier: Apache-2.0
*/
#if EN_INCLUDE_ZEPHYR_DEPS
#include <zephyr.h>
#include <zephyr/types.h>
#include <stddef.h>
#include <sys/printk.h>
#include <sys/util.h>
#endif
#include <string.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/hkdf.h>
#include <mbedtls/sha256.h>
#include <mbedtls/aes.h>
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/hkdf.h"
#include "mbedtls/sha256.h"
#include "mbedtls/aes.h"
#include "exposure-notification.h"
static mbedtls_ctr_drbg_context ctr_drbg;
static ENRandomBytesCallback random_bytes_callback = NULL;

36
platformio.ini

@ -0,0 +1,36 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:nrf52840_dk]
platform = nordicnrf52
board = nrf52840_dk
framework = zephyr
monitor_speed = 115200
test_ignore = test_desktop
build_flags =
-Iinclude/tls_config
# For testing: -DUNITY_EXCLUDE_SETJMP_H=1
-DEN_INCLUDE_ZEPHYR_DEPS=1
-DEN_INIT_MBEDTLS_ENTROPY=0
lib_deps = exposure-notification
[env:desktop]
platform = native
test_ignore = test_embedded
lib_compat_mode = off
lib_deps = mbedtls@~2
build_flags =
-Iinclude/desktop
-Iinclude/tls_config
-Wno-nullability-completeness
-DMBEDTLS_USER_CONFIG_FILE='"user-tls.conf"'
src_filter = --<.src/>

11
test/README

@ -0,0 +1,11 @@
This directory is intended for PIO Unit Testing and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PIO Unit Testing:
- https://docs.platformio.org/page/plus/unit-testing.html

222
test/test_common/test_common.cpp

@ -0,0 +1,222 @@
#include <unity.h>
#include <string.h>
#include "exposure-notification.h"
#define TEST_ASSERT_EQUAL_KEY(k1, k2) TEST_ASSERT_EQUAL(0, memcmp(k1.b, k2.b, sizeof(k1.b)))
#define TEST_ASSERT_NOT_EQUAL_KEY(k1, k2) TEST_ASSERT_NOT_EQUAL(0, memcmp(k1.b, k2.b, sizeof(k1.b)))
void test_init(void) {
int ret = en_init(NULL);
TEST_ASSERT_EQUAL(0, ret);
}
void test_get_interval_number(void) {
TEST_ASSERT_EQUAL(0, en_get_interval_number(0));
TEST_ASSERT_EQUAL(0, en_get_interval_number(EN_INTERVAL_LENGTH-1));
TEST_ASSERT_EQUAL(1, en_get_interval_number(EN_INTERVAL_LENGTH));
TEST_ASSERT_EQUAL(42, en_get_interval_number(EN_INTERVAL_LENGTH*42));
}
void test_get_interval_number_at_period_start(void) {
TEST_ASSERT_EQUAL(0, en_get_interval_number_at_period_start(0));
TEST_ASSERT_EQUAL(0, en_get_interval_number_at_period_start(EN_INTERVAL_LENGTH-1));
TEST_ASSERT_EQUAL(0, en_get_interval_number_at_period_start(EN_INTERVAL_LENGTH));
TEST_ASSERT_EQUAL(0, en_get_interval_number_at_period_start(EN_INTERVAL_LENGTH*42));
TEST_ASSERT_EQUAL(EN_TEK_ROLLING_PERIOD, en_get_interval_number_at_period_start(EN_INTERVAL_LENGTH*EN_TEK_ROLLING_PERIOD));
TEST_ASSERT_EQUAL(EN_TEK_ROLLING_PERIOD, en_get_interval_number_at_period_start(EN_INTERVAL_LENGTH*EN_TEK_ROLLING_PERIOD+1));
}
void test_generate_period_key(void) {
ENPeriodKey p1, p2;
en_generate_period_key(&p1);
en_generate_period_key(&p2);
// yes there is a minimal chance that both are the same ;)
TEST_ASSERT_NOT_EQUAL_KEY(p1, p2);
}
void test_get_period_identifier_key(void) {
ENPeriodKey pk;
en_generate_period_key(&pk);
ENPeriodIdentifierKey k1, k2;
en_derive_period_identifier_key(&k1, &pk);
en_derive_period_identifier_key(&k2, &pk);
// This time both should be the same key as the depent on the period key
TEST_ASSERT_EQUAL_KEY(k1, k2);
// BUT: they should be different than the period key itself
TEST_ASSERT_NOT_EQUAL_KEY(k1, pk);
}
void test_get_interval_identifier(void) {
ENPeriodKey pk;
en_generate_period_key(&pk);
ENIntervalNumber iv = en_get_interval_number(0);
ENIntervalIdentifier id1, id2;
en_derive_interval_identifier(&id1, &pk, iv);
en_derive_interval_identifier(&id2, &pk, iv);
// identities should be the same for the same intervalnumber and period key
TEST_ASSERT_EQUAL_KEY(id1, id2);
iv = en_get_interval_number(EN_INTERVAL_LENGTH);
en_derive_interval_identifier(&id2, &pk, iv);
// BUT: they should be different when we are using another interval number
TEST_ASSERT_NOT_EQUAL_KEY(id1, id2);
// They should also be different for another period key but the the same interval number
en_generate_period_key(&pk);
en_derive_interval_identifier(&id1, &pk, iv);
en_generate_period_key(&pk);
en_derive_interval_identifier(&id2, &pk, iv);
TEST_ASSERT_NOT_EQUAL_KEY(id1, id2);
}
void test_get_period_metadata_encryption_key(void) {
ENPeriodKey pk;
en_generate_period_key(&pk);
ENPeriodMetadataEncryptionKey k1, k2;
en_derive_period_metadata_encryption_key(&k1, &pk);
en_derive_period_metadata_encryption_key(&k2, &pk);
// This time both should be the same key as the depent on the period key
TEST_ASSERT_EQUAL_KEY(k1, k2);
// BUT: they should be different than the period key itself
TEST_ASSERT_NOT_EQUAL_KEY(k1, pk);
// and they should also be different than the periodIdentifierKey
ENPeriodIdentifierKey pik;
en_derive_period_identifier_key(&pik, &pk);
TEST_ASSERT_NOT_EQUAL_KEY(k1, pik);
}
void test_en_encrypt_interval_metadata(void) {
ENPeriodKey pk;
en_generate_period_key(&pk);
ENPeriodMetadataEncryptionKey k1;
en_derive_period_metadata_encryption_key(&k1, &pk);
ENIntervalNumber iv = en_get_interval_number(0);
ENIntervalIdentifier id;
en_derive_interval_identifier(&id, &pk, iv);
unsigned char testData[42] = "This is some test data :)";
unsigned char encryptedData[42] = "";
en_encrypt_interval_metadata(&k1, &id, testData, encryptedData, sizeof(testData));
// the original data should not be changed
TEST_ASSERT_EQUAL_CHAR_ARRAY("This is some test data :)", testData, sizeof("This is some test data :)")-1);
// but the encrypted one should be changed
TEST_ASSERT_NOT_EQUAL(0, memcmp(testData, encryptedData, sizeof(testData)));
unsigned char decryptedData[42] = "";
en_decrypt_interval_metadata(&k1, &id, encryptedData, decryptedData, sizeof(testData));
// the decrypted metadata should be the same as the testData
TEST_ASSERT_EQUAL_CHAR_ARRAY(testData, decryptedData, sizeof(testData));
}
void test_identifier_generation_performance(void) {
int runs = 1000000;
for(int i = 0; i < runs; i++) {
ENPeriodKey pk;
en_generate_period_key(&pk);
ENPeriodIdentifierKey ik;
en_derive_period_identifier_key(&ik, &pk);
for(int iv = 0; iv < EN_TEK_ROLLING_PERIOD; iv++) {
ENIntervalNumber intervalNumber = en_get_interval_number(iv);
ENIntervalIdentifier id;
en_derive_interval_identifier(&id, &ik, intervalNumber);
}
}
}
void test_generate_and_derive_period_keys(void) {
// Test multiple generation
ENPeriodKey periodKey;
ENPeriodIdentifierKey periodIdentifierKey;
ENPeriodMetadataEncryptionKey periodMetadaEncryptionKey;
for(int i = 0; i < 10; i++) {
en_generate_and_derive_period_keys(&periodKey, &periodIdentifierKey, &periodMetadaEncryptionKey);
}
}
void test_against_fixtures(void) {
// First define base values
ENIntervalNumber intervalNumber = 2642976;
ENPeriodKey periodKey = {.b = {0x75, 0xc7, 0x34, 0xc6, 0xdd, 0x1a, 0x78, 0x2d, 0xe7, 0xa9, 0x65, 0xda, 0x5e, 0xb9, 0x31, 0x25}};
unsigned char metadata[4] = {0x40, 0x08, 0x00, 0x00};
// define the expected values
ENPeriodIdentifierKey expectedPIK = {.b = {0x18, 0x5a, 0xd9, 0x1d, 0xb6, 0x9e, 0xc7, 0xdd, 0x04, 0x89, 0x60, 0xf1, 0xf3, 0xba, 0x61, 0x75}};
ENPeriodMetadataEncryptionKey expectedPMEK = {.b = {0xd5, 0x7c, 0x46, 0xaf, 0x7a, 0x1d, 0x83, 0x96, 0x5b, 0x9b, 0xed, 0x8b, 0xd1, 0x52, 0x93, 0x6a}};
ENIntervalIdentifier expectedIntervalIdentifier = {.b = {0x8b, 0xe6, 0xcd, 0x37, 0x1c, 0x5c, 0x89, 0x16, 0x04, 0xbf, 0xbe, 0x49, 0xdf, 0x84, 0x50, 0x96}};
unsigned char expectedEncryptedMetadata[4] = {0x72, 0x03, 0x38, 0x74};
ENPeriodIdentifierKey pik;
en_derive_period_identifier_key(&pik, &periodKey);
TEST_ASSERT_EQUAL_KEY(expectedPIK, pik);
ENPeriodMetadataEncryptionKey pmek;
en_derive_period_metadata_encryption_key(&pmek, &periodKey);
TEST_ASSERT_EQUAL_KEY(expectedPMEK, pmek);
ENIntervalIdentifier intervalIdentifier;
en_derive_interval_identifier(&intervalIdentifier, &pik, intervalNumber);
TEST_ASSERT_EQUAL_KEY(expectedIntervalIdentifier, intervalIdentifier);
unsigned char encryptedMetadata[sizeof(metadata)] = {0};
en_encrypt_interval_metadata(&pmek, &intervalIdentifier, metadata, encryptedMetadata, sizeof(metadata));
TEST_ASSERT_EQUAL_CHAR_ARRAY(expectedEncryptedMetadata, encryptedMetadata, sizeof(expectedEncryptedMetadata));
}
void test_exposure_notification() {
UNITY_BEGIN();
RUN_TEST(test_init);
RUN_TEST(test_get_interval_number);
RUN_TEST(test_get_interval_number_at_period_start);
RUN_TEST(test_generate_period_key);
RUN_TEST(test_get_period_identifier_key);
RUN_TEST(test_get_interval_identifier);
RUN_TEST(test_get_period_metadata_encryption_key);
RUN_TEST(test_en_encrypt_interval_metadata);
RUN_TEST(test_generate_and_derive_period_keys);
RUN_TEST(test_against_fixtures);
//RUN_TEST(test_identifier_generation_performance);
UNITY_END();
}
int main(int argc, char **argv) {
test_exposure_notification();
return 0;
}

6
zephyr/CMakeLists.txt

@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.13.1)
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
project(test)
FILE(GLOB app_sources ../src/*.c*)
target_sources(app PRIVATE ${app_sources})

2
prj.conf → zephyr/prj.conf

@ -8,8 +8,6 @@ CONFIG_BT_DEVICE_NAME="BlueCovid"
CONFIG_ENTROPY_GENERATOR=y
CONFIG_MBEDTLS=y
#CONFIG_MBEDTLS_USER_CONFIG_ENABLE=y
#CONFIG_MBEDTLS_CFG_FILE="mbedtls_config.h"
CONFIG_MBEDTLS_USER_CONFIG_ENABLE=y
CONFIG_MBEDTLS_USER_CONFIG_FILE="user-tls.conf"
Loading…
Cancel
Save