Skip to content

Commit

Permalink
Merge pull request #77 from bigbrett/whnvmtool
Browse files Browse the repository at this point in the history
NVM provisioning tool
  • Loading branch information
billphipps authored Oct 17, 2024
2 parents a46eceb + dae5ac4 commit 90f8c8b
Show file tree
Hide file tree
Showing 18 changed files with 1,556 additions and 7 deletions.
39 changes: 39 additions & 0 deletions .github/workflows/build-and-test-whnvmtool.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: whnvmtool build and test

on:
push:
branches: [ 'master', 'main', 'release/**' ]
pull_request:
branches: [ '*' ]

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

# List host CPU info
- name: Host CPU info
run: cat /proc/cpuinfo

# List compiler version
- name: List compiler version
run: gcc --version

# pull and build wolfssl
- name: Checkout wolfssl
uses: actions/checkout@v4
with:
repository: wolfssl/wolfssl
path: wolfssl

# Build and test standard build of whnvmtool
- name: Build and test NVM tool
run: cd tools/whnvmtool && make clean && make check WOLFSSL_DIR=../../wolfssl

# Build and test ASAN
- name: Build and test NVM tool with ASAN
run: cd tools/whnvmtool && make clean && make check WOLFSSL_DIR=../../wolfssl ASAN=1

6 changes: 3 additions & 3 deletions port/posix/posix_transport_shm.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

#include <fcntl.h> /* For O_* constants */
#include <sys/mman.h> /* For shm_open, mmap */
#include <sys/stat.h> /* For mode constants */
Expand All @@ -7,6 +6,7 @@
#include <stdlib.h> /* For exit */
#include <string.h> /* For memset */
#include <stdint.h>
#include <stdio.h>

#include "wolfhsm/wh_error.h"
#include "wolfhsm/wh_utils.h"
Expand Down Expand Up @@ -370,7 +370,7 @@ int posixTransportShm_ServerInit(void* c, const void* cf,

if (ret == WH_ERROR_OK) {
memset(ctx, 0, sizeof(*ctx));
strncpy(ctx->name, config->name, sizeof(ctx->name));
snprintf(ctx->name, sizeof(ctx->name), "%s", config->name);
ctx->connectcb = connectcb;
ctx->connectcb_arg = connectcb_arg;

Expand Down Expand Up @@ -416,7 +416,7 @@ int posixTransportShm_ClientInit(void* c, const void* cf,
}

memset(ctx, 0, sizeof(*ctx));
strncpy(ctx->name, config->name, sizeof(ctx->name));
snprintf(ctx->name, sizeof(ctx->name), "%s", config->name);
ctx->connectcb = connectcb;
ctx->connectcb_arg = connectcb_arg;

Expand Down
8 changes: 6 additions & 2 deletions src/wh_flash_ramsim.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,12 @@ int whFlashRamsim_Init(void* context, const void* config)
return WH_ERROR_BADARGS;
}

/* Simulate starting from erased flash */
memset(ctx->memory, ctx->erasedByte, ctx->size);
/* Initialize memory based on initData or simulate starting from erased flash */
if (cfg->initData != NULL) {
memcpy(ctx->memory, cfg->initData, ctx->size);
} else {
memset(ctx->memory, ctx->erasedByte, ctx->size);
}

return WH_ERROR_OK;
}
Expand Down
2 changes: 1 addition & 1 deletion src/wh_server_keystore.c
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,7 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic,
ret = hsmCacheKey(server, meta, in);
}
if (ret == 0) {
/* remove the cleint_id, client may set type */
/* remove the client_id, client may set type */
packet->keyCacheRes.id = WH_KEYID_ID(meta->id);
*size = WH_PACKET_STUB_SIZE + sizeof(packet->keyCacheRes);
}
Expand Down
4 changes: 4 additions & 0 deletions tools/whnvmtool/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
whnvmtool
whNvmImage.bin
whNvmImage.hex
test/test_whnvmtool
92 changes: 92 additions & 0 deletions tools/whnvmtool/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
TARGET = whnvmtool
CC ?= gcc

# wolfHSM source files
WOLFHSM_DIR ?= $(CURDIR)/../../
WOLFHSM_SRC = $(wildcard $(WOLFHSM_DIR)/src/*.c)
WOLFHSM_SRC += $(wildcard $(WOLFHSM_DIR)/port/posix/*.c)

# wolfCrypt source files
WOLFSSL_DIR ?= $(CURDIR)/../../../wolfssl
WOLFCRYPT_SRC = \
$(WOLFSSL_DIR)/wolfcrypt/src/wc_port.c \
$(WOLFSSL_DIR)/wolfcrypt/src/memory.c \
$(WOLFSSL_DIR)/wolfcrypt/src/misc.c \
$(WOLFSSL_DIR)/wolfcrypt/src/cryptocb.c \
$(WOLFSSL_DIR)/wolfcrypt/src/random.c \
$(WOLFSSL_DIR)/wolfcrypt/src/asn.c \
$(WOLFSSL_DIR)/wolfcrypt/src/coding.c \
$(WOLFSSL_DIR)/wolfcrypt/src/wolfmath.c \
$(WOLFSSL_DIR)/wolfcrypt/src/tfm.c \
$(WOLFSSL_DIR)/wolfcrypt/src/fe_operations.c \
$(WOLFSSL_DIR)/wolfcrypt/src/rsa.c \
$(WOLFSSL_DIR)/wolfcrypt/src/curve25519.c \
$(WOLFSSL_DIR)/wolfcrypt/src/hash.c \
$(WOLFSSL_DIR)/wolfcrypt/src/sha256.c \
$(WOLFSSL_DIR)/wolfcrypt/src/aes.c \
$(WOLFSSL_DIR)/wolfcrypt/src/ecc.c \
$(WOLFSSL_DIR)/wolfcrypt/src/cmac.c


SRC = \
$(WOLFHSM_SRC) \
$(WOLFCRYPT_SRC) \
$(TARGET).c


INCLUDE_DIRS = \
-I$(WOLFHSM_DIR) \
-I$(WOLFSSL_DIR) \
-I.

LIBS = \
-lm \
-lpthread

LIB_DIRS =

CFLAGS = -Wall $(INCLUDE_DIRS)
CFLAGS += -DWOLFSSL_USER_SETTINGS
CFLAGS += -std=c90 -D_GNU_SOURCE -Wno-cpp

CFLAGS_EXTRA = # Additional CFLAGS from the command line
LDFLAGS = $(LIB_DIRS) $(LIBS)
OUT = $(TARGET) # Output executable name

# DEBUG flag
ifeq ($(DEBUG), 1)
CFLAGS += -g -O0 -DDEBUG -ggdb3
else
CFLAGS += -O2
endif

ifeq ($(ASAN), 1)
CFLAGS_EXTRA += -fsanitize=address
endif

# Targets
all: $(OUT)

$(OUT): $(SRC)
$(CC) $(CFLAGS) $(CFLAGS_EXTRA) $(SRC) -o $(OUT) $(LDFLAGS)

# Generate the test NVM image
test-gen: $(OUT)
rm -f whNvmImage.bin whNvmImage.hex
./$(OUT) --test test/nvminit/test.nvminit --invert-erased-byte

# Run the test suite, which requires first generating the test NVM image
check: test
test: $(OUT) test-gen
$(MAKE) -C test/ CFLAGS_EXTRA="-DFLASH_ERASED_BYTE=0x00 $(CFLAGS_EXTRA)" WOLFSSL_DIR=$$(realpath $(WOLFSSL_DIR))
cd test && ./test_whnvmtool

clean: clean-test
rm -f whNvmImage.bin whNvmImage.hex
rm -f $(OUT)

clean-test:
$(MAKE) -C test clean

# PHONY targets
.PHONY: all clean test-gen test
108 changes: 108 additions & 0 deletions tools/whnvmtool/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# whnvmtool

## Overview

`whnvmtool` is a utility for creating Non-Volatile Memory (NVM) images for wolfHSM. It allows users to create NVM images with predefined objects and keys, which can be used for provisioning a wolfHSM device. The tool creates an NVM image and loads it with objects and keys specified by the user in a configuration file. The generated image can then be loaded into device memory, or used for to initialize an instance of a `whNvmFlash` provider.

## Supported NVM Providers

Currently, `whnvmtool` only supports the `whNvmFlash` provider.

## Usage

```
./whnvmtool [--test] [--image[=<file>]] [--size <size>] [--invert-erased-byte] <config-file>
```

where:

- `--image[=<file>]`: Specifies the output NVM image file. If not provided, defaults to `whNvmImage.bin`.
- `--size <size>`: Sets the partition size for the NVM image. Can be specified in decimal or hexadecimal (with '0x' prefix).
- `--invert-erased-byte`: Inverts the erased byte value (default is 0xFF, this option changes it to 0x00).
- `--test`: Enables test mode. In this mode, the tool generates an intermediate file (`nvm_metadata.txt`) containing comma separated metadata ID/file path pairs, associating each object ID with the file path containing the object's original data. This option is used by the `whnvmtool` tests to verify the contents of the generated NVM image, and is not required for normal operation.

## Configuration File Schema

The configuration file follows a specific schema for defining objects and keys to be stored in the NVM image. Each line in the file represents either an object or a key entry. The schema also supports comments and empty lines for readability. Comments use the `#` character, and all text after the `#` on a line is ignored. There are no multi-line comments.

### Object Entry Format

Lines beginning with `obj` define objects to be stored in the NVM image. The format of an object entry is as follows:

```
obj <metaDataId> <access> <flags> <label> <file>
```

where:

- `<metaDataId>`: Unsigned 16-bit integer (1-65535) representing the object metadata ID. Note that 0 is an invalid metadata ID.
- `<access>`: Unsigned 16-bit integer (0-65535) representing the access permissions.
- `<flags>`: Unsigned 16-bit integer (0-65535) representing object flags.
- `<label>`: Label string enclosed in double quotes, maximum 24 characters.
- `<file>`: Valid file path to a file containing the object's data. Data will be read from this file and stored in the NVM object.

### Key Entry Format

Lines beginning with `key` define keys (a special case of NVM objects)to be stored in the NVM image. The format of a key entry is as follows:

```
key <clientId> <keyId> <access> <flags> <label> <file>
```

where:

- `<clientId>`: Unsigned 8-bit integer (0-255) representing the client ID the key belongs to.
- `<keyId>`: Unsigned 16-bit integer (1-65535) representing the key ID. Note that 0 is an invalid key ID.
- `<access>`: Unsigned 16-bit integer (0-65535) representing access permissions.
- `<flags>`: Unsigned 16-bit integer (0-65535) representing key flags.
- `<label>`: Label string enclosed in double quotes, maximum 24 characters.
- `<file>`: Valid file path to a file containing the key's data. Data will be read from this file and stored in the NVM key.


### General Schema Rules and Restrictions

1. Each entry must be on a separate line.
2. Fields must be separated by single spaces.
3. The `<label>` field must be enclosed in double quotes and cannot contain newlines.
4. Comments can be added using the `#` character. Anything after `#` on a line is ignored.
5. Empty lines and lines containing only whitespace or comments are ignored.
6. `<id>`, `<client_id>`, `<key_id>`, `<access>`, and `<flags>` can be specified in decimal or hexadecimal (with '0x' prefix).
7. File paths must be valid and accessible.


### Example Configuration File

```
# This is a comment
obj 1 0xFFFF 0x0000 "My Object" "path/to/object.bin" # This is a trailing comment
key 1 1 0x0001 0x0000 "My Key" "path/to/key.bin"
```

## Generated NVM Image

The generated NVM image is a binary file that can be used to initialize an instance of `whNvmFlash` or loaded directly into device memory at a device-specific address. In order for a generated NVM image to be compatible with a wolfHSM server implemenation, the following must be true:

1. `whnvmtool` must be compiled against the same version of wolfHSM as the server, and be compiled to use the same value of `WOLFHSM_CFG_NVM_OBJECT_COUNT`
2. The partition size specified for the NVM image must match that of the server's `whNvmFlash` provider
3. If using a real flash implementation, the binary NVM image must be programmed to the correct address

### Generating a Hex File

Users may find it useful to generate a hex file to program the NVM image into device memory. This can be accomplished by using the `objcopy` utility to convert the generated NVM image to a hex file, making sure to specify the correct offset into the image for the start of the NVM partition. For example:

```
objcopy -I binary -O ihex --change-address <offset> <input-file> <output-file>
```

where:

- `<offset>` is the offset to the base address that will be applied to the generated hex file. Without this option, the offset is 0x0, so automated programming tools will attempt to load the hex file starting at address 0x0, which is likely not the desired behavior. The `<offset>` parameter should correspond to the base address of the NVM partition used by wolfHSM in the device's address space.
- `<input-file>` is the NVM image file generated by `whnvmtool`
- `<output-file>` is the name of the output hex file

## Testing

Tests for `whnvmtool` can be run by invoking `make check` or `make test`. This will perform the following steps:

1. Invoke `whnvmtool` to generate an NVM image using an example configuration file, using the `--test` option to export the ID/data file pairs to a file
2. Build and run a test program `test/test_whnvmtool.c`, which loads the generated NVM image and verifies the contents of the objects and keys using the exported ID/data file pairs. The compatibility of the generated image is verified by loading the image into two `whNvmFlash` providers: the POSIX port file-based NVM flash file simulator (`port/posix/posix_flash_file.c`) and the RAM-based NVM flash simulator (`src/wh_flash_ramsim.c`).
69 changes: 69 additions & 0 deletions tools/whnvmtool/test/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
TARGET = test_whnvmtool
CC ?= gcc

# wolfHSM source files
WOLFHSM_DIR ?= $(CURDIR)/../../../
WOLFHSM_SRC = $(wildcard $(WOLFHSM_DIR)/src/*.c)
WOLFHSM_SRC += $(wildcard $(WOLFHSM_DIR)/port/posix/*.c)

# wolfCrypt source files
WOLFSSL_DIR ?= $(CURDIR)/../../../../wolfssl
WOLFCRYPT_SRC = \
$(WOLFSSL_DIR)/wolfcrypt/src/wc_port.c \
$(WOLFSSL_DIR)/wolfcrypt/src/memory.c \
$(WOLFSSL_DIR)/wolfcrypt/src/misc.c \
$(WOLFSSL_DIR)/wolfcrypt/src/cryptocb.c \
$(WOLFSSL_DIR)/wolfcrypt/src/random.c \
$(WOLFSSL_DIR)/wolfcrypt/src/asn.c \
$(WOLFSSL_DIR)/wolfcrypt/src/coding.c \
$(WOLFSSL_DIR)/wolfcrypt/src/wolfmath.c \
$(WOLFSSL_DIR)/wolfcrypt/src/tfm.c \
$(WOLFSSL_DIR)/wolfcrypt/src/fe_operations.c \
$(WOLFSSL_DIR)/wolfcrypt/src/rsa.c \
$(WOLFSSL_DIR)/wolfcrypt/src/curve25519.c \
$(WOLFSSL_DIR)/wolfcrypt/src/hash.c \
$(WOLFSSL_DIR)/wolfcrypt/src/sha256.c \
$(WOLFSSL_DIR)/wolfcrypt/src/aes.c \
$(WOLFSSL_DIR)/wolfcrypt/src/ecc.c \
$(WOLFSSL_DIR)/wolfcrypt/src/cmac.c

SRC = \
$(WOLFHSM_SRC) \
$(WOLFCRYPT_SRC) \
$(TARGET).c

INCLUDE_DIRS = \
-I$(WOLFHSM_DIR) \
-I$(WOLFSSL_DIR) \
-I..

LIBS = \
-lm \
-lpthread

LIB_DIRS =

CFLAGS = -Wall $(INCLUDE_DIRS)
CFLAGS += -DWOLFSSL_USER_SETTINGS
CFLAGS_EXTRA = # Additional CFLAGS from the command line
LDFLAGS = $(LIB_DIRS) $(LIBS)
OUT = $(TARGET) # Output executable name

# DEBUG flag
ifeq ($(DEBUG), 1)
CFLAGS += -g -O0 -DDEBUG -ggdb3
else
CFLAGS += -O2
endif

# Targets
all: $(OUT)

$(OUT): $(SRC)
$(CC) $(CFLAGS) $(CFLAGS_EXTRA) $(SRC) -o $(OUT) $(LDFLAGS)

clean:
rm -f $(OUT)

# PHONY targets
.PHONY: all clean
1 change: 1 addition & 0 deletions tools/whnvmtool/test/data/key1.bin
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
KEY_1_DATA_BRAH
1 change: 1 addition & 0 deletions tools/whnvmtool/test/data/key2.bin
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
KEY_2_DATA_BRAH
1 change: 1 addition & 0 deletions tools/whnvmtool/test/data/obj1.bin
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
OBJ_1_DATA_BRAH
1 change: 1 addition & 0 deletions tools/whnvmtool/test/data/obj2.bin
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
OBJ_2_DATA_BRAH
8 changes: 8 additions & 0 deletions tools/whnvmtool/test/nvminit/test.nvminit
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Key format is:
# key <clientId> <keyId> <access> <flags> <label> <file>
key 0xC 0xFE 0xFF 0x00 "Label for key 1" test/data/key1.bin # hex values
key 12 255 255 0 "Label for key 2" test/data/key2.bin # decimal values
# NVM object format is:
# obj <metaDataId> <access> <flags> <label> <file>
obj 14 0xFF 0x00 "Label for object 1" test/data/obj1.bin # arbitrary object
obj 15 0xFF 0x00 "Label for object 2" test/data/obj2.bin # another arbitrary object
Loading

0 comments on commit 90f8c8b

Please sign in to comment.