├── __init__.py ├── common ├── __init__.py ├── configuration_common.py ├── names.py ├── configuration.py.example ├── stereotype_tags.py ├── configuration.py.iris.example └── packet_log_processor.py ├── tools ├── __init__.py ├── deploy │ ├── __init__.py │ ├── motedev_backend │ │ ├── __init__.py │ │ └── nrf.py │ ├── motelist_backend │ │ └── __init__.py │ ├── term_backend │ │ └── jlink_term.seg │ ├── config_backend │ │ ├── msddisable.seg │ │ └── nrf.py │ ├── motelist.py │ ├── config.py │ ├── motedev.py │ ├── flash_backend │ │ └── nrf.py │ └── flash.py ├── keygen │ ├── __init__.py │ ├── util.py │ ├── keygen.py │ └── contiking_format.py ├── run │ ├── __init__.py │ ├── bad_edge.py │ ├── wsn.py │ ├── profile.py │ └── adversary.py ├── regenerate_pcaps.py ├── fetch_results.py ├── regenerate_pcap.py ├── setup_profile.py └── eckeygen.py ├── analysis ├── __init__.py ├── graph │ ├── __init__.py │ ├── all.sh │ └── challenge_response_perf.py └── parser │ ├── __init__.py │ └── common.py ├── wsn ├── bad_edge │ ├── bad_edge.c │ ├── bad │ │ └── radio-off-driver.h │ └── Makefile ├── common │ ├── float-helpers.h │ ├── mqtt-over-coap │ │ └── mqtt-over-coap.h │ ├── trust │ │ ├── choose │ │ │ ├── trust-choose.h │ │ │ ├── fcfs │ │ │ │ └── trust-choose.c │ │ │ ├── random │ │ │ │ └── trust-choose.c │ │ │ └── highest │ │ │ │ └── trust-choose.c │ │ ├── edge-ping.h │ │ ├── stereotypes │ │ │ ├── device-classes.h │ │ │ ├── stereotype-tags.h │ │ │ └── stereotype-tags.c │ │ ├── trust-common.h │ │ ├── stereotypes.h │ │ ├── interaction-history.h │ │ ├── capability-info.h │ │ ├── interaction-history.c │ │ └── models │ │ │ └── none │ │ │ └── trust-model.h │ ├── nanocbor │ │ ├── Makefile.include │ │ └── config │ │ │ ├── nanocbor-helper.h │ │ │ ├── endian-helper.h │ │ │ └── nanocbor-helper.c │ ├── base16.h │ ├── random-helpers.h │ ├── float-helpers.c │ ├── serial-helpers.h │ ├── base64.h │ ├── root-endpoint.h │ ├── crypto │ │ ├── keystore-oscore.h │ │ ├── static-keys.c.default │ │ ├── keys.h │ │ ├── keystore.h │ │ ├── keystore-oscore.c │ │ ├── certificate.h │ │ └── crypto-support.h │ ├── random-helpers.c │ ├── serial-helpers.c │ ├── eui64.h │ ├── timed-unlock.h │ ├── pcap │ │ └── pcap-loggers.c │ ├── root-endpoint.c │ ├── base16.c │ ├── timed-unlock.c │ └── eui64.c ├── applications │ ├── monitoring │ │ ├── monitoring.h │ │ └── monitoring-info.c │ ├── routing │ │ ├── node │ │ │ └── test │ │ │ │ └── routing-periodic-test.h │ │ ├── routing.h │ │ ├── edge │ │ │ ├── routing-edge.h │ │ │ └── routing.c │ │ └── routing-info.c │ ├── application-serial.h │ ├── challenge-response │ │ ├── edge │ │ │ ├── challenge-response-edge.h │ │ │ └── challenge-response.c │ │ ├── challenge-response.h │ │ └── challenge-response-common.c │ ├── application-common.h │ ├── Makefile.include │ └── applications.h ├── node │ ├── trust │ │ └── trust.h │ ├── project-conf.h │ ├── Makefile │ └── node.c ├── Makefile ├── profile │ ├── project-conf.h │ └── Makefile ├── edge │ ├── Makefile │ ├── project-conf.h │ ├── edge.h │ └── capability │ │ └── capability.h ├── adversary │ ├── attacks │ │ ├── template.c.example │ │ └── radio_off.c │ ├── project-conf.h │ ├── adversary.c │ └── Makefile └── Makefile.common ├── resource_rich ├── __init__.py ├── monitor │ └── __init__.py ├── root │ └── __init__.py └── applications │ ├── __init__.py │ ├── config.py │ ├── monitoring.py │ ├── challenge_response.py │ └── bad_challenge_response.py ├── tests ├── scenarios │ ├── all-good │ │ ├── README.md │ │ ├── root.sh │ │ ├── wsn.sh │ │ ├── setup.sh │ │ ├── edge.sh │ │ └── run.yaml │ ├── throughput-always-good │ │ ├── README.md │ │ ├── root.sh │ │ ├── wsn.sh │ │ ├── setup.sh │ │ ├── edge.sh │ │ └── run.yaml │ ├── throughput-dos-edge │ │ ├── README.md │ │ ├── wsn.sh │ │ ├── root.sh │ │ ├── adversary.sh │ │ ├── edge.sh │ │ ├── setup.sh │ │ └── run.yaml │ ├── routing-always-bad │ │ ├── README.md │ │ ├── root.sh │ │ ├── setup.sh │ │ ├── wsn.sh │ │ ├── edge.sh │ │ └── bad_edge.sh │ ├── routing-periodically-bad │ │ ├── setup.sh │ │ ├── root.sh │ │ ├── README.md │ │ ├── wsn.sh │ │ ├── edge.sh │ │ └── bad_edge.sh │ ├── throughput-periodically-slow │ │ ├── root.sh │ │ ├── wsn.sh │ │ ├── README.md │ │ ├── setup.sh │ │ ├── edge.sh │ │ ├── bad_edge.sh │ │ └── run.yaml │ ├── throughput-routing-always-slow │ │ ├── wsn.sh │ │ ├── root.sh │ │ ├── README.md │ │ ├── setup.sh │ │ ├── edge.sh │ │ ├── bad_edge.sh │ │ └── run.yaml │ └── throughput-power-periodically-off │ │ ├── root.sh │ │ ├── wsn.sh │ │ ├── README.md │ │ ├── edge.sh │ │ ├── bad_edge.sh │ │ ├── setup.sh │ │ └── run.yaml ├── papers │ ├── infocom2021 │ │ ├── setup.sh │ │ ├── root.sh │ │ ├── wsn.sh │ │ ├── edge-always-good.sh │ │ ├── edge-always-bad.sh │ │ ├── edge-unstable.sh │ │ ├── configuration.py │ │ └── README.md │ ├── sac2021 │ │ ├── setup.sh │ │ ├── wsn.sh │ │ ├── root.sh │ │ ├── edge-always-bad.sh │ │ ├── edge-always-good.sh │ │ ├── configuration.py │ │ └── README.md │ └── tiot2022 │ │ ├── wsn.sh │ │ ├── root.sh │ │ ├── adversary-dos.sh │ │ ├── setup.sh │ │ ├── setup-lazy-removal.sh │ │ ├── setup-aggressive-removal.sh │ │ ├── setup-small-buffer.sh │ │ ├── edge-always-good.sh │ │ ├── edge-unstable.sh │ │ ├── edge-always-bad.sh │ │ ├── edge-aggressive-capability-remove.sh │ │ ├── edge-aggressive-unannounce.sh │ │ └── configuration.py ├── run │ ├── root.sh │ ├── wsn.sh │ ├── adversary.sh │ ├── profile.sh │ ├── edge.sh │ └── bad_edge.sh ├── kill-test.sh └── common.sh ├── .gitmodules ├── playbooks ├── stop-experiments.yaml ├── configure-nrf.yaml ├── motelist.yaml ├── deploy.yaml ├── fetch-results.yaml └── setup-root.yaml ├── .gitignore ├── SUPPORT.md └── LICENCE /__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /common/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tools/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /analysis/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wsn/bad_edge/bad_edge.c: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /analysis/graph/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /analysis/parser/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resource_rich/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tools/deploy/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tools/keygen/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resource_rich/monitor/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resource_rich/root/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resource_rich/applications/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tools/deploy/motedev_backend/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tools/deploy/motelist_backend/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tools/deploy/term_backend/jlink_term.seg: -------------------------------------------------------------------------------- 1 | connect 2 | resetx 1000 3 | -------------------------------------------------------------------------------- /tools/deploy/config_backend/msddisable.seg: -------------------------------------------------------------------------------- 1 | connect 2 | msddisable 3 | exit 4 | -------------------------------------------------------------------------------- /tests/scenarios/all-good/README.md: -------------------------------------------------------------------------------- 1 | # All Good 2 | 3 | Edge behaves well for all applications that it runs. 4 | -------------------------------------------------------------------------------- /wsn/common/float-helpers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | bool isclose(float a, float b); 6 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-always-good/README.md: -------------------------------------------------------------------------------- 1 | # All Good 2 | 3 | Edge behaves well for all applications that it runs. 4 | -------------------------------------------------------------------------------- /wsn/bad_edge/bad/radio-off-driver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | void radio_off_driver_set(bool state); 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "wsn/common/nanocbor/repo"] 2 | path = wsn/common/nanocbor/repo 3 | url = https://github.com/MBradbury/NanoCBOR 4 | -------------------------------------------------------------------------------- /resource_rich/applications/config.py: -------------------------------------------------------------------------------- 1 | edge_marker = "!" 2 | application_edge_marker = "@" 3 | serial_sep = "|" 4 | 5 | edge_server_port = 10_000 6 | -------------------------------------------------------------------------------- /wsn/common/mqtt-over-coap/mqtt-over-coap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | bool 4 | mqtt_over_coap_publish(const char* topic, const void* data, size_t data_len); 5 | -------------------------------------------------------------------------------- /wsn/common/trust/choose/trust-choose.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct edge_resource; 4 | 5 | struct edge_resource* choose_edge(const char* capability_name); 6 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-dos-edge/README.md: -------------------------------------------------------------------------------- 1 | # Flooding 2 | 3 | The sensor node floods one of the edge with a large number of messages, realizing a DoS attack. 4 | -------------------------------------------------------------------------------- /tools/run/__init__.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | supported_mote_types = ["zolertia", "nRF52840"] 4 | supported_firmware_types = ["contiki", "riot"] 5 | DEFAULT_LOG_DIR = Path("./logs") 6 | -------------------------------------------------------------------------------- /tests/papers/infocom2021/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | python3 -m tools.setup basic banded \ 3 | --applications challenge-response \ 4 | --target remote-revb \ 5 | --deploy ansible \ 6 | --with-pcap 7 | -------------------------------------------------------------------------------- /tests/papers/sac2021/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | python3 -m tools.setup basic banded \ 3 | --applications monitoring routing \ 4 | --target remote-revb \ 5 | --deploy ansible \ 6 | --with-pcap 7 | -------------------------------------------------------------------------------- /tests/run/root.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.root \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/run/wsn.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.wsn \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /wsn/applications/monitoring/monitoring.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define MONITORING_APPLICATION_NAME "envmon" 4 | #define MONITORING_APPLICATION_URI "envmon" 5 | 6 | void init_trust_weights_monitoring(void); 7 | -------------------------------------------------------------------------------- /wsn/node/trust/trust.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "edge-info.h" 4 | 5 | #include "keys.h" 6 | 7 | #define TRUST_COAP_URI "trust" 8 | #define MAX_TRUST_PAYLOAD (COAP_MAX_CHUNK_SIZE - DTLS_EC_SIG_SIZE) 9 | -------------------------------------------------------------------------------- /wsn/Makefile: -------------------------------------------------------------------------------- 1 | TOPTARGETS := all clean distclean 2 | 3 | SUBDIRS := node edge 4 | 5 | $(TOPTARGETS): $(SUBDIRS) 6 | $(SUBDIRS): 7 | $(MAKE) -C $@ $(MAKECMDGOALS) 8 | 9 | .PHONY: $(TOPTARGETS) $(SUBDIRS) 10 | -------------------------------------------------------------------------------- /tests/papers/sac2021/wsn.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.wsn \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/papers/tiot2022/wsn.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.wsn \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/run/adversary.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.adversary \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/run/profile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.profile \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /wsn/common/nanocbor/Makefile.include: -------------------------------------------------------------------------------- 1 | MODULES_REL += ../common/nanocbor/repo/src ../common/nanocbor/config 2 | CFLAGS += -I../common/nanocbor/repo/include 3 | CFLAGS += -DNANOCBOR_BYTEORDER_HEADER=\"endian-helper.h\" 4 | -------------------------------------------------------------------------------- /tests/papers/infocom2021/root.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.root \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/papers/infocom2021/wsn.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.wsn \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/papers/sac2021/root.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.root \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/papers/tiot2022/root.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.root \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/scenarios/all-good/root.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.root \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/scenarios/all-good/wsn.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.wsn \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/scenarios/routing-always-bad/README.md: -------------------------------------------------------------------------------- 1 | # Routing Always Bad 2 | 3 | In this scenario one edge node (`bad_edge.sh`) always executes the routing application badly and another (`edge.sh`) can always execute it correctly. -------------------------------------------------------------------------------- /wsn/applications/routing/node/test/routing-periodic-test.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef ROUTING_PERIODIC_TEST 4 | #error "Must define ROUTING_PERIODIC_TEST to use" 5 | #endif 6 | 7 | void routing_periodic_test_init(void); 8 | -------------------------------------------------------------------------------- /tests/scenarios/all-good/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | python3 -m tools.setup basic banded \ 3 | --applications routing monitoring challenge-response \ 4 | --target nRF52840DK \ 5 | --deploy ansible \ 6 | --with-pcap 7 | -------------------------------------------------------------------------------- /tests/scenarios/routing-always-bad/root.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.root \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/scenarios/routing-always-bad/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | python3 -m tools.setup basic banded \ 3 | --applications routing monitoring challenge-response \ 4 | --target nRF52840DK \ 5 | --deploy ansible \ 6 | --with-pcap -------------------------------------------------------------------------------- /tests/scenarios/routing-always-bad/wsn.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.wsn \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-dos-edge/wsn.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.wsn \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/papers/tiot2022/adversary-dos.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.adversary \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/scenarios/routing-periodically-bad/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | python3 -m tools.setup basic banded \ 3 | --applications routing monitoring challenge-response \ 4 | --target nRF52840DK \ 5 | --deploy ansible \ 6 | --with-pcap -------------------------------------------------------------------------------- /tests/scenarios/throughput-always-good/root.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.root \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-always-good/wsn.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.wsn \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-dos-edge/root.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.root \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/scenarios/routing-periodically-bad/root.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.root \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-periodically-slow/root.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.root \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-periodically-slow/wsn.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.wsn \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-routing-always-slow/wsn.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.wsn \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/scenarios/routing-periodically-bad/README.md: -------------------------------------------------------------------------------- 1 | # Routing Periodically Bad 2 | 3 | In this scenario one edge node (`bad_edge.sh`) periodically executes the routing application badly and another (`edge.sh`) can always execute it correctly. 4 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-dos-edge/adversary.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.adversary \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-power-periodically-off/root.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.root \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-power-periodically-off/wsn.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.wsn \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-routing-always-slow/root.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | nohup python3 -m tools.run.root \ 8 | logs/$(hostname).nohup.out 2>&1 & 9 | 10 | end_test 11 | -------------------------------------------------------------------------------- /tests/scenarios/routing-periodically-bad/wsn.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | rm -f nohup.out 8 | 9 | nohup python3 -m tools.run.wsn \ 10 | logs/$(hostname).nohup.out 2>&1 & 11 | 12 | end_test 13 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-power-periodically-off/README.md: -------------------------------------------------------------------------------- 1 | # Power periodically off 2 | 3 | The edge node periodically switches off its radio. It becomes unreachable when its radio is off and the ping metric degrades. The radio is off for 5 seconds every 300 seconds. 4 | -------------------------------------------------------------------------------- /wsn/common/base16.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | ssize_t base16_decode(const char* source, uint8_t* buf, ssize_t length); 7 | ssize_t base16_decode_length(const char* source, size_t source_len, uint8_t* buf, ssize_t length); 8 | -------------------------------------------------------------------------------- /tests/kill-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ -f pidfile ] 3 | then 4 | while IFS="" read -r line || [ -n "$line" ] 5 | do 6 | echo "Killing $line and children" 7 | rkill $1 $line 8 | done 4 | 5 | // Inclusive and biased 6 | uint16_t random_in_range(uint16_t min, uint16_t max); 7 | 8 | // Inclusive and unbiased, but slower 9 | uint16_t random_in_range_unbiased(uint16_t min, uint16_t max); 10 | -------------------------------------------------------------------------------- /wsn/common/float-helpers.c: -------------------------------------------------------------------------------- 1 | #include "float-helpers.h" 2 | 3 | #include 4 | 5 | bool isclose(float a, float b) 6 | { 7 | const float rel_tol = 2.5e-4f; 8 | 9 | const float comp = (fabs(a) < fabs(b) ? fabs(b) : fabs(a)); 10 | 11 | return fabs(a - b) <= (rel_tol * comp); 12 | } 13 | -------------------------------------------------------------------------------- /wsn/common/trust/edge-ping.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /*-------------------------------------------------------------------------------------------------------------------*/ 3 | void edge_ping_start(void); 4 | /*-------------------------------------------------------------------------------------------------------------------*/ 5 | -------------------------------------------------------------------------------- /tests/papers/tiot2022/setup-lazy-removal.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | python3 -m tools.setup basic_with_reputation banded \ 3 | --applications routing monitoring \ 4 | --target remote-revb \ 5 | --deploy ansible \ 6 | --with-pcap \ 7 | --defines BAND_SIZE 0.5f \ 8 | --defines NO_ACTIVE_REMOVAL_ON_UNANNOUNCE 1 9 | -------------------------------------------------------------------------------- /tests/papers/tiot2022/setup-aggressive-removal.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | python3 -m tools.setup basic_with_reputation banded \ 3 | --applications routing monitoring \ 4 | --target remote-revb \ 5 | --deploy ansible \ 6 | --with-pcap \ 7 | --defines BAND_SIZE 0.5f \ 8 | --defines AGGRESSIVE_REMOVAL_ON_UNANNOUNCE 1 9 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-periodically-slow/README.md: -------------------------------------------------------------------------------- 1 | # Routing Periodically Bad 2 | 3 | In this scenario one edge node (`bad_edge.sh`) periodically executes the routing application badly and another (`edge.sh`) can always execute it correctly. 4 | The period is 300 seconds: every 300 seconds the edge nodes switches its behaviour. 5 | The wait before sending a message is 1 second. -------------------------------------------------------------------------------- /tests/papers/tiot2022/setup-small-buffer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | python3 -m tools.setup basic_with_reputation banded \ 3 | --applications routing monitoring \ 4 | --target remote-revb \ 5 | --deploy ansible \ 6 | --with-pcap \ 7 | --with-adversary dos_certificate_verification \ 8 | --defines MESSAGES_TO_SIGN_SIZE 2 \ 9 | --defines MESSAGES_TO_VERIFY_SIZE 2 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build artifacts 2 | Makefile.target 3 | setup 4 | results 5 | wsn/*/build 6 | wsn/common/crypto/static-keys.c 7 | *.pem 8 | *.zoul 9 | *.nrf52840 10 | 11 | # Project Editing 12 | *.sublime-project 13 | *.sublime-workspace 14 | 15 | # Application-specific temporary files and directories 16 | __pycache__ 17 | tilescache 18 | *.pickle 19 | *.pcap 20 | 21 | common/configuration.py 22 | -------------------------------------------------------------------------------- /analysis/graph/all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for d in results/* 4 | do 5 | echo $d/graph 6 | rm -rf "$d/graph" 7 | done 8 | 9 | ./analysis/graph/challenge_response_epoch.py --log-dir results/* 10 | ./analysis/graph/challenge_response_perf.py --log-dir results/* 11 | ./analysis/graph/correctly_evaluated.py --log-dir results/* 12 | ./analysis/graph/offloading_when_bad.py --log-dir results/* 13 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-periodically-slow/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | python3 -m tools.setup throughput banded \ 3 | --applications routing monitoring \ 4 | --target nRF52840DK \ 5 | --deploy ansible \ 6 | --with-pcap \ 7 | --defines APPLICATIONS_MONITOR_THROUGHPUT 1 \ 8 | --defines TRUST_MODEL_PERIODIC_EDGE_PING 1 \ 9 | --defines TRUST_MODEL_PERIODIC_EDGE_PING_INTERVAL 10 10 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-always-good/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | python3 -m tools.setup throughput_pr badlisted_banded \ 3 | --applications routing monitoring \ 4 | --target nRF52840DK \ 5 | --deploy ansible \ 6 | --with-pcap \ 7 | --defines APPLICATIONS_MONITOR_THROUGHPUT 1 \ 8 | --defines EXPECTED_TIME_THROUGHPUT_BAD 10 \ 9 | --defines EXPECTED_TIME_THROUGHPUT_BAD_TO_GOOD_PR 0.6 10 | -------------------------------------------------------------------------------- /playbooks/configure-nrf.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Configure NRF 3 | hosts: all 4 | gather_facts: no 5 | 6 | tasks: 7 | - name: Configure the nrf execution environment 8 | ansible.builtin.command: 9 | cmd: python3 -m tools.deploy.config_backend.nrf 10 | chdir: ~/deploy/iot-trust-task-alloc 11 | 12 | - name: Unconditionally reboot the machine 13 | reboot: 14 | become: yes 15 | -------------------------------------------------------------------------------- /playbooks/motelist.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Motelist 3 | hosts: all 4 | gather_facts: false 5 | 6 | vars: 7 | output: "table" 8 | 9 | tasks: 10 | - name: Mostlist 11 | ansible.builtin.command: "python3 ~/deploy/iot-trust-task-alloc/tools/deploy/motelist_backend/nrf.py --output {{ output }}" 12 | register: motelist_output 13 | 14 | - debug: 15 | var: motelist_output.stdout 16 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-routing-always-slow/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | python3 -m tools.setup throughput_pr badlisted_banded \ 3 | --applications routing monitoring \ 4 | --target nRF52840DK \ 5 | --deploy ansible \ 6 | --with-pcap \ 7 | --defines APPLICATIONS_MONITOR_THROUGHPUT 1 \ 8 | --defines EXPECTED_TIME_THROUGHPUT_BAD 10 \ 9 | --defines EXPECTED_TIME_THROUGHPUT_BAD_TO_GOOD_PR 0.6 10 | -------------------------------------------------------------------------------- /common/configuration_common.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from enum import Enum 3 | from ipaddress import IPv6Address 4 | 5 | class DeviceKind(Enum): 6 | NRF52840 = "nRF52840" 7 | ZOLERTIA = "zolertia" 8 | 9 | @dataclass 10 | class Device: 11 | hostname: str 12 | identifier: int 13 | eui64: str 14 | kind: DeviceKind 15 | 16 | root_ipv6_addr = IPv6Address("fd00::1") 17 | -------------------------------------------------------------------------------- /wsn/common/serial-helpers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | /*-------------------------------------------------------------------------------------------------------------------*/ 6 | bool match_action(const char* data, const char* data_end, const char* action); 7 | /*-------------------------------------------------------------------------------------------------------------------*/ 8 | -------------------------------------------------------------------------------- /tests/papers/infocom2021/edge-always-good.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.edge \ 11 | --application challenge_response 1 \ 12 | logs/$(hostname).nohup.out 2>&1 & 13 | 14 | end_test 15 | -------------------------------------------------------------------------------- /tests/papers/sac2021/edge-always-bad.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.edge \ 11 | --application monitoring 2 \ 12 | --application bad_routing 0 \ 13 | logs/$(hostname).nohup.out 2>&1 & 14 | 15 | end_test 16 | -------------------------------------------------------------------------------- /tests/papers/sac2021/edge-always-good.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.edge \ 11 | --application monitoring 2 \ 12 | --application routing 0 \ 13 | logs/$(hostname).nohup.out 2>&1 & 14 | 15 | end_test 16 | -------------------------------------------------------------------------------- /tests/papers/tiot2022/edge-always-good.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.edge \ 11 | --application monitoring 2 \ 12 | --application routing 0 \ 13 | logs/$(hostname).nohup.out 2>&1 & 14 | 15 | end_test 16 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-dos-edge/edge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.edge \ 11 | --application monitoring 2 \ 12 | --application routing 0 \ 13 | logs/$(hostname).nohup.out 2>&1 & 14 | 15 | end_test 16 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-always-good/edge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.edge \ 11 | --application monitoring 2 \ 12 | --application routing 0 \ 13 | logs/$(hostname).nohup.out 2>&1 & 14 | 15 | end_test 16 | -------------------------------------------------------------------------------- /tests/papers/tiot2022/edge-unstable.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.edge \ 11 | --application bad_challenge_response 0 " --duration inf --approach random" \ 12 | logs/$(hostname).nohup.out 2>&1 & 13 | 14 | end_test 15 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-periodically-slow/edge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.edge \ 11 | --application monitoring 2 \ 12 | --application routing 0 \ 13 | logs/$(hostname).nohup.out 2>&1 & 14 | 15 | end_test 16 | -------------------------------------------------------------------------------- /tests/papers/infocom2021/edge-always-bad.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.edge \ 11 | --application bad_challenge_response 0 " --duration 1200 --approach random" \ 12 | logs/$(hostname).nohup.out 2>&1 & 13 | 14 | end_test 15 | -------------------------------------------------------------------------------- /tests/papers/infocom2021/edge-unstable.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.edge \ 11 | --application bad_challenge_response 0 " --duration inf --approach random" \ 12 | logs/$(hostname).nohup.out 2>&1 & 13 | 14 | end_test 15 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-power-periodically-off/edge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.edge \ 11 | --application monitoring 2 \ 12 | --application routing 0 \ 13 | logs/$(hostname).nohup.out 2>&1 & 14 | 15 | end_test 16 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-routing-always-slow/edge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.edge \ 11 | --application monitoring 2 \ 12 | --application routing 0 \ 13 | logs/$(hostname).nohup.out 2>&1 & 14 | 15 | end_test 16 | -------------------------------------------------------------------------------- /tests/run/edge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.edge \ 11 | --application monitoring 2 \ 12 | --application routing 0 \ 13 | --application challenge_response 1 \ 14 | logs/$(hostname).nohup.out 2>&1 & 15 | 16 | end_test 17 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-power-periodically-off/bad_edge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.bad_edge \ 11 | --application monitoring 2 \ 12 | --application routing 0 \ 13 | logs/$(hostname).nohup.out 2>&1 & 14 | 15 | end_test 16 | -------------------------------------------------------------------------------- /tests/scenarios/all-good/edge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.edge \ 11 | --application monitoring 2 \ 12 | --application routing 0 \ 13 | --application challenge_response 1 \ 14 | logs/$(hostname).nohup.out 2>&1 & 15 | 16 | end_test 17 | -------------------------------------------------------------------------------- /tests/papers/tiot2022/edge-always-bad.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.edge \ 11 | --application monitoring 2 \ 12 | --application bad_routing 0 " --duration inf --approach random" \ 13 | logs/$(hostname).nohup.out 2>&1 & 14 | 15 | end_test 16 | -------------------------------------------------------------------------------- /tests/run/bad_edge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.bad_edge \ 11 | --application monitoring 2 \ 12 | --application routing 0 \ 13 | --application challenge_response 1 \ 14 | logs/$(hostname).nohup.out 2>&1 & 15 | 16 | end_test 17 | -------------------------------------------------------------------------------- /tests/scenarios/routing-always-bad/edge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.edge \ 11 | --application monitoring 2 \ 12 | --application routing 0 \ 13 | --application challenge_response 1 \ 14 | logs/$(hostname).nohup.out 2>&1 & 15 | 16 | end_test 17 | -------------------------------------------------------------------------------- /tests/scenarios/routing-periodically-bad/edge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.edge \ 11 | --application monitoring 2 \ 12 | --application routing 0 \ 13 | --application challenge_response 1 \ 14 | logs/$(hostname).nohup.out 2>&1 & 15 | 16 | end_test 17 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-periodically-slow/bad_edge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.edge \ 11 | --application monitoring 2 \ 12 | --application bad_routing 0 " --approach slow --duration 300 --slow-wait 1" \ 13 | logs/$(hostname).nohup.out 2>&1 & 14 | 15 | end_test 16 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-routing-always-slow/bad_edge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.edge \ 11 | --application monitoring 2 \ 12 | --application bad_routing 0 " --approach slow --duration inf --slow-wait 1" \ 13 | logs/$(hostname).nohup.out 2>&1 & 14 | 15 | end_test 16 | -------------------------------------------------------------------------------- /tests/scenarios/routing-always-bad/bad_edge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.edge \ 11 | --application monitoring 2 \ 12 | --application bad_routing 0 " --duration inf --approach random" --application challenge_response 1 \ 13 | logs/$(hostname).nohup.out 2>&1 & 14 | 15 | end_test -------------------------------------------------------------------------------- /tests/scenarios/throughput-dos-edge/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | python3 -m tools.setup throughput banded \ 3 | --applications routing monitoring \ 4 | --target nRF52840DK \ 5 | --deploy ansible \ 6 | --with-pcap \ 7 | --with-adversary dos_target_network \ 8 | --defines APPLICATIONS_MONITOR_THROUGHPUT 1 \ 9 | --defines TRUST_MODEL_PERIODIC_EDGE_PING 1 \ 10 | --defines TRUST_MODEL_PERIODIC_EDGE_PING_INTERVAL 10 \ 11 | --defines DOS_ADDRESS 'CC_STRINGIFY(fd00::f6ce:3646:7fb7:cac7)' \ 12 | --defines DOS_PERIOD_MS 50 13 | -------------------------------------------------------------------------------- /tests/scenarios/routing-periodically-bad/bad_edge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.edge \ 11 | --application monitoring 2 \ 12 | --application bad_routing 0 " --duration 300 --approach random" \ 13 | --application challenge_response 1 \ 14 | logs/$(hostname).nohup.out 2>&1 & 15 | 16 | end_test 17 | -------------------------------------------------------------------------------- /wsn/applications/routing/routing.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define ROUTING_APPLICATION_NAME "routing" 4 | #define ROUTING_APPLICATION_URI "routing" 5 | 6 | #define ROUTING_SUBMIT_TASK "submit-task:route-req:" 7 | 8 | void init_trust_weights_routing(void); 9 | 10 | typedef struct { 11 | float latitude; 12 | float longitude; 13 | } coordinate_t; 14 | 15 | typedef enum { 16 | ROUTING_SUCCESS = 0, 17 | ROUTING_NO_ROUTE = 1, 18 | ROUTING_GAVE_UP = 2, 19 | ROUTING_UNKNOWN_ERROR = 3, 20 | ROUTING_PARSING_ERROR = 4, 21 | } pyroutelib3_status_t; 22 | -------------------------------------------------------------------------------- /playbooks/deploy.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Deploy 3 | hosts: all 4 | gather_facts: no 5 | 6 | tasks: 7 | - name: Perform syncrhonisation of all files 8 | ansible.builtin.synchronize: 9 | src: "{{ playbook_dir | dirname }}" 10 | dest: ~/deploy/ 11 | delete: yes 12 | dirs: yes 13 | 14 | - name: Configure keystore 15 | ansible.builtin.synchronize: 16 | src: "{{ playbook_dir | dirname }}/setup/keystore" 17 | dest: ~/deploy/iot-trust-task-alloc/resource_rich/root/ 18 | delete: yes 19 | dirs: yes 20 | -------------------------------------------------------------------------------- /tests/common.sh: -------------------------------------------------------------------------------- 1 | INTERACTIVE=1 2 | 3 | begin_test() { 4 | local OPTIND 5 | while getopts "d" flag 6 | do 7 | case "${flag}" in 8 | d) INTERACTIVE=0;; 9 | esac 10 | done 11 | 12 | # Stop anything currently running 13 | ./tests/kill-test.sh -9 14 | 15 | # Remove logs 16 | rm -rf logs 17 | mkdir logs 18 | } 19 | 20 | end_test() { 21 | if [[ $INTERACTIVE == 1 ]] 22 | then 23 | # Wait for nohup.out to be created 24 | sleep 1 25 | 26 | tail -f logs/$(hostname).nohup.out 27 | fi 28 | } 29 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-power-periodically-off/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | python3 -m tools.setup throughput banded \ 3 | --applications routing monitoring \ 4 | --target nRF52840DK \ 5 | --deploy ansible \ 6 | --with-pcap \ 7 | --with-bad-edge radio_off \ 8 | --defines APPLICATIONS_MONITOR_THROUGHPUT 1 \ 9 | --defines TRUST_MODEL_PERIODIC_EDGE_PING 1 \ 10 | --defines TRUST_MODEL_PERIODIC_EDGE_PING_INTERVAL 10 \ 11 | --defines EDGE_ATTACK_RADIO_OFF_START 180 \ 12 | --defines EDGE_ATTACK_RADIO_OFF_INTERVAL 300 \ 13 | --defines EDGE_ATTACK_RADIO_OFF_DURATION 5 14 | -------------------------------------------------------------------------------- /wsn/common/base64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Base64 encoding/decoding (RFC1341) 3 | * Copyright (c) 2005, Jouni Malinen 4 | * 5 | * This software may be distributed under the terms of the BSD license. 6 | * See README for more details. 7 | */ 8 | 9 | // from: http://web.mit.edu/freebsd/head/contrib/wpa/src/utils/base64.h 10 | 11 | #pragma once 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | bool base64_encode(const uint8_t* src, size_t len, char* out, size_t* out_len); 18 | bool base64_decode(const char* source, size_t len, uint8_t* out, size_t* out_len); 19 | -------------------------------------------------------------------------------- /common/names.py: -------------------------------------------------------------------------------- 1 | import common.configuration as conf 2 | from tools.keygen.util import ip_to_eui64 3 | 4 | from ipaddress import IPv6Address 5 | 6 | def hostname_to_name(hostname: str) -> str: 7 | return conf.hostname_to_names[hostname] 8 | 9 | def ip_to_name(ip: IPv6Address) -> str: 10 | (hostname,) = [k for (k, v) in conf.hostname_to_ips.items() if v == ip] 11 | return conf.hostname_to_names[hostname] 12 | 13 | def eui64_to_name(eui64: str) -> str: 14 | (hostname,) = [k for (k, v) in conf.hostname_to_ips.items() if ip_to_eui64(v).hex() == eui64] 15 | return conf.hostname_to_names[hostname] 16 | -------------------------------------------------------------------------------- /tests/papers/tiot2022/edge-aggressive-capability-remove.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.edge \ 11 | --application monitoring 2 \ 12 | --application bad_routing 0 " --duration inf --fake-restart-type application --fake-restart-duration 180 --fake-restart-period 1800 --approach random" \ 13 | logs/$(hostname).nohup.out 2>&1 & 14 | 15 | end_test 16 | -------------------------------------------------------------------------------- /tests/papers/tiot2022/edge-aggressive-unannounce.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source ./tests/common.sh 4 | 5 | begin_test 6 | 7 | # Cannot set negative niceness without running at higher privilege, so just use higher positive numbers to indicate 8 | # a lower priority relative to each application. 9 | 10 | nohup python3 -m tools.run.edge \ 11 | --application monitoring 2 \ 12 | --application bad_routing 0 " --duration inf --fake-restart-type server --fake-restart-duration 180 --fake-restart-period 1800 --fake-restart-applications envmon --approach random" \ 13 | logs/$(hostname).nohup.out 2>&1 & 14 | 15 | end_test 16 | -------------------------------------------------------------------------------- /wsn/common/root-endpoint.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /*-------------------------------------------------------------------------------------------------------------------*/ 3 | #include "coap-endpoint.h" 4 | #include 5 | /*-------------------------------------------------------------------------------------------------------------------*/ 6 | bool root_endpoint_init(void); 7 | /*-------------------------------------------------------------------------------------------------------------------*/ 8 | extern coap_endpoint_t root_ep; 9 | /*-------------------------------------------------------------------------------------------------------------------*/ 10 | -------------------------------------------------------------------------------- /wsn/common/crypto/keystore-oscore.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "coap.h" 6 | #include "coap-endpoint.h" 7 | /*-------------------------------------------------------------------------------------------------------------------*/ 8 | void coap_set_random_token(coap_message_t* request); 9 | /*-------------------------------------------------------------------------------------------------------------------*/ 10 | #ifdef WITH_OSCORE 11 | bool keystore_protect_coap_with_oscore(coap_message_t* request, const coap_endpoint_t* ep); 12 | #endif 13 | /*-------------------------------------------------------------------------------------------------------------------*/ 14 | -------------------------------------------------------------------------------- /wsn/profile/project-conf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Disable Low Power Mode 2 to enable access to all them RAM 4 | // See: https://github.com/contiki-ng/contiki-ng/wiki/Platform-zoul#low-power-modes 5 | #define LPM_CONF_MAX_PM 1 6 | 7 | #define LOG_CONF_LEVEL_COAP LOG_LEVEL_WARN 8 | #define LOG_CONF_LEVEL_OSCORE LOG_LEVEL_INFO 9 | 10 | // This is the address of the observer node connected to the border router 11 | #define MQTT_CLIENT_CONF_BROKER_IP_ADDR "fd00::1" 12 | 13 | #define COAP_MAX_CHUNK_SIZE 256 14 | 15 | // Enable coloured log prefix 16 | #define LOG_CONF_WITH_COLOR 1 17 | 18 | // We are using 256 bit ECC, so can decrease RAM cost a bit here 19 | #define ECC_MAXIMUM_LENGTH 8 20 | -------------------------------------------------------------------------------- /wsn/common/trust/stereotypes/device-classes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define DEVICE_CLASS_MINIMUM 1 4 | #define DEVICE_CLASS_MAXIMUM 8 5 | 6 | #define DEVICE_CLASS_RASPBERRY_PI 1 7 | #define DEVICE_CLASS_PHONE 2 8 | #define DEVICE_CLASS_LAPTOP 3 9 | #define DEVICE_CLASS_DESKTOP 4 10 | #define DEVICE_CLASS_SERVER 5 11 | 12 | // e.g., TelosB 13 | #define DEVICE_CLASS_IOT_LOW 6 14 | 15 | // e.g., Zolertia RE-Mote 16 | #define DEVICE_CLASS_IOT_MEDIUM 7 17 | 18 | // e.g., nRF52840 19 | #define DEVICE_CLASS_IOT_HIGH 8 20 | 21 | _Static_assert(DEVICE_CLASS_MINIMUM > 0, "Zero is a reserved device class"); 22 | _Static_assert(DEVICE_CLASS_MAXIMUM < 23, "Can't allow 23 or more classes to fit in a single CBOR uint"); 23 | -------------------------------------------------------------------------------- /wsn/common/random-helpers.c: -------------------------------------------------------------------------------- 1 | #include "random-helpers.h" 2 | 3 | #include "os/lib/random.h" 4 | 5 | // See: https://stackoverflow.com/questions/11758809/what-is-the-optimal-algorithm-for-generating-an-unbiased-random-integer-within-a 6 | 7 | uint16_t random_in_range(uint16_t min, uint16_t max) 8 | { 9 | return min + (random_rand() % (uint16_t)(max - min + 1)); 10 | } 11 | 12 | uint16_t random_in_range_unbiased(uint16_t min, uint16_t max) 13 | { 14 | const uint16_t n = max - min + 1; 15 | const uint16_t remainder = RANDOM_RAND_MAX % n; 16 | uint16_t x; 17 | do 18 | { 19 | x = random_rand(); 20 | } while (x >= RANDOM_RAND_MAX - remainder); 21 | return min + x % n; 22 | } 23 | -------------------------------------------------------------------------------- /wsn/edge/Makefile: -------------------------------------------------------------------------------- 1 | CONTIKI_PROJECT = edge 2 | all: $(CONTIKI_PROJECT) 3 | 4 | include ../Makefile.common 5 | 6 | CFLAGS += -DTRUST_EDGE=1 7 | 8 | ifeq ($(TRUST_MODEL),) 9 | $(error "TRUST_MODEL not set") 10 | else 11 | CFLAGS += -DTRUST_MODEL=TRUST_MODEL_$(shell echo $(TRUST_MODEL) | tr '[:lower:]' '[:upper:]' | tr '-' '_') 12 | endif 13 | 14 | # Include application modules 15 | MODULES_REL += ./capability 16 | MODULES_REL += ../common/trust/models/$(TRUST_MODEL) 17 | 18 | # Applications to include 19 | ifndef APPLICATIONS 20 | # Set default applications if not requesting specifics 21 | APPLICATIONS = monitoring routing challenge-response 22 | endif 23 | include ../applications/Makefile.include 24 | 25 | # Main Contiki-NG compile 26 | include $(CONTIKI)/Makefile.include 27 | -------------------------------------------------------------------------------- /wsn/common/serial-helpers.c: -------------------------------------------------------------------------------- 1 | #include "serial-helpers.h" 2 | #include 3 | #include "os/sys/log.h" 4 | /*-------------------------------------------------------------------------------------------------------------------*/ 5 | #define LOG_MODULE "serial-help" 6 | #define LOG_LEVEL LOG_LEVEL_ERR 7 | /*-------------------------------------------------------------------------------------------------------------------*/ 8 | bool 9 | match_action(const char* data, const char* data_end, const char* action) 10 | { 11 | size_t action_len = strlen(action); 12 | return data_end - data >= action_len && 13 | strncmp(action, data, action_len) == 0; 14 | } 15 | /*-------------------------------------------------------------------------------------------------------------------*/ 16 | -------------------------------------------------------------------------------- /wsn/applications/application-serial.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /*-------------------------------------------------------------------------------------------------------------------*/ 4 | #define SERIAL_SEP "|" 5 | /*-------------------------------------------------------------------------------------------------------------------*/ 6 | #define EDGE_SERIAL_PREFIX "!" 7 | #define EDGE_SERIAL_START "start" 8 | #define EDGE_SERIAL_STOP "stop" 9 | /*------------------------------------------------------------------------------------------------------------------*/ 10 | #define APPLICATION_SERIAL_PREFIX "@" 11 | #define APPLICATION_SERIAL_START "start" 12 | #define APPLICATION_SERIAL_STOP "stop" 13 | #define APPLICATION_SERIAL_APP "app" 14 | /*-------------------------------------------------------------------------------------------------------------------*/ 15 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Requesting Support 2 | 3 | This code is provided "as is" without expectation of support. 4 | 5 | Any requests for support that do not include the following information will not be responded to: 6 | 7 | 1. A description of your setup environment, including: 8 | * the platform you are using to build the software, 9 | * the hardware deployment that is being used to run experiments (both observers and IoT devices), and 10 | * your `common/configuration.py` file. 11 | 3. Demonstration that you have a working Contiki-NG install and have been able to deploy and receive serial output from Contiki-NG's [hello world example](https://github.com/MBradbury/contiki-ng/tree/petras/examples/hello-world). 12 | 4. The text or a screenshot of the error message you have encountered. 13 | 5. A detailed description of the steps taken to produce that error message. 14 | -------------------------------------------------------------------------------- /tests/scenarios/all-good/run.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Always Good - Root 3 | hosts: iris1 4 | gather_facts: no 5 | 6 | tasks: 7 | - name: Root 8 | ansible.builtin.shell: 9 | cmd: nohup ./tests/scenarios/all-good/root.sh -d & 10 | chdir: ~/deploy/iot-trust-task-alloc/ 11 | 12 | - name: Always Good - Edge 13 | hosts: iris3 iris10 14 | gather_facts: no 15 | 16 | tasks: 17 | - name: Edge 18 | ansible.builtin.shell: 19 | cmd: nohup ./tests/scenarios/all-good/edge.sh -d & 20 | chdir: ~/deploy/iot-trust-task-alloc/ 21 | 22 | - name: Always Good - WSN 23 | hosts: iris2 iris4 iris5 iris6 iris7 iris9 24 | gather_facts: no 25 | 26 | tasks: 27 | - name: WSN 28 | ansible.builtin.shell: 29 | cmd: nohup ./tests/scenarios/all-good/wsn.sh -d & 30 | chdir: ~/deploy/iot-trust-task-alloc/ 31 | -------------------------------------------------------------------------------- /wsn/adversary/attacks/template.c.example: -------------------------------------------------------------------------------- 1 | #include "contiki.h" 2 | #include "sys/log.h" 3 | /*-------------------------------------------------------------------------------------------------------------------*/ 4 | #define LOG_MODULE "attack-tem" 5 | #define LOG_LEVEL LOG_LEVEL_DBG 6 | /*-------------------------------------------------------------------------------------------------------------------*/ 7 | PROCESS(template, "template"); 8 | /*-------------------------------------------------------------------------------------------------------------------*/ 9 | PROCESS_THREAD(template, ev, data) 10 | { 11 | PROCESS_BEGIN(); 12 | 13 | LOG_INFO("Starting %s\n", PROCESS_NAME_STRING(PROCESS_CURRENT())); 14 | 15 | PROCESS_END(); 16 | } 17 | /*-------------------------------------------------------------------------------------------------------------------*/ 18 | -------------------------------------------------------------------------------- /wsn/node/project-conf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Disable Low Power Mode 2 to enable access to all them RAM 4 | // See: https://github.com/contiki-ng/contiki-ng/wiki/Platform-zoul#low-power-modes 5 | #define LPM_CONF_MAX_PM 1 6 | 7 | #define LOG_CONF_LEVEL_COAP LOG_LEVEL_WARN 8 | #define LOG_CONF_LEVEL_OSCORE LOG_LEVEL_INFO 9 | 10 | //#define UIP_CONF_UDP_CONNS 4 11 | //#define QUEUEBUF_CONF_NUM 8 12 | //#define NBR_TABLE_CONF_MAX_NEIGHBORS 6 13 | //#define NETSTACK_MAX_ROUTE_ENTRIES 6 14 | 15 | // This is the address of the observer node connected to the border router 16 | #define MQTT_CLIENT_CONF_BROKER_IP_ADDR "fd00::1" 17 | 18 | #define COAP_MAX_CHUNK_SIZE 256 19 | 20 | // Enable coloured log prefix 21 | #define LOG_CONF_WITH_COLOR 1 22 | 23 | // We are using 256 bit ECC, so can decrease RAM cost a bit here 24 | #define ECC_MAXIMUM_LENGTH 8 25 | 26 | #define AIOCOAP_SUPPORTS_OSCORE 27 | -------------------------------------------------------------------------------- /wsn/adversary/project-conf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Disable Low Power Mode 2 to enable access to all them RAM 4 | // See: https://github.com/contiki-ng/contiki-ng/wiki/Platform-zoul#low-power-modes 5 | #define LPM_CONF_MAX_PM 1 6 | 7 | #define LOG_CONF_LEVEL_COAP LOG_LEVEL_WARN 8 | #define LOG_CONF_LEVEL_OSCORE LOG_LEVEL_INFO 9 | 10 | //#define UIP_CONF_UDP_CONNS 4 11 | //#define QUEUEBUF_CONF_NUM 8 12 | //#define NBR_TABLE_CONF_MAX_NEIGHBORS 6 13 | //#define NETSTACK_MAX_ROUTE_ENTRIES 6 14 | 15 | // This is the address of the observer node connected to the border router 16 | #define MQTT_CLIENT_CONF_BROKER_IP_ADDR "fd00::1" 17 | 18 | #define COAP_MAX_CHUNK_SIZE 256 19 | 20 | // Enable coloured log prefix 21 | #define LOG_CONF_WITH_COLOR 1 22 | 23 | // We are using 256 bit ECC, so can decrease RAM cost a bit here 24 | #define ECC_MAXIMUM_LENGTH 8 25 | 26 | #define AIOCOAP_SUPPORTS_OSCORE 27 | -------------------------------------------------------------------------------- /tools/deploy/motelist.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import subprocess 3 | 4 | def main(mote_type: str): 5 | if mote_type == "zolertia": 6 | subprocess.run("motelist-zolertia", 7 | cwd="tools/deploy/motelist_backend", 8 | shell=True, 9 | check=True) 10 | 11 | elif mote_type == "nRF52840": 12 | from tools.deploy.motelist_backend.nrf import print_motelist_nrf 13 | print_motelist_nrf() 14 | 15 | else: 16 | raise RuntimeError(f"Unknown mote type {mote_type}") 17 | 18 | if __name__ == "__main__": 19 | import argparse 20 | 21 | parser = argparse.ArgumentParser(description='Motelist') 22 | parser.add_argument("--mote-type", choices=["zolertia", "nRF52840"], default="zolertia", help="The type of mote.") 23 | 24 | args = parser.parse_args() 25 | 26 | main(args.mote_type) 27 | -------------------------------------------------------------------------------- /tools/deploy/config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | def nRF52840_config(mote, **kwargs): 4 | from tools.deploy.config_backend.nrf import config_nrf 5 | config_nrf(mote, "nRF52840_xxAA", speed=8000) 6 | 7 | def config(mote, mote_type): 8 | if mote_type == "zolertia": 9 | pass 10 | elif mote_type == "nRF52840": 11 | return nRF52840_config(mote) 12 | else: 13 | raise NotImplementedError(f"Support for configuring {mote_type} has not been implemented") 14 | 15 | if __name__ == "__main__": 16 | import argparse 17 | 18 | parser = argparse.ArgumentParser(description='Configure sensor nodes.') 19 | parser.add_argument("mote", help="The device identifier to configure.") 20 | parser.add_argument("mote_type", choices=["zolertia", "nRF52840"], help="The type of mote.") 21 | args = parser.parse_args() 22 | 23 | config(args.mote, args.mote_type) 24 | -------------------------------------------------------------------------------- /tools/keygen/util.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from ipaddress import IPv6Address 4 | 5 | def ip_to_eui64(subject: Union[IPv6Address,str], root_ip: Union[IPv6Address,str]="fd00::1") -> bytes: 6 | subject = IPv6Address(subject) 7 | root_ip = IPv6Address(root_ip) 8 | 9 | # Last 8 bytes of the ip address 10 | eui64 = bytearray(int(subject).to_bytes(16, byteorder='big')[-8:]) 11 | 12 | # See: uip_ds6_set_lladdr_from_iid 13 | if subject != root_ip: 14 | eui64[0] ^= 0x02 15 | 16 | return bytes(eui64) 17 | 18 | def eui64_to_ipv6(eui64: Union[str,bytes,bytearray]) -> IPv6Address: 19 | if isinstance(eui64, str): 20 | eui64 = bytearray.fromhex(eui64.replace(":", "")) 21 | else: 22 | eui64 = bytearray(eui64) 23 | 24 | # See: uip_ds6_set_lladdr_from_iid 25 | eui64[0] ^= 0x02 26 | 27 | return IPv6Address(b"\xfd\x00" + b"\x00"*6 + eui64) 28 | -------------------------------------------------------------------------------- /wsn/edge/project-conf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "device-classes.h" 4 | 5 | // Disable Low Power Mode 2 to enable access to all them RAM 6 | // See: https://github.com/contiki-ng/contiki-ng/wiki/Platform-zoul#low-power-modes 7 | #define LPM_CONF_MAX_PM 1 8 | 9 | #define LOG_CONF_LEVEL_COAP LOG_LEVEL_WARN 10 | #define LOG_CONF_LEVEL_OSCORE LOG_LEVEL_INFO 11 | 12 | //#define UIP_CONF_UDP_CONNS 4 13 | //#define QUEUEBUF_CONF_NUM 4 14 | //#define NBR_TABLE_CONF_MAX_NEIGHBORS 6 15 | //#define NETSTACK_MAX_ROUTE_ENTRIES 6 16 | 17 | // This is the address of the observer node connected to the border router 18 | #define MQTT_CLIENT_CONF_BROKER_IP_ADDR "fd00::1" 19 | 20 | #define COAP_MAX_CHUNK_SIZE 256 21 | 22 | // Enable coloured log prefix 23 | #define LOG_CONF_WITH_COLOR 1 24 | 25 | // We are using 256 bit ECC, so can decrease RAM cost a bit here 26 | #define ECC_MAXIMUM_LENGTH 8 27 | 28 | #define AIOCOAP_SUPPORTS_OSCORE 29 | -------------------------------------------------------------------------------- /wsn/applications/routing/edge/routing-edge.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "routing.h" 4 | 5 | #include 6 | // process-task 7 | /*-------------------------------------------------------------------------------------------------------------------*/ 8 | void 9 | routing_taskrecv_init(void); 10 | /*-------------------------------------------------------------------------------------------------------------------*/ 11 | 12 | // process-task-response 13 | /*-------------------------------------------------------------------------------------------------------------------*/ 14 | void 15 | routing_taskresp_init(void); 16 | /*-------------------------------------------------------------------------------------------------------------------*/ 17 | void 18 | routing_taskresp_process_serial_input(const char* data); 19 | /*-------------------------------------------------------------------------------------------------------------------*/ 20 | -------------------------------------------------------------------------------- /wsn/applications/challenge-response/edge/challenge-response-edge.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "challenge-response.h" 4 | 5 | #include 6 | // process-task 7 | /*-------------------------------------------------------------------------------------------------------------------*/ 8 | void 9 | cr_taskrecv_init(void); 10 | /*-------------------------------------------------------------------------------------------------------------------*/ 11 | 12 | // process-task-response 13 | /*-------------------------------------------------------------------------------------------------------------------*/ 14 | void 15 | cr_taskresp_init(void); 16 | /*-------------------------------------------------------------------------------------------------------------------*/ 17 | void 18 | cr_taskresp_process_serial_input(const char* data); 19 | /*-------------------------------------------------------------------------------------------------------------------*/ 20 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-always-good/run.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Run Throughput Always Good - Root 3 | hosts: iris1 4 | gather_facts: no 5 | 6 | tasks: 7 | - name: Root 8 | ansible.builtin.shell: 9 | cmd: nohup ./tests/scenarios/throughput-always-good/root.sh -d & 10 | chdir: ~/deploy/iot-trust-task-alloc/ 11 | 12 | - name: Run Throughput Always Good - Edge 13 | hosts: iris3 iris10 14 | gather_facts: no 15 | 16 | tasks: 17 | - name: Edge 18 | ansible.builtin.shell: 19 | cmd: nohup ./tests/scenarios/throughput-always-good/edge.sh -d & 20 | chdir: ~/deploy/iot-trust-task-alloc/ 21 | 22 | - name: Run Throughput Always Good - WSN 23 | hosts: iris2 iris4 iris5 iris6 iris7 iris9 24 | gather_facts: no 25 | 26 | tasks: 27 | - name: WSN 28 | ansible.builtin.shell: 29 | cmd: nohup ./tests/scenarios/throughput-always-good/wsn.sh -d & 30 | chdir: ~/deploy/iot-trust-task-alloc/ 31 | -------------------------------------------------------------------------------- /playbooks/fetch-results.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Fetch Results 3 | hosts: all:!iris8 4 | 5 | vars_prompt: 6 | - name: destination 7 | prompt: Destination to store logs 8 | private: no 9 | 10 | tasks: 11 | - name: Create local directory 12 | ansible.builtin.file: 13 | path: "{{ playbook_dir | dirname }}//results/{{ destination }}" 14 | state: directory 15 | delegate_to: localhost 16 | 17 | - name: Fetching folder 18 | ansible.posix.synchronize: 19 | src: ~/deploy/iot-trust-task-alloc/logs/* 20 | dest: "{{ playbook_dir | dirname }}/results/{{ destination }}/" 21 | mode: pull 22 | delete: no 23 | 24 | - name: Fetching keystore 25 | ansible.posix.synchronize: 26 | src: ~/deploy/iot-trust-task-alloc/resource_rich/root/keystore/ 27 | dest: "{{ playbook_dir | dirname }}/results/{{ destination }}/keystore" 28 | mode: pull 29 | delete: no 30 | when: ansible_hostname == 'iris1' 31 | -------------------------------------------------------------------------------- /playbooks/setup-root.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Setup root 3 | hosts: iris1 4 | gather_facts: no 5 | 6 | tasks: 7 | - name: Clone contiki 8 | ansible.builtin.git: 9 | repo: https://github.com/MBradbury/contiki-ng.git 10 | dest: ~/deploy/contiki-ng 11 | version: petras 12 | recursive: yes 13 | force: yes 14 | 15 | - name: Clean tunslip 16 | ansible.builtin.command: 17 | cmd: make clean 18 | chdir: ~/deploy/contiki-ng/tools/serial-io 19 | 20 | - name: Build tunslip 21 | ansible.builtin.command: 22 | cmd: make 23 | chdir: ~/deploy/contiki-ng/tools/serial-io 24 | 25 | - name: Clean border router native 26 | ansible.builtin.command: 27 | cmd: make clean 28 | chdir: ~/deploy/contiki-ng/examples/rpl-border-router 29 | 30 | - name: Build border router native 31 | ansible.builtin.command: 32 | cmd: make TARGET=native 33 | chdir: ~/deploy/contiki-ng/examples/rpl-border-router 34 | -------------------------------------------------------------------------------- /tools/deploy/motedev.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | def get_mote_device(device: str, mote_type: str) -> str: 4 | if mote_type == "zolertia": 5 | return device 6 | 7 | elif mote_type == "nRF52840": 8 | from tools.deploy.motedev_backend.nrf import get_com_ports_for_mote 9 | ports = get_com_ports_for_mote(device) 10 | return ports[0] 11 | 12 | else: 13 | raise RuntimeError(f"Unknown mote type {mote_type}") 14 | 15 | def main(device: str, mote_type: str): 16 | print(get_mote_device(device, mote_type)) 17 | 18 | if __name__ == "__main__": 19 | import argparse 20 | 21 | parser = argparse.ArgumentParser(description='Get Mote Device') 22 | parser.add_argument("--device", required=True, help="The device identifier") 23 | parser.add_argument("--mote-type", choices=["zolertia", "nRF52840"], required=True, help="The type of mote.") 24 | 25 | args = parser.parse_args() 26 | 27 | main(args.device, args.mote_type) 28 | -------------------------------------------------------------------------------- /wsn/edge/edge.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "contiki.h" 4 | /*-------------------------------------------------------------------------------------------------------------------*/ 5 | extern const char* const application_names[APPLICATION_NUM]; 6 | extern bool applications_available[APPLICATION_NUM]; 7 | /*-------------------------------------------------------------------------------------------------------------------*/ 8 | extern bool resource_rich_edge_started; 9 | /*-------------------------------------------------------------------------------------------------------------------*/ 10 | // Process event that is sent to relevant applications when 11 | // application data is received over the serial line 12 | extern process_event_t pe_data_from_resource_rich_node; 13 | /*-------------------------------------------------------------------------------------------------------------------*/ 14 | bool application_available(const char* name); 15 | /*-------------------------------------------------------------------------------------------------------------------*/ 16 | -------------------------------------------------------------------------------- /tools/deploy/motedev_backend/nrf.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | import pynrfjprog.HighLevel 4 | 5 | def get_com_ports_for_mote(node_id: str) -> list: 6 | node_id = int(node_id) 7 | 8 | with pynrfjprog.HighLevel.API() as api: 9 | with pynrfjprog.HighLevel.DebugProbe(api, node_id) as probe: 10 | probe_info = probe.get_probe_info() 11 | return [com_port.path for com_port in probe_info.com_ports] 12 | 13 | def get_usb_dev_for_mote(node_id: str) -> str: 14 | com_ports = get_com_ports_for_mote(node_id) 15 | 16 | # Remove leading "/dev/" 17 | com_ports = [com_port.removeprefix("/dev/") for com_port in com_ports] 18 | 19 | usbs = list(Path("/sys/bus/usb/devices/").rglob("usb*")) 20 | 21 | for usb in usbs: 22 | usb_devs = list(usb.rglob("dev")) 23 | 24 | if any(com_port in str(usb_dev_path) 25 | for com_port in com_ports 26 | for usb_dev_path in usb_devs 27 | ): 28 | return usb 29 | 30 | raise RuntimeError(f"Unable to find usb for {node_id}") 31 | -------------------------------------------------------------------------------- /wsn/edge/capability/capability.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | /*-------------------------------------------------------------------------------------------------------------------*/ 7 | bool 8 | publish_announce(void); 9 | /*-------------------------------------------------------------------------------------------------------------------*/ 10 | bool 11 | publish_unannounce(void); 12 | /*-------------------------------------------------------------------------------------------------------------------*/ 13 | bool 14 | publish_add_capability(const char* name, bool include_certificate); 15 | /*-------------------------------------------------------------------------------------------------------------------*/ 16 | bool 17 | publish_remove_capability(const char* name, bool include_certificate); 18 | /*-------------------------------------------------------------------------------------------------------------------*/ 19 | void 20 | trigger_faster_publish(void); 21 | /*-------------------------------------------------------------------------------------------------------------------*/ 22 | -------------------------------------------------------------------------------- /wsn/common/eui64.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "uip.h" 5 | /*-------------------------------------------------------------------------------------------------------------------*/ 6 | #define EUI64_LENGTH 8 7 | /*-------------------------------------------------------------------------------------------------------------------*/ 8 | const uint8_t* current_eui64(void); 9 | /*-------------------------------------------------------------------------------------------------------------------*/ 10 | void eui64_from_ipaddr(const uip_ip6addr_t* ipaddr, uint8_t* eui64); 11 | void eui64_to_ipaddr(const uint8_t* eui64, uip_ip6addr_t* ipaddr); 12 | /*-------------------------------------------------------------------------------------------------------------------*/ 13 | bool eui64_from_str(const char* eui64_str, uint8_t* eui64); 14 | bool eui64_from_strn(const char* eui64_str, size_t length, uint8_t* eui64); 15 | int eui64_to_str(const uint8_t* eui64, char* eui64_str, size_t eui64_str_size); 16 | /*-------------------------------------------------------------------------------------------------------------------*/ 17 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Matthew Bradbury 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /wsn/common/crypto/static-keys.c.default: -------------------------------------------------------------------------------- 1 | #include "keys.h" 2 | /*-------------------------------------------------------------------------------------------------------------------*/ 3 | /** 4 | * This file provides a template to store the ECC public/private keys for this device and the public key of the 5 | * root node. These keys can be generated using the tool in tools/eckeygen.py. 6 | * 7 | * This file should be renamed to static-keys.c and should not be commited to a git repository. 8 | */ 9 | /*-------------------------------------------------------------------------------------------------------------------*/ 10 | const ecdsa_secp256r1_key_t our_key = { 11 | .priv_key = { }, 12 | .pub_key = { 13 | .x = { }, 14 | .y = { } } 15 | }; 16 | /*-------------------------------------------------------------------------------------------------------------------*/ 17 | const ecdsa_secp256r1_pubkey_t root_key = { // ./eckeygen.py -d "fd00::1" 18 | .x = { }, 19 | .y = { } 20 | }; 21 | /*-------------------------------------------------------------------------------------------------------------------*/ 22 | -------------------------------------------------------------------------------- /wsn/profile/Makefile: -------------------------------------------------------------------------------- 1 | CONTIKI_PROJECT = profile 2 | all: $(CONTIKI_PROJECT) 3 | 4 | include ../Makefile.common 5 | 6 | #CFLAGS += -Wconversion 7 | 8 | ifeq ($(PROFILE_ECC),1) 9 | CFLAGS += -DPROFILE_ECC 10 | else ifeq ($(PROFILE_AES),1) 11 | CFLAGS += -DPROFILE_AES 12 | else 13 | $(error "Unknown profile option please specify either PROFILE_ECC=1 or PROFILE_AES=1") 14 | endif 15 | 16 | ifeq ($(TRUST_MODEL),) 17 | $(error "TRUST_MODEL not set") 18 | else 19 | CFLAGS += -DTRUST_MODEL=TRUST_MODEL_$(shell echo $(TRUST_MODEL) | tr '[:lower:]' '[:upper:]' | tr '-' '_') 20 | endif 21 | 22 | MODULES_REL += ./trust 23 | MODULES_REL += ../common/trust/models/$(TRUST_MODEL) 24 | 25 | # Applications to include 26 | ifndef APPLICATIONS 27 | # Set default applications if not requesting specifics 28 | APPLICATIONS = monitoring 29 | endif 30 | include ../applications/Makefile.include 31 | 32 | # Add additional CFLAGS 33 | CFLAGS += -DCRYPTO_SUPPORT_LOG_LEVEL=LOG_LEVEL_DBG 34 | CFLAGS += -DKEYSTORE_LOG_LEVEL=LOG_LEVEL_DBG 35 | 36 | CFLAGS += -DCRYPTO_SUPPORT_TIME_METRICS=1 37 | 38 | # Main Contiki-NG compile 39 | include $(CONTIKI)/Makefile.include 40 | -------------------------------------------------------------------------------- /resource_rich/applications/monitoring.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import logging 4 | import time 5 | 6 | from config import serial_sep 7 | import client_common 8 | 9 | NAME = "envmon" 10 | 11 | logging.basicConfig(level=logging.INFO) 12 | logger = logging.getLogger(f"app-{NAME}") 13 | logger.setLevel(logging.DEBUG) 14 | 15 | def _task_runner(task): 16 | (src, dt, payload) = task 17 | 18 | (node_time, temp, vdd3) = payload 19 | 20 | start_timer = time.perf_counter() 21 | 22 | logger.info(f"Received message at {dt} from {src} ") 23 | 24 | end_timer = time.perf_counter() 25 | duration = end_timer - start_timer 26 | 27 | return (src, None, duration) 28 | 29 | class MonitoringClient(client_common.Client): 30 | 31 | internal_error = None 32 | 33 | def __init__(self): 34 | super().__init__(NAME, task_runner=_task_runner, max_workers=1) 35 | 36 | async def _send_result(self, dest, message_response): 37 | # TODO: do something here 38 | pass 39 | 40 | if __name__ == "__main__": 41 | client = MonitoringClient() 42 | 43 | client_common.main(NAME, client) 44 | -------------------------------------------------------------------------------- /tools/deploy/flash_backend/nrf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import pynrfjprog.HighLevel 4 | from pynrfjprog.Parameters import ProgramOptions, VerifyAction, EraseAction, ResetAction 5 | 6 | def flash_nrf(filename: str, serial_number: str): 7 | serial_number = int(serial_number) 8 | 9 | program_options = ProgramOptions( 10 | verify=VerifyAction.VERIFY_READ, 11 | erase_action=EraseAction.ERASE_ALL, 12 | qspi_erase_action=EraseAction.ERASE_NONE, 13 | reset=ResetAction.RESET_SYSTEM 14 | ) 15 | 16 | with pynrfjprog.HighLevel.API() as api: 17 | with pynrfjprog.HighLevel.DebugProbe(api, serial_number) as probe: 18 | probe.program(filename, program_options) 19 | 20 | if __name__ == "__main__": 21 | import argparse 22 | 23 | parser = argparse.ArgumentParser(description='Flash firmware to nrf.') 24 | parser.add_argument("filename", help="The path to the binary to flash.") 25 | parser.add_argument("serial-number", required=True, help="The serial number of the mote to flash") 26 | 27 | args = parser.parse_args() 28 | 29 | flash_nrf(args.filename, args.serial_number) 30 | -------------------------------------------------------------------------------- /tools/run/bad_edge.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | from pathlib import Path 5 | 6 | from tools.run import supported_firmware_types, DEFAULT_LOG_DIR 7 | from tools.run.edge import EdgeRunner, ApplicationAction 8 | 9 | class BadEdgeRunner(EdgeRunner): 10 | binary_name = "bad_edge.bin" 11 | 12 | if __name__ == "__main__": 13 | parser = argparse.ArgumentParser(description='Edge runner') 14 | parser.add_argument('--log-dir', type=Path, default=DEFAULT_LOG_DIR, help='The directory to store log output') 15 | parser.add_argument("--firmware-type", 16 | choices=supported_firmware_types, 17 | default=supported_firmware_types[0], 18 | help="The OS that was used to create the firmware.") 19 | 20 | parser.add_argument("--application", nargs='*', metavar='application-name nice params', 21 | action=ApplicationAction, 22 | help="The applications to start") 23 | 24 | args = parser.parse_args() 25 | 26 | runner = BadEdgeRunner(args.log_dir, args.firmware_type, args.application) 27 | runner.run() 28 | -------------------------------------------------------------------------------- /common/configuration.py.example: -------------------------------------------------------------------------------- 1 | from common.stereotype_tags import StereotypeTags, DeviceClass 2 | 3 | from ipaddress import IPv6Address 4 | 5 | hostname_to_ips = { 6 | "wsn1": IPv6Address("fd00::1"), 7 | "wsn2": IPv6Address("fd00::212:4b00:14d5:2bd6"), 8 | "wsn3": IPv6Address("fd00::212:4b00:14d5:2ddb"), 9 | "wsn4": IPv6Address("fd00::212:4b00:14d5:2be6"), 10 | "wsn5": IPv6Address("fd00::212:4b00:14b5:da27"), 11 | "wsn6": IPv6Address("fd00::212:4b00:14d5:2f05"), 12 | } 13 | 14 | root_node = "wsn1" 15 | 16 | device_stereotypes = { 17 | "wsn1": StereotypeTags(device_class=DeviceClass.SERVER), # Root 18 | "wsn2": StereotypeTags(device_class=DeviceClass.RASPBERRY_PI), # Edge 19 | "wsn3": StereotypeTags(device_class=DeviceClass.IOT_MEDIUM), # IoT 20 | "wsn4": StereotypeTags(device_class=DeviceClass.IOT_MEDIUM), # IoT 21 | "wsn5": StereotypeTags(device_class=DeviceClass.IOT_MEDIUM), # IoT 22 | "wsn6": StereotypeTags(device_class=DeviceClass.RASPBERRY_PI), # Edge 23 | } 24 | 25 | hostname_to_names = { 26 | "wsn1": "root", 27 | "wsn2": "rr2", 28 | "wsn3": "wsn3", 29 | "wsn4": "wsn4", 30 | "wsn5": "wsn5", 31 | "wsn6": "rr6", 32 | } 33 | -------------------------------------------------------------------------------- /wsn/applications/monitoring/monitoring-info.c: -------------------------------------------------------------------------------- 1 | #include "monitoring.h" 2 | #include "trust-models.h" 3 | 4 | static const trust_weight_t weights[] = { 5 | #ifdef APPLICATIONS_MONITOR_THROUGHPUT 6 | { TRUST_METRIC_TASK_SUBMISSION, 2.0f/3.0f }, 7 | { TRUST_METRIC_THROUGHPUT, 1.0f/3.0f }, 8 | #else 9 | { TRUST_METRIC_TASK_SUBMISSION, 1.0f }, 10 | #endif 11 | 12 | // If the trust model uses reputation, only assign up to 13 | // this much of the total trust value from reputation 14 | { TRUST_CONF_REPUTATION_WEIGHT, 0.25f} 15 | }; 16 | 17 | static trust_weights_t weights_info = { 18 | .application_name = MONITORING_APPLICATION_NAME, 19 | .weights = weights, 20 | .num = sizeof(weights)/sizeof(*weights) 21 | }; 22 | 23 | #ifdef APPLICATIONS_MONITOR_THROUGHPUT 24 | static trust_throughput_threshold_t threshold_info = { 25 | .application_name = MONITORING_APPLICATION_NAME, 26 | .in_threshold = 0, // unused 27 | .out_threshold = 27 28 | }; 29 | #endif 30 | 31 | void init_trust_weights_monitoring(void) 32 | { 33 | trust_weights_add(&weights_info); 34 | 35 | #ifdef APPLICATIONS_MONITOR_THROUGHPUT 36 | trust_throughput_thresholds_add(&threshold_info); 37 | #endif 38 | } 39 | -------------------------------------------------------------------------------- /wsn/common/nanocbor/config/nanocbor-helper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "nanocbor/nanocbor.h" 4 | 5 | #include "cc.h" 6 | #include "uip.h" 7 | 8 | #define NANOCBOR_CHECK(expr) \ 9 | do { \ 10 | const int result = (expr); \ 11 | if (result < 0) \ 12 | { \ 13 | LOG_ERR("Failed '" CC_STRINGIFY(expr) "' at " __FILE__ ":" CC_STRINGIFY(__LINE__) " (result=%d)\n", result); \ 14 | return result; \ 15 | } \ 16 | } while (0) 17 | 18 | #define NANOCBOR_GET_OBJECT(dec, obj) \ 19 | do { \ 20 | size_t len; \ 21 | NANOCBOR_CHECK(nanocbor_get_bstr(dec, (const uint8_t**)obj, &len)); \ 22 | if (len != sizeof(**obj)) \ 23 | { \ 24 | LOG_ERR("Failed NANOCBOR_GET_OBJECT at " __FILE__ ":" CC_STRINGIFY(__LINE__) " (%zu != %zu)\n", len, sizeof(**obj)); \ 25 | return -1; \ 26 | } \ 27 | } while (0) 28 | 29 | #define IPV6ADDR_CBOR_MAX_LEN ((1) + (16)) 30 | 31 | int nanocbor_fmt_ipaddr(nanocbor_encoder_t *enc, const uip_ip6addr_t *addr); 32 | int nanocbor_get_ipaddr(nanocbor_value_t *cvalue, const uip_ip6addr_t **addr); 33 | 34 | int nanocbor_get_bstr_of_len(nanocbor_value_t *cvalue, uint8_t *buf, size_t len); 35 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-dos-edge/run.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Run Throughput Dos Edge - Root 3 | hosts: iris1 4 | gather_facts: no 5 | 6 | tasks: 7 | - name: Root 8 | ansible.builtin.shell: 9 | cmd: nohup ./tests/scenarios/throughput-dos-edge/root.sh -d & 10 | chdir: ~/deploy/iot-trust-task-alloc/ 11 | 12 | - name: Run Throughput Dos Edge - Edge 13 | hosts: iris3 iris10 14 | gather_facts: no 15 | 16 | tasks: 17 | - name: Edge 18 | ansible.builtin.shell: 19 | cmd: nohup ./tests/scenarios/throughput-dos-edge/edge.sh -d & 20 | chdir: ~/deploy/iot-trust-task-alloc/ 21 | 22 | - name: Run Throughput Dos Edge - WSN 23 | hosts: iris2 iris4 iris5 24 | gather_facts: no 25 | 26 | tasks: 27 | - name: WSN 28 | ansible.builtin.shell: 29 | cmd: nohup ./tests/scenarios/throughput-dos-edge/wsn.sh -d & 30 | chdir: ~/deploy/iot-trust-task-alloc/ 31 | 32 | - name: Run Throughput Dos Edge - Adversary 33 | hosts: iris6 iris7 iris9 34 | gather_facts: no 35 | 36 | tasks: 37 | - name: Adversary 38 | ansible.builtin.shell: 39 | cmd: nohup ./tests/scenarios/throughput-dos-edge/adversary.sh -d & 40 | chdir: ~/deploy/iot-trust-task-alloc/ 41 | -------------------------------------------------------------------------------- /common/stereotype_tags.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | from dataclasses import dataclass 3 | 4 | class DeviceClass(IntEnum): 5 | RASPBERRY_PI = 1 6 | PHONE = 2 7 | LAPTOP = 3 8 | DESKTOP = 4 9 | SERVER = 5 10 | 11 | IOT_LOW = 6 12 | IOT_MEDIUM = 7 13 | IOT_HIGH = 8 14 | 15 | def encode(self): 16 | return int(self) 17 | 18 | def cname(self): 19 | return "DEVICE_CLASS_" + self.name 20 | 21 | def is_iot(self): 22 | return self in (self.IOT_LOW, self.IOT_MEDIUM, self.IOT_HIGH) 23 | 24 | def __str__(self): 25 | return self.name 26 | 27 | @staticmethod 28 | def from_string(s): 29 | try: 30 | return DeviceClass[s] 31 | except KeyError: 32 | raise ValueError() 33 | 34 | @dataclass 35 | class StereotypeTags: 36 | device_class: DeviceClass 37 | 38 | def __post_init__(self): 39 | super().__setattr__("device_class", DeviceClass(self.device_class)) 40 | 41 | def encode(self): 42 | return [ 43 | self.device_class.encode() 44 | ] 45 | 46 | @staticmethod 47 | def decode(data: bytes): 48 | return StereotypeTags( 49 | device_class=DeviceClass(data[0]) 50 | ) 51 | -------------------------------------------------------------------------------- /tests/papers/infocom2021/configuration.py: -------------------------------------------------------------------------------- 1 | from common.stereotype_tags import StereotypeTags, DeviceClass 2 | 3 | from ipaddress import IPv6Address 4 | 5 | hostname_to_ips = { 6 | "wsn1": IPv6Address("fd00::1"), 7 | "wsn2": IPv6Address("fd00::212:4b00:14d5:2bd6"), 8 | "wsn3": IPv6Address("fd00::212:4b00:14d5:2ddb"), 9 | "wsn4": IPv6Address("fd00::212:4b00:14d5:2be6"), 10 | "wsn5": IPv6Address("fd00::212:4b00:14b5:da27"), 11 | "wsn6": IPv6Address("fd00::212:4b00:14d5:2f05"), 12 | } 13 | 14 | root_node = "wsn1" 15 | 16 | device_stereotypes = { 17 | "wsn1": StereotypeTags(device_class=DeviceClass.SERVER), # Root 18 | "wsn2": StereotypeTags(device_class=DeviceClass.RASPBERRY_PI), # Edge 19 | "wsn3": StereotypeTags(device_class=DeviceClass.IOT_MEDIUM), # IoT 20 | "wsn4": StereotypeTags(device_class=DeviceClass.IOT_MEDIUM), # IoT 21 | "wsn5": StereotypeTags(device_class=DeviceClass.IOT_MEDIUM), # IoT 22 | "wsn6": StereotypeTags(device_class=DeviceClass.RASPBERRY_PI), # Edge 23 | } 24 | 25 | hostname_to_names = { 26 | "wsn1": "root", 27 | "wsn2": "rr2", 28 | "wsn3": "wsn3", 29 | "wsn4": "wsn4", 30 | "wsn5": "wsn5", 31 | "wsn6": "rr6", 32 | } 33 | -------------------------------------------------------------------------------- /tests/papers/sac2021/configuration.py: -------------------------------------------------------------------------------- 1 | from common.stereotype_tags import StereotypeTags, DeviceClass 2 | 3 | from ipaddress import IPv6Address 4 | 5 | hostname_to_ips = { 6 | "wsn1": IPv6Address("fd00::1"), 7 | "wsn2": IPv6Address("fd00::212:4b00:14d5:2bd6"), 8 | "wsn3": IPv6Address("fd00::212:4b00:14d5:2ddb"), 9 | "wsn4": IPv6Address("fd00::212:4b00:14d5:2be6"), 10 | "wsn5": IPv6Address("fd00::212:4b00:14b5:da27"), 11 | "wsn6": IPv6Address("fd00::212:4b00:14d5:2f05"), 12 | } 13 | 14 | root_node = "wsn1" 15 | 16 | device_stereotypes = { 17 | "wsn1": StereotypeTags(device_class=DeviceClass.SERVER), # Root 18 | "wsn2": StereotypeTags(device_class=DeviceClass.RASPBERRY_PI), # Edge 19 | "wsn3": StereotypeTags(device_class=DeviceClass.IOT_MEDIUM), # IoT 20 | "wsn4": StereotypeTags(device_class=DeviceClass.IOT_MEDIUM), # IoT 21 | "wsn5": StereotypeTags(device_class=DeviceClass.IOT_MEDIUM), # IoT 22 | "wsn6": StereotypeTags(device_class=DeviceClass.RASPBERRY_PI), # Edge 23 | } 24 | 25 | hostname_to_names = { 26 | "wsn1": "root", 27 | "wsn2": "rr2", 28 | "wsn3": "wsn3", 29 | "wsn4": "wsn4", 30 | "wsn5": "wsn5", 31 | "wsn6": "rr6", 32 | } 33 | -------------------------------------------------------------------------------- /tests/papers/tiot2022/configuration.py: -------------------------------------------------------------------------------- 1 | from common.stereotype_tags import StereotypeTags, DeviceClass 2 | 3 | from ipaddress import IPv6Address 4 | 5 | hostname_to_ips = { 6 | "wsn1": IPv6Address("fd00::1"), 7 | "wsn2": IPv6Address("fd00::212:4b00:14d5:2bd6"), 8 | "wsn3": IPv6Address("fd00::212:4b00:14d5:2ddb"), 9 | "wsn4": IPv6Address("fd00::212:4b00:14d5:2be6"), 10 | "wsn5": IPv6Address("fd00::212:4b00:14b5:da27"), 11 | "wsn6": IPv6Address("fd00::212:4b00:14d5:2f05"), 12 | } 13 | 14 | root_node = "wsn1" 15 | 16 | device_stereotypes = { 17 | "wsn1": StereotypeTags(device_class=DeviceClass.SERVER), # Root 18 | "wsn2": StereotypeTags(device_class=DeviceClass.RASPBERRY_PI), # Edge 19 | "wsn3": StereotypeTags(device_class=DeviceClass.IOT_MEDIUM), # IoT 20 | "wsn4": StereotypeTags(device_class=DeviceClass.IOT_MEDIUM), # IoT 21 | "wsn5": StereotypeTags(device_class=DeviceClass.IOT_MEDIUM), # IoT 22 | "wsn6": StereotypeTags(device_class=DeviceClass.RASPBERRY_PI), # Edge 23 | } 24 | 25 | hostname_to_names = { 26 | "wsn1": "root", 27 | "wsn2": "rr2", 28 | "wsn3": "wsn3", 29 | "wsn4": "wsn4", 30 | "wsn5": "wsn5", 31 | "wsn6": "rr6", 32 | } 33 | -------------------------------------------------------------------------------- /wsn/node/Makefile: -------------------------------------------------------------------------------- 1 | CONTIKI_PROJECT = node 2 | all: $(CONTIKI_PROJECT) 3 | 4 | include ../Makefile.common 5 | 6 | CFLAGS += -DTRUST_NODE=1 7 | 8 | ifeq ($(TRUST_MODEL),) 9 | $(error "TRUST_MODEL not set") 10 | else 11 | CFLAGS += -DTRUST_MODEL=TRUST_MODEL_$(shell echo $(TRUST_MODEL) | tr '[:lower:]' '[:upper:]' | tr '-' '_') 12 | endif 13 | 14 | ifeq ($(TRUST_CHOOSE),) 15 | $(error "TRUST_CHOOSE not set") 16 | else 17 | CFLAGS += -DTRUST_CHOOSE=TRUST_CHOOSE_$(shell echo $(TRUST_CHOOSE) | tr '[:lower:]' '[:upper:]' | tr '-' '_') 18 | endif 19 | 20 | # Include application modules 21 | MODULES_REL += ./trust 22 | MODULES_REL += ../common/trust/models/$(TRUST_MODEL) 23 | MODULES_REL += ../common/trust/choose/$(TRUST_CHOOSE) ../common/trust/choose/ 24 | 25 | # Applications to include 26 | ifndef APPLICATIONS 27 | # Set default applications if not requesting specifics 28 | APPLICATIONS = monitoring routing challenge-response 29 | endif 30 | include ../applications/Makefile.include 31 | 32 | # Enable when automatic job submission for routing is required 33 | ifneq (,$(findstring routing,$(APPLICATIONS))) 34 | MODULES_REL += ../applications/routing/node/test 35 | CFLAGS += -DROUTING_PERIODIC_TEST 36 | endif 37 | 38 | # Main Contiki-NG compile 39 | include $(CONTIKI)/Makefile.include 40 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-periodically-slow/run.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Run Throughput Periodically Slow - Root 3 | hosts: iris1 4 | gather_facts: no 5 | 6 | tasks: 7 | - name: Root 8 | ansible.builtin.shell: 9 | cmd: nohup ./tests/scenarios/throughput-periodically-slow/root.sh -d & 10 | chdir: ~/deploy/iot-trust-task-alloc/ 11 | 12 | - name: Run Throughput Periodically Slow - Edge 13 | hosts: iris3 14 | gather_facts: no 15 | 16 | tasks: 17 | - name: Edge 18 | ansible.builtin.shell: 19 | cmd: nohup ./tests/scenarios/throughput-periodically-slow/edge.sh -d & 20 | chdir: ~/deploy/iot-trust-task-alloc/ 21 | 22 | - name: Run Throughput Periodically Slow - Bad Edge 23 | hosts: iris10 24 | gather_facts: no 25 | 26 | tasks: 27 | - name: Bad Edge 28 | ansible.builtin.shell: 29 | cmd: nohup ./tests/scenarios/throughput-periodically-slow/bad_edge.sh -d & 30 | chdir: ~/deploy/iot-trust-task-alloc/ 31 | 32 | - name: Run Throughput Periodically Slow - WSN 33 | hosts: iris2 iris4 iris5 iris6 iris7 iris9 34 | gather_facts: no 35 | 36 | tasks: 37 | - name: WSN 38 | ansible.builtin.shell: 39 | cmd: nohup ./tests/scenarios/throughput-periodically-slow/wsn.sh -d & 40 | chdir: ~/deploy/iot-trust-task-alloc/ 41 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-routing-always-slow/run.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Run Throughput Routing Always Slow - Root 3 | hosts: iris1 4 | gather_facts: no 5 | 6 | tasks: 7 | - name: Root 8 | ansible.builtin.shell: 9 | cmd: nohup ./tests/scenarios/throughput-routing-always-slow/root.sh -d & 10 | chdir: ~/deploy/iot-trust-task-alloc/ 11 | 12 | - name: Run Throughput Routing Always Slow - Edge 13 | hosts: iris3 14 | gather_facts: no 15 | 16 | tasks: 17 | - name: Edge 18 | ansible.builtin.shell: 19 | cmd: nohup ./tests/scenarios/throughput-routing-always-slow/edge.sh -d & 20 | chdir: ~/deploy/iot-trust-task-alloc/ 21 | 22 | - name: Run Throughput Routing Always Slow - Bad Edge 23 | hosts: iris10 24 | gather_facts: no 25 | 26 | tasks: 27 | - name: Bad Edge 28 | ansible.builtin.shell: 29 | cmd: nohup ./tests/scenarios/throughput-routing-always-slow/bad_edge.sh -d & 30 | chdir: ~/deploy/iot-trust-task-alloc/ 31 | 32 | - name: Run Throughput Routing Always Slow - WSN 33 | hosts: iris2 iris4 iris5 iris6 iris7 iris9 34 | gather_facts: no 35 | 36 | tasks: 37 | - name: WSN 38 | ansible.builtin.shell: 39 | cmd: nohup ./tests/scenarios/throughput-routing-always-slow/wsn.sh -d & 40 | chdir: ~/deploy/iot-trust-task-alloc/ 41 | -------------------------------------------------------------------------------- /wsn/common/trust/stereotypes/stereotype-tags.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "nanocbor/nanocbor.h" 6 | 7 | #include "device-classes.h" 8 | /*-------------------------------------------------------------------------------------------------------------------*/ 9 | typedef struct { 10 | uint8_t device_class; 11 | 12 | } stereotype_tags_t; 13 | /*-------------------------------------------------------------------------------------------------------------------*/ 14 | int serialise_stereotype_tags(nanocbor_encoder_t* enc, const stereotype_tags_t* tags); 15 | int deserialise_stereotype_tags(nanocbor_value_t* dec, stereotype_tags_t* tags); 16 | /*-------------------------------------------------------------------------------------------------------------------*/ 17 | #define STEREOTYPE_TAGS_CBOR_MAX_LEN ((1) + (1)) 18 | /*-------------------------------------------------------------------------------------------------------------------*/ 19 | bool stereotype_tags_equal(const stereotype_tags_t* a, const stereotype_tags_t* b); 20 | /*-------------------------------------------------------------------------------------------------------------------*/ 21 | void stereotype_tags_print(const stereotype_tags_t* tags); 22 | /*-------------------------------------------------------------------------------------------------------------------*/ 23 | -------------------------------------------------------------------------------- /tests/scenarios/throughput-power-periodically-off/run.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Run Throughput Power Periodically Off - Root 3 | hosts: iris1 4 | gather_facts: no 5 | 6 | tasks: 7 | - name: Root 8 | ansible.builtin.shell: 9 | cmd: nohup ./tests/scenarios/throughput-power-periodically-off/root.sh -d & 10 | chdir: ~/deploy/iot-trust-task-alloc/ 11 | 12 | - name: Run Throughput Power Periodically Off - Edge 13 | hosts: iris3 14 | gather_facts: no 15 | 16 | tasks: 17 | - name: Edge 18 | ansible.builtin.shell: 19 | cmd: nohup ./tests/scenarios/throughput-power-periodically-off/edge.sh -d & 20 | chdir: ~/deploy/iot-trust-task-alloc/ 21 | 22 | - name: Run Throughput Power Periodically Off - Bad Edge 23 | hosts: iris10 24 | gather_facts: no 25 | 26 | tasks: 27 | - name: Edge 28 | ansible.builtin.shell: 29 | cmd: nohup ./tests/scenarios/throughput-power-periodically-off/bad_edge.sh -d & 30 | chdir: ~/deploy/iot-trust-task-alloc/ 31 | 32 | - name: Run Throughput Power Periodically Off - WSN 33 | hosts: iris2 iris4 iris5 iris6 iris7 iris9 34 | gather_facts: no 35 | 36 | tasks: 37 | - name: WSN 38 | ansible.builtin.shell: 39 | cmd: nohup ./tests/scenarios/throughput-power-periodically-off/wsn.sh -d & 40 | chdir: ~/deploy/iot-trust-task-alloc/ 41 | -------------------------------------------------------------------------------- /tools/regenerate_pcaps.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from __future__ import annotations 3 | 4 | import os 5 | import pathlib 6 | import multiprocessing.pool 7 | 8 | import regenerate_pcap 9 | 10 | def main(directory: pathlib.Path, num_procs: int, timeout: Optional[int]): 11 | sources = list(directory.glob("*.packet.log")) 12 | destinations = [src.parent / (src.name + '.pcap') for src in sources] 13 | 14 | args = list(zip(sources, destinations, [timeout]*len(sources))) 15 | 16 | print(f"Generating pcaps for {sources}") 17 | print(f"using {num_procs} processes") 18 | 19 | with multiprocessing.pool.Pool(num_procs) as pool: 20 | pool.starmap(regenerate_pcap.main, args) 21 | 22 | if __name__ == "__main__": 23 | import argparse 24 | 25 | parser = argparse.ArgumentParser(description='Regenerate pcap files from the raw log') 26 | parser.add_argument('directory', type=pathlib.Path, help='The directory containing multiple pcap logs to convert') 27 | parser.add_argument('--num-procs', type=int, required=False, default=len(os.sched_getaffinity(0)), help='The number of processes to use') 28 | parser.add_argument('--timeout', type=regenerate_pcap.int_or_None, default=600, help='The timeout per file in seconds. pass "None" for no timeout.') 29 | 30 | args = parser.parse_args() 31 | 32 | main(args.directory, args.num_procs, args.timeout) 33 | -------------------------------------------------------------------------------- /wsn/applications/challenge-response/challenge-response.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | /*-------------------------------------------------------------------------------------------------------------------*/ 5 | #define CHALLENGE_RESPONSE_APPLICATION_NAME "cr" 6 | #define CHALLENGE_RESPONSE_APPLICATION_URI "cr" 7 | /*-------------------------------------------------------------------------------------------------------------------*/ 8 | typedef struct { 9 | uint8_t data[32]; 10 | uint8_t difficulty; 11 | uint32_t max_duration_secs; 12 | } challenge_t; 13 | /*-------------------------------------------------------------------------------------------------------------------*/ 14 | typedef struct { 15 | const uint8_t* data_prefix; 16 | uint8_t data_length; 17 | uint32_t duration_secs; 18 | } challenge_response_t; 19 | /*-------------------------------------------------------------------------------------------------------------------*/ 20 | int nanocbor_fmt_challenge(uint8_t* buf, size_t buf_len, const challenge_t* c); 21 | /*-------------------------------------------------------------------------------------------------------------------*/ 22 | int nanocbor_get_challenge_response(const uint8_t* buf, size_t buf_len, challenge_response_t* cr); 23 | /*-------------------------------------------------------------------------------------------------------------------*/ 24 | -------------------------------------------------------------------------------- /wsn/applications/routing/routing-info.c: -------------------------------------------------------------------------------- 1 | #include "routing.h" 2 | #include "trust-models.h" 3 | 4 | static const trust_weight_t weights[] = { 5 | #ifdef APPLICATIONS_MONITOR_THROUGHPUT 6 | { TRUST_METRIC_TASK_SUBMISSION, 1.0f/4.0f }, 7 | { TRUST_METRIC_TASK_RESULT, 1.0f/4.0f }, 8 | { TRUST_METRIC_RESULT_QUALITY, 1.0f/4.0f }, 9 | { TRUST_METRIC_THROUGHPUT, 1.0f/4.0f }, 10 | #else 11 | { TRUST_METRIC_TASK_SUBMISSION, 1.0f/3.0f }, 12 | { TRUST_METRIC_TASK_RESULT, 1.0f/3.0f }, 13 | { TRUST_METRIC_RESULT_QUALITY, 1.0f/3.0f }, 14 | #endif 15 | 16 | // If the trust model uses reputation, only assign up to 17 | // this much of the total trust value from reputation 18 | { TRUST_CONF_REPUTATION_WEIGHT, 0.25f } 19 | }; 20 | 21 | static trust_weights_t weights_info = { 22 | .application_name = ROUTING_APPLICATION_NAME, 23 | .weights = weights, 24 | .num = sizeof(weights)/sizeof(*weights) 25 | }; 26 | 27 | #ifdef APPLICATIONS_MONITOR_THROUGHPUT 28 | static trust_throughput_threshold_t threshold_info = { 29 | .application_name = ROUTING_APPLICATION_NAME, 30 | .in_threshold = 425, 31 | .out_threshold = 75 32 | }; 33 | #endif 34 | 35 | void init_trust_weights_routing(void) 36 | { 37 | trust_weights_add(&weights_info); 38 | 39 | #ifdef APPLICATIONS_MONITOR_THROUGHPUT 40 | trust_throughput_thresholds_add(&threshold_info); 41 | #endif 42 | } 43 | -------------------------------------------------------------------------------- /wsn/common/timed-unlock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /*-------------------------------------------------------------------------------------------------------------------*/ 3 | #include 4 | #include "ctimer.h" 5 | #include "process.h" 6 | /*-------------------------------------------------------------------------------------------------------------------*/ 7 | typedef struct { 8 | bool locked; 9 | const char* name; 10 | struct ctimer timer; 11 | clock_time_t duration; 12 | struct process* p; 13 | } timed_unlock_t; 14 | /*-------------------------------------------------------------------------------------------------------------------*/ 15 | void timed_unlock_global_init(void); 16 | /*-------------------------------------------------------------------------------------------------------------------*/ 17 | void timed_unlock_init(timed_unlock_t* l, const char* name, clock_time_t duration); 18 | bool timed_unlock_is_locked(const timed_unlock_t* l); 19 | void timed_unlock_lock(timed_unlock_t* l); 20 | void timed_unlock_unlock(timed_unlock_t* l); 21 | void timed_unlock_restart_timer(timed_unlock_t* l); 22 | /*-------------------------------------------------------------------------------------------------------------------*/ 23 | extern process_event_t pe_timed_unlock_unlocked; 24 | /*-------------------------------------------------------------------------------------------------------------------*/ 25 | -------------------------------------------------------------------------------- /wsn/common/trust/trust-common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "os/net/ipv6/uip.h" 7 | /*-------------------------------------------------------------------------------------------------------------------*/ 8 | #define MQTT_EDGE_NAMESPACE "edge" 9 | #define MQTT_EDGE_NAMESPACE_LEN 4 10 | 11 | #define MQTT_IDENTITY_LEN (8 * 2) // Eight two character hex digits 12 | 13 | #define EDGE_CAPABILITY_NAME_LEN 15 14 | 15 | #define MQTT_EDGE_ACTION_ANNOUNCE "announce" 16 | #define MQTT_EDGE_ACTION_UNANNOUNCE "unannounce" 17 | #define MQTT_EDGE_ACTION_CAPABILITY "capability" 18 | #define MQTT_EDGE_ACTION_CAPABILITY_ADD "add" 19 | #define MQTT_EDGE_ACTION_CAPABILITY_REMOVE "remove" 20 | /*-------------------------------------------------------------------------------------------------------------------*/ 21 | void trust_common_init(void); 22 | /*-------------------------------------------------------------------------------------------------------------------*/ 23 | int serialise_trust(const uip_ipaddr_t* addr, uint8_t* buffer, size_t buffer_len); 24 | /*-------------------------------------------------------------------------------------------------------------------*/ 25 | int process_received_trust(const uip_ipaddr_t* src, const uint8_t* buffer, size_t buffer_len); 26 | /*-------------------------------------------------------------------------------------------------------------------*/ 27 | -------------------------------------------------------------------------------- /wsn/adversary/adversary.c: -------------------------------------------------------------------------------- 1 | #include "contiki.h" 2 | #include "sys/log.h" 3 | 4 | #include "timed-unlock.h" 5 | #include "root-endpoint.h" 6 | /*-------------------------------------------------------------------------------------------------------------------*/ 7 | #define LOG_MODULE "attack" 8 | #define LOG_LEVEL LOG_LEVEL_DBG 9 | /*-------------------------------------------------------------------------------------------------------------------*/ 10 | PROCESS_NAME(mqtt_client_process); 11 | PROCESS_NAME(keystore_add_verifier); 12 | //APPLICATION_PROCESSES_DECL; 13 | ATTACK_PROCESSES_DECL; 14 | PROCESS(adversary, "adversary"); 15 | /*-------------------------------------------------------------------------------------------------------------------*/ 16 | AUTOSTART_PROCESSES(&adversary, &mqtt_client_process, 17 | &keystore_add_verifier, 18 | //APPLICATION_PROCESSES, 19 | ATTACK_PROCESSES); 20 | /*-------------------------------------------------------------------------------------------------------------------*/ 21 | PROCESS_THREAD(adversary, ev, data) 22 | { 23 | PROCESS_BEGIN(); 24 | 25 | #ifdef BUILD_NUMBER 26 | LOG_INFO("BUILD NUMBER = %u\n", BUILD_NUMBER); 27 | #endif 28 | 29 | timed_unlock_global_init(); 30 | root_endpoint_init(); 31 | 32 | PROCESS_END(); 33 | } 34 | /*-------------------------------------------------------------------------------------------------------------------*/ 35 | -------------------------------------------------------------------------------- /wsn/common/pcap/pcap-loggers.c: -------------------------------------------------------------------------------- 1 | #include "os/sys/log.h" 2 | /*-------------------------------------------------------------------------------------------------------------------*/ 3 | #define LOG_MODULE "serial-pcap" 4 | #define LOG_LEVEL LOG_LEVEL_DBG 5 | /*-------------------------------------------------------------------------------------------------------------------*/ 6 | #define PCAP_PREFIX "#" 7 | /*-------------------------------------------------------------------------------------------------------------------*/ 8 | void pcap_log_input(const void *payload, unsigned short payload_len) 9 | { 10 | LOG_PRINT_(PCAP_PREFIX "In|%hu|", payload_len); 11 | LOG_PRINT_BYTES(payload, payload_len); 12 | LOG_PRINT_("\n"); 13 | } 14 | /*-------------------------------------------------------------------------------------------------------------------*/ 15 | void pcap_log_output(const void *payload, unsigned short payload_len) 16 | { 17 | LOG_PRINT_(PCAP_PREFIX "Out|%hu|", payload_len); 18 | LOG_PRINT_BYTES(payload, payload_len); 19 | LOG_PRINT_("\n"); 20 | } 21 | /*-------------------------------------------------------------------------------------------------------------------*/ 22 | void pcap_log_output_result(unsigned short payload_len, int res) 23 | { 24 | LOG_PRINT_(PCAP_PREFIX "OutRes|%hu|%d\n", payload_len, res); 25 | } 26 | /*-------------------------------------------------------------------------------------------------------------------*/ 27 | -------------------------------------------------------------------------------- /tools/fetch_results.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | import getpass 5 | import argparse 6 | import pathlib 7 | import pexpect 8 | 9 | from common.configuration import hostname_to_ips as ips, root_node 10 | 11 | parser = argparse.ArgumentParser(description='Fetch Results') 12 | parser.add_argument('target', type=pathlib.Path, help='The target directory to save results to') 13 | args = parser.parse_args() 14 | 15 | password = getpass.getpass("Password: ") 16 | 17 | # Create the target directory 18 | args.target.mkdir(parents=True, exist_ok=True) 19 | 20 | print(f"Saving to {args.target}") 21 | 22 | # Also very important to fetch the keystore, in order to faciltate decrypting the results 23 | print(f"Fetching keystore from root node on {root_node}") 24 | cmd = f"/bin/bash -c 'rsync -avz pi@{root_node}:/home/pi/iot-trust-task-alloc/resource_rich/root/keystore/ {args.target/'keystore'}'" 25 | print(cmd) 26 | child = pexpect.spawn(cmd, encoding='utf-8') 27 | child.logfile_read = sys.stdout 28 | child.expect('password:') 29 | child.sendline(password) 30 | child.expect(pexpect.EOF) 31 | 32 | for hostname in ips.keys(): 33 | print(f"Fetching results for {hostname}...") 34 | cmd = f"/bin/bash -c 'rsync -avz pi@{hostname}:/home/pi/iot-trust-task-alloc/logs/* {args.target}'" 35 | print(cmd) 36 | child = pexpect.spawn(cmd, encoding='utf-8') 37 | child.logfile_read = sys.stdout 38 | child.expect('password:') 39 | child.sendline(password) 40 | child.expect(pexpect.EOF) 41 | -------------------------------------------------------------------------------- /wsn/node/node.c: -------------------------------------------------------------------------------- 1 | #include "contiki.h" 2 | #include "sys/log.h" 3 | 4 | #include "timed-unlock.h" 5 | #include "root-endpoint.h" 6 | /*-------------------------------------------------------------------------------------------------------------------*/ 7 | #define LOG_MODULE "node" 8 | #define LOG_LEVEL LOG_LEVEL_DBG 9 | /*-------------------------------------------------------------------------------------------------------------------*/ 10 | PROCESS_NAME(mqtt_client_process); 11 | PROCESS_NAME(trust_model); 12 | PROCESS_NAME(keystore_add_verifier); 13 | APPLICATION_PROCESSES_DECL; 14 | PROCESS(node, "node"); 15 | /*-------------------------------------------------------------------------------------------------------------------*/ 16 | AUTOSTART_PROCESSES(&node, &trust_model, &mqtt_client_process, 17 | &keystore_add_verifier, 18 | APPLICATION_PROCESSES); 19 | /*-------------------------------------------------------------------------------------------------------------------*/ 20 | PROCESS_THREAD(node, ev, data) 21 | { 22 | PROCESS_BEGIN(); 23 | 24 | #ifdef BUILD_NUMBER 25 | LOG_INFO("BUILD NUMBER = %u\n", BUILD_NUMBER); 26 | #endif 27 | #ifdef ADDITIONAL_CFLAGS 28 | LOG_INFO("Built with ADDITIONAL_CFLAGS = '" ADDITIONAL_CFLAGS "'\n"); 29 | #endif 30 | 31 | timed_unlock_global_init(); 32 | root_endpoint_init(); 33 | 34 | PROCESS_END(); 35 | } 36 | /*-------------------------------------------------------------------------------------------------------------------*/ 37 | -------------------------------------------------------------------------------- /tools/run/wsn.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import time 5 | from pathlib import Path 6 | 7 | from tools.run import supported_firmware_types, DEFAULT_LOG_DIR 8 | from tools.run.util import TermApplicationRunner 9 | from tools.keygen.util import eui64_to_ipv6 10 | 11 | class WSNRunner(TermApplicationRunner): 12 | log_name = "wsn" 13 | 14 | def run(self): 15 | print(f"CWD: {Path.cwd()}", flush=True) 16 | print(f"Logging motelist to {self.motelist_log_path}", flush=True) 17 | print(f"Logging flash to {self.flash_log_path}", flush=True) 18 | print(f"Logging pyterm to {self.pyterm_log_path}", flush=True) 19 | 20 | self.run_motelist() 21 | 22 | time.sleep(0.1) 23 | 24 | device_firmware_dir = str(eui64_to_ipv6(self.device.eui64)).replace(":", "_") 25 | firmware_path = f"{device_firmware_dir}/node.bin" 26 | 27 | self.run_flash(firmware_path) 28 | 29 | time.sleep(0.1) 30 | 31 | self.run_pyterm() 32 | 33 | parser = argparse.ArgumentParser(description='WSN runner') 34 | parser.add_argument('--log-dir', type=Path, default=DEFAULT_LOG_DIR, help='The directory to store log output') 35 | parser.add_argument("--firmware-type", 36 | choices=supported_firmware_types, 37 | default=supported_firmware_types[0], 38 | help="The OS that was used to create the firmware.") 39 | args = parser.parse_args() 40 | 41 | runner = WSNRunner(args.log_dir, args.firmware_type) 42 | runner.run() 43 | -------------------------------------------------------------------------------- /tools/run/profile.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import time 5 | from pathlib import Path 6 | 7 | from tools.run import supported_firmware_types, DEFAULT_LOG_DIR 8 | from tools.run.util import TermApplicationRunner 9 | from tools.keygen.util import eui64_to_ipv6 10 | 11 | class ProfileRunner(TermApplicationRunner): 12 | log_name = "profile" 13 | 14 | def run(self): 15 | print(f"CWD: {Path.cwd()}", flush=True) 16 | print(f"Logging motelist to {self.motelist_log_path}", flush=True) 17 | print(f"Logging flash to {self.flash_log_path}", flush=True) 18 | print(f"Logging pyterm to {self.pyterm_log_path}", flush=True) 19 | 20 | self.run_motelist() 21 | 22 | time.sleep(0.1) 23 | 24 | device_firmware_dir = str(eui64_to_ipv6(self.device.eui64)).replace(":", "_") 25 | firmware_path = f"{device_firmware_dir}/profile.bin" 26 | 27 | self.run_flash(firmware_path) 28 | 29 | time.sleep(0.1) 30 | 31 | self.run_pyterm() 32 | 33 | parser = argparse.ArgumentParser(description='Profile runner') 34 | parser.add_argument('--log-dir', type=Path, default=DEFAULT_LOG_DIR, help='The directory to store log output') 35 | parser.add_argument("--firmware-type", 36 | choices=supported_firmware_types, 37 | default=supported_firmware_types[0], 38 | help="The OS that was used to create the firmware.") 39 | args = parser.parse_args() 40 | 41 | runner = ProfileRunner(args.log_dir, args.firmware_type) 42 | runner.run() 43 | -------------------------------------------------------------------------------- /wsn/common/root-endpoint.c: -------------------------------------------------------------------------------- 1 | #include "root-endpoint.h" 2 | 3 | #include "os/sys/log.h" 4 | /*-------------------------------------------------------------------------------------------------------------------*/ 5 | #define LOG_MODULE "common" 6 | #ifdef MQTT_CLIENT_CONF_LOG_LEVEL 7 | #define LOG_LEVEL MQTT_CLIENT_CONF_LOG_LEVEL 8 | #else 9 | #define LOG_LEVEL LOG_LEVEL_ERR 10 | #endif 11 | /*-------------------------------------------------------------------------------------------------------------------*/ 12 | #ifndef ROOT_IP_ADDR 13 | #define ROOT_IP_ADDR "fd00::1" 14 | #endif 15 | /*-------------------------------------------------------------------------------------------------------------------*/ 16 | #define ROOT_COAP_ADDR "coap://[" ROOT_IP_ADDR "]" 17 | /*-------------------------------------------------------------------------------------------------------------------*/ 18 | coap_endpoint_t root_ep; 19 | /*-------------------------------------------------------------------------------------------------------------------*/ 20 | bool root_endpoint_init(void) 21 | { 22 | int ret = coap_endpoint_parse(ROOT_COAP_ADDR, strlen(ROOT_COAP_ADDR), &root_ep); 23 | if (!ret) 24 | { 25 | LOG_ERR("CoAP Endpoint failed to be set to %s\n", ROOT_COAP_ADDR); 26 | return false; 27 | } 28 | else 29 | { 30 | LOG_DBG("CoAP Endpoint set to %s\n", ROOT_COAP_ADDR); 31 | } 32 | 33 | return true; 34 | } 35 | /*-------------------------------------------------------------------------------------------------------------------*/ 36 | -------------------------------------------------------------------------------- /tools/run/adversary.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import time 5 | from pathlib import Path 6 | 7 | from tools.run import supported_firmware_types, DEFAULT_LOG_DIR 8 | from tools.run.util import TermApplicationRunner 9 | from tools.keygen.util import eui64_to_ipv6 10 | 11 | class AdversaryRunner(TermApplicationRunner): 12 | log_name = "adversary" 13 | 14 | def run(self): 15 | print(f"CWD: {Path.cwd()}", flush=True) 16 | print(f"Logging motelist to {self.motelist_log_path}", flush=True) 17 | print(f"Logging flash to {self.flash_log_path}", flush=True) 18 | print(f"Logging pyterm to {self.pyterm_log_path}", flush=True) 19 | 20 | self.run_motelist() 21 | 22 | time.sleep(0.1) 23 | 24 | device_firmware_dir = str(eui64_to_ipv6(self.device.eui64)).replace(":", "_") 25 | firmware_path = f"{device_firmware_dir}/adversary.bin" 26 | 27 | self.run_flash(firmware_path) 28 | 29 | time.sleep(0.1) 30 | 31 | self.run_pyterm() 32 | 33 | parser = argparse.ArgumentParser(description='Adversary runner') 34 | parser.add_argument('--log-dir', type=Path, default=DEFAULT_LOG_DIR, help='The directory to store log output') 35 | parser.add_argument("--firmware_type", 36 | choices=supported_firmware_types, 37 | default=supported_firmware_types[0], 38 | help="The OS that was used to create the firmware.") 39 | args = parser.parse_args() 40 | 41 | runner = AdversaryRunner(args.log_dir, args.firmware_type) 42 | runner.run() 43 | -------------------------------------------------------------------------------- /wsn/common/trust/stereotypes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "stereotype-tags.h" 4 | #include "trust-model.h" 5 | 6 | // This should be the maximum number of tag combinations 7 | // Likely to get big, so try to keep small 8 | #ifndef MAX_NUM_STEREOTYPES 9 | #define MAX_NUM_STEREOTYPES 5 10 | #endif 11 | 12 | /*-------------------------------------------------------------------------------------------------------------------*/ 13 | typedef struct edge_stereotype { 14 | struct edge_stereotype* next; 15 | 16 | stereotype_tags_t tags; 17 | 18 | edge_resource_tm_t edge_tm; 19 | 20 | // TODO: Could consider edge capability stereotypes, 21 | // for now focus on the edge stereotypes only. 22 | 23 | } edge_stereotype_t; 24 | /*-------------------------------------------------------------------------------------------------------------------*/ 25 | void stereotypes_init(void); 26 | /*-------------------------------------------------------------------------------------------------------------------*/ 27 | bool stereotypes_request(const stereotype_tags_t* tags); 28 | /*-------------------------------------------------------------------------------------------------------------------*/ 29 | edge_stereotype_t* edge_stereotype_find(const stereotype_tags_t* tags); 30 | /*-------------------------------------------------------------------------------------------------------------------*/ 31 | bool edge_stereotype_remove(edge_stereotype_t* stereotype); 32 | /*-------------------------------------------------------------------------------------------------------------------*/ 33 | -------------------------------------------------------------------------------- /wsn/common/trust/choose/fcfs/trust-choose.c: -------------------------------------------------------------------------------- 1 | #include "trust-choose.h" 2 | #include "trust-model.h" 3 | #include "edge-info.h" 4 | #include "os/sys/log.h" 5 | /*-------------------------------------------------------------------------------------------------------------------*/ 6 | #define LOG_MODULE "trust-fcfs" 7 | #ifdef TRUST_MODEL_LOG_LEVEL 8 | #define LOG_LEVEL TRUST_MODEL_LOG_LEVEL 9 | #else 10 | #define LOG_LEVEL LOG_LEVEL_NONE 11 | #endif 12 | /*-------------------------------------------------------------------------------------------------------------------*/ 13 | // Use the first edge node we are aware of that supports 14 | // the provided capability 15 | edge_resource_t* choose_edge(const char* capability_name) 16 | { 17 | for (edge_resource_t* iter = edge_info_iter(); iter != NULL; iter = edge_info_next(iter)) 18 | { 19 | // Skip inactive edges 20 | if (!edge_info_is_active(iter)) 21 | { 22 | continue; 23 | } 24 | 25 | edge_capability_t* capability = edge_info_capability_find(iter, capability_name); 26 | if (capability == NULL) 27 | { 28 | continue; 29 | } 30 | 31 | // Skip inactive capabilities 32 | if (!edge_capability_is_active(capability)) 33 | { 34 | continue; 35 | } 36 | 37 | // Use the first edge we find that we can use 38 | return iter; 39 | } 40 | 41 | return NULL; 42 | } 43 | /*-------------------------------------------------------------------------------------------------------------------*/ 44 | -------------------------------------------------------------------------------- /wsn/common/nanocbor/config/endian-helper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "uipopt.h" 4 | 5 | #include "machine/endian.h" 6 | 7 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 8 | 9 | #if UIP_BYTE_ORDER != UIP_LITTLE_ENDIAN 10 | #error "Compiler byte order differs from UIP byte order" 11 | #endif 12 | 13 | #define htobe16(x) __bswap16(x) 14 | #define htole16(x) (uint16_t)(x) 15 | #define be16toh(x) __bswap16(x) 16 | #define le16toh(x) (uint16_t)(x) 17 | 18 | #define htobe32(x) __bswap32(x) 19 | #define htole32(x) (uint32_t)(x) 20 | #define be32toh(x) __bswap32(x) 21 | #define le32toh(x) (uint32_t)(x) 22 | 23 | #define htobe64(x) __bswap64(x) 24 | #define htole64(x) (uint64_t)(x) 25 | #define be64toh(x) __bswap64(x) 26 | #define le64toh(x) (uint64_t)(x) 27 | 28 | #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 29 | 30 | #if UIP_BYTE_ORDER == UIP_LITTLE_ENDIAN 31 | #error "Compiler byte order differs from UIP byte order" 32 | #endif 33 | 34 | #define htobe16(x) (uint16_t)(x) 35 | #define htole16(x) __bswap16(x) 36 | #define be16toh(x) (uint16_t)(x) 37 | #define le16toh(x) __bswap16(x) 38 | 39 | #define htobe32(x) (uint32_t)(x) 40 | #define htole32(x) __bswap32(x) 41 | #define be32toh(x) (uint32_t)(x) 42 | #define le32toh(x) __bswap32(x) 43 | 44 | #define htobe64(x) (uint64_t)(x) 45 | #define htole64(x) __bswap64(x) 46 | #define be64toh(x) (uint64_t)(x) 47 | #define le64toh(x) __bswap64(x) 48 | 49 | #else 50 | #error "Unknown byte order" 51 | #endif 52 | 53 | /* BSD Names */ 54 | 55 | #define betoh16(x) be16toh(x) 56 | #define betoh32(x) be32toh(x) 57 | #define betoh64(x) be64toh(x) 58 | #define letoh16(x) le16toh(x) 59 | #define letoh32(x) le32toh(x) 60 | #define letoh64(x) le64toh(x) 61 | -------------------------------------------------------------------------------- /wsn/common/crypto/keys.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /*-------------------------------------------------------------------------------------------------------------------*/ 3 | #include 4 | #include 5 | /*-------------------------------------------------------------------------------------------------------------------*/ 6 | #define DTLS_EC_KEY_SIZE (256 / CHAR_BIT) // 256 bits 7 | #define DTLS_EC_SIG_SIZE (DTLS_EC_KEY_SIZE * 2) 8 | /*-------------------------------------------------------------------------------------------------------------------*/ 9 | typedef struct ecdsa_secp256r1_pubkey { 10 | uint8_t x[DTLS_EC_KEY_SIZE]; /** < x part of the public key for the given private key (big-endian) > */ 11 | uint8_t y[DTLS_EC_KEY_SIZE]; /** < y part of the public key for the given private key (big-endian) > */ 12 | } ecdsa_secp256r1_pubkey_t; 13 | /*-------------------------------------------------------------------------------------------------------------------*/ 14 | typedef struct ecdsa_secp256r1_privkey { 15 | uint8_t k[DTLS_EC_KEY_SIZE]; /** < private key as bytes (big-endian) > */ 16 | } ecdsa_secp256r1_privkey_t; 17 | /*-------------------------------------------------------------------------------------------------------------------*/ 18 | typedef struct ecdsa_secp256r1_sig { 19 | uint8_t r[DTLS_EC_KEY_SIZE]; 20 | uint8_t s[DTLS_EC_KEY_SIZE]; 21 | } ecdsa_secp256r1_sig_t; 22 | /*-------------------------------------------------------------------------------------------------------------------*/ 23 | extern const ecdsa_secp256r1_privkey_t our_privkey; 24 | /*-------------------------------------------------------------------------------------------------------------------*/ 25 | -------------------------------------------------------------------------------- /wsn/common/trust/interaction-history.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | /*-------------------------------------------------------------------------------------------------------------------*/ 4 | #ifndef INTERACTION_HISTORY_SIZE 5 | #define INTERACTION_HISTORY_SIZE 8 6 | #endif 7 | /*-------------------------------------------------------------------------------------------------------------------*/ 8 | typedef struct interaction_history 9 | { 10 | // TODO: could consider better packing interactions (4 interactions per byte - 2 bits per interaction) 11 | uint8_t interactions[INTERACTION_HISTORY_SIZE]; 12 | 13 | uint8_t head, tail; 14 | uint8_t count; 15 | 16 | } interaction_history_t; 17 | /*-------------------------------------------------------------------------------------------------------------------*/ 18 | void interaction_history_init(interaction_history_t* hist); 19 | /*-------------------------------------------------------------------------------------------------------------------*/ 20 | void interaction_history_push(interaction_history_t* hist, uint8_t interaction); 21 | /*-------------------------------------------------------------------------------------------------------------------*/ 22 | const uint8_t* interaction_history_iter(const interaction_history_t* hist); 23 | const uint8_t* interaction_history_next(const interaction_history_t* hist, const uint8_t* iter); 24 | /*-------------------------------------------------------------------------------------------------------------------*/ 25 | void interaction_history_print(const interaction_history_t* hist); 26 | /*-------------------------------------------------------------------------------------------------------------------*/ 27 | -------------------------------------------------------------------------------- /wsn/applications/application-common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "edge-info.h" 6 | /*-------------------------------------------------------------------------------------------------------------------*/ 7 | typedef struct { 8 | const char* name; 9 | const char* uri; 10 | 11 | bool running; 12 | 13 | #ifdef APPLICATIONS_MONITOR_THROUGHPUT 14 | clock_time_t out_time; 15 | size_t out_len; 16 | 17 | clock_time_t in_time; 18 | size_t in_len; 19 | #endif 20 | 21 | } app_state_t; 22 | /*-------------------------------------------------------------------------------------------------------------------*/ 23 | void app_state_init(app_state_t* state, const char* name, const char* uri); 24 | /*-------------------------------------------------------------------------------------------------------------------*/ 25 | bool app_state_edge_capability_add(app_state_t* state, edge_resource_t* edge); 26 | bool app_state_edge_capability_remove(app_state_t* state, edge_resource_t* edge); 27 | /*-------------------------------------------------------------------------------------------------------------------*/ 28 | // Throughput is measured in bytes per clock ticks 29 | // One second is CLOCK_SECOND ticks (defaults to 32) 30 | void app_state_throughput_start_out(app_state_t* state, size_t len); 31 | uint32_t app_state_throughput_end_out(app_state_t* state, clock_time_t now); 32 | void app_state_throughput_start_in(app_state_t* state, size_t len); 33 | void app_state_throughput_update_in(app_state_t* state, size_t len); 34 | uint32_t app_state_throughput_end_in(app_state_t* state, clock_time_t now); 35 | /*-------------------------------------------------------------------------------------------------------------------*/ 36 | -------------------------------------------------------------------------------- /wsn/bad_edge/Makefile: -------------------------------------------------------------------------------- 1 | CONTIKI_PROJECT = bad_edge 2 | all: $(CONTIKI_PROJECT) 3 | 4 | include ../Makefile.common 5 | 6 | CFLAGS += -DTRUST_EDGE=1 7 | 8 | ifeq ($(TRUST_MODEL),) 9 | $(error "TRUST_MODEL not set") 10 | else 11 | CFLAGS += -DTRUST_MODEL=TRUST_MODEL_$(shell echo $(TRUST_MODEL) | tr '[:lower:]' '[:upper:]' | tr '-' '_') 12 | endif 13 | 14 | CFLAGS += -DNETSTACK_CONF_CUSTOM_RADIO=radio_off_driver 15 | 16 | # Include application modules 17 | MODULES_REL += ../edge ../edge/capability 18 | MODULES_REL += ../common/trust/models/$(TRUST_MODEL) 19 | 20 | # Applications to include 21 | ifndef APPLICATIONS 22 | # Set default applications if not requesting specifics 23 | APPLICATIONS = monitoring routing challenge-response 24 | endif 25 | include ../applications/Makefile.include 26 | 27 | # Attack configuration 28 | ifeq ($(MAKE_ATTACKS),) 29 | $(error "Please specify at least one attack") 30 | endif 31 | 32 | $(info Building these attacks: $(MAKE_ATTACKS)) 33 | 34 | MODULES_REL += ./bad 35 | 36 | # From: https://stackoverflow.com/questions/1541844/joining-elements-of-a-list-in-gnu-make 37 | noop:= 38 | space := $(noop) $(noop) 39 | comma := , 40 | 41 | ATTACK_NAMES := $(subst $(comma),$(space),$(MAKE_ATTACKS)) 42 | 43 | ATTACK_PROCESSES := ${addprefix &,$(ATTACK_NAMES)} 44 | ATTACK_PROCESSES := $(subst $(space),$(comma),$(ATTACK_PROCESSES)) 45 | CFLAGS += -DATTACK_PROCESSES='$(ATTACK_PROCESSES)' 46 | 47 | prefix := PROCESS_NAME( 48 | suffix := ); 49 | ATTACK_PROCESSES_DECL := ${addprefix $(prefix),$(ATTACK_NAMES)} 50 | ATTACK_PROCESSES_DECL := ${addsuffix $(suffix),$(ATTACK_PROCESSES_DECL)} 51 | CFLAGS += -DATTACK_PROCESSES_DECL='$(ATTACK_PROCESSES_DECL)' 52 | 53 | # Main Contiki-NG compile 54 | include $(CONTIKI)/Makefile.include 55 | -------------------------------------------------------------------------------- /common/configuration.py.iris.example: -------------------------------------------------------------------------------- 1 | from common.stereotype_tags import StereotypeTags, DeviceClass 2 | from common.configuration_common import Device, DeviceKind, root_ipv6_addr 3 | from tools.keygen.util import eui64_to_ipv6 4 | 5 | devices = [ 6 | Device("iris1", "683867147", "f4:ce:36:d7:43:96:31:62", DeviceKind.NRF52840), 7 | Device("iris3", "683405900", "f4:ce:36:46:7f:b7:ca:c7", DeviceKind.NRF52840), 8 | Device("iris5", "683883730", "f4:ce:36:fe:6c:65:c7:73", DeviceKind.NRF52840), 9 | Device("iris6", "683113778", "f4:ce:36:92:2e:36:98:20", DeviceKind.NRF52840), 10 | Device("iris7", "683849822", "f4:ce:36:d2:fc:ba:75:a2", DeviceKind.NRF52840), 11 | Device("iris9", "683835663", "f4:ce:36:f9:79:87:a4:4a", DeviceKind.NRF52840), 12 | Device("iris10", "683836538", "f4:ce:36:b2:9c:b5:9a:de", DeviceKind.NRF52840), 13 | ] 14 | 15 | root_node = "iris1" 16 | 17 | hostname_to_ips = { 18 | device.hostname: root_ipv6_addr if device.hostname == root_node else eui64_to_ipv6(device.eui64) 19 | for device 20 | in devices 21 | } 22 | 23 | device_stereotypes = { 24 | "iris1": StereotypeTags(device_class=DeviceClass.SERVER), # Root 25 | "iris3": StereotypeTags(device_class=DeviceClass.RASPBERRY_PI), # Edge 26 | "iris5": StereotypeTags(device_class=DeviceClass.IOT_MEDIUM), # IoT 27 | "iris6": StereotypeTags(device_class=DeviceClass.IOT_MEDIUM), # IoT 28 | "iris7": StereotypeTags(device_class=DeviceClass.IOT_MEDIUM), # IoT 29 | "iris9": StereotypeTags(device_class=DeviceClass.IOT_MEDIUM), # IoT 30 | "iris10": StereotypeTags(device_class=DeviceClass.RASPBERRY_PI), # Edge 31 | } 32 | 33 | hostname_to_names = { 34 | "iris1": "root", 35 | "iris3": "rr3", 36 | "iris5": "wsn5", 37 | "iris6": "wsn6", 38 | "iris7": "wsn7", 39 | "iris9": "wsn9", 40 | "iris10": "rr10", 41 | } 42 | -------------------------------------------------------------------------------- /wsn/common/base16.c: -------------------------------------------------------------------------------- 1 | #include "base16.h" 2 | #include 3 | // From: https://stackoverflow.com/questions/3408706/hexadecimal-string-to-byte-array-in-c 4 | /*-------------------------------------------------------------------------------------------------------------------*/ 5 | static int hex_char(char c) 6 | { 7 | if ('0' <= c && c <= '9') return (c - '0'); 8 | if ('A' <= c && c <= 'F') return (c - 'A' + 10); 9 | if ('a' <= c && c <= 'f') return (c - 'a' + 10); 10 | return -1; 11 | } 12 | /*-------------------------------------------------------------------------------------------------------------------*/ 13 | ssize_t base16_decode(const char* source, uint8_t* buf, ssize_t length) 14 | { 15 | return base16_decode_length(source, strlen(source), buf, length); 16 | } 17 | /*-------------------------------------------------------------------------------------------------------------------*/ 18 | ssize_t base16_decode_length(const char* source, size_t source_len, uint8_t* buf, ssize_t length) 19 | { 20 | ssize_t result = 0; 21 | if (!source || !buf || length <= 0) return -2; 22 | 23 | // Length needs to be a multiple of 2 24 | if ((source_len % 2) != 0) return -6; 25 | 26 | const char* const source_end = source + source_len; 27 | 28 | // Needs to be atleast 2 remaining characters 29 | while ((source_end - source) >= 2) 30 | { 31 | int nib1 = hex_char(*source++); 32 | if (nib1 < 0) return -3; 33 | int nib2 = hex_char(*source++); 34 | if (nib2 < 0) return -4; 35 | 36 | uint8_t bin = ((0xF & (uint8_t)nib1) << 4) | (0xF & (uint8_t)nib2); 37 | 38 | if (length-- <= 0) return -5; 39 | *buf++ = bin; 40 | ++result; 41 | } 42 | return result; 43 | } 44 | /*-------------------------------------------------------------------------------------------------------------------*/ 45 | -------------------------------------------------------------------------------- /wsn/applications/routing/edge/routing.c: -------------------------------------------------------------------------------- 1 | #include "routing-edge.h" 2 | #include "applications.h" 3 | 4 | #include "contiki.h" 5 | #include "os/sys/log.h" 6 | 7 | #include "edge.h" 8 | 9 | #include 10 | /*-------------------------------------------------------------------------------------------------------------------*/ 11 | #define LOG_MODULE "A-" ROUTING_APPLICATION_NAME 12 | #ifdef APP_ROUTING_LOG_LEVEL 13 | #define LOG_LEVEL APP_ROUTING_LOG_LEVEL 14 | #else 15 | #define LOG_LEVEL LOG_LEVEL_NONE 16 | #endif 17 | /*-------------------------------------------------------------------------------------------------------------------*/ 18 | application_stats_t routing_stats; 19 | /*-------------------------------------------------------------------------------------------------------------------*/ 20 | PROCESS(routing_process, ROUTING_APPLICATION_NAME); 21 | /*-------------------------------------------------------------------------------------------------------------------*/ 22 | static void 23 | init(void) 24 | { 25 | routing_taskrecv_init(); 26 | routing_taskresp_init(); 27 | 28 | init_trust_weights_routing(); 29 | 30 | application_stats_init(&routing_stats); 31 | } 32 | /*-------------------------------------------------------------------------------------------------------------------*/ 33 | PROCESS_THREAD(routing_process, ev, data) 34 | { 35 | PROCESS_BEGIN(); 36 | 37 | init(); 38 | 39 | while (1) 40 | { 41 | PROCESS_YIELD(); 42 | 43 | if (ev == pe_data_from_resource_rich_node) 44 | { 45 | //LOG_INFO("Received pe_data_from_resource_rich_node %s\n", (const char*)data); 46 | routing_taskresp_process_serial_input((const char*)data); 47 | } 48 | } 49 | 50 | PROCESS_END(); 51 | } 52 | /*-------------------------------------------------------------------------------------------------------------------*/ 53 | -------------------------------------------------------------------------------- /tools/regenerate_pcap.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from __future__ import annotations 3 | 4 | import pathlib 5 | 6 | from pyshark.capture.inmem_capture import LinkTypes as LinkTypesBase, InMemCapture 7 | from common.packet_log_processor import PacketLogProcessor 8 | 9 | class LinkTypes(LinkTypesBase): 10 | IEEE802_15_4_NOFCS = 230 11 | 12 | def main(source: pathlib.Path, dest: pathlib.Path, timeout: Optional[int]): 13 | print(f"Converting {source} to {dest}") 14 | 15 | plp = PacketLogProcessor() 16 | with open(source, "r") as f: 17 | l, kinds, times = plp.process_all(f) 18 | 19 | custom_parameters = {"-w": str(dest)} 20 | 21 | with InMemCapture(debug=True, linktype=LinkTypes.IEEE802_15_4_NOFCS, custom_parameters=custom_parameters) as cap: 22 | # This will not reassemble fragments into a single packet 23 | packets = cap.parse_packets(l, sniff_times=times, timeout=timeout) 24 | 25 | if len(packets) != len(kinds): 26 | raise RuntimeError("Invalid length") 27 | 28 | print(f"Finished converting {source} to {dest}!") 29 | 30 | def int_or_None(arg: str) -> Optional[int]: 31 | try: 32 | return int(arg) 33 | except ValueError: 34 | if arg == "None": 35 | return None 36 | else: 37 | raise 38 | 39 | if __name__ == "__main__": 40 | import argparse 41 | 42 | parser = argparse.ArgumentParser(description='Regenerate pcap files from the raw log') 43 | parser.add_argument('--source', type=pathlib.Path, required=True, help='The file which contains the raw pcap log output') 44 | parser.add_argument('--dest', type=pathlib.Path, required=True, help='The output pcap file') 45 | parser.add_argument('--timeout', type=int_or_None, default=600, help='The timeout in seconds, pass "None" for no timeout.') 46 | 47 | args = parser.parse_args() 48 | 49 | main(args.source, args.dest, args.timeout) 50 | -------------------------------------------------------------------------------- /wsn/applications/challenge-response/edge/challenge-response.c: -------------------------------------------------------------------------------- 1 | #include "challenge-response-edge.h" 2 | #include "applications.h" 3 | 4 | #include "contiki.h" 5 | #include "os/sys/log.h" 6 | 7 | #include "edge.h" 8 | 9 | #include 10 | /*-------------------------------------------------------------------------------------------------------------------*/ 11 | #define LOG_MODULE "A-" CHALLENGE_RESPONSE_APPLICATION_NAME 12 | #ifdef APP_CHALLENGE_RESPONSE_LOG_LEVEL 13 | #define LOG_LEVEL APP_CHALLENGE_RESPONSE_LOG_LEVEL 14 | #else 15 | #define LOG_LEVEL LOG_LEVEL_NONE 16 | #endif 17 | /*-------------------------------------------------------------------------------------------------------------------*/ 18 | application_stats_t cr_stats; 19 | /*-------------------------------------------------------------------------------------------------------------------*/ 20 | PROCESS(challenge_response_process, CHALLENGE_RESPONSE_APPLICATION_NAME); 21 | /*-------------------------------------------------------------------------------------------------------------------*/ 22 | static void 23 | init(void) 24 | { 25 | cr_taskrecv_init(); 26 | cr_taskresp_init(); 27 | 28 | application_stats_init(&cr_stats); 29 | } 30 | /*-------------------------------------------------------------------------------------------------------------------*/ 31 | PROCESS_THREAD(challenge_response_process, ev, data) 32 | { 33 | PROCESS_BEGIN(); 34 | 35 | init(); 36 | 37 | while (1) 38 | { 39 | PROCESS_YIELD(); 40 | 41 | if (ev == pe_data_from_resource_rich_node) 42 | { 43 | //LOG_INFO("Received pe_data_from_resource_rich_node %s\n", (const char*)data); 44 | cr_taskresp_process_serial_input((const char*)data); 45 | } 46 | } 47 | 48 | PROCESS_END(); 49 | } 50 | /*-------------------------------------------------------------------------------------------------------------------*/ 51 | -------------------------------------------------------------------------------- /wsn/common/trust/choose/random/trust-choose.c: -------------------------------------------------------------------------------- 1 | #include "trust-choose.h" 2 | #include "trust-model.h" 3 | #include "edge-info.h" 4 | #include "random-helpers.h" 5 | #include "os/sys/log.h" 6 | /*-------------------------------------------------------------------------------------------------------------------*/ 7 | #define LOG_MODULE "trust-random" 8 | #ifdef TRUST_MODEL_LOG_LEVEL 9 | #define LOG_LEVEL TRUST_MODEL_LOG_LEVEL 10 | #else 11 | #define LOG_LEVEL LOG_LEVEL_NONE 12 | #endif 13 | /*-------------------------------------------------------------------------------------------------------------------*/ 14 | // Use a random edge node we are aware of that supports 15 | // the requested capability 16 | edge_resource_t* choose_edge(const char* capability_name) 17 | { 18 | edge_resource_t* candidates[NUM_EDGE_RESOURCES]; 19 | uint16_t candidates_len = 0; 20 | 21 | for (edge_resource_t* iter = edge_info_iter(); iter != NULL; iter = edge_info_next(iter)) 22 | { 23 | // Skip inactive edges 24 | if (!edge_info_is_active(iter)) 25 | { 26 | continue; 27 | } 28 | 29 | edge_capability_t* capability = edge_info_capability_find(iter, capability_name); 30 | if (capability == NULL) 31 | { 32 | continue; 33 | } 34 | 35 | // Skip inactive capabilities 36 | if (!edge_capability_is_active(capability)) 37 | { 38 | continue; 39 | } 40 | 41 | // Consider this edge 42 | candidates[candidates_len] = iter; 43 | candidates_len++; 44 | } 45 | 46 | // No valid options 47 | if (candidates_len == 0) 48 | { 49 | return NULL; 50 | } 51 | 52 | uint16_t idx = random_in_range_unbiased(0, candidates_len-1); 53 | 54 | return candidates[idx]; 55 | } 56 | /*-------------------------------------------------------------------------------------------------------------------*/ 57 | -------------------------------------------------------------------------------- /wsn/applications/Makefile.include: -------------------------------------------------------------------------------- 1 | # Add application path to MODULES_REL 2 | 3 | ifeq ($(CONTIKI_PROJECT),bad_edge) 4 | APPLICATION_SUFFIX=edge 5 | else 6 | APPLICATION_SUFFIX=$(CONTIKI_PROJECT) 7 | endif 8 | 9 | APPLICATION_DIRS := ${addprefix ../applications/,$(APPLICATIONS)} 10 | APPLICATION_SPECIFC_DIR := ${addsuffix /$(APPLICATION_SUFFIX),$(APPLICATION_DIRS)} 11 | 12 | MODULES_REL += ../applications $(APPLICATION_DIRS) $(APPLICATION_SPECIFC_DIR) 13 | 14 | # Any application names with a hyphen need it translated to an underscore 15 | APPLICATIONS_SANITISED := $(shell echo '$(APPLICATIONS)' | tr '-' '_') 16 | 17 | # Create a list of application names that are supported 18 | 19 | APPLICATIONS_CAP := $(shell echo '$(APPLICATIONS_SANITISED)' | tr '[:lower:]' '[:upper:]') 20 | 21 | # From: https://stackoverflow.com/questions/1541844/joining-elements-of-a-list-in-gnu-make 22 | noop:= 23 | space := $(noop) $(noop) 24 | comma := , 25 | 26 | APPLICATION_NAMES := ${addsuffix _APPLICATION_NAME,$(APPLICATIONS_CAP)} 27 | APPLICATION_NAMES := $(subst $(space),$(comma),$(APPLICATION_NAMES)) 28 | 29 | CFLAGS += -DAPPLICATION_NUM='$(words $(APPLICATIONS_SANITISED))' 30 | CFLAGS += -DAPPLICATION_NAMES='{$(APPLICATION_NAMES)}' 31 | 32 | # Need a list of processes to autostart 33 | prefix := & 34 | suffix := _process 35 | APPLICATION_PROCESSES := ${addsuffix $(suffix),$(APPLICATIONS_SANITISED)} 36 | APPLICATION_PROCESSES := ${addprefix $(prefix),$(APPLICATION_PROCESSES)} 37 | APPLICATION_PROCESSES := $(subst $(space),$(comma),$(APPLICATION_PROCESSES)) 38 | CFLAGS += -DAPPLICATION_PROCESSES='$(APPLICATION_PROCESSES)' 39 | 40 | prefix := PROCESS_NAME( 41 | suffix := _process); 42 | APPLICATION_PROCESSES_DECL := ${addprefix $(prefix),$(APPLICATIONS_SANITISED)} 43 | APPLICATION_PROCESSES_DECL := ${addsuffix $(suffix),$(APPLICATION_PROCESSES_DECL)} 44 | CFLAGS += -DAPPLICATION_PROCESSES_DECL='$(APPLICATION_PROCESSES_DECL)' 45 | 46 | CFLAGS += ${addsuffix =1,${addprefix -DAPPLICATION_,$(APPLICATIONS_CAP)}} 47 | -------------------------------------------------------------------------------- /wsn/adversary/Makefile: -------------------------------------------------------------------------------- 1 | CONTIKI_PROJECT = adversary 2 | all: $(CONTIKI_PROJECT) 3 | 4 | include ../Makefile.common 5 | 6 | ifeq ($(TRUST_MODEL),) 7 | $(error "TRUST_MODEL not set") 8 | else 9 | CFLAGS += -DTRUST_MODEL=TRUST_MODEL_$(shell echo $(TRUST_MODEL) | tr '[:lower:]' '[:upper:]' | tr '-' '_') 10 | endif 11 | 12 | #ifeq ($(TRUST_CHOOSE),) 13 | # $(error "TRUST_CHOOSE not set") 14 | #else 15 | # CFLAGS += -DTRUST_CHOOSE=TRUST_CHOOSE_$(shell echo $(TRUST_CHOOSE) | tr '[:lower:]' '[:upper:]' | tr '-' '_') 16 | #endif 17 | 18 | # Include application modules 19 | MODULES_REL += ../common/trust/models/$(TRUST_MODEL) 20 | #MODULES_REL += ../common/trust/choose/$(TRUST_CHOOSE) ../common/trust/choose/ 21 | 22 | # Applications to include 23 | ifndef APPLICATIONS 24 | # Set default applications if not requesting specifics 25 | APPLICATIONS = monitoring routing challenge-response 26 | endif 27 | include ../applications/Makefile.include 28 | 29 | # Attack configuration 30 | ifeq ($(MAKE_ATTACKS),) 31 | $(error "Please specify at least one attack") 32 | endif 33 | 34 | $(info Building these attacks: $(MAKE_ATTACKS)) 35 | 36 | MODULES_REL += ./attacks 37 | 38 | # From: https://stackoverflow.com/questions/1541844/joining-elements-of-a-list-in-gnu-make 39 | noop:= 40 | space := $(noop) $(noop) 41 | comma := , 42 | 43 | ATTACK_NAMES := $(subst $(comma),$(space),$(MAKE_ATTACKS)) 44 | 45 | ATTACK_PROCESSES := ${addprefix &,$(ATTACK_NAMES)} 46 | ATTACK_PROCESSES := $(subst $(space),$(comma),$(ATTACK_PROCESSES)) 47 | CFLAGS += -DATTACK_PROCESSES='$(ATTACK_PROCESSES)' 48 | 49 | prefix := PROCESS_NAME( 50 | suffix := ); 51 | ATTACK_PROCESSES_DECL := ${addprefix $(prefix),$(ATTACK_NAMES)} 52 | ATTACK_PROCESSES_DECL := ${addsuffix $(suffix),$(ATTACK_PROCESSES_DECL)} 53 | CFLAGS += -DATTACK_PROCESSES_DECL='$(ATTACK_PROCESSES_DECL)' 54 | 55 | # Certain attacks require code to be pulled in from different areas 56 | CFLAGS += -I../node/trust 57 | 58 | # Main Contiki-NG compile 59 | include $(CONTIKI)/Makefile.include 60 | -------------------------------------------------------------------------------- /wsn/common/trust/capability-info.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "contiki.h" 4 | #include "net/ipv6/uip.h" 5 | #include "lib/list.h" 6 | 7 | #include 8 | 9 | #include "trust-common.h" 10 | #include "trust-model.h" 11 | #include "stereotype-tags.h" 12 | #include "edge-info.h" 13 | 14 | #include "coap-endpoint.h" 15 | 16 | // Provide empty capability struct when trust model does not provide one 17 | #ifndef TRUST_MODEL_HAS_PER_CAPABILITY_INFO 18 | typedef struct capability_tm 19 | { 20 | } capability_tm_t; 21 | 22 | void capability_tm_init(capability_tm_t* cap_tm); 23 | #endif 24 | 25 | /*-------------------------------------------------------------------------------------------------------------------*/ 26 | typedef struct capability 27 | { 28 | struct capability *next; 29 | 30 | char name[EDGE_CAPABILITY_NAME_LEN + 1]; 31 | 32 | capability_tm_t tm; 33 | 34 | } capability_t; 35 | /*-------------------------------------------------------------------------------------------------------------------*/ 36 | void capability_info_init(void); 37 | /*-------------------------------------------------------------------------------------------------------------------*/ 38 | capability_t* capability_info_add(const char* name); 39 | bool capability_info_remove(capability_t* edge); 40 | /*-------------------------------------------------------------------------------------------------------------------*/ 41 | capability_t* capability_info_find(const char* name); 42 | /*-------------------------------------------------------------------------------------------------------------------*/ 43 | capability_t* capability_info_iter(void); 44 | capability_t* capability_info_next(capability_t* iter); 45 | /*-------------------------------------------------------------------------------------------------------------------*/ 46 | size_t capability_info_count(void); 47 | /*-------------------------------------------------------------------------------------------------------------------*/ 48 | 49 | 50 | -------------------------------------------------------------------------------- /tests/papers/sac2021/README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | These are the raw results that were used to present the results in: 4 | 5 | Matthew Bradbury, Arshad Jhumka and Tim Watson. 6 | Trust Assessment in 32 KiB of RAM: Multi-application Trust-based Task Offloading for Resource-constrained IoT Nodes. 7 | Proceedings of the Symposium on Applied Computing, ACM, 2021, 1-10. 8 | 9 | Generating the graphs requires scripts from: [iot-trust-task-alloc](https://github.com/MBradbury/iot-trust-task-alloc) 10 | 11 | # Reproducing Results 12 | 13 | In order to reproduce the results, the setup instructions provided at [iot-trust-task-alloc](https://github.com/MBradbury/iot-trust-task-alloc) should first be followed. 14 | 15 | Then the test scripts in tests/run need to be edited to match the configuration used for these experiments. Six nodes were used, one configured as the root, two as edges and three as wsn nodes. The start script for edge needs to be edited differently on rr2 and rr6 to contain the correct configurations. 16 | 17 | On rr2: 18 | ```bash 19 | ./tests/papers/sac2021/edge-always-good.sh 20 | ``` 21 | 22 | On rr6: 23 | ```bash 24 | ./tests/papers/sac2021/edge-always-bad.sh 25 | ``` 26 | 27 | # Generating Graphs and Tables 28 | 29 | ## Table 2 30 | 31 | ```bash 32 | make -C wsn TRUST_MODEl=basic TRUST_CHOOSE=banded 33 | ./tools/binprof.py wsn/edge/edge.zoul 34 | ``` 35 | 36 | ## Table 4 37 | 38 | ```bash 39 | make -C wsn TRUST_MODEl=basic TRUST_CHOOSE=banded 40 | ./tools/binprof.py wsn/edge/edge.zoul 41 | ``` 42 | 43 | ## Table 5 44 | 45 | ```bash 46 | ./analysis/parser/profile_pyterm.py --log-dir results/2020-08-28-profile 47 | ./analysis/parser/profile_pyterm.py --log-dir results/2020-09-01-profile-aes-ccm 48 | ``` 49 | 50 | ## Figure 8 51 | 52 | ```bash 53 | ./analysis/graph/trust_choose_evolution.py --log-dir results/2020-09-10-bad-routing-for-paper 54 | ``` 55 | 56 | ## Figure 10 57 | 58 | ```bash 59 | ./analysis/graph/messages.py --log-dir results/2020-09-10-bad-routing-for-paper 60 | ``` 61 | -------------------------------------------------------------------------------- /tools/setup_profile.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | 5 | from tools.setup import Setup as BaseSetup, available_targets 6 | 7 | class Setup(BaseSetup): 8 | def __init__(self, mode: str, target: str, verbose_make: bool, deploy: str): 9 | super().__init__(trust_model="basic", 10 | trust_choose=None, 11 | applications=["monitoring"], 12 | with_pcap=False, 13 | with_adversary=None, 14 | defines={}, 15 | target=target, 16 | verbose_make=verbose_make, 17 | deploy=deploy) 18 | 19 | self.mode = mode 20 | self.binaries = ["profile"] 21 | 22 | def _target_build_args(self): 23 | build_args = super()._target_build_args() 24 | 25 | if self.mode == "AES": 26 | build_args["PROFILE_AES"] = 1 27 | elif self.mode == "ECC": 28 | build_args["PROFILE_ECC"] = 1 29 | else: 30 | raise RuntimeError(f"Unknown profile mode {self.mode}") 31 | 32 | return build_args 33 | 34 | def _build_border_router(self): 35 | # Don't need this 36 | pass 37 | 38 | if __name__ == "__main__": 39 | import argparse 40 | 41 | parser = argparse.ArgumentParser(description='Setup') 42 | parser.add_argument('mode', choices=['ECC', 'AES'], help='What to profile') 43 | parser.add_argument('--target', choices=available_targets, default=available_targets[0], help="Which target to compile for") 44 | parser.add_argument('--verbose-make', action='store_true', help='Outputs greater detail while compiling') 45 | parser.add_argument('--deploy', choices=['none', 'ansible', 'fabric'], default='none', help='Choose how deployment is performed to observers') 46 | args = parser.parse_args() 47 | 48 | setup = Setup(args.mode, 49 | args.target, 50 | args.verbose_make, 51 | args.deploy) 52 | setup.run() 53 | -------------------------------------------------------------------------------- /wsn/common/trust/choose/highest/trust-choose.c: -------------------------------------------------------------------------------- 1 | #include "trust-choose.h" 2 | #include "trust-model.h" 3 | #include "edge-info.h" 4 | #include "os/sys/log.h" 5 | /*-------------------------------------------------------------------------------------------------------------------*/ 6 | #define LOG_MODULE "trust-high" 7 | #ifdef TRUST_MODEL_LOG_LEVEL 8 | #define LOG_LEVEL TRUST_MODEL_LOG_LEVEL 9 | #else 10 | #define LOG_LEVEL LOG_LEVEL_NONE 11 | #endif 12 | /*-------------------------------------------------------------------------------------------------------------------*/ 13 | // Pick the edge node with the highest trust level that supports 14 | // the provided capability. 15 | edge_resource_t* choose_edge(const char* capability_name) 16 | { 17 | edge_resource_t* best_edge = NULL; 18 | 19 | // Start trust at -1, so even edges with 0 trust will be considered 20 | float best_trust = -1.0f; 21 | 22 | for (edge_resource_t* iter = edge_info_iter(); iter != NULL; iter = edge_info_next(iter)) 23 | { 24 | // Skip inactive edges 25 | if (!edge_info_is_active(iter)) 26 | { 27 | continue; 28 | } 29 | 30 | edge_capability_t* capability = edge_info_capability_find(iter, capability_name); 31 | if (capability == NULL) 32 | { 33 | LOG_WARN("Cannot find capability %s for edge %s\n", capability_name, edge_info_name(iter)); 34 | continue; 35 | } 36 | 37 | // Skip inactive capabilities 38 | if (!edge_capability_is_active(capability)) 39 | { 40 | continue; 41 | } 42 | 43 | float trust_value = calculate_trust_value(iter, capability); 44 | 45 | LOG_INFO("Trust value for edge %s and capability %s=%f\n", 46 | edge_info_name(iter), capability_name, trust_value); 47 | 48 | if (trust_value > best_trust) 49 | { 50 | best_edge = iter; 51 | best_trust = trust_value; 52 | } 53 | } 54 | 55 | return best_edge; 56 | } 57 | /*-------------------------------------------------------------------------------------------------------------------*/ 58 | -------------------------------------------------------------------------------- /wsn/common/crypto/keystore.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /*-------------------------------------------------------------------------------------------------------------------*/ 3 | //#include "clock.h" 4 | #include "net/ipv6/uip.h" 5 | 6 | #ifdef WITH_OSCORE 7 | #include "oscore.h" 8 | #endif 9 | 10 | #include "certificate.h" 11 | /*-------------------------------------------------------------------------------------------------------------------*/ 12 | #ifndef PUBLIC_KEYSTORE_SIZE 13 | #define PUBLIC_KEYSTORE_SIZE 12 14 | #endif 15 | /*-------------------------------------------------------------------------------------------------------------------*/ 16 | typedef struct public_key_item { 17 | struct public_key_item *next; 18 | 19 | certificate_t cert; 20 | 21 | #ifdef WITH_OSCORE 22 | oscore_ctx_t context; 23 | #endif 24 | 25 | //clock_time_t age; 26 | 27 | uint16_t pin_count; 28 | } public_key_item_t; 29 | /*-------------------------------------------------------------------------------------------------------------------*/ 30 | bool keystore_add(const certificate_t* cert); 31 | bool keystore_remove(public_key_item_t* item); 32 | /*-------------------------------------------------------------------------------------------------------------------*/ 33 | public_key_item_t* keystore_find(const uint8_t* eui64); 34 | public_key_item_t* keystore_find_addr(const uip_ip6addr_t* addr); 35 | const ecdsa_secp256r1_pubkey_t* keystore_find_pubkey(const uip_ip6addr_t* addr); 36 | /*-------------------------------------------------------------------------------------------------------------------*/ 37 | bool keystore_certificate_contains_tags(const stereotype_tags_t* tags); 38 | /*-------------------------------------------------------------------------------------------------------------------*/ 39 | void keystore_pin(public_key_item_t* item); 40 | void keystore_unpin(public_key_item_t* item); 41 | bool keystore_is_pinned(const public_key_item_t* item); 42 | /*-------------------------------------------------------------------------------------------------------------------*/ 43 | bool request_public_key(const uip_ip6addr_t* addr); 44 | /*-------------------------------------------------------------------------------------------------------------------*/ 45 | -------------------------------------------------------------------------------- /tools/eckeygen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ 4 | This document outputs the equivalent of the following, but also in a format that can be used in C files. 5 | ```bash 6 | openssl ecparam -name prime256v1 -genkey -noout -out private.pem 7 | openssl ec -in private.pem -pubout -out public.pem 8 | ``` 9 | """ 10 | 11 | from tools.keygen.keygen import generate_and_save_key, derive_private_key 12 | from tools.keygen.contiking_format import contiking_format_our_privkey, contiking_format_certificate 13 | from tools.keygen.util import ip_to_eui64 14 | 15 | from common.certificate import TBSCertificate 16 | from common.stereotype_tags import StereotypeTags, DeviceClass 17 | 18 | if __name__ == "__main__": 19 | import argparse 20 | import sys 21 | 22 | parser = argparse.ArgumentParser(description='ECC Keygen') 23 | parser.add_argument('-d', '--deterministic', type=str, default=None, help='The deterministic string to use.') 24 | parser.add_argument('-r', '--root', type=str, default=None, help='The deterministic root string to use.') 25 | parser.add_argument('-k', '--keystore-dir', type=str, default="keystore", help='The location to store the output files.') 26 | 27 | parser.add_argument('-s', '--stereo-device-class', 28 | type=DeviceClass.from_string, choices=list(DeviceClass), default=DeviceClass.RASPBERRY_PI, help='The device class.') 29 | 30 | args = parser.parse_args() 31 | 32 | private_key = generate_and_save_key(args.keystore_dir, args.deterministic) 33 | root_private_key = derive_private_key(args.root) 34 | 35 | print(contiking_format_our_privkey(private_key, args.deterministic)) 36 | 37 | tags = StereotypeTags( 38 | device_class=args.stereo_device_class 39 | ) 40 | 41 | tbscert = TBSCertificate( 42 | serial_number=0, 43 | issuer=ip_to_eui64(args.root), 44 | validity_from=0, 45 | validity_to=None, 46 | subject=ip_to_eui64(args.deterministic), 47 | stereotype_tags=tags, 48 | public_key=private_key.public_key(), 49 | ) 50 | 51 | cert = tbscert.build(root_private_key) 52 | print(cert) 53 | 54 | enc_cert = cert.encode() 55 | print(enc_cert, len(enc_cert)) 56 | 57 | print(contiking_format_certificate(cert, "our_cert")) 58 | -------------------------------------------------------------------------------- /tools/keygen/keygen.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from textwrap import wrap 4 | import pathlib 5 | from more_itertools import chunked 6 | 7 | from hashlib import sha256 8 | 9 | from cryptography.hazmat.backends import default_backend 10 | from cryptography.hazmat.primitives import hashes, serialization 11 | from cryptography.hazmat.primitives.asymmetric import ec, utils 12 | 13 | def derive_private_key(deterministic_string: Optional[str]=None): 14 | if deterministic_string is None: 15 | return ec.generate_private_key(ec.SECP256R1(), default_backend()) 16 | else: 17 | # Byteorder and signed here doesn't matter, is just needed to convert into an int 18 | private_value = int.from_bytes(sha256(deterministic_string.encode("utf-8")).digest(), byteorder="little", signed=False) 19 | 20 | return ec.derive_private_key(private_value, ec.SECP256R1(), default_backend()) 21 | 22 | def save_key(pk, name: str, keystore_dir: str): 23 | """From: https://stackoverflow.com/questions/45146504/python-cryptography-module-save-load-rsa-keys-to-from-file""" 24 | 25 | pathlib.Path(keystore_dir).mkdir(parents=True, exist_ok=True) 26 | 27 | if name is not None: 28 | prefix = name.replace(":", "_") + "-" 29 | else: 30 | prefix = "" 31 | 32 | pem = pk.private_bytes( 33 | encoding=serialization.Encoding.PEM, 34 | format=serialization.PrivateFormat.TraditionalOpenSSL, 35 | encryption_algorithm=serialization.NoEncryption() 36 | ) 37 | with open(f"{keystore_dir}/{prefix}private.pem", 'wb') as pem_out: 38 | pem_out.write(pem) 39 | 40 | pem = pk.public_key().public_bytes( 41 | encoding=serialization.Encoding.PEM, 42 | format=serialization.PublicFormat.SubjectPublicKeyInfo 43 | ) 44 | with open(f"{keystore_dir}/{prefix}public.pem", 'wb') as pem_out: 45 | pem_out.write(pem) 46 | 47 | def generate_and_save_key(keystore_dir: str="keystore", deterministic_string: Optional[str]=None): 48 | print(f"Generating key using {deterministic_string}") 49 | private_key = derive_private_key(deterministic_string) 50 | 51 | print(f"Saving key to {keystore_dir}") 52 | save_key(private_key, deterministic_string, keystore_dir) 53 | 54 | return private_key 55 | -------------------------------------------------------------------------------- /wsn/common/trust/stereotypes/stereotype-tags.c: -------------------------------------------------------------------------------- 1 | #include "stereotype-tags.h" 2 | 3 | #include "os/sys/log.h" 4 | 5 | #include "device-classes.h" 6 | 7 | #include "nanocbor-helper.h" 8 | /*-------------------------------------------------------------------------------------------------------------------*/ 9 | #define LOG_MODULE "stereotype" 10 | #ifdef TRUST_MODEL_LOG_LEVEL 11 | #define LOG_LEVEL TRUST_MODEL_LOG_LEVEL 12 | #else 13 | #define LOG_LEVEL LOG_LEVEL_NONE 14 | #endif 15 | /*-------------------------------------------------------------------------------------------------------------------*/ 16 | int serialise_stereotype_tags(nanocbor_encoder_t* enc, const stereotype_tags_t* tags) 17 | { 18 | NANOCBOR_CHECK(nanocbor_fmt_array(enc, 1)); 19 | NANOCBOR_CHECK(nanocbor_fmt_uint(enc, tags->device_class)); 20 | 21 | return NANOCBOR_OK; 22 | } 23 | /*-------------------------------------------------------------------------------------------------------------------*/ 24 | int deserialise_stereotype_tags(nanocbor_value_t* dec, stereotype_tags_t* tags) 25 | { 26 | nanocbor_value_t arr; 27 | NANOCBOR_CHECK(nanocbor_enter_array(dec, &arr)); 28 | 29 | NANOCBOR_CHECK(nanocbor_get_uint8(&arr, &tags->device_class)); 30 | if (tags->device_class < DEVICE_CLASS_MINIMUM || tags->device_class > DEVICE_CLASS_MAXIMUM) 31 | { 32 | LOG_ERR("Invalid device class %" PRIu8 "\n", tags->device_class); 33 | return -1; 34 | } 35 | 36 | if (!nanocbor_at_end(&arr)) 37 | { 38 | LOG_ERR("!nanocbor_at_end\n"); 39 | return -1; 40 | } 41 | 42 | nanocbor_leave_container(dec, &arr); 43 | 44 | return NANOCBOR_OK; 45 | } 46 | /*-------------------------------------------------------------------------------------------------------------------*/ 47 | bool stereotype_tags_equal(const stereotype_tags_t* a, const stereotype_tags_t* b) 48 | { 49 | return a->device_class == b->device_class; 50 | } 51 | /*-------------------------------------------------------------------------------------------------------------------*/ 52 | void stereotype_tags_print(const stereotype_tags_t* tags) 53 | { 54 | printf("StereotypeTags(device_class=%" PRIu8 ")", tags->device_class); 55 | } 56 | /*-------------------------------------------------------------------------------------------------------------------*/ 57 | -------------------------------------------------------------------------------- /wsn/applications/challenge-response/challenge-response-common.c: -------------------------------------------------------------------------------- 1 | #include "challenge-response.h" 2 | 3 | #include "nanocbor-helper.h" 4 | 5 | #include "os/sys/log.h" 6 | /*-------------------------------------------------------------------------------------------------------------------*/ 7 | #define LOG_MODULE "A-" CHALLENGE_RESPONSE_APPLICATION_NAME 8 | #ifdef APP_CHALLENGE_RESPONSE_LOG_LEVEL 9 | #define LOG_LEVEL APP_CHALLENGE_RESPONSE_LOG_LEVEL 10 | #else 11 | #define LOG_LEVEL LOG_LEVEL_NONE 12 | #endif 13 | /*-------------------------------------------------------------------------------------------------------------------*/ 14 | int nanocbor_fmt_challenge(uint8_t* buf, size_t buf_len, const challenge_t* c) 15 | { 16 | nanocbor_encoder_t enc; 17 | nanocbor_encoder_init(&enc, buf, buf_len); 18 | 19 | NANOCBOR_CHECK(nanocbor_fmt_array(&enc, 3)); 20 | NANOCBOR_CHECK(nanocbor_fmt_uint(&enc, c->difficulty)); 21 | NANOCBOR_CHECK(nanocbor_put_bstr(&enc, c->data, sizeof(c->data))); 22 | NANOCBOR_CHECK(nanocbor_fmt_uint(&enc, c->max_duration_secs)); 23 | 24 | return nanocbor_encoded_len(&enc); 25 | } 26 | /*-------------------------------------------------------------------------------------------------------------------*/ 27 | int nanocbor_get_challenge_response(const uint8_t* buf, size_t buf_len, challenge_response_t* cr) 28 | { 29 | nanocbor_value_t dec; 30 | nanocbor_decoder_init(&dec, buf, buf_len); 31 | 32 | nanocbor_value_t arr; 33 | NANOCBOR_CHECK(nanocbor_enter_array(&dec, &arr)); 34 | 35 | const uint8_t* data; 36 | size_t len; 37 | NANOCBOR_CHECK(nanocbor_get_bstr(&arr, &data, &len)); 38 | 39 | if (len > sizeof(cr->data_prefix)) 40 | { 41 | return NANOCBOR_ERR_OVERFLOW; 42 | } 43 | 44 | cr->data_length = len; 45 | cr->data_prefix = data; 46 | 47 | NANOCBOR_CHECK(nanocbor_get_uint32(&arr, &cr->duration_secs)); 48 | 49 | if (!nanocbor_at_end(&arr)) 50 | { 51 | LOG_ERR("!nanocbor_at_end 1\n"); 52 | return -1; 53 | } 54 | 55 | nanocbor_leave_container(&dec, &arr); 56 | 57 | if (!nanocbor_at_end(&dec)) 58 | { 59 | LOG_ERR("!nanocbor_at_end 2\n"); 60 | return -1; 61 | } 62 | 63 | return NANOCBOR_OK; 64 | } 65 | /*-------------------------------------------------------------------------------------------------------------------*/ 66 | -------------------------------------------------------------------------------- /wsn/common/crypto/keystore-oscore.c: -------------------------------------------------------------------------------- 1 | #include "keystore-oscore.h" 2 | #include "keystore.h" 3 | #include "oscore.h" 4 | #include "crypto-support.h" 5 | #include "assert.h" 6 | 7 | #include "os/sys/log.h" 8 | 9 | /*-------------------------------------------------------------------------------------------------------------------*/ 10 | #define LOG_MODULE "keystore" 11 | #ifdef KEYSTORE_LOG_LEVEL 12 | #define LOG_LEVEL KEYSTORE_LOG_LEVEL 13 | #else 14 | #define LOG_LEVEL LOG_LEVEL_NONE 15 | #endif 16 | /*-------------------------------------------------------------------------------------------------------------------*/ 17 | void coap_set_random_token(coap_message_t* request) 18 | { 19 | // See: https://tools.ietf.org/html/rfc7252#section-5.3. 20 | // Given this is a 64-bit random token and we are sending few messages 21 | // the probability of a collision is fairly low (~10 in 18 quintillion), 22 | // not taking into account bias in the PRNG. 23 | 24 | assert(crypto_fill_random(request->token, COAP_TOKEN_LEN)); 25 | request->token_len = COAP_TOKEN_LEN; 26 | } 27 | /*-------------------------------------------------------------------------------------------------------------------*/ 28 | #ifdef WITH_OSCORE 29 | bool keystore_protect_coap_with_oscore(coap_message_t* request, const coap_endpoint_t* ep) 30 | { 31 | assert(request); 32 | assert(ep); 33 | 34 | if (uip_is_addr_linklocal_allnodes_mcast(&ep->ipaddr)) 35 | { 36 | #ifdef WITH_GROUPCOMM 37 | // TODO: FIX ME 38 | LOG_ERR("Protecting with group oscore not yet supported.\n"); 39 | return false; 40 | #else 41 | LOG_ERR("Cannot send to multicast address without Group OSCORE.\n"); 42 | return false; 43 | #endif 44 | } 45 | else 46 | { 47 | public_key_item_t* pubkeyitem = keystore_find_addr(&ep->ipaddr); 48 | if (pubkeyitem) 49 | { 50 | coap_set_oscore(request, &pubkeyitem->context); 51 | } 52 | else 53 | { 54 | LOG_WARN("Failed to find oscore context for "); 55 | LOG_WARN_6ADDR(&ep->ipaddr); 56 | LOG_WARN_(", request will not be protected.\n"); 57 | } 58 | 59 | return pubkeyitem != NULL; 60 | } 61 | } 62 | #endif 63 | /*-------------------------------------------------------------------------------------------------------------------*/ 64 | -------------------------------------------------------------------------------- /tests/papers/infocom2021/README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | These are the raw results that were used to present the results in: 4 | 5 | Matthew Bradbury, Arshad Jhumka and Tim Watson. 6 | Trust Trackers for Computation Offloading in Edge-Based IoT Networks. In IEEE INFOCOM, 1–10. IEEE, 10–13 May 2021. 7 | 8 | Generating the graphs requires scripts from: [iot-trust-task-alloc](https://github.com/MBradbury/iot-trust-task-alloc) 9 | 10 | # Reproducing Results 11 | 12 | In order to reproduce the results, the setup instructions provided at [iot-trust-task-alloc](https://github.com/MBradbury/iot-trust-task-alloc) should first be followed. 13 | 14 | Then the test scripts in tests/run need to be edited to match the configuration used for these experiments. Six nodes were used, one configured as the root, two as edges and three as wsn nodes. The start script for edge needs to be edited differently on rr2 and rr6 to contain the correct configurations. 15 | 16 | On rr2: 17 | ```bash 18 | ./tests/papers/infocom2021/edge-always-good.sh 19 | ``` 20 | 21 | On rr6 (always good): 22 | ```bash 23 | ./tests/papers/infocom2021/edge-always-good.sh 24 | ``` 25 | 26 | On rr6 (always bad): 27 | ```bash 28 | ./tests/papers/infocom2021/edge-always-bad.sh 29 | ``` 30 | 31 | On rr6 (unstable): 32 | ```bash 33 | ./tests/papers/infocom2021/edge-unstable.sh 34 | ``` 35 | 36 | # Generating Graphs and Tables 37 | 38 | ## Figure 2 39 | 40 | ```bash 41 | ./g.py 42 | ``` 43 | 44 | ## Figure 3a and 4b 45 | 46 | ```bash 47 | ./analysis/graph/challenge_response_perf.py --lor-dir results/2020-08-09-pm-two-good 48 | ``` 49 | 50 | ## Figure 4a and 4b 51 | 52 | ```bash 53 | ./analysis/graph/challenge_response_epoch.py --lor-dir results/2020-08-09-pm-two-good 54 | ``` 55 | 56 | ## Figure 5a and 5b 57 | 58 | ```bash 59 | ./analysis/graph/challenge_response_epoch.py --lor-dir results/2020-08-09-pm-one-good-one-bad 60 | ``` 61 | 62 | ## Figure 6a and 6b 63 | 64 | ```bash 65 | ./analysis/graph/challenge_response_epoch.py --lor-dir results/2020-08-10-pm3-one-good-one-unstable-1200 66 | ``` 67 | 68 | ## Figure 6c 69 | 70 | ```bash 71 | ./analysis/graph/offloading_when_bad.py --lor-dir results/2020-08-10-pm3-one-good-one-unstable-1200 72 | ``` 73 | 74 | ## Figure 6d 75 | 76 | ```bash 77 | ./analysis/graph/correctly_evaluated.py --lor-dir results/2020-08-10-pm3-one-good-one-unstable-1200 78 | ``` 79 | -------------------------------------------------------------------------------- /wsn/common/trust/interaction-history.c: -------------------------------------------------------------------------------- 1 | #include "interaction-history.h" 2 | #include 3 | #include 4 | #include 5 | /*-------------------------------------------------------------------------------------------------------------------*/ 6 | void interaction_history_init(interaction_history_t* hist) 7 | { 8 | hist->head = hist->tail = 0; 9 | hist->count = 0; 10 | } 11 | /*-------------------------------------------------------------------------------------------------------------------*/ 12 | void interaction_history_push(interaction_history_t* hist, uint8_t interaction) 13 | { 14 | // If reachex maximum, then remove first element 15 | if (hist->count == INTERACTION_HISTORY_SIZE) 16 | { 17 | hist->head = (hist->head + 1) % INTERACTION_HISTORY_SIZE; 18 | hist->count -= 1; 19 | } 20 | 21 | hist->interactions[hist->tail] = interaction; 22 | 23 | hist->tail = (hist->tail + 1) % INTERACTION_HISTORY_SIZE; 24 | 25 | hist->count += 1; 26 | } 27 | /*-------------------------------------------------------------------------------------------------------------------*/ 28 | const uint8_t* interaction_history_iter(const interaction_history_t* hist) 29 | { 30 | if (hist->count == 0) 31 | { 32 | return NULL; 33 | } 34 | 35 | return &hist->interactions[hist->head]; 36 | } 37 | /*-------------------------------------------------------------------------------------------------------------------*/ 38 | const uint8_t* interaction_history_next(const interaction_history_t* hist, const uint8_t* iter) 39 | { 40 | ++iter; 41 | 42 | // Wrap around 43 | if (iter == hist->interactions + INTERACTION_HISTORY_SIZE) 44 | { 45 | iter = hist->interactions; 46 | } 47 | 48 | if (iter == hist->interactions + hist->tail) 49 | { 50 | return NULL; 51 | } 52 | else 53 | { 54 | return iter; 55 | } 56 | } 57 | /*-------------------------------------------------------------------------------------------------------------------*/ 58 | void interaction_history_print(const interaction_history_t* hist) 59 | { 60 | printf("["); 61 | for (const uint8_t* iter = interaction_history_iter(hist); iter != NULL; iter = interaction_history_next(hist, iter)) 62 | { 63 | printf("%" PRIu8 ", ", *iter); 64 | } 65 | printf("]"); 66 | } 67 | /*-------------------------------------------------------------------------------------------------------------------*/ 68 | -------------------------------------------------------------------------------- /common/packet_log_processor.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime, timezone 2 | 3 | class PacketLogProcessor: 4 | def __init__(self): 5 | self.previous_out = None 6 | 7 | def process_all(self, f): 8 | packets = [] 9 | 10 | for line in f: 11 | result = self.process(line) 12 | if result is not None: 13 | packets.append(result) 14 | 15 | return zip(*packets) 16 | 17 | def process(self, line: str): 18 | line = line.rstrip() 19 | 20 | (time, kind, rest) = line.split(",", 2) 21 | 22 | if kind == "in": 23 | now = datetime.now(timezone.utc) if time is None else datetime.fromisoformat(time) 24 | 25 | length, message = rest.split(",") 26 | return self._process_in(int(length), bytes.fromhex(message), now=now) 27 | 28 | elif kind == "out": 29 | now = datetime.now(timezone.utc) if time is None else datetime.fromisoformat(time) 30 | 31 | length, message = rest.split(",") 32 | return self._process_out(int(length), bytes.fromhex(message), now=now) 33 | 34 | elif kind == "outres": 35 | now = datetime.now(timezone.utc) if time is None else datetime.fromisoformat(time) 36 | 37 | length, result = rest.split(",") 38 | return self._process_out_res(int(length), int(result), now=now) 39 | 40 | else: 41 | raise RuntimeError(f"Unknown line {line}") 42 | 43 | def _process_in(self, length: int, message: bytes, now: datetime): 44 | if length != len(message): 45 | logger.warning("Inconsistent length of received message") 46 | 47 | return (message, "rx", now) 48 | 49 | def _process_out(self, length: int, message: bytes, now: datetime): 50 | if length != len(message): 51 | logger.warning("Inconsistent length of sent message") 52 | 53 | self.previous_out = (now, length, message) 54 | 55 | def _process_out_res(self, length: int, result: int, now: datetime): 56 | if self.previous_out is None: 57 | logger.warning("Received out result, when no previous out message") 58 | return 59 | 60 | previous_now, previous_length, message = self.previous_out 61 | 62 | if previous_length != length: 63 | return 64 | 65 | self.previous_out = None 66 | 67 | # 0 is RADIO_TX_OK 68 | if result != 0: 69 | return 70 | 71 | return (message, "tx", previous_now) 72 | -------------------------------------------------------------------------------- /wsn/common/timed-unlock.c: -------------------------------------------------------------------------------- 1 | #include "timed-unlock.h" 2 | #include "os/sys/log.h" 3 | /*-------------------------------------------------------------------------------------------------------------------*/ 4 | #define LOG_MODULE "timed-lock" 5 | #define LOG_LEVEL LOG_LEVEL_WARN 6 | /*-------------------------------------------------------------------------------------------------------------------*/ 7 | process_event_t pe_timed_unlock_unlocked; 8 | /*-------------------------------------------------------------------------------------------------------------------*/ 9 | void timed_unlock_global_init(void) 10 | { 11 | pe_timed_unlock_unlocked = process_alloc_event(); 12 | } 13 | /*-------------------------------------------------------------------------------------------------------------------*/ 14 | static void timed_unlock_callack(void* data) 15 | { 16 | timed_unlock_t* l = (timed_unlock_t*)data; 17 | 18 | timed_unlock_unlock(l); 19 | 20 | LOG_WARN("Unlocked %p[%s] after %lu ticks (%lu secs)\n", l, l->name, l->duration, l->duration / CLOCK_SECOND); 21 | 22 | process_post_synch(l->p, pe_timed_unlock_unlocked, l); 23 | } 24 | /*-------------------------------------------------------------------------------------------------------------------*/ 25 | void timed_unlock_init(timed_unlock_t* l, const char* name, clock_time_t duration) 26 | { 27 | l->locked = false; 28 | l->name = name; 29 | l->duration = duration; 30 | l->p = PROCESS_CURRENT(); 31 | } 32 | /*-------------------------------------------------------------------------------------------------------------------*/ 33 | bool timed_unlock_is_locked(const timed_unlock_t* l) 34 | { 35 | return l->locked; 36 | } 37 | /*-------------------------------------------------------------------------------------------------------------------*/ 38 | void timed_unlock_lock(timed_unlock_t* l) 39 | { 40 | l->locked = true; 41 | ctimer_set(&l->timer, l->duration, timed_unlock_callack, l); 42 | } 43 | /*-------------------------------------------------------------------------------------------------------------------*/ 44 | void timed_unlock_unlock(timed_unlock_t* l) 45 | { 46 | l->locked = false; 47 | ctimer_stop(&l->timer); 48 | } 49 | /*-------------------------------------------------------------------------------------------------------------------*/ 50 | void timed_unlock_restart_timer(timed_unlock_t* l) 51 | { 52 | ctimer_restart(&l->timer); 53 | } 54 | /*-------------------------------------------------------------------------------------------------------------------*/ 55 | -------------------------------------------------------------------------------- /tools/deploy/config_backend/nrf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import subprocess 4 | import pathlib 5 | from typing import Optional 6 | 7 | import pynrfjprog.HighLevel 8 | 9 | def config_nrf(mote: str, device_type: str, speed="auto", log_dir: Optional[pathlib.Path]=None): 10 | # nrf need to have mass storage disabled in order to support receiving more 11 | # than 64 bytes over uart 12 | # This script disables mass storage 13 | # powers off the target sleeps for a bit and then powers it back on 14 | # See: https://github.com/openthread/openthread/issues/2857 15 | 16 | JLINK_DIR = pathlib.Path("/opt/SEGGER/JLink") 17 | JLINK_EXE = JLINK_DIR / "JLinkExe" 18 | 19 | opts = { 20 | "-nogui": 1, 21 | "-exitonerror": 1, 22 | "-device": device_type, 23 | "-speed": speed, 24 | "-if": "swd", 25 | "-jtagconf": "-1,-1", 26 | "-SelectEmuBySN": mote, 27 | "-AutoConnect": 1, 28 | "-CommanderScript": "tools/deploy/config_backend/msddisable.seg" 29 | } 30 | 31 | if log_dir is not None: 32 | opts["-log"] = log_dir / "JLinkExe-configure.log" 33 | 34 | opts_str = " ".join(f"{k} {v}" for (k, v) in opts.items()) 35 | 36 | print(f"{JLINK_EXE} {opts_str}") 37 | subprocess.run(f"{JLINK_EXE} {opts_str}", 38 | shell=True, 39 | check=True) 40 | 41 | if __name__ == "__main__": 42 | import argparse 43 | 44 | parser = argparse.ArgumentParser(description='Configure nrf.') 45 | parser.add_argument("--mote", default="all", help="The mote to configure") 46 | parser.add_argument("--log-dir", default=None, type=pathlib.Path, help="The directory to output logs to.") 47 | args = parser.parse_args() 48 | 49 | if args.mote == "all": 50 | nodes = [] 51 | 52 | with pynrfjprog.HighLevel.API() as api: 53 | for node_id in api.get_connected_probes(): 54 | with pynrfjprog.HighLevel.DebugProbe(api, node_id) as probe: 55 | device_info = probe.get_device_info() 56 | device_type = device_info.device_type.name 57 | 58 | # Need to remove rev from end 59 | device_type, _ = device_type.rsplit("_", 1) 60 | 61 | nodes.append((node_id, device_type)) 62 | 63 | for (node_id, node_type) in nodes: 64 | print(f"Configuring {node_id} {node_type}") 65 | config_nrf(node_id, node_type, log_dir=args.log_dir) 66 | else: 67 | config_nrf(args.mote, "nRF52840_xxAA", speed=8000, log_dir=args.log_dir) 68 | -------------------------------------------------------------------------------- /wsn/common/nanocbor/config/nanocbor-helper.c: -------------------------------------------------------------------------------- 1 | #include "nanocbor-helper.h" 2 | 3 | #include "os/sys/log.h" 4 | /*-------------------------------------------------------------------------------------------------------------------*/ 5 | #define LOG_MODULE "nanocbor" 6 | #define LOG_LEVEL LOG_LEVEL_ERR 7 | /*-------------------------------------------------------------------------------------------------------------------*/ 8 | // Tags defined at https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml 9 | #define NANOCBOR_TAG_NETWORK_ADDRESS 260 10 | /*-------------------------------------------------------------------------------------------------------------------*/ 11 | int nanocbor_fmt_ipaddr(nanocbor_encoder_t *enc, const uip_ip6addr_t *addr) 12 | { 13 | int ret; 14 | 15 | #if 0 16 | // Tag is the correct way to do this, it will also add 3 bytes of overhead (1 for tag, 2 for tag value) 17 | ret = nanocbor_fmt_tag(enc, NANOCBOR_TAG_NETWORK_ADDRESS); 18 | if (ret < 0) 19 | { 20 | return ret; 21 | } 22 | #endif 23 | 24 | ret = nanocbor_put_bstr(enc, addr->u8, sizeof(*addr)); 25 | 26 | return ret; 27 | } 28 | /*-------------------------------------------------------------------------------------------------------------------*/ 29 | int nanocbor_get_ipaddr(nanocbor_value_t *cvalue, const uip_ip6addr_t **addr) 30 | { 31 | #if 0 32 | int ret; 33 | 34 | // Tag is the correct way to do this, it will also add 3 bytes of overhead (1 for tag, 2 for tag value) 35 | uint32_t tag; 36 | ret = nanocbor_get_tag(cvalue, &tag); 37 | if (ret < 0) 38 | { 39 | return ret; 40 | } 41 | 42 | if (tag != NANOCBOR_TAG_NETWORK_ADDRESS) 43 | { 44 | return NANOCBOR_ERR_INVALID_TAG; 45 | } 46 | #endif 47 | 48 | NANOCBOR_GET_OBJECT(cvalue, addr); 49 | 50 | return NANOCBOR_OK; 51 | } 52 | /*-------------------------------------------------------------------------------------------------------------------*/ 53 | int nanocbor_get_bstr_of_len(nanocbor_value_t *cvalue, uint8_t *buf, size_t len) 54 | { 55 | const uint8_t* bufptr; 56 | size_t bufptr_length; 57 | NANOCBOR_CHECK(nanocbor_get_bstr(cvalue, &bufptr, &bufptr_length)); 58 | 59 | if (bufptr_length > len) 60 | { 61 | return NANOCBOR_ERR_OVERFLOW; 62 | } 63 | if (bufptr_length < len) 64 | { 65 | return NANOCBOR_ERR_TOO_SMALL; 66 | } 67 | 68 | memcpy(buf, bufptr, len); 69 | 70 | return NANOCBOR_OK; 71 | } 72 | /*-------------------------------------------------------------------------------------------------------------------*/ 73 | -------------------------------------------------------------------------------- /wsn/common/trust/models/none/trust-model.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "distributions.h" 4 | 5 | #include "nanocbor-helper.h" 6 | 7 | #define TRUST_MODEL_TAG 0 8 | #define TRUST_MODEL_NO_PEER_PROVIDED 9 | #define TRUST_MODEL_NO_PERIODIC_BROADCAST 10 | 11 | struct edge_resource; 12 | 13 | /*-------------------------------------------------------------------------------------------------------------------*/ 14 | // Per-Edge interactions 15 | typedef struct edge_resource_tm { 16 | 17 | } edge_resource_tm_t; 18 | /*-------------------------------------------------------------------------------------------------------------------*/ 19 | void edge_resource_tm_init(edge_resource_tm_t* tm); 20 | void edge_resource_tm_print(const edge_resource_tm_t* tm); 21 | /*-------------------------------------------------------------------------------------------------------------------*/ 22 | 23 | /*-------------------------------------------------------------------------------------------------------------------*/ 24 | // Per-Application of Edge interactions 25 | typedef struct edge_capability_tm { 26 | 27 | } edge_capability_tm_t; 28 | /*-------------------------------------------------------------------------------------------------------------------*/ 29 | void edge_capability_tm_init(edge_capability_tm_t* tm); 30 | void edge_capability_tm_print(const edge_capability_tm_t* tm); 31 | /*-------------------------------------------------------------------------------------------------------------------*/ 32 | 33 | /*-------------------------------------------------------------------------------------------------------------------*/ 34 | typedef struct peer_tm { 35 | 36 | } peer_tm_t; 37 | /*-------------------------------------------------------------------------------------------------------------------*/ 38 | void peer_tm_init(peer_tm_t* tm); 39 | void peer_tm_print(const peer_tm_t* tm); 40 | /*-------------------------------------------------------------------------------------------------------------------*/ 41 | 42 | /*-------------------------------------------------------------------------------------------------------------------*/ 43 | int serialise_trust_edge_resource(nanocbor_encoder_t* enc, const edge_resource_tm_t* edge); 44 | int serialise_trust_edge_capability(nanocbor_encoder_t* enc, const edge_capability_tm_t* cap); 45 | int deserialise_trust_edge_resource(nanocbor_value_t* dec, edge_resource_tm_t* edge); 46 | int deserialise_trust_edge_capability(nanocbor_value_t* dec, edge_capability_tm_t* cap); 47 | /*-------------------------------------------------------------------------------------------------------------------*/ 48 | -------------------------------------------------------------------------------- /wsn/Makefile.common: -------------------------------------------------------------------------------- 1 | CONTIKI = $(CONTIKING_OSCORE_DIR) 2 | 3 | ifeq ($(CONTIKI),) 4 | $(error "Contiki directory not set") 5 | endif 6 | 7 | # Include Contiki-NG Make variables 8 | include $(CONTIKI)/Makefile.dir-variables 9 | 10 | ifdef BUILD_NUMBER 11 | CFLAGS += -DBUILD_NUMBER=$(BUILD_NUMBER) 12 | endif 13 | 14 | CFLAGS += -g 15 | 16 | #CFLAGS += -Wconversion 17 | CFLAGS += -Wno-error=char-subscripts -Wno-error=array-bounds 18 | 19 | # Add additional CFLAGS 20 | CFLAGS += -DMQTT_CLIENT_CONF_LOG_LEVEL=LOG_LEVEL_DBG 21 | CFLAGS += -DTRUST_MODEL_LOG_LEVEL=LOG_LEVEL_DBG 22 | CFLAGS += -DAPP_MONITORING_LOG_LEVEL=LOG_LEVEL_DBG 23 | CFLAGS += -DAPP_ROUTING_LOG_LEVEL=LOG_LEVEL_DBG 24 | CFLAGS += -DAPP_CHALLENGE_RESPONSE_LOG_LEVEL=LOG_LEVEL_DBG 25 | CFLAGS += -DCRYPTO_SUPPORT_LOG_LEVEL=LOG_LEVEL_DBG 26 | CFLAGS += -DKEYSTORE_LOG_LEVEL=LOG_LEVEL_DBG 27 | 28 | ifneq ($(OSCORE_MASTER_SALT),) 29 | $(info "Using master salt of $(OSCORE_MASTER_SALT)") 30 | CFLAGS += -DOSCORE_MASTER_SALT="${OSCORE_MASTER_SALT}" 31 | endif 32 | 33 | ifneq ($(OSCORE_ID_CONTEXT),) 34 | $(info "Using id context of $(OSCORE_ID_CONTEXT)") 35 | CFLAGS += -DOSCORE_ID_CONTEXT="${OSCORE_ID_CONTEXT}" 36 | endif 37 | 38 | # Include common application modules 39 | MODULES_REL += ../common ${addprefix ../common/,mqtt-over-coap trust trust/stereotypes crypto crypto/targets/$(TARGET)} 40 | 41 | include ../common/nanocbor/Makefile.include 42 | 43 | ifeq ($(MAKE_WITH_PCAP),1) 44 | MAKE_NET_WITH_PCAP=1 45 | MODULES_REL += ../common/pcap 46 | endif 47 | 48 | # MQTT configuration 49 | CFLAGS += -DTOPICS_TO_SUBSCRIBE_LEN=4 50 | 51 | # CoAP configuration 52 | MAKE_WITH_OSCORE = 1 53 | MAKE_WITH_GROUPCOM = 1 54 | MAKE_WITH_HW_CRYPTO = 1 55 | MODULES += $(CONTIKI_NG_APP_LAYER_DIR)/coap 56 | #MODULES_REL += ${addprefix ../common/tinydtls/cc2538/,sha2 ecc} 57 | 58 | ifeq ($(TARGET),nrf52840) 59 | NRF52840_CRYPTO=1 60 | NRF52840_CRYPTO_BACKEND=cc310 61 | CFLAGS += -DNRF_CRYPTO_BACKEND_CC310_ECC_SECP256R1_ENABLED=1 62 | CFLAGS += -DNRF_CRYPTO_BACKEND_CC310_HASH_SHA256_ENABLED=1 63 | 64 | # Need to define this to prevent the SDK complaining 65 | CFLAGS += -DNRF_CRYPTO_BACKEND_CC310_BL_HASH_SHA256_ENABLED 66 | 67 | # Need to build using RTT so we can get serial output 68 | #NRF52840_USE_RTT=1 69 | #CFLAGS += -DSEGGER_RTT_MODE_DEFAULT=SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL 70 | #CFLAGS += -DBUFFER_SIZE_DOWN=256 71 | #CFLAGS += -DSEGGER_RTT_MAX_NUM_UP_BUFFERS=1 72 | #CFLAGS += -DSEGGER_RTT_MAX_NUM_DOWN_BUFFERS=1 73 | endif 74 | 75 | # Set MAC protocol 76 | #MAKE_MAC = MAKE_MAC_TSCH 77 | 78 | CFLAGS += $(ADDITIONAL_CFLAGS) -DADDITIONAL_CFLAGS="\"$(ADDITIONAL_CFLAGS)\"" 79 | -------------------------------------------------------------------------------- /wsn/common/crypto/certificate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /*-------------------------------------------------------------------------------------------------------------------*/ 3 | // Implementation similar to https://www.sciencedirect.com/science/article/pii/S0167404819302019 4 | // Assumes that the profile is restricted to secp256r1 (aka prime256v1) 5 | /*-------------------------------------------------------------------------------------------------------------------*/ 6 | #include 7 | 8 | #include "nanocbor/nanocbor.h" 9 | 10 | #include "eui64.h" 11 | #include "keys.h" 12 | #include "stereotype-tags.h" 13 | 14 | #include "uip.h" 15 | /*-------------------------------------------------------------------------------------------------------------------*/ 16 | #define TBS_CERTIFICATE_CBOR_LENGTH ( \ 17 | (1) + \ 18 | (1 + sizeof(uint32_t)) + \ 19 | (1 + EUI64_LENGTH) + \ 20 | (1 + (1 + sizeof(uint32_t)) + (1 + sizeof(uint32_t))) + \ 21 | (1 + EUI64_LENGTH) + \ 22 | STEREOTYPE_TAGS_CBOR_MAX_LEN + \ 23 | (1 + 1 + DTLS_EC_KEY_SIZE*2) \ 24 | ) 25 | 26 | #define CERTIFICATE_CBOR_LENGTH ( \ 27 | (1) + \ 28 | TBS_CERTIFICATE_CBOR_LENGTH + \ 29 | (1 + 1 + DTLS_EC_SIG_SIZE) \ 30 | ) 31 | /*-------------------------------------------------------------------------------------------------------------------*/ 32 | typedef struct certificate { 33 | uint32_t serial_number; 34 | 35 | // EUI-64, so needs to be 8 bytes 36 | uint8_t issuer[EUI64_LENGTH]; 37 | uint8_t subject[EUI64_LENGTH]; 38 | 39 | // UnixTime 40 | uint32_t validity_not_before; 41 | uint32_t validity_not_after; 42 | 43 | stereotype_tags_t tags; 44 | 45 | ecdsa_secp256r1_pubkey_t public_key; 46 | ecdsa_secp256r1_sig_t signature; 47 | 48 | } certificate_t; 49 | /*-------------------------------------------------------------------------------------------------------------------*/ 50 | int certificate_encode(nanocbor_encoder_t* enc, const certificate_t* certificate); 51 | int certificate_encode_tbs(nanocbor_encoder_t* enc, const certificate_t* certificate); 52 | /*-------------------------------------------------------------------------------------------------------------------*/ 53 | int certificate_decode(nanocbor_value_t* dec, certificate_t* certificate); 54 | /*-------------------------------------------------------------------------------------------------------------------*/ 55 | extern const certificate_t our_cert; 56 | extern const certificate_t root_cert; 57 | /*-------------------------------------------------------------------------------------------------------------------*/ 58 | -------------------------------------------------------------------------------- /tools/deploy/flash.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import subprocess 3 | 4 | def cc2538_flash(mote, filename, target_addr=None, **kwargs): 5 | """ 6 | Flash firmware for Zolertia RE-Motes (CC2538-Based) 7 | 8 | Args: 9 | mote (str): port to flash to 10 | filename (str): filename of firmware file 11 | target_addr (str): start address for flashing (Contiki starts from 12 | address 0x00202000 on this platform) 13 | 14 | Returns: 15 | Return code of flashing process 16 | """ 17 | args = [f"-p {mote}"] 18 | 19 | if target_addr is not None: 20 | args.append(f"-a {target_addr}") 21 | 22 | cmd = f'cc2538-bsl.py -e -w -v -b 460800 {" ".join(args)} {filename}' 23 | 24 | subprocess.run(cmd, cwd="tools/deploy/flash_backend", shell=True, check=True) 25 | 26 | def nRF52840_flash(mote, filename, **kwargs): 27 | from flash_backend.nrf import flash_nrf 28 | 29 | flash_nrf(filename, mote) 30 | 31 | def flash(mote, filename, mote_type, firmware_type): 32 | """ 33 | Call the appropriate flashing function with the correct arguments 34 | for the given firmware and mote 35 | 36 | Args: 37 | mote (str): port to flash to 38 | filename (str): filename of firmware file 39 | mote_type (str): zolertia or telosb 40 | firmware_type (str): contiki or riot 41 | 42 | Raises: 43 | NotImplementedError: unsupported mote-OS combination 44 | RuntimeError: unrecognised firmware OS 45 | """ 46 | kwargs = {} 47 | 48 | if firmware_type == "contiki" and mote_type == "zolertia": 49 | kwargs["target_addr"] = "0x00202000" 50 | 51 | if mote_type == "zolertia": 52 | return cc2538_flash(mote, filename, **kwargs) 53 | elif mote_type == "nRF52840": 54 | return nRF52840_flash(mote, filename) 55 | else: 56 | raise NotImplementedError(f"Support for flashing {mote_type} for {firmware_type} has not been implemented") 57 | 58 | if __name__ == "__main__": 59 | import argparse 60 | 61 | parser = argparse.ArgumentParser(description='Flash firmware to sensor nodes.') 62 | parser.add_argument("mote", help="The device identifier to flash.") 63 | parser.add_argument("filename", help="The path to the binary to flash.") 64 | parser.add_argument("mote_type", choices=["zolertia", "nRF52840"], help="The type of mote.") 65 | parser.add_argument("firmware_type", choices=["contiki", "riot"], help="The OS that was used to create the firmware.") 66 | 67 | args = parser.parse_args() 68 | 69 | flash(args.mote, args.filename, args.mote_type, args.firmware_type) 70 | -------------------------------------------------------------------------------- /resource_rich/applications/challenge_response.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import cbor2 4 | 5 | import logging 6 | import time 7 | import math 8 | import base64 9 | import hashlib 10 | 11 | from config import serial_sep 12 | import client_common 13 | 14 | NAME = "cr" 15 | 16 | logging.basicConfig(level=logging.INFO) 17 | logger = logging.getLogger(f"app-{NAME}") 18 | logger.setLevel(logging.DEBUG) 19 | 20 | def _task_runner(task): 21 | (src, dt, (difficulty, data, max_duration)) = task 22 | 23 | start_timer = time.perf_counter() 24 | 25 | # find a suitable prefix such that the first `difficulty` bytes of the hash are zero 26 | prefix_int = 0 27 | 28 | timeout = False 29 | 30 | while True: 31 | # Give up 32 | if time.perf_counter() - start_timer >= max_duration: 33 | timeout = True 34 | break 35 | 36 | prefix = prefix_int.to_bytes((prefix_int.bit_length() + 7) // 8, byteorder='big') 37 | 38 | m = hashlib.sha256() 39 | m.update(prefix) 40 | m.update(data) 41 | digest = m.digest() 42 | 43 | # Have we found a suitable prefix 44 | if all(x == 0 for x in digest[0:difficulty]): 45 | break 46 | else: 47 | prefix_int += 1 48 | 49 | end_timer = time.perf_counter() 50 | duration = end_timer - start_timer 51 | 52 | if timeout: 53 | logger.warning(f"Job {task} took {duration} seconds and {prefix_int} iterations and failed to find prefix") 54 | else: 55 | logger.info(f"Job {task} took {duration} seconds and {prefix_int} iterations and found prefix {prefix}") 56 | 57 | response = (prefix if not timeout else b"", int(math.ceil(duration))) 58 | 59 | return (src, response, duration) 60 | 61 | class ChallengeResponseClient(client_common.Client): 62 | 63 | task_resp_prefix = f"app{serial_sep}resp{serial_sep}" 64 | 65 | internal_error = (b"", 0) 66 | 67 | def __init__(self): 68 | super().__init__(NAME, task_runner=_task_runner, max_workers=2) 69 | 70 | async def _send_result(self, dest, message_response): 71 | # Push the updated stats to the node, this is used to inform the expected time to perform the task 72 | await self._write_task_stats() 73 | await self._write_task_result(dest, message_response) 74 | 75 | async def _write_task_result(self, dest, message_response): 76 | encoded = base64.b64encode(cbor2.encoder.dumps(message_response)).decode("utf-8") 77 | 78 | await self._write_to_application(f"{self.task_resp_prefix}{dest}{serial_sep}{encoded}") 79 | await self._receive_ack() 80 | 81 | if __name__ == "__main__": 82 | client = ChallengeResponseClient() 83 | 84 | client_common.main(NAME, client) 85 | -------------------------------------------------------------------------------- /resource_rich/applications/bad_challenge_response.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import logging 4 | import random 5 | import asyncio 6 | 7 | from challenge_response import ChallengeResponseClient as ChallengeResponseClientGood, NAME 8 | import client_common 9 | from bad import PeriodicBad 10 | 11 | logging.basicConfig(level=logging.INFO) 12 | logger = logging.getLogger(f"app-{NAME}-bad") 13 | logger.setLevel(logging.DEBUG) 14 | 15 | MISBEHAVE_CHOICES = ["bad-response", "no-response"] 16 | 17 | class ChallengeResponseClientBad(ChallengeResponseClientGood): 18 | def __init__(self, approach, duration): 19 | super().__init__() 20 | 21 | self.approach = approach 22 | 23 | self.bad = PeriodicBad(duration, NAME) 24 | 25 | async def start(self): 26 | await super().start() 27 | self.bad.start() 28 | 29 | async def shutdown(self): 30 | self.bad.shutdown() 31 | await super().shutdown() 32 | 33 | async def _send_result(self, dest, message_response): 34 | if self.bad.is_bad: 35 | await self._write_task_stats() 36 | 37 | if self.approach == "random": 38 | selected_approach = random.choice(MISBEHAVE_CHOICES) 39 | else: 40 | selected_approach = self.approach 41 | 42 | logger.debug(f"Currently bad, so behaving incorrectly with {selected_approach}") 43 | 44 | # Instead of sending a result, we pick one of two options 45 | # 1. Send a bad response 46 | # 2. Don't send any response 47 | 48 | if selected_approach == "bad-response": 49 | # A bad message response 50 | message_response = (b'', 0) 51 | await self._write_task_result(dest, message_response) 52 | 53 | elif selected_approach == "no-response": 54 | # Nothing to do 55 | pass 56 | 57 | else: 58 | logger.error(f"Unknown misbehaviour {selected_approach}") 59 | 60 | else: 61 | logger.debug(f"Currently good, so behaving correctly") 62 | await super()._send_result(dest, message_response) 63 | 64 | 65 | if __name__ == "__main__": 66 | import argparse 67 | parser = argparse.ArgumentParser(description='challenge-reponse always bad') 68 | parser.add_argument('--approach', type=str, choices=MISBEHAVE_CHOICES + ["random"], required=True, help='How will this application misbehave') 69 | parser.add_argument('--duration', type=float, required=True, help='How long will this application misbehave for in seconds') 70 | args = parser.parse_args() 71 | 72 | client = ChallengeResponseClientBad(args.approach, args.duration) 73 | 74 | client_common.main(NAME, client) 75 | -------------------------------------------------------------------------------- /wsn/common/eui64.c: -------------------------------------------------------------------------------- 1 | #include "eui64.h" 2 | #include "base16.h" 3 | #include "linkaddr.h" 4 | #include "uip-ds6.h" 5 | #include "root-endpoint.h" 6 | #include 7 | /*-------------------------------------------------------------------------------------------------------------------*/ 8 | const uint8_t* current_eui64(void) 9 | { 10 | return linkaddr_node_addr.u8; 11 | } 12 | /*-------------------------------------------------------------------------------------------------------------------*/ 13 | void eui64_from_ipaddr(const uip_ip6addr_t* ipaddr, uint8_t* eui64) 14 | { 15 | uip_lladdr_t lladdr; 16 | uip_ds6_set_lladdr_from_iid(&lladdr, ipaddr); 17 | 18 | // Need to unset this value 19 | if (uip_ip6addr_cmp(ipaddr, &root_ep.ipaddr)) 20 | { 21 | lladdr.addr[0] ^= 0x02; 22 | } 23 | 24 | memcpy(eui64, &lladdr, EUI64_LENGTH); 25 | } 26 | /*-------------------------------------------------------------------------------------------------------------------*/ 27 | void eui64_to_ipaddr(const uint8_t* eui64, uip_ip6addr_t* ipaddr) 28 | { 29 | uip_lladdr_t lladdr; 30 | memcpy(&lladdr, eui64, EUI64_LENGTH); 31 | 32 | // Need to unset this value 33 | if (uip_ip6addr_cmp(ipaddr, &root_ep.ipaddr)) 34 | { 35 | lladdr.addr[0] ^= 0x02; 36 | } 37 | 38 | memset(ipaddr, 0, sizeof(*ipaddr)); 39 | 40 | ipaddr->u8[0] = 0xFD; 41 | ipaddr->u8[1] = 0x00; 42 | 43 | uip_ds6_set_addr_iid(ipaddr, &lladdr); 44 | } 45 | /*-------------------------------------------------------------------------------------------------------------------*/ 46 | bool eui64_from_str(const char* eui64_str, uint8_t* eui64) 47 | { 48 | int len = strlen(eui64_str); 49 | return eui64_from_strn(eui64_str, len, eui64); 50 | } 51 | /*-------------------------------------------------------------------------------------------------------------------*/ 52 | bool eui64_from_strn(const char* eui64_str, size_t length, uint8_t* eui64) 53 | { 54 | if (length != EUI64_LENGTH * 2) 55 | { 56 | return false; 57 | } 58 | 59 | ssize_t filled = base16_decode_length(eui64_str, length, eui64, EUI64_LENGTH); 60 | 61 | return filled == EUI64_LENGTH; 62 | } 63 | /*-------------------------------------------------------------------------------------------------------------------*/ 64 | int eui64_to_str(const uint8_t* eui64, char* eui64_str, size_t eui64_str_size) 65 | { 66 | return snprintf(eui64_str, eui64_str_size, 67 | "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", 68 | eui64[0], eui64[1], eui64[2], eui64[3], 69 | eui64[4], eui64[5], eui64[6], eui64[7]); 70 | } 71 | /*-------------------------------------------------------------------------------------------------------------------*/ 72 | -------------------------------------------------------------------------------- /tools/keygen/contiking_format.py: -------------------------------------------------------------------------------- 1 | from textwrap import wrap 2 | from more_itertools import chunked 3 | 4 | from cryptography.hazmat.primitives import hashes 5 | from cryptography.hazmat.primitives.asymmetric import ec, utils 6 | 7 | from common.certificate import SignedCertificate 8 | 9 | def format_individual(number, size, line_group_size=None, spacing=18): 10 | if not isinstance(number, bytes): 11 | number = number.to_bytes(32, 'big') 12 | hex_num = number.hex().upper() 13 | 14 | wrapped = [f"0x{part}" for part in wrap(hex_num, size)] 15 | 16 | if line_group_size is None: 17 | return ", ".join(wrapped) 18 | else: 19 | chunks = list(chunked(wrapped, line_group_size)) 20 | return f",\n{' '*spacing}".join([", ".join(chunk) for chunk in chunks]) 21 | 22 | def contiking_format_our_privkey(private_key, our_deterministic_string=None): 23 | public_key_nums = private_key.public_key().public_numbers() 24 | private_value = private_key.private_numbers().private_value 25 | 26 | private_key_hex_formatted = format_individual(private_value, 2, line_group_size=8, spacing=11) 27 | 28 | return f"""const ecdsa_secp256r1_privkey_t our_privkey = {{ // {our_deterministic_string} 29 | .k = {{ {private_key_hex_formatted} }}, 30 | }};""" 31 | 32 | def contiking_format_certificate(cert: SignedCertificate, variable_name, deterministic_string=None): 33 | issuer_formatted = format_individual(cert.issuer, 2) 34 | subject_formatted = format_individual(cert.subject, 2) 35 | 36 | public_key_nums_x_formatted = format_individual(cert.public_key[0:32], 2, line_group_size=8, spacing=23) 37 | public_key_nums_y_formatted = format_individual(cert.public_key[32:64], 2, line_group_size=8, spacing=23) 38 | 39 | signature_nums_r_formatted = format_individual(cert.signature[0:32], 2, line_group_size=8, spacing=23) 40 | signature_nums_s_formatted = format_individual(cert.signature[32:64], 2, line_group_size=8, spacing=23) 41 | 42 | return f"""const certificate_t {variable_name} = {{ // {deterministic_string} 43 | .serial_number = {cert.serial_number}, 44 | 45 | .issuer = {{ {issuer_formatted} }}, 46 | .subject = {{ {subject_formatted} }}, 47 | 48 | .validity_not_before = {cert.validity_from}, 49 | .validity_not_after = {cert.validity_to}, 50 | 51 | .tags = {{ 52 | .device_class = {cert.stereotype_tags.device_class.cname()}, 53 | }}, 54 | 55 | .public_key = {{ 56 | .x = {{ {public_key_nums_x_formatted} }}, 57 | .y = {{ {public_key_nums_y_formatted} }} 58 | }}, 59 | 60 | .signature = {{ 61 | .r = {{ {signature_nums_r_formatted} }}, 62 | .s = {{ {signature_nums_s_formatted} }} 63 | }} 64 | }};""" 65 | -------------------------------------------------------------------------------- /analysis/graph/challenge_response_perf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import subprocess 5 | import math 6 | import pathlib 7 | 8 | import numpy as np 9 | import scipy.stats as stats 10 | 11 | import matplotlib.pyplot as plt 12 | 13 | from analysis.parser.edge_challenge_response import main as parse_cr 14 | from analysis.graph.util import savefig 15 | 16 | plt.rcParams['text.usetex'] = True 17 | plt.rcParams['font.size'] = 12 18 | 19 | def print_mean_ci(name, x, confidence=0.95): 20 | mean, sem, n = np.mean(x), stats.sem(x), len(x) 21 | print(name, mean, mean - stats.t.interval(0.95, len(x)-1, loc=np.mean(x), scale=stats.sem(x))[0]) 22 | 23 | def main(log_dir: pathlib.Path): 24 | (log_dir / "graphs").mkdir(parents=True, exist_ok=True) 25 | 26 | results = parse_cr(log_dir) 27 | 28 | XYs = { 29 | hostname: [ 30 | (cr.response.iterations, cr.response.duration) 31 | for cr 32 | in result.challenge_responses 33 | ] 34 | for (hostname, result) 35 | in results.items() 36 | } 37 | 38 | iterations = [ 39 | cr.response.iterations 40 | for (hostname, result) in results.items() 41 | for cr in result.challenge_responses 42 | ] 43 | durations = [ 44 | cr.response.duration 45 | for (hostname, result) in results.items() 46 | for cr in result.challenge_responses 47 | ] 48 | print_mean_ci("iterations", iterations) 49 | print_mean_ci("durations", durations) 50 | 51 | 52 | 53 | fig = plt.figure() 54 | ax = fig.gca() 55 | 56 | for (hostname, XY) in sorted(XYs.items(), key=lambda x: x[0]): 57 | X, Y = zip(*XY) 58 | ax.scatter(X, Y, label=hostname) 59 | 60 | ax.set_xlabel('Iterations') 61 | ax.set_ylabel('Time Taken (secs)') 62 | 63 | ax.legend() 64 | 65 | savefig(fig, log_dir / "graphs" / "cr_iterations_vs_timetaken.pdf") 66 | 67 | fig = plt.figure() 68 | ax = fig.gca() 69 | 70 | Xs = [] 71 | labels = [] 72 | 73 | for (hostname, XY) in sorted(XYs.items(), key=lambda x: x[0]): 74 | X, Y = zip(*XY) 75 | Xs.append(X) 76 | labels.append(hostname) 77 | 78 | ax.boxplot(Xs) 79 | ax.set_xticklabels(labels) 80 | 81 | ax.set_xlabel('Resource Rich Nodes') 82 | ax.set_ylabel('Iterations') 83 | 84 | savefig(fig, log_dir / "graphs" / "cr_iterations_boxplot.pdf") 85 | 86 | 87 | if __name__ == "__main__": 88 | import argparse 89 | 90 | parser = argparse.ArgumentParser(description='Graph Challenge Response') 91 | parser.add_argument('--log-dir', type=pathlib.Path, default="results", nargs='+', help='The directory which contains the log output') 92 | 93 | args = parser.parse_args() 94 | 95 | for log_dir in args.log_dir: 96 | print(f"Graphing for {log_dir}") 97 | main(log_dir) 98 | -------------------------------------------------------------------------------- /wsn/adversary/attacks/radio_off.c: -------------------------------------------------------------------------------- 1 | #include "contiki.h" 2 | #include "sys/log.h" 3 | #include "netstack.h" 4 | #include "etimer.h" 5 | /*-------------------------------------------------------------------------------------------------------------------*/ 6 | #define LOG_MODULE "attack-ro" 7 | #define LOG_LEVEL LOG_LEVEL_DBG 8 | /*-------------------------------------------------------------------------------------------------------------------*/ 9 | #ifndef ATTACK_RADIO_OFF_INTERVAL 10 | #define ATTACK_RADIO_OFF_INTERVAL 5 11 | #endif 12 | #ifndef ATTACK_RADIO_OFF_DURATION 13 | #define ATTACK_RADIO_OFF_DURATION 300 14 | #endif 15 | /*-------------------------------------------------------------------------------------------------------------------*/ 16 | PROCESS(radio_off, "radio_off"); 17 | /*-------------------------------------------------------------------------------------------------------------------*/ 18 | #define RADIO_OFF_INTERVAL (CLOCK_CONF_SECOND * (unsigned int)ATTACK_RADIO_OFF_INTERVAL) 19 | #define RADIO_OFF_DURATION (CLOCK_CONF_SECOND * (unsigned int)ATTACK_RADIO_OFF_DURATION) 20 | /*-------------------------------------------------------------------------------------------------------------------*/ 21 | static struct etimer radio_off_start_timer; 22 | /*-------------------------------------------------------------------------------------------------------------------*/ 23 | PROCESS_THREAD(radio_off, ev, data) 24 | { 25 | PROCESS_BEGIN(); 26 | 27 | LOG_INFO("Starting %s\n", PROCESS_NAME_STRING(PROCESS_CURRENT())); 28 | LOG_INFO("Turning radio off every %u for %u\n", 29 | (unsigned int)ATTACK_RADIO_OFF_INTERVAL, 30 | (unsigned int)ATTACK_RADIO_OFF_DURATION); 31 | 32 | etimer_set(&radio_off_start_timer, RADIO_OFF_INTERVAL); 33 | 34 | // Just using NETSTACK_MAC.off() and NETSTACK_MAC.on() is insufficient 35 | // as it does nothing to prevent the MAC / routing drivers turning 36 | // the radio back on. 37 | // So we need to NOT yield control back to anyone else to ensure 38 | // that the radio is kept off. 39 | 40 | while (true) 41 | { 42 | LOG_INFO("Waiting for %u to turn radio off\n", (unsigned int)ATTACK_RADIO_OFF_INTERVAL); 43 | PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_TIMER && data == &radio_off_start_timer); 44 | 45 | LOG_INFO("Turning MAC off\n"); 46 | NETSTACK_MAC.off(); 47 | 48 | LOG_INFO("Waiting for %u to turn radio on\n", (unsigned int)ATTACK_RADIO_OFF_DURATION); 49 | clock_wait(RADIO_OFF_DURATION); 50 | 51 | LOG_INFO("Turning MAC on\n"); 52 | NETSTACK_MAC.on(); 53 | 54 | etimer_restart(&radio_off_start_timer); 55 | } 56 | 57 | PROCESS_END(); 58 | } 59 | /*-------------------------------------------------------------------------------------------------------------------*/ 60 | -------------------------------------------------------------------------------- /wsn/applications/applications.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "contiki.h" 4 | 5 | #include "edge-info.h" 6 | 7 | #include "nanocbor/nanocbor.h" 8 | /*-------------------------------------------------------------------------------------------------------------------*/ 9 | #define APPLICATION_NAME_MAX_LEN 8 10 | /*-------------------------------------------------------------------------------------------------------------------*/ 11 | #ifdef APPLICATION_MONITORING 12 | #include "monitoring.h" 13 | #endif 14 | /*-------------------------------------------------------------------------------------------------------------------*/ 15 | #ifdef APPLICATION_ROUTING 16 | #include "routing.h" 17 | #endif 18 | /*-------------------------------------------------------------------------------------------------------------------*/ 19 | #ifdef APPLICATION_CHALLENGE_RESPONSE 20 | #include "challenge-response.h" 21 | #endif 22 | /*-------------------------------------------------------------------------------------------------------------------*/ 23 | struct process* find_process_with_name(const char* name); 24 | struct process* find_process_for_capability(const edge_capability_t* cap); 25 | /*-------------------------------------------------------------------------------------------------------------------*/ 26 | void post_to_capability_process(const edge_capability_t* cap, process_event_t pe, void* data); 27 | /*-------------------------------------------------------------------------------------------------------------------*/ 28 | void edge_capability_add_common(edge_resource_t* edge); 29 | /*-------------------------------------------------------------------------------------------------------------------*/ 30 | void edge_capability_remove_common(edge_resource_t* edge); 31 | /*-------------------------------------------------------------------------------------------------------------------*/ 32 | typedef struct { 33 | uint32_t mean; 34 | uint32_t maximum; 35 | uint32_t minimum; 36 | uint32_t variance; 37 | } application_stats_t; 38 | /*-------------------------------------------------------------------------------------------------------------------*/ 39 | void application_stats_init(application_stats_t* application_stats); 40 | /*-------------------------------------------------------------------------------------------------------------------*/ 41 | #define APPLICATION_STATS_MAX_CBOR_LENGTH ((1) + (1 + 4)*4) 42 | 43 | int application_stats_serialise(const application_stats_t* application_stats, uint8_t* buffer, size_t len); 44 | int application_stats_nil_serialise(uint8_t* buffer, size_t len); 45 | /*-------------------------------------------------------------------------------------------------------------------*/ 46 | int application_stats_deserialise(nanocbor_value_t* dec, application_stats_t* application_stats); 47 | /*-------------------------------------------------------------------------------------------------------------------*/ 48 | -------------------------------------------------------------------------------- /analysis/parser/common.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import re 4 | from datetime import datetime 5 | import sys 6 | 7 | # 7-bit C1 ANSI sequences 8 | ansi_escape = re.compile(r''' 9 | \x1B # ESC 10 | (?: # 7-bit C1 Fe (except CSI) 11 | [@-Z\\-_] 12 | | # or [ for CSI, followed by a control sequence 13 | \[ 14 | [0-?]* # Parameter bytes 15 | [ -/]* # Intermediate bytes 16 | [@-~] # Final byte 17 | ) 18 | ''', re.VERBOSE) 19 | 20 | contiki_log = re.compile(r"\[(.+)\:(.+)\] (.*)") 21 | 22 | def parse_contiki_debug(line: str) -> Tuple[str, str, str]: 23 | # Remove colour escape sequences from the line 24 | line = ansi_escape.sub('', line) 25 | 26 | m = contiki_log.match(line) 27 | if m is None: 28 | return None 29 | 30 | m_log_level = m.group(1).strip() 31 | m_module = m.group(2).strip() 32 | m_rest = m.group(3).strip() 33 | 34 | return (m_log_level, m_module, m_rest) 35 | 36 | SKIP_LINES = { 37 | "Serial port disconnected, waiting to get reconnected...", 38 | "Try to reconnect to /dev/ttyACM0 again...", 39 | "Reconnected to serial port /dev/ttyACM0", 40 | } 41 | 42 | def parse_contiki(f, throw_on_error=True): 43 | saved_time = None 44 | saved_line = None 45 | 46 | for (i, line) in enumerate(f): 47 | try: 48 | time, rest = line.strip().split(" # ", 1) 49 | except ValueError as ex: 50 | if throw_on_error: 51 | raise 52 | else: 53 | print(line) 54 | print(ex) 55 | continue 56 | 57 | if rest in SKIP_LINES: 58 | print(f"Skipping line '{rest}'", file=sys.stderr) 59 | continue 60 | 61 | result = parse_contiki_debug(rest) 62 | if result is None: 63 | if saved_line is not None: 64 | saved_line = (saved_line[0], saved_line[1], saved_line[2] + "\n" + rest) 65 | else: 66 | # If the first line was bad, there may have been some initial corruption 67 | # Skip it and continue onwards 68 | if i == 0: 69 | print(f"Something went wrong with '{line}' in {f}, skipping as it is the first line", file=sys.stderr) 70 | else: 71 | if throw_on_error: 72 | raise RuntimeError(f"Something went wrong with '{line}' in {f}") 73 | else: 74 | print(f"Something went wrong with '{line}' in {f}", file=sys.stderr) 75 | continue 76 | else: 77 | if saved_line is not None: 78 | yield (datetime.fromisoformat(saved_time),) + saved_line 79 | saved_time = time 80 | saved_line = result 81 | 82 | if saved_line is not None: 83 | yield (datetime.fromisoformat(saved_time),) + saved_line 84 | -------------------------------------------------------------------------------- /wsn/common/crypto/crypto-support.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /*-------------------------------------------------------------------------------------------------------------------*/ 3 | #include 4 | #include 5 | #include 6 | 7 | #include "keys.h" 8 | #include "platform-crypto-support.h" 9 | 10 | #include "contiki.h" 11 | /*-------------------------------------------------------------------------------------------------------------------*/ 12 | #ifndef SHA256_DIGEST_LEN_BYTES 13 | #define SHA256_DIGEST_LEN_BYTES (256 / 8) 14 | #endif 15 | /*-------------------------------------------------------------------------------------------------------------------*/ 16 | void crypto_support_init(void); 17 | /*-------------------------------------------------------------------------------------------------------------------*/ 18 | typedef struct messages_to_sign_entry 19 | { 20 | struct messages_to_sign_entry* next; 21 | 22 | // The process to notify on end of sign 23 | struct process* process; 24 | 25 | uint8_t* message; 26 | uint16_t message_buffer_len; 27 | uint16_t message_len; 28 | 29 | // User supplied data 30 | void* data; 31 | 32 | // The result of signing 33 | uint8_t result; 34 | 35 | } messages_to_sign_entry_t; 36 | /*-------------------------------------------------------------------------------------------------------------------*/ 37 | bool queue_message_to_sign(struct process* process, void* data, 38 | uint8_t* message, uint16_t message_buffer_len, uint16_t message_len); 39 | void queue_message_to_sign_done(messages_to_sign_entry_t* item); 40 | /*-------------------------------------------------------------------------------------------------------------------*/ 41 | typedef struct messages_to_verify_entry 42 | { 43 | struct messages_to_verify_entry* next; 44 | 45 | // The process to notify on end of sign 46 | struct process* process; 47 | 48 | const uint8_t* message; 49 | uint16_t message_len; 50 | 51 | // The result of signing 52 | uint8_t result; 53 | 54 | const ecdsa_secp256r1_pubkey_t* pubkey; 55 | 56 | // User supplied data 57 | void* data; 58 | 59 | } messages_to_verify_entry_t; 60 | /*-------------------------------------------------------------------------------------------------------------------*/ 61 | bool queue_message_to_verify(struct process* process, void* data, 62 | const uint8_t* message, uint16_t message_len, 63 | const ecdsa_secp256r1_pubkey_t* pubkey); 64 | void queue_message_to_verify_done(messages_to_verify_entry_t* item); 65 | /*-------------------------------------------------------------------------------------------------------------------*/ 66 | extern process_event_t pe_message_signed; 67 | extern process_event_t pe_message_verified; 68 | /*-------------------------------------------------------------------------------------------------------------------*/ 69 | --------------------------------------------------------------------------------