Skip to content

Commit bea4a28

Browse files
authored
Merge pull request #518 from pqcfox/root-of-trust-tutorial
tutorials: root-of-trust: add Root of Trust Tutorial screen and encryption service
2 parents 9d96571 + dfc7dd9 commit bea4a28

File tree

23 files changed

+1120
-0
lines changed

23 files changed

+1120
-0
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Makefile for user application
2+
3+
# Specify this directory relative to the current application.
4+
TOCK_USERLAND_BASE_DIR = ../../../../
5+
6+
PACKAGE_NAME = org.tockos.tutorials.attestation.encryption
7+
8+
# Which files to compile.
9+
C_SRCS := $(wildcard *.c)
10+
11+
# Include userland master makefile. Contains rules and flags for actually
12+
# building the application.
13+
include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Hardware Root of Trust (HWRoT) Demo Encryption Service Application
2+
------------------------------------------------------------------
3+
4+
This application implements a basic UART encryption service for a mock hardware
5+
root of trust (HWRoT) which inputs user-provided plaintext and encrypts it using
6+
a fixed key stored in a kernel driver, returning the ciphertext to the user.
7+
8+
This is part of a tutorial which improves the application in multiple steps. A
9+
writeup for the tutorial is available at https://book.tockos.org/.
10+
11+
Specific abilities of this version:
12+
13+
* Allows logging to screen over IPC
14+
* Does NOT allow prompting for plaintext over returning results in hex over UART
15+
* Does NOT allow for encrypting user-provided plaintext using an encryption
16+
oracle driver
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Hardware Root of Trust (HWRoT) Demo Encryption Service Application
2+
//
3+
// When selected by the main screen HWRoT Demo application, listens for user-provided
4+
// plaintexts over UART and encrypts them, logging status over IPC back to the screen
5+
// application.
6+
7+
#include "libtock/tock.h"
8+
#include <stdio.h>
9+
#include <stdlib.h>
10+
11+
#include <libtock-sync/interface/console.h>
12+
#include <libtock/kernel/ipc.h>
13+
14+
#define LOG_WIDTH 32
15+
16+
bool started = false;
17+
bool log_done = false;
18+
size_t screen_service = -1;
19+
char log_buf[LOG_WIDTH] __attribute__((aligned(LOG_WIDTH)));
20+
21+
const char SCREEN_SERVICE_NAME[] = "org.tockos.tutorials.attestation.screen";
22+
23+
static void ipc_callback(__attribute__ ((unused)) int pid,
24+
__attribute__ ((unused)) int len,
25+
__attribute__ ((unused)) int arg2,
26+
__attribute__ ((unused)) void* ud) {
27+
started = true;
28+
}
29+
30+
static void log_done_callback(__attribute__ ((unused)) int pid,
31+
__attribute__ ((unused)) int len,
32+
__attribute__ ((unused)) int arg2,
33+
__attribute__ ((unused)) void* ud) {
34+
log_done = true;
35+
}
36+
37+
static void wait_for_start(void) {
38+
// Register an IPC callback and wait for it to be called by the
39+
// screen app based on the user's app selection.
40+
ipc_register_service_callback("org.tockos.tutorials.attestation.encryption", ipc_callback,
41+
NULL);
42+
yield_for(&started);
43+
}
44+
45+
static int setup_logging() {
46+
returncode_t ret;
47+
48+
// Find the PID of the screen logging service
49+
ret = ipc_discover(SCREEN_SERVICE_NAME, &screen_service);
50+
if (ret != RETURNCODE_SUCCESS) {
51+
printf("Screen logging service not found.\n");
52+
return ret;
53+
}
54+
55+
// Set up a callback and share so we can supply log messages
56+
// and know when they've been completely logged.
57+
ipc_register_client_callback(screen_service, log_done_callback, NULL);
58+
ipc_share(screen_service, log_buf, LOG_WIDTH);
59+
60+
return 0;
61+
}
62+
63+
static int log_to_screen(const char* message) {
64+
returncode_t ret;
65+
66+
// Copy up to the log buffer's size of the message, with room for a null byte.
67+
uint16_t len = strnlen(message, sizeof(log_buf) - 1);
68+
memcpy(log_buf, message, len);
69+
70+
// Add the null byte.
71+
log_buf[len] = '\0';
72+
73+
// Start the logging process.
74+
ret = ipc_notify_service(screen_service);
75+
if (ret != RETURNCODE_SUCCESS) {
76+
printf("Failed to request a log to screen.\n");
77+
return ret;
78+
}
79+
80+
// Wait for the log to complete.
81+
yield_for(&log_done);
82+
log_done = false;
83+
84+
return 0;
85+
}
86+
87+
int main(void) {
88+
returncode_t ret;
89+
90+
// Wait to receive the signal to start from the app selector.
91+
wait_for_start();
92+
93+
// Set up logging service.
94+
ret = setup_logging();
95+
if (ret < 0) {
96+
printf("ERROR: cannot set up logging");
97+
}
98+
99+
// Test logging to screen over IPC.
100+
char message_buf[32];
101+
for (int i = 0; i < 10; i++) {
102+
sprintf(message_buf, "Test message #%i...", i);
103+
ret = log_to_screen(message_buf);
104+
if (ret < 0) {
105+
printf("ERROR: cannot log to screen");
106+
}
107+
}
108+
109+
return 0;
110+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Makefile for user application
2+
3+
# Specify this directory relative to the current application.
4+
TOCK_USERLAND_BASE_DIR = ../../../../
5+
6+
PACKAGE_NAME = org.tockos.tutorials.attestation.encryption
7+
8+
# Which files to compile.
9+
C_SRCS := $(wildcard *.c)
10+
11+
# Include userland master makefile. Contains rules and flags for actually
12+
# building the application.
13+
include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Hardware Root of Trust (HWRoT) Demo Encryption Service Application
2+
------------------------------------------------------------------
3+
4+
This application implements a basic UART encryption service for a mock hardware
5+
root of trust (HWRoT) which inputs user-provided plaintext and encrypts it using
6+
a fixed key stored in a kernel driver, returning the ciphertext to the user.
7+
8+
This is part of a tutorial which improves the application in multiple steps. A
9+
writeup for the tutorial is available at https://book.tockos.org/.
10+
11+
Specific abilities of this version:
12+
13+
* Allows logging to screen over IPC
14+
* Allows prompting for plaintext over returning results in hex over UART
15+
* Allows for encrypting user-provided plaintext using an encryption oracle
16+
driver
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
// Hardware Root of Trust (HWRoT) Demo Encryption Service Application
2+
//
3+
// When selected by the main screen HWRoT Demo application, listens for user-provided
4+
// plaintexts over UART and encrypts them, logging status over IPC back to the screen
5+
// application.
6+
7+
#include "libtock/tock.h"
8+
#include <stdio.h>
9+
#include <stdlib.h>
10+
11+
#include <libtock-sync/interface/console.h>
12+
#include <libtock/kernel/ipc.h>
13+
14+
#include "oracle.h"
15+
16+
#define LOG_WIDTH 32
17+
#define AES_BLOCK_SIZE 16
18+
19+
bool started = false;
20+
bool log_done = false;
21+
size_t screen_service = -1;
22+
char log_buf[LOG_WIDTH] __attribute__((aligned(LOG_WIDTH)));
23+
24+
const char SCREEN_SERVICE_NAME[] = "org.tockos.tutorials.attestation.screen";
25+
26+
static void ipc_callback(__attribute__ ((unused)) int pid,
27+
__attribute__ ((unused)) int len,
28+
__attribute__ ((unused)) int arg2,
29+
__attribute__ ((unused)) void* ud) {
30+
started = true;
31+
}
32+
33+
static void log_done_callback(__attribute__ ((unused)) int pid,
34+
__attribute__ ((unused)) int len,
35+
__attribute__ ((unused)) int arg2,
36+
__attribute__ ((unused)) void* ud) {
37+
log_done = true;
38+
}
39+
40+
static void wait_for_start(void) {
41+
// Register an IPC callback and wait for it to be called by the
42+
// screen app based on the user's app selection.
43+
ipc_register_service_callback("org.tockos.tutorials.attestation.encryption", ipc_callback,
44+
NULL);
45+
yield_for(&started);
46+
}
47+
48+
static int setup_logging() {
49+
returncode_t ret;
50+
51+
// Find the PID of the screen logging service
52+
ret = ipc_discover(SCREEN_SERVICE_NAME, &screen_service);
53+
if (ret != RETURNCODE_SUCCESS) {
54+
printf("Screen logging service not found.\n");
55+
return ret;
56+
}
57+
58+
// Set up a callback and share so we can supply log messages
59+
// and know when they've been completely logged.
60+
ipc_register_client_callback(screen_service, log_done_callback, NULL);
61+
ipc_share(screen_service, log_buf, LOG_WIDTH);
62+
63+
return 0;
64+
}
65+
66+
static int log_to_screen(const char* message) {
67+
returncode_t ret;
68+
69+
// Copy up to the log buffer's size of the message, with room for a null byte.
70+
uint16_t len = strnlen(message, sizeof(log_buf) - 1);
71+
memcpy(log_buf, message, len);
72+
73+
// Add the null byte.
74+
log_buf[len] = '\0';
75+
76+
// Start the logging process.
77+
ret = ipc_notify_service(screen_service);
78+
if (ret != RETURNCODE_SUCCESS) {
79+
printf("Failed to request a log to screen.\n");
80+
return ret;
81+
}
82+
83+
// Wait for the log to complete.
84+
yield_for(&log_done);
85+
log_done = false;
86+
87+
return 0;
88+
}
89+
90+
static size_t request_plaintext(uint8_t* plaintext, size_t size) {
91+
char c;
92+
int number_read, number_written;
93+
94+
printf("Enter plaintext to encrypt:\n");
95+
96+
// Clear all leading whitespace left in the buffer.
97+
do {
98+
libtocksync_console_read((uint8_t*)&c, 1, &number_read);
99+
} while (c == '\n' || c == '\r');
100+
101+
for (uint8_t i = 0; i < size; i++) {
102+
// Break on enter.
103+
if (c == '\n' || c == '\r') {
104+
libtocksync_console_write((uint8_t*)"\n", 1, &number_written);
105+
return i;
106+
}
107+
108+
// Otherwise, echo the character.
109+
libtocksync_console_write((uint8_t*)&c, 1, &number_written);
110+
111+
// Record the output.
112+
plaintext[i] = c;
113+
114+
// Fetch a new character from input to add.
115+
libtocksync_console_read((uint8_t*)&c, 1, &number_read);
116+
}
117+
118+
return size;
119+
}
120+
121+
static void bytes_to_hex(char* hex_chars, uint8_t* bytes, size_t bytes_len) {
122+
char hex_byte[3];
123+
124+
for (uint8_t i = 0; i < bytes_len; i++) {
125+
// Convert the current byte into hex
126+
sprintf(hex_byte, "%02X", bytes[i]);
127+
128+
// Load that serialized byte into the destination string.
129+
hex_chars[2 * i] = hex_byte[0];
130+
hex_chars[2 * i + 1] = hex_byte[1];
131+
}
132+
133+
// Add a null-terminator.
134+
hex_chars[2 * bytes_len] = '\0';
135+
}
136+
137+
int main(void) {
138+
returncode_t ret;
139+
140+
// Wait to receive the signal to start from the app selector.
141+
wait_for_start();
142+
143+
// Set up logging service.
144+
setup_logging();
145+
146+
// Prepare buffers for encryption.
147+
uint8_t plaintext[4 * AES_BLOCK_SIZE];
148+
uint8_t output[4 * AES_BLOCK_SIZE];
149+
char output_hex[33];
150+
uint8_t iv[16];
151+
char iv_hex[33];
152+
153+
while (1) {
154+
// Request a plaintext.
155+
log_to_screen("Requesting plaintext...");
156+
int plaintext_len = request_plaintext(plaintext, sizeof(plaintext));
157+
158+
// Encrypt the plaintext.
159+
log_to_screen("Encrypting...");
160+
ret = oracle_encrypt(plaintext, plaintext_len, output, sizeof(output), iv);
161+
if (ret < 0) {
162+
printf("ERROR(%i): %s.\r\n", ret, tock_strrcode(ret));
163+
printf("ERROR cannot encrypt plaintext\r\n");
164+
return ret;
165+
}
166+
167+
// Show generated IV.
168+
bytes_to_hex(iv_hex, iv, sizeof(iv));
169+
log_to_screen("Generated IV:\n");
170+
log_to_screen(iv_hex);
171+
printf("IV: %s\n", iv_hex);
172+
173+
// Show first 16 bytes of ciphertext.
174+
bytes_to_hex(output_hex, output, 16);
175+
log_to_screen("Returning ciphertext:\n");
176+
log_to_screen(output_hex);
177+
printf("Ciphertext: %s\n\n", output_hex);
178+
}
179+
}

0 commit comments

Comments
 (0)