diff --git a/Makefile b/Makefile index be6abe5..5392fca 100644 --- a/Makefile +++ b/Makefile @@ -27,9 +27,29 @@ LIB = libse050_wireguard.a # Test executables TEST_SCP03 = test_scp03 TEST_HARDWARE = test_scp03_hardware +TEST_SE050 = test_scp03_se050 + +# Chip selection (default: SE050C0) +SE050_CHIP ?= SE050C0 + +# I2C bus options +I2C_OPTS ?= + +# Chip ID mapping +ifeq ($(SE050_CHIP),SE050C0) + CHIP_ID = 0 +else ifeq ($(SE050_CHIP),SE050C1) + CHIP_ID = 1 +else ifeq ($(SE050_CHIP),SE050E0) + CHIP_ID = 2 +else ifeq ($(SE050_CHIP),SE050E1) + CHIP_ID = 3 +else + $(error Invalid SE050_CHIP. Use SE050C0, SE050C1, SE050E0, or SE050E1) +endif # Default target -all: $(LIB) $(TEST_SCP03) $(TEST_HARDWARE) +all: $(LIB) $(TEST_SCP03) $(TEST_HARDWARE) $(TEST_SE050) # Create build directory build: @@ -49,6 +69,11 @@ $(TEST_HARDWARE): tests/test_scp03_hardware.c $(LIB) @mkdir -p build $(CC) $(CFLAGS) -o build/$@ $< build/$(LIB) $(LDFLAGS) +# SE050 hardware test with chip selection +$(TEST_SE050): tests/test_scp03_se050.c $(LIB) + @mkdir -p build + $(CC) $(CFLAGS) -DSE050_CHIP=$(CHIP_ID) -o build/$@ $< build/$(LIB) $(LDFLAGS) + # Compile source files src/%.o: src/%.c $(CC) $(CFLAGS) -c $< -o $@ @@ -57,13 +82,23 @@ src/%.o: src/%.c tests/%.o: tests/%.c $(CC) $(CFLAGS) -c $< -o $@ -# Run tests +# Run all tests test: all @echo "Running SCP03 tests..." ./build/$(TEST_SCP03) @echo "" - @echo "Running SCP03 hardware tests..." + @echo "Running SCP03 hardware tests (mock)..." ./build/$(TEST_HARDWARE) + @echo "" + @echo "Note: To run SE050 hardware tests, use:" + @echo " make SE050_CHIP=SE050C0 test_se050" + +# Run SE050 hardware tests (requires actual hardware) +test_se050: $(TEST_SE050) + @echo "Running SE050 hardware tests..." + @echo "Chip: $(SE050_CHIP)" + @echo "I2C Bus: /dev/i2c-1 (use I2C_BUS=/dev/i2c-X to change)" + ./build/$(TEST_SE050) $(I2C_OPTS) # Clean build artifacts clean: diff --git a/README.md b/README.md index b867ddb..4c8afa4 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,24 @@ MIT ライセンスで実装された NXP SE050 用 WireGuard クリーンルー - ✅ AN12436 デフォルトキー実装 - ✅ キー管理 API (`se050_scp03_load_keys_from_file`) - ✅ 安全なメモリ操作 (`memzero_explicit`, `crypto_memneq`, `secure_memcpy`) +- ✅ **SE050 ハードウェア接続テスト** (chip 選択可能) + +### 対応チップ + +- SE050C0, SE050C1, SE050E0, SE050E1 (すべて X25519 サポート) + +### ハードウェアテスト + +```bash +# SE050C0 でテスト +make SE050_CHIP=SE050C0 test_se050 + +# SE050E1 でテスト +make SE050_CHIP=SE050E1 test_se050 + +# 別の I2C バス指定 +make SE050_CHIP=SE050C0 test_se050 I2C_OPTS="-b /dev/i2c-2" +``` ### 対応チップ diff --git a/tests/test_scp03_se050.c b/tests/test_scp03_se050.c new file mode 100644 index 0000000..6185f87 --- /dev/null +++ b/tests/test_scp03_se050.c @@ -0,0 +1,541 @@ +/** + * @file test_scp03_se050.c + * @brief SE050 Hardware Platform SCP03 Connection Test + * + * Tests actual SE050 hardware connection using AN12436 default PlatformSCP03 keys. + * Supports multiple SE050 variants via compile-time options. + * + * Usage: + * make SE050_CHIP=SE050C0 test_hardware + * make SE050_CHIP=SE050C1 test_hardware + * make SE050_CHIP=SE050E0 test_hardware + * + * License: MIT (Clean-room implementation) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "se050_wireguard.h" +#include "se050_crypto_utils.h" + +/* ============================================================================ + * SE050 Chip Selection (compile-time) + * ============================================================================ */ + +#ifndef SE050_CHIP +#define SE050_CHIP SE050C0 +#endif + +#if SE050_CHIP == 0 + #define CHIP_NAME "SE050C0" + #define SE050_DEFAULT_I2C_ADDR 0x90 +#elif SE050_CHIP == 1 + #define CHIP_NAME "SE050C1" + #define SE050_DEFAULT_I2C_ADDR 0x90 +#elif SE050_CHIP == 2 + #define CHIP_NAME "SE050E0" + #define SE050_DEFAULT_I2C_ADDR 0x90 +#elif SE050_CHIP == 3 + #define CHIP_NAME "SE050E1" + #define SE050_DEFAULT_I2C_ADDR 0x90 +#else + #error "Invalid SE050_CHIP value. Use 0=SE050C0, 1=SE050C1, 2=SE050E0, or 3=SE050E1" +#endif + +/* ============================================================================ + * AN12436 Default Platform SCP03 Keys + * ============================================================================ */ + +static const uint8_t DEFAULT_ENC_KEY[16] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF +}; + +static const uint8_t DEFAULT_MAC_KEY[16] = { + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 +}; + +static const uint8_t DEFAULT_DEK_KEY[16] = { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF +}; + +/* ============================================================================ + * Test Result Tracking + * ============================================================================ */ + +static int test_passed = 0; +static int test_failed = 0; + +#define TEST_ASSERT(cond, msg) \ + do { \ + if (cond) { \ + printf("[PASS] %s\n", msg); \ + test_passed++; \ + } else { \ + printf("[FAIL] %s\n", msg); \ + test_failed++; \ + } \ + } while(0) + +#define TEST_ASSERT_EQ(a, b, msg) \ + do { \ + if ((a) == (b)) { \ + printf("[PASS] %s\n", msg); \ + test_passed++; \ + } else { \ + printf("[FAIL] %s (expected %d, got %d)\n", msg, (int)(b), (int)(a)); \ + test_failed++; \ + } \ + } while(0) + +/* ============================================================================ + * Real I2C HAL Implementation + * ============================================================================ */ + +typedef struct { + int fd; + uint8_t slave_addr; + const char *dev_path; +} real_i2c_ctx_t; + +static int real_i2c_init(real_i2c_ctx_t *ctx, const char *dev_path, uint8_t addr) +{ + int fd = open(dev_path, O_RDWR); + if (fd < 0) { + perror("I2C open failed"); + return -1; + } + + if (ioctl(fd, I2C_SLAVE, addr) < 0) { + perror("I2C set slave address failed"); + close(fd); + return -1; + } + + ctx->fd = fd; + ctx->slave_addr = addr; + ctx->dev_path = dev_path; + + return 0; +} + +static int real_i2c_read(real_i2c_ctx_t *ctx, uint8_t *buffer, int length) +{ + if (ctx->fd < 0 || !buffer || length <= 0) { + return -1; + } + + int bytes_read = read(ctx->fd, buffer, length); + if (bytes_read < 0) { + perror("I2C read failed"); + } + + return bytes_read; +} + +static int real_i2c_write(real_i2c_ctx_t *ctx, const uint8_t *buffer, int length) +{ + if (ctx->fd < 0 || !buffer || length <= 0) { + return -1; + } + + int bytes_written = write(ctx->fd, buffer, length); + if (bytes_written < 0) { + perror("I2C write failed"); + } + + return bytes_written; +} + +static void real_i2c_close(real_i2c_ctx_t *ctx) +{ + if (ctx->fd >= 0) { + close(ctx->fd); + ctx->fd = -1; + } +} + +/* ============================================================================ + * SE050 APDU Commands + * ============================================================================ */ + +/* APDU header structure */ +typedef struct { + uint8_t cla; + uint8_t ins; + uint8_t p1; + uint8_t p2; + uint8_t lc; + uint8_t data[255]; + uint8_t le; +} apdu_cmd_t; + +/* SE050 APDU commands */ +#define SE050_INS_OPEN_SESSION 0x70 +#define SE050_INS_CLOSE_SESSION 0x71 +#define SE050_INS_GET_VERSION 0x6F +#define SE050_INS_CONNECT 0x72 + +/* ============================================================================ + * Test Case 1: I2C Connection Check + */ +static void test_i2c_connection(const char *i2c_bus) +{ + printf("\n=== Test 1: I2C Connection Check ===\n"); + printf("Chip: %s\n", CHIP_NAME); + printf("I2C Bus: %s\n", i2c_bus); + printf("I2C Address: 0x%02X\n", SE050_DEFAULT_I2C_ADDR); + + real_i2c_ctx_t i2c; + + int ret = real_i2c_init(&i2c, i2c_bus, SE050_DEFAULT_I2C_ADDR); + if (ret == 0) { + TEST_ASSERT(1, "I2C connection established"); + + /* Try to read device ID (if supported) */ + uint8_t buffer[4]; + int bytes_read = real_i2c_read(&i2c, buffer, 4); + if (bytes_read > 0) { + printf("Device response: "); + for (int i = 0; i < bytes_read; i++) { + printf("%02X ", buffer[i]); + } + printf("\n"); + TEST_ASSERT(1, "Device responded to I2C read"); + } else { + printf("[INFO] Device did not respond to read (may be normal for sleep mode)\n"); + TEST_ASSERT(1, "I2C bus accessible (device may be in sleep mode)"); + } + + real_i2c_close(&i2c); + } else { + TEST_ASSERT(0, "I2C connection failed"); + printf("[WARN] Check that:\n"); + printf(" 1. SE050 is properly connected to I2C bus %s\n", i2c_bus); + printf(" 2. I2C permissions are correct (sudo or i2c group)\n"); + printf(" 3. SE050 is powered and not in sleep mode\n"); + } +} + +/* ============================================================================ + * Test Case 2: Session Creation with SCP03 + */ +static void test_session_with_scp03(const char *i2c_bus) +{ + printf("\n=== Test 2: Session Creation with SCP03 ===\n"); + + real_i2c_ctx_t i2c; + se050_i2c_hal_t hal; + se050_session_ctx_t *session = NULL; + + /* Initialize I2C */ + int ret = real_i2c_init(&i2c, i2c_bus, SE050_DEFAULT_I2C_ADDR); + TEST_ASSERT_EQ(ret, 0, "I2C initialization"); + + /* Setup HAL */ + memset(&hal, 0, sizeof(hal)); + hal.handle = &i2c; + hal.slave_addr = SE050_DEFAULT_I2C_ADDR; + hal.dev_path = i2c_bus; + + /* Create session */ + se050_status_t status = se050_session_create(&session, &hal); + TEST_ASSERT_EQ(status, SE050_OK, "Session creation"); + + if (session) { + /* Initialize SCP03 */ + status = se050_session_scp03_init(session); + TEST_ASSERT_EQ(status, SE050_OK, "SCP03 initialization"); + + /* Set AN12436 default keys */ + status = se050_session_scp03_set_keys(session, + DEFAULT_ENC_KEY, + DEFAULT_MAC_KEY, + DEFAULT_DEK_KEY); + TEST_ASSERT_EQ(status, SE050_OK, "Set AN12436 default PlatformSCP03 keys"); + + se050_session_delete(session); + TEST_ASSERT(1, "Session with SCP03 cleanup successful"); + } + + real_i2c_close(&i2c); +} + +/* ============================================================================ + * Test Case 3: SCP03 Command Encryption (Real Hardware) + */ +static void test_scp03_encrypt_hardware(const char *i2c_bus) +{ + printf("\n=== Test 3: SCP03 Command Encryption (Hardware) ===\n"); + + real_i2c_ctx_t i2c; + se050_i2c_hal_t hal; + se050_session_ctx_t *session = NULL; + + /* Initialize I2C */ + int ret = real_i2c_init(&i2c, i2c_bus, SE050_DEFAULT_I2C_ADDR); + if (ret != 0) { + TEST_ASSERT(0, "I2C not available - skipping hardware test"); + return; + } + + /* Setup HAL */ + memset(&hal, 0, sizeof(hal)); + hal.handle = &i2c; + hal.slave_addr = SE050_DEFAULT_I2C_ADDR; + hal.dev_path = i2c_bus; + + /* Create session with SCP03 */ + se050_status_t status = se050_session_create(&session, &hal); + TEST_ASSERT_EQ(status, SE050_OK, "Session creation"); + + if (!session) { + real_i2c_close(&i2c); + return; + } + + status = se050_session_scp03_init(session); + TEST_ASSERT_EQ(status, SE050_OK, "SCP03 initialization"); + + status = se050_session_scp03_set_keys(session, + DEFAULT_ENC_KEY, + DEFAULT_MAC_KEY, + DEFAULT_DEK_KEY); + TEST_ASSERT_EQ(status, SE050_OK, "Set PlatformSCP03 keys"); + + /* Prepare APDU command */ + uint8_t cmd[64]; + size_t cmd_len = 6; + + /* Simple APDU: GET VERSION */ + cmd[0] = 0x80; /* CLA */ + cmd[1] = 0x6F; /* INS - GET VERSION */ + cmd[2] = 0x00; /* P1 */ + cmd[3] = 0x00; /* P2 */ + cmd[4] = 0x00; /* LC */ + cmd[5] = 0x00; /* LE */ + + /* Encrypt command with SCP03 */ + status = se050_session_scp03_encrypt(session, cmd, &cmd_len); + TEST_ASSERT_EQ(status, SE050_OK, "SCP03 command encryption"); + + if (status == SE050_OK) { + printf("Encrypted command (%zu bytes): ", cmd_len); + for (size_t i = 0; i < cmd_len && i < 32; i++) { + printf("%02X ", cmd[i]); + } + if (cmd_len > 32) printf("..."); + printf("\n"); + + /* Send to hardware */ + int written = real_i2c_write(&i2c, cmd, (int)cmd_len); + if (written > 0) { + TEST_ASSERT(1, "Encrypted command sent to SE050"); + + /* Read response */ + uint8_t response[64]; + int bytes_read = real_i2c_read(&i2c, response, sizeof(response)); + + if (bytes_read > 0) { + TEST_ASSERT(1, "Response received from SE050"); + printf("Response (%d bytes): ", bytes_read); + for (int i = 0; i < bytes_read && i < 32; i++) { + printf("%02X ", response[i]); + } + if (bytes_read > 32) printf("..."); + printf("\n"); + + /* Decrypt response */ + size_t resp_len = (size_t)bytes_read; + uint16_t sw = se050_session_scp03_decrypt(session, cmd_len, response, &resp_len); + printf("Status word: 0x%04X\n", sw); + + if (sw == 0x9000) { + TEST_ASSERT(1, "SCP03 decryption successful - SE050 responded OK"); + } else { + TEST_ASSERT(0, "SE050 returned non-success status"); + } + } else { + TEST_ASSERT(0, "No response from SE050"); + } + } else { + TEST_ASSERT(0, "Failed to send command to SE050"); + } + } + + se050_session_delete(session); + real_i2c_close(&i2c); +} + +/* ============================================================================ + * Test Case 4: Full PlatformSCP03 Flow + */ +static void test_platform_scp03_full_flow(const char *i2c_bus) +{ + printf("\n=== Test 4: Full PlatformSCP03 Authentication Flow ===\n"); + printf("Chip: %s\n", CHIP_NAME); + + real_i2c_ctx_t i2c; + se050_i2c_hal_t hal; + se050_session_ctx_t *session = NULL; + + /* Initialize I2C */ + int ret = real_i2c_init(&i2c, i2c_bus, SE050_DEFAULT_I2C_ADDR); + if (ret != 0) { + TEST_ASSERT(0, "I2C not available - skipping full flow test"); + return; + } + + /* Setup HAL */ + memset(&hal, 0, sizeof(hal)); + hal.handle = &i2c; + hal.slave_addr = SE050_DEFAULT_I2C_ADDR; + hal.dev_path = i2c_bus; + + /* Step 1: Create session */ + se050_status_t status = se050_session_create(&session, &hal); + TEST_ASSERT_EQ(status, SE050_OK, "Step 1: Session creation"); + + if (!session) { + real_i2c_close(&i2c); + return; + } + + /* Step 2: Initialize SCP03 */ + status = se050_session_scp03_init(session); + TEST_ASSERT_EQ(status, SE050_OK, "Step 2: SCP03 context initialization"); + + /* Step 3: Set PlatformSCP03 keys (AN12436 defaults) */ + status = se050_session_scp03_set_keys(session, + DEFAULT_ENC_KEY, + DEFAULT_MAC_KEY, + DEFAULT_DEK_KEY); + TEST_ASSERT_EQ(status, SE050_OK, "Step 3: PlatformSCP03 key provisioning"); + + /* Step 4: Prepare and encrypt OPEN_SESSION command */ + uint8_t open_cmd[16]; + size_t open_cmd_len = 4; + open_cmd[0] = 0x80; /* CLA */ + open_cmd[1] = 0x70; /* INS - OPEN_SESSION */ + open_cmd[2] = 0x00; /* P1 */ + open_cmd[3] = 0x00; /* P2 */ + + status = se050_session_scp03_encrypt(session, open_cmd, &open_cmd_len); + TEST_ASSERT_EQ(status, SE050_OK, "Step 4: Encrypt OPEN_SESSION command"); + + /* Step 5: Send to hardware */ + int written = real_i2c_write(&i2c, open_cmd, (int)open_cmd_len); + if (written > 0) { + TEST_ASSERT(1, "Step 5: OPEN_SESSION command sent"); + + /* Step 6: Read and decrypt response */ + uint8_t response[64]; + int bytes_read = real_i2c_read(&i2c, response, sizeof(response)); + + if (bytes_read > 0) { + TEST_ASSERT(1, "Step 6: Response received"); + + size_t resp_len = (size_t)bytes_read; + uint16_t sw = se050_session_scp03_decrypt(session, open_cmd_len, response, &resp_len); + + printf("Session open status: 0x%04X\n", sw); + + if (sw == 0x9000) { + TEST_ASSERT(1, "Step 7: PlatformSCP03 authentication successful!"); + printf("\n*** PlatformSCP03 connection established with %s ***\n", CHIP_NAME); + } else { + TEST_ASSERT(0, "PlatformSCP03 authentication failed"); + printf("[WARN] SE050 may not have PlatformSCP03 keys configured\n"); + } + } else { + TEST_ASSERT(0, "No response from SE050"); + } + } else { + TEST_ASSERT(0, "Failed to send OPEN_SESSION command"); + } + + /* Cleanup */ + if (session) { + se050_session_delete(session); + } + real_i2c_close(&i2c); +} + +/* ============================================================================ + * Print Usage + */ +static void print_usage(const char *prog) +{ + printf("Usage: %s [options]\n", prog); + printf("\nOptions:\n"); + printf(" -b I2C bus device (default: /dev/i2c-1)\n"); + printf(" -h Show this help\n"); + printf("\nCompile-time chip selection:\n"); + printf(" make SE050_CHIP=SE050C0 test_hardware\n"); + printf(" make SE050_CHIP=SE050C1 test_hardware\n"); + printf(" make SE050_CHIP=SE050E0 test_hardware\n"); + printf(" make SE050_CHIP=SE050E1 test_hardware\n"); + printf("\nSupported chips:\n"); + printf(" SE050C0, SE050C1, SE050E0, SE050E1\n"); +} + +/* ============================================================================ + * Main Test Runner + */ +int main(int argc, char *argv[]) +{ + const char *i2c_bus = "/dev/i2c-1"; /* Default */ + + /* Parse command line arguments */ + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "-b") == 0 && i + 1 < argc) { + i2c_bus = argv[++i]; + } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { + print_usage(argv[0]); + return 0; + } + } + + printf("========================================\n"); + printf("SE050 Hardware Platform SCP03 Test\n"); + printf("========================================\n"); + printf("Chip Type: %s (SE050_CHIP=%d)\n", CHIP_NAME, SE050_CHIP); + printf("I2C Bus: %s\n", i2c_bus); + printf("PlatformSCP03 Keys: AN12436 Defaults\n"); + printf("========================================\n"); + + /* Run all test cases */ + test_i2c_connection(i2c_bus); + test_session_with_scp03(i2c_bus); + test_scp03_encrypt_hardware(i2c_bus); + test_platform_scp03_full_flow(i2c_bus); + + /* Summary */ + printf("\n========================================\n"); + printf("Test Summary\n"); + printf("========================================\n"); + printf("Passed: %d\n", test_passed); + printf("Failed: %d\n", test_failed); + printf("Total: %d\n", test_passed + test_failed); + printf("========================================\n"); + + if (test_failed == 0) { + printf("\n✓ All tests passed!\n"); + printf(" PlatformSCP03 connection verified with %s\n", CHIP_NAME); + } else { + printf("\n✗ Some tests failed.\n"); + printf(" Check I2C connection and SE050 configuration.\n"); + } + + return test_failed > 0 ? 1 : 0; +}