Skip to content

Commit

Permalink
Update readme
Browse files Browse the repository at this point in the history
  • Loading branch information
FranciscoLlobet committed Jan 7, 2024
1 parent 60de8ae commit fb8a27a
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 107 deletions.
141 changes: 97 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@ Our primary aim with `MISO` is to maximize the use of library functions provided
The current version of `MISO` boasts a set of features, including:

- read configuration files from a SD card,
- provide configuration persistance using non-volatile memory (NVM),
- connect to a designated WiFi AP,
- get a sNTP timestamp from an internet server,
- get a sNTP timestamp from an internet server and run a real-time clock (RTC),
- provide a basic secured LWM2M service client with connection management,
- provide a basic MQTT service client (QOS0 and QOS1 support),
- provide a basic MQTT service client (QOS0 and QOS1 support, QOS2 experimental),
- provide a HTTP file download client for configuration and firmware updates
- mbedTLS PSK and x509 certificate authentication tested with DTLS,
- Watchdog
- Bootloader

## Non-Features

Expand Down Expand Up @@ -55,6 +57,8 @@ Download and install the Zig Compiler

> The Arm GNU Toolchain is now optional for building since `miso`'s move to `picolibc`.
Install the Arm GNU toolchain if debugging the code is required.

https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads

### Picolibc
Expand Down Expand Up @@ -106,7 +110,7 @@ zig build

### Filesystem

- [FatFs 15](http://elm-chan.org/fsw/ff/00index_e.html). The "standard" FatFS driver for embedded devices.
- [FatFs 15](http://elm-chan.org/fsw/ff/00index_e.html). The standard FatFS driver for embedded devices.

### Utils

Expand Down Expand Up @@ -134,74 +138,123 @@ zig build

Configuration can be loaded via SD card by `config.txt`

| Field | Description | Type | |
|----------------|------------------------|-----------------------|-----------|
| wifi.ssid | Wifi WPA2 SSID | String | Mandadory |
| wifi.key | Wifi WPA2 SSID Key | String | Mandatory |
| lwm2m.endpoint | LWM2M endpoint | String | If LwM2M is compiled |
| lwm2m.uri | LWM2M Server Uri | URI String | If LwM2M is compiled |
| lwm2m.psk.id | LwM2M DTLS Psk ID | String | Optional |
| lwm2m.psk.key | LwM2M DTLS PSK Key | Base64 encoded String | Optional |
| ntp.url[] | sNTP server URI/URL | URI String Array | Mandatory |
| http.uri | Firmware image URI | URI String | Mandatory |
| http.sig | Firmware signature URI | URI String | Mandatory |
| http.key | Firmware public key | Base64 encoded string | Mandatory |

```json
{
"wifi":{
"ssid":"WIFI_SSID",
"key":"WIFI_KEY"
},
"lwm2m":{
"endpoint":"LWM2M_DEVICE_NAME",
"uri":"coaps://leshan.eclipseprojects.io:5684",
"psk":{
"id":"LWM2M_PSK_ID",
"key":"LWM2M_PSK_KEY"
},
"bootstrap":false,
"server_cert":"LWM2M_SERVER_CERT"
"wifi": {
"ssid": "WIFI_SSID",
"key": "WIFI_KEY"
},
"lwm2m": {
"endpoint": "LWM2M_DEVICE_NAME",
"uri": "coaps://leshan.eclipseprojects.io:5684",
"psk": {
"id": "LWM2M_DTLS_PSK_ID",
"key": "LWM2M_DTLS_PSK_KEY_BASE64"
},
"ntp":{
"url":[
"0.de.pool.ntp.org",
"1.de.pool.ntp.org"
]
"bootstrap": false,
},
"ntp": {
"url": [
"0.de.pool.ntp.org",
"1.de.pool.ntp.org"
]
},
"mqtt": {
"url": "mqtts://MQTT_BROKER_HOST:8883",
"device": "MQTT_DEVICE_ID",
"username": "MQTT_USER_NAME",
"password": "MQTT_PASSWORD",
"psk": {
"id": "MQTT_PSK_TLS_ID",
"key": "MQTT_PSK_TLS_KEY_BASE64"
},
"mqtt":{
"url":"mqtt://MQTT_BROKER_HOST:1883",
"device":"MQTT_DEVICE_ID",
"username": "MQTT_USER_NAME",
"password": "MQTT_PASSWORD",
"psk" : {
"id": "MQTT_PSK_ID",
"key":"MQTT_PSK_KEY"
},
"cert" : {
"client" : "MQTT_CERT",
"server_ca" : "MQTT_SERVER_CA",
}
},
"http":{
"url":"http://HTTP_SERVER_HOST:80/XDK110.bin",
"cert": {
"client": "MQTT_CERT",
"server_cert": "MQTT_SERVER_C"
}
},
"http": {
"url": "http://192.168.50.133:80/app.bin",
"sig": "http://192.168.50.133:80/app.sig",
"key": "APP_PUB_KEY_BASE64"
}
}
```

## Firmware signature
## Signature Algorithms

`miso` uses elliptic curve cryptography for signature creation and validation of configuration and firmware images using the ECDSA (*Eliptic Curve Digital Signature Algorithm*).

Parameters:

- `prime256v1` (OpenSSL)/`secp256r1`(mbedTLS)/`P-256` Weierstrass curve
- `SHA256` hash digest.

> The algorithms have been tested using OpenSSL on host (MacOS, Win11) and mbedTLS on target (EFM32/XDK110)
### Reference

- <https://wiki.openssl.org/index.php/Command_Line_Elliptic_Curve_Operations>

## Firmware Update

To perform a firmware update, the `miso` application needs to fetch both,

1. a firmware image (in binary plain, non-encrypted format) and
2. a signature (in binary plain format)

These files can be stored in a HTTP server that must support [range requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests) for the downloads.
The public key is provided in the configuration file.

The firmware update process takes the signature, binary and the locally stored public key to perform the validation.

> It should be possible to generate a firmware packet with integrated signature in the future. This, is however not in the current plans.
> FW download has been tested on a non-public (https://nginx.org) server.
### Generate the private key

> This is an example using openssl. Please keep the private key secret and offline.
```console
openssl ecparam -genkey -name prime256v1 -noout -out fw_private_key.pem
```

Generate the public key
### Public Key in PEM Format

### PEM Format
Generate the public key in PEM format.

```console
openssl ec -in fw_private_key.pem -pubout -out fw.pub
```

### DER Format
### Public Key in DER Format

```console
openssl ec -in fw_private_key.pem -pubout -outform DER -out fw.der
```

### Base64 DER
### Convert DER to Base64

```console
openssl base64 --in fw.der --out fw.b64
```

Use the base64 output as a one-line string in the config (`http.key`)

### Generate FW signature

```console
Expand All @@ -216,15 +269,15 @@ openssl dgst -sha256 -verify .\fw.der -signature .\zig-out\firmware\app.sig .\zi

## Configuration signature

Sign Configuration
### Sign Configuration

For signing the configuration, please create a private key

```console
openssl ecparam -genkey -name prime256v1 -noout -out private_key.pem
```

Generate the public key
### Generate the public key

```console
openssl ec -in private_key.pem -pubout -out config.pub
Expand Down
4 changes: 2 additions & 2 deletions src/buttons.zig
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ fn initFromHandle(comptime handle: button_handle) @This() {
return @This(){ .handle = handle };
}

pub fn getState(self: *const @This()) state {
pub inline fn getState(self: *const @This()) state {
return @as(state, @enumFromInt(c.sl_simple_button_get_state(self.handle)));
}
pub fn getHandle(self: *const @This()) button_handle {
pub inline fn getHandle(self: *const @This()) button_handle {
return self.handle;
}

Expand Down
22 changes: 11 additions & 11 deletions src/fatfs.zig
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,12 @@ pub const dir = struct {
handle: c.DIR,

/// Rename file
pub fn rename(old_name: [*:0]const u8, new_name: [*:0]const u8) frError!void {
pub inline fn rename(old_name: [*:0]const u8, new_name: [*:0]const u8) frError!void {
return fRet.check(c.f_rename(old_name, new_name));
}

/// Unlink (delete) a file
pub fn unlink(path: [*:0]const u8) frError!void {
pub inline fn unlink(path: [*:0]const u8) frError!void {
return fRet.check(c.f_unlink(path));
}

Expand All @@ -103,7 +103,7 @@ pub const dir = struct {
}

/// Close the current directory
pub fn close(self: *@This()) frError!void {
pub inline fn close(self: *@This()) frError!void {
try fRet.check(c.f_closedir(&self.handle));
}
};
Expand Down Expand Up @@ -134,7 +134,7 @@ pub const file = struct {
}

/// Close the current file
pub fn close(self: *@This()) frError!void {
pub inline fn close(self: *@This()) frError!void {
try fRet.check(c.f_close(&self.handle));
}

Expand Down Expand Up @@ -171,38 +171,38 @@ pub const file = struct {

/// Perform sync on the current file
/// Flush cached data
pub fn sync(self: *@This()) frError!void {
pub inline fn sync(self: *@This()) frError!void {
return fRet.check(c.f_sync(&self.handle));
}

/// Get the size of the file
pub fn size(self: *@This()) usize {
pub inline fn size(self: *@This()) usize {
return c.f_size(&self.handle);
}

/// Change the file pointer position
pub fn lseek(self: *@This(), offset: usize) frError!void {
pub inline fn lseek(self: *@This(), offset: usize) frError!void {
try fRet.check(c.f_lseek(&self.handle, offset));
}

/// Tell the current file pointer position
pub fn tell(self: *@This()) usize {
pub inline fn tell(self: *@This()) usize {
return c.f_tell(&self.handle);
}

/// Rewind the file pointer to the beginning
pub fn rewind(self: *@This()) frError!void {
pub inline fn rewind(self: *@This()) frError!void {
try self.lseek(0);
}

/// Test for end-of-file
/// Returns true if the file pointer is at the end of the file
pub fn eof(self: *@This()) bool {
pub inline fn eof(self: *@This()) bool {
return (0 != c.f_eof(&self.handle));
}

/// Truncate the file to the current file pointer position
pub fn truncate(self: *@This()) frError!void {
pub inline fn truncate(self: *@This()) frError!void {
try fRet.check(c.f_truncate(&self.handle));
}
};
Expand Down
Loading

0 comments on commit fb8a27a

Please sign in to comment.