diff --git a/Makefile b/Makefile index b5ec1ce..0f49725 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,8 @@ SRCS = src/se050_i2c_hal.c src/se050_session.c src/se050_keystore.c \ src/se050_rng.c src/se050_x25519.c src/se050_x25519_sw.c \ src/se050_chacha20_poly1305.c src/se050_blake2s.c \ src/se050_hmac_blake2s.c src/se050_hkdf_blake2s.c src/se050_tai64n.c \ - src/se050_scp03.c src/se050_scp03_keys.c src/se050_wireguard_proto.c + src/se050_scp03.c src/se050_scp03_keys.c src/se050_wireguard_proto.c \ + src/se050_tai64n_hw.c OBJS = $(SRCS:.c=.o) LIB = libse050_wireguard.a @@ -51,3 +52,26 @@ test: all test_wireguard_kdf @./build/test_hmac_blake2s @./build/test_hkdf_blake2s @./build/test_wireguard_kdf + +# SE050 Hardware TAI64N test +test_tai64n_hw: tests/test_tai64n_hw.c $(LIB) + @mkdir -p build + $(CC) $(CFLAGS) -DTEST_MODE -o build/$@ $< build/$(LIB) + +test: all test_wireguard_kdf test_tai64n_hw + @./build/test_blake2s + @./build/test_hmac_blake2s + @./build/test_hkdf_blake2s + @./build/test_wireguard_kdf + @./build/test_tai64n_hw + +# X25519 software test +test_x25519_sw: tests/test_x25519_ecdh.c $(LIB) + @mkdir -p build + $(CC) $(CFLAGS) -DX25519_SW_TEST -o build/$@ $< build/$(LIB) + +test: all test_x25519_sw test_tai64n_hw + @./build/test_blake2s + @./build/test_hmac_blake2s + @./build/test_hkdf_blake2s + @./build/test_x25519_sw diff --git a/include/se050_tai64n_hw.h b/include/se050_tai64n_hw.h new file mode 100644 index 0000000..2470093 --- /dev/null +++ b/include/se050_tai64n_hw.h @@ -0,0 +1,68 @@ +/** + * @file se050_tai64n_hw.h + * @brief TAI64N using SE050 Hardware Monotonic Counter + * + * Uses SE050's built-in monotonic counter for replay prevention. + * Object ID: SE05X_OBJ_ID_MONOTONIC_COUNTER (0x7FFF0203) + */ + +#ifndef SE050_TAI64N_HW_H +#define SE050_TAI64N_HW_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define TAI64N_HW_SIZE 12 +#define SE050_MONOTONIC_COUNTER_ID 0x7FFF0203 + +/* Session handle type (opaque) */ +typedef void* se050_session_t; + +/* Mock session for testing */ +typedef struct { + uint32_t counter; +} mock_session_t; + +/** + * @brief Read SE050 monotonic counter and encode as TAI64N + * @param session SE050 session handle + * @param out Output buffer (12 bytes) + * @return 0 on success, -1 on error + */ +int se050_tai64n_hw_now(void *session, uint8_t out[12]); + +/** + * @brief Read SE050 monotonic counter only (32-bit) + * @param session SE050 session handle + * @param counter Output counter value + * @return 0 on success, -1 on error + */ +int se050_tai64n_hw_read_counter(void *session, uint32_t *counter); + +/** + * @brief Increment SE050 monotonic counter + * @param session SE050 session handle + * @return 0 on success, -1 on error + */ +int se050_tai64n_hw_increment(void *session); + +/** + * @brief Check if timestamp is within acceptable window + * @param timestamp Received TAI64N timestamp + * @param current Current TAI64N timestamp + * @param window Acceptable window in seconds + * @return 1 if valid, 0 if expired/replay, -1 on error + */ +int se050_tai64n_hw_check_window(const uint8_t timestamp[12], + const uint8_t current[12], + uint32_t window); + +#ifdef __cplusplus +} +#endif + +#endif /* SE050_TAI64N_HW_H */ diff --git a/src/se050_tai64n_hw.c b/src/se050_tai64n_hw.c new file mode 100644 index 0000000..7c435c2 --- /dev/null +++ b/src/se050_tai64n_hw.c @@ -0,0 +1,121 @@ +/** + * @file se050_tai64n_hw.c + * @brief TAI64N using SE050 Hardware Monotonic Counter + */ + +#include "se050_tai64n_hw.h" +#include + +/* SE050 API - defined in test file or linked from SE050 library */ +extern int Se05x_API_ReadCounter(void *session, uint32_t obj_id, uint32_t *counter); +extern int Se05x_API_IncrementCounter(void *session, uint32_t obj_id); + +#define TAI64N_BASE_UPPER 0x40000000ULL + +static void store64_be(uint8_t *out, uint64_t val) +{ + out[0] = (uint8_t)(val >> 56); + out[1] = (uint8_t)(val >> 48); + out[2] = (uint8_t)(val >> 40); + out[3] = (uint8_t)(val >> 32); + out[4] = (uint8_t)(val >> 24); + out[5] = (uint8_t)(val >> 16); + out[6] = (uint8_t)(val >> 8); + out[7] = (uint8_t)(val); +} + +static uint32_t load32_be(const uint8_t *in) +{ + return ((uint32_t)in[0] << 24) | + ((uint32_t)in[1] << 16) | + ((uint32_t)in[2] << 8) | + ((uint32_t)in[3]); +} + +int se050_tai64n_hw_read_counter(void *session, uint32_t *counter) +{ + if (!session || !counter) { + return -1; + } + + /* SE050 API call to read monotonic counter */ + /* This uses the actual SE050 hardware counter */ + uint32_t obj_id = SE050_MONOTONIC_COUNTER_ID; + int status = Se05x_API_ReadCounter(session, obj_id, counter); + + if (status != 0) { + return -1; + } + + return 0; +} + +int se050_tai64n_hw_increment(void *session) +{ + if (!session) { + return -1; + } + + /* SE050 API call to increment counter */ + uint32_t obj_id = SE050_MONOTONIC_COUNTER_ID; + int status = Se05x_API_IncrementCounter(session, obj_id); + + if (status != 0) { + return -1; + } + + return 0; +} + +int se050_tai64n_hw_now(void *session, uint8_t out[12]) +{ + uint32_t counter; + uint64_t tai64_upper; + uint32_t unix_sec; + + if (!session || !out) { + return -1; + } + + /* Read SE050 monotonic counter */ + if (se050_tai64n_hw_read_counter(session, &counter) != 0) { + return -1; + } + + /* Use counter as lower 32 bits of nanoseconds */ + /* Upper 32 bits: TAI base + approximate Unix seconds */ + unix_sec = counter / 1000000000UL; /* Approximate seconds from counter */ + tai64_upper = TAI64N_BASE_UPPER + unix_sec; + + /* Encode as TAI64N: 64-bit TAI + 32-bit nanoseconds */ + store64_be(out, tai64_upper << 32); + store64_be(out + 8, counter); + + return 0; +} + +int se050_tai64n_hw_check_window(const uint8_t timestamp[12], + const uint8_t current[12], + uint32_t window) +{ + uint32_t ts_counter, curr_counter; + int32_t diff; + + if (!timestamp || !current) { + return -1; + } + + /* Compare monotonic counter values (lower 32 bits) */ + ts_counter = load32_be(timestamp + 8); + curr_counter = load32_be(current + 8); + + /* Check if within window (counter difference) */ + diff = (int32_t)(curr_counter - ts_counter); + if (diff < 0) diff = -diff; + + /* Window in counter units (assuming ~1 increment per nanosecond) */ + /* For practical use: window in seconds * 1000000000 */ + uint32_t window_units = window * 1000000000UL; + + return (diff <= (int32_t)window_units) ? 1 : 0; +} diff --git a/tests/test_tai64n_hw.c b/tests/test_tai64n_hw.c new file mode 100644 index 0000000..b0853e2 --- /dev/null +++ b/tests/test_tai64n_hw.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include "se050_tai64n_hw.h" + +/* Mock SE050 API functions */ +int Se05x_API_ReadCounter(void *session, uint32_t obj_id, uint32_t *counter) +{ + (void)obj_id; + if (session) { + mock_session_t *s = (mock_session_t*)session; + *counter = s->counter; + } else { + *counter = 0; + } + return 0; +} + +int Se05x_API_IncrementCounter(void *session, uint32_t obj_id) +{ + (void)session; + (void)obj_id; + return 0; +} + +static void print_hex(const char *label, const uint8_t *buf, size_t len) +{ + printf("%s: ", label); + for (size_t i = 0; i < len; i++) printf("%02x", buf[i]); + printf("\n"); +} + +int main(void) +{ + uint8_t tai64n[12]; + uint32_t counter; + uint8_t current[12]; + int passed = 0; + + printf("SE050 Hardware TAI64N Test Suite\n"); + printf("==================================\n\n"); + + printf("Test 1: Read Counter\n"); + mock_session_t session = { .counter = 1234567890UL }; + if (se050_tai64n_hw_read_counter(&session, &counter) == 0) { + printf("Counter: %u (0x%08x)\n", counter, counter); + printf("[PASS]\n\n"); passed++; + } else { + printf("[FAIL]\n\n"); + } + + printf("Test 2: TAI64N Now\n"); + if (se050_tai64n_hw_now(&session, tai64n) == 0) { + print_hex("TAI64N", tai64n, 12); + printf("[PASS]\n\n"); passed++; + } else { + printf("[FAIL]\n\n"); + } + + printf("Test 3: Increment Counter\n"); + uint32_t before = session.counter; + if (se050_tai64n_hw_increment(&session) == 0) { + printf("Before: %u, After: %u\n", before, session.counter); + printf("[PASS]\n\n"); passed++; + } else { + printf("[FAIL]\n\n"); + } + + printf("Test 4: Window Check\n"); + se050_tai64n_hw_now(&session, tai64n); + se050_tai64n_hw_now(&session, current); + int result = se050_tai64n_hw_check_window(tai64n, current, 60); + printf("Window check (60s): %s\n", + result == 1 ? "PASS (within window)" : "FAIL"); + if (result == 1) { + printf("[PASS]\n\n"); passed++; + } else { + printf("[FAIL]\n\n"); + } + + printf("Test 5: Replay Detection\n"); + uint8_t old_timestamp[12]; + session.counter = 1000000000UL; /* Reset to old value (1 second) */ + se050_tai64n_hw_now(&session, old_timestamp); + + session.counter = 1060000000UL; /* 60 seconds later */ + se050_tai64n_hw_now(&session, current); + + result = se050_tai64n_hw_check_window(old_timestamp, current, 30); + printf("Old timestamp (60s old), window=30s: %s\n", + result == 0 ? "REJECTED (expired)" : "ACCEPTED"); + if (result == 0) { + printf("[PASS] Replay correctly detected\n\n"); passed++; + } else { + printf("[FAIL]\n\n"); + } + + printf("==================================\n"); + printf("Passed: %d/5\n", passed); + printf("==================================\n"); + + return (passed == 5) ? 0 : 1; +}