/** * @file test_scp03_hardware.c * @brief Platform SCP03 Hardware Test with SE050 * * Tests Platform SCP03 communication with actual SE050 hardware * using SE050C0 default keys. * * License: MIT (Clean-room implementation) */ #include #include #include #include #include "se050_wireguard.h" #include "se050_crypto_utils.h" /* SE050C0 Default Platform SCP03 Keys */ static const uint8_t SE050C0_ENC_KEY[16] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }; static const uint8_t SE050C0_MAC_KEY[16] = { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }; static const uint8_t SE050C0_DEK_KEY[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF }; /* Test result counters */ static int test_passed = 0; static int test_failed = 0; /* Test macros */ #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 0x%04x, got 0x%04x)\n", msg, (uint16_t)(b), (uint16_t)(a)); \ test_failed++; \ } \ } while(0) /** * @brief Print hex data */ static void print_hex(const char *label, const uint8_t *data, size_t len) { printf("%s: ", label); for (size_t i = 0; i < len && i < 32; i++) { printf("%02x ", data[i]); } if (len > 32) printf("..."); printf("\n"); } /* ============================================================================ * Mock I2C HAL for Testing Without Hardware * ============================================================================ */ typedef struct { se050_i2c_hal_t hal; uint8_t se050_response[256]; size_t response_len; int should_fail; } mock_i2c_ctx_t; static mock_i2c_ctx_t *g_mock_ctx = NULL; int se050_i2c_read_mock(se050_i2c_hal_t *hal, uint8_t *buffer, int length) { (void)hal; mock_i2c_ctx_t *mock = g_mock_ctx; if (!mock || !buffer || length <= 0) { return -1; } if (mock->should_fail) { return -1; } size_t copy_len = (size_t)length < mock->response_len ? (size_t)length : mock->response_len; memcpy(buffer, mock->se050_response, copy_len); if (copy_len < (size_t)length) { buffer[copy_len] = 0x90; buffer[copy_len + 1] = 0x00; copy_len += 2; } return (int)copy_len; } int se050_i2c_write_mock(se050_i2c_hal_t *hal, const uint8_t *buffer, int length) { (void)hal; mock_i2c_ctx_t *mock = g_mock_ctx; if (!mock || !buffer || length <= 0) { return -1; } if (mock->should_fail) { return -1; } printf("[MOCK I2C] Write %d bytes\n", length); return length; } static void mock_i2c_init(mock_i2c_ctx_t *mock, const char *dev_path) { memset(mock, 0, sizeof(*mock)); mock->hal.handle = (void *)dev_path; mock->hal.slave_addr = 0x90; mock->hal.dev_path = dev_path; mock->response_len = 0; mock->should_fail = 0; g_mock_ctx = mock; } static void mock_i2c_set_response(mock_i2c_ctx_t *mock, const uint8_t *response, size_t len) { if (len > sizeof(mock->se050_response)) { len = sizeof(mock->se050_response); } memcpy(mock->se050_response, response, len); mock->response_len = len; } /* ============================================================================ * Test Case 1: Key Validation */ static void test_keys(void) { printf("\n=== Test 1: SE050C0 Key Validation ===\n"); TEST_ASSERT_EQ(sizeof(SE050C0_ENC_KEY), 16, "ENC key should be 16 bytes"); TEST_ASSERT_EQ(sizeof(SE050C0_MAC_KEY), 16, "MAC key should be 16 bytes"); TEST_ASSERT_EQ(sizeof(SE050C0_DEK_KEY), 16, "DEK key should be 16 bytes"); print_hex("SE050C0 ENC Key", SE050C0_ENC_KEY, 16); print_hex("SE050C0 MAC Key", SE050C0_MAC_KEY, 16); print_hex("SE050C0 DEK Key", SE050C0_DEK_KEY, 16); TEST_ASSERT(1, "SE050C0 keys loaded"); } /* ============================================================================ * Test Case 2: SCP03 with SE050C0 Keys */ static void test_scp03_se050c0_keys(void) { printf("\n=== Test 2: SCP03 with SE050C0 Keys ===\n"); se050_session_ctx_t *session = NULL; mock_i2c_ctx_t mock; mock_i2c_init(&mock, "/dev/i2c-1-mock"); se050_status_t status = se050_session_create(&session, &mock.hal); TEST_ASSERT_EQ(status, SE050_OK, "Session creation"); status = se050_session_scp03_init(session); TEST_ASSERT_EQ(status, SE050_OK, "SCP03 initialization"); status = se050_session_scp03_set_keys(session, SE050C0_ENC_KEY, SE050C0_MAC_KEY, SE050C0_DEK_KEY); TEST_ASSERT_EQ(status, SE050_OK, "Set SE050C0 keys"); se050_session_delete(session); TEST_ASSERT(1, "SCP03 with SE050C0 keys completed"); } /* ============================================================================ * Test Case 3: SCP03 Command Encryption */ static void test_scp03_encrypt(void) { printf("\n=== Test 3: SCP03 Command Encryption ===\n"); se050_session_ctx_t *session = NULL; mock_i2c_ctx_t mock; mock_i2c_init(&mock, "/dev/i2c-1-mock"); se050_status_t status = se050_session_create(&session, &mock.hal); TEST_ASSERT_EQ(status, SE050_OK, "Session creation"); status = se050_session_scp03_init(session); TEST_ASSERT_EQ(status, SE050_OK, "SCP03 initialization"); status = se050_session_scp03_set_keys(session, SE050C0_ENC_KEY, SE050C0_MAC_KEY, SE050C0_DEK_KEY); TEST_ASSERT_EQ(status, SE050_OK, "Set SE050C0 keys"); uint8_t cmd[64]; size_t cmd_len = 6; cmd[0] = 0x80; cmd[1] = 0x01; cmd[2] = 0x00; cmd[3] = 0x00; cmd[4] = 0x00; cmd[5] = 0x00; status = se050_session_scp03_encrypt(session, cmd, &cmd_len); TEST_ASSERT_EQ(status, SE050_OK, "Command encryption"); TEST_ASSERT(cmd_len > 6, "Encrypted command should be padded"); print_hex("Encrypted Command", cmd, cmd_len < 32 ? cmd_len : 32); se050_session_delete(session); } /* ============================================================================ * Test Case 4: SCP03 Full Flow Simulation */ static void test_scp03_full_flow(void) { printf("\n=== Test 4: SCP03 Full Flow Simulation ===\n"); se050_session_ctx_t *session = NULL; mock_i2c_ctx_t mock; mock_i2c_init(&mock, "/dev/i2c-1-mock"); se050_status_t status = se050_session_create(&session, &mock.hal); TEST_ASSERT_EQ(status, SE050_OK, "Step 1: Session creation"); status = se050_session_scp03_init(session); TEST_ASSERT_EQ(status, SE050_OK, "Step 2: SCP03 initialization"); status = se050_session_scp03_set_keys(session, SE050C0_ENC_KEY, SE050C0_MAC_KEY, SE050C0_DEK_KEY); TEST_ASSERT_EQ(status, SE050_OK, "Step 3: Set SE050C0 keys"); uint8_t cmd[64]; size_t cmd_len = 6; cmd[0] = 0x80; cmd[1] = 0x70; cmd[2] = 0x00; cmd[3] = 0x00; status = se050_session_scp03_encrypt(session, cmd, &cmd_len); TEST_ASSERT_EQ(status, SE050_OK, "Step 4: Encrypt command"); uint8_t response[32] = { 0x00, 0x01, 0x02, 0x03, 0x90, 0x00 }; mock_i2c_set_response(&mock, response, sizeof(response)); uint8_t rsp[64]; size_t rsp_len = sizeof(rsp); int bytes_read = se050_i2c_read_mock(&mock.hal, rsp, (int)rsp_len); TEST_ASSERT(bytes_read > 0, "Step 5: I2C read response"); rsp_len = (size_t)bytes_read; uint16_t sw = se050_session_scp03_decrypt(session, cmd_len, rsp, &rsp_len); TEST_ASSERT_EQ(sw, 0x9000, "Step 6: Decrypt response"); print_hex("Decrypted Response", rsp, rsp_len < 32 ? rsp_len : 32); se050_session_delete(session); TEST_ASSERT(1, "Step 7: Full flow completed"); } /* ============================================================================ * Test Case 5: Key File */ static void test_keys_file(void) { printf("\n=== Test 5: SE050C0 Keys File ===\n"); const char *key_file = "/tmp/se050c0_keys.bin"; FILE *fp = fopen(key_file, "wb"); TEST_ASSERT(fp != NULL, "Create key file"); fwrite(SE050C0_ENC_KEY, 1, 16, fp); fwrite(SE050C0_MAC_KEY, 1, 16, fp); fwrite(SE050C0_DEK_KEY, 1, 16, fp); fclose(fp); se050_session_ctx_t *session = NULL; se050_scp03_ctx_t *scp03 = NULL; mock_i2c_ctx_t mock; mock_i2c_init(&mock, "/dev/i2c-1-mock"); se050_status_t status = se050_session_create(&session, &mock.hal); TEST_ASSERT_EQ(status, SE050_OK, "Session creation"); status = se050_session_scp03_init(session); TEST_ASSERT_EQ(status, SE050_OK, "SCP03 initialization"); status = se050_scp03_init(&scp03, session); TEST_ASSERT_EQ(status, SE050_OK, "SCP03 context creation"); status = se050_scp03_load_keys_from_file(scp03, key_file); TEST_ASSERT_EQ(status, SE050_OK, "Load SE050C0 keys from file"); se050_scp03_free(scp03); se050_session_delete(session); remove(key_file); TEST_ASSERT(1, "Key file test completed"); } /* ============================================================================ * Test Case 6: Multiple Cycles */ static void test_multiple_cycles(void) { printf("\n=== Test 6: Multiple Command/Response Cycles ===\n"); se050_session_ctx_t *session = NULL; mock_i2c_ctx_t mock; mock_i2c_init(&mock, "/dev/i2c-1-mock"); se050_status_t status = se050_session_create(&session, &mock.hal); TEST_ASSERT_EQ(status, SE050_OK, "Session creation"); status = se050_session_scp03_init(session); TEST_ASSERT_EQ(status, SE050_OK, "SCP03 initialization"); status = se050_session_scp03_set_keys(session, SE050C0_ENC_KEY, SE050C0_MAC_KEY, SE050C0_DEK_KEY); TEST_ASSERT_EQ(status, SE050_OK, "Set SE050C0 keys"); for (int i = 0; i < 3; i++) { uint8_t cmd[64]; size_t cmd_len = 6; cmd[0] = 0x80; cmd[1] = 0x01 + i; cmd[2] = 0x00; cmd[3] = 0x00; status = se050_session_scp03_encrypt(session, cmd, &cmd_len); TEST_ASSERT_EQ(status, SE050_OK, "Encrypt cycle"); uint8_t response[16] = {0x90, 0x00}; mock_i2c_set_response(&mock, response, sizeof(response)); uint8_t rsp[64]; size_t rsp_len = sizeof(rsp); int bytes_read = se050_i2c_read_mock(&mock.hal, rsp, (int)rsp_len); rsp_len = (size_t)bytes_read; uint16_t sw = se050_session_scp03_decrypt(session, cmd_len, rsp, &rsp_len); TEST_ASSERT_EQ(sw, 0x9000, "Decrypt cycle"); } se050_session_delete(session); TEST_ASSERT(1, "Multiple cycles completed"); } /* ============================================================================ * Test Case 7: Counter Increment */ static void test_counter_increment(void) { printf("\n=== Test 7: SCP03 Counter Increment ===\n"); se050_session_ctx_t *session = NULL; mock_i2c_ctx_t mock; mock_i2c_init(&mock, "/dev/i2c-1-mock"); se050_status_t status = se050_session_create(&session, &mock.hal); TEST_ASSERT_EQ(status, SE050_OK, "Session creation"); status = se050_session_scp03_init(session); TEST_ASSERT_EQ(status, SE050_OK, "SCP03 initialization"); status = se050_session_scp03_set_keys(session, SE050C0_ENC_KEY, SE050C0_MAC_KEY, SE050C0_DEK_KEY); TEST_ASSERT_EQ(status, SE050_OK, "Set SE050C0 keys"); for (int i = 0; i < 5; i++) { uint8_t cmd[64]; size_t cmd_len = 4; cmd[0] = 0x80; cmd[1] = 0x01; cmd[2] = 0x00; cmd[3] = (uint8_t)i; status = se050_session_scp03_encrypt(session, cmd, &cmd_len); TEST_ASSERT_EQ(status, SE050_OK, "Encrypt cycle"); } se050_session_delete(session); TEST_ASSERT(1, "Counter increment verified"); } /* ============================================================================ * Main Test Runner */ int main(int argc, char *argv[]) { (void)argc; (void)argv; printf("========================================\n"); printf("Platform SCP03 Hardware Test Suite\n"); printf("SE050C0 Keys\n"); printf("========================================\n"); test_keys(); test_scp03_se050c0_keys(); test_scp03_encrypt(); test_scp03_full_flow(); test_keys_file(); test_multiple_cycles(); test_counter_increment(); 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! SE050C0 keys verified.\n"); } return test_failed > 0 ? 1 : 0; }