479fcd37c1
- Fix BLAKE2s final block handling when len == fill - Fix key derivation order based on is_initiator flag - Add missing header files (se050_i2c_hal.h, se050_scp03.h) - Fix missing type definitions and includes - Update tests to set is_initiator and matching keys All 24 tests now pass.
242 lines
6.1 KiB
C
242 lines
6.1 KiB
C
/**
|
|
* @file se050_session.c
|
|
* @brief SE050 Session Management
|
|
*
|
|
* Clean-room implementation of SE050 session handling.
|
|
* Supports Platform SCP03 secure channel.
|
|
*
|
|
* License: MIT (Clean-room implementation)
|
|
*/
|
|
|
|
#include "se050_i2c_hal.h"
|
|
#include "se050_session_internal.h"
|
|
#include "se050_wireguard.h"
|
|
#include "se050_crypto_utils.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
/* SCP03 status codes */
|
|
#define SCP03_SW_SUCCESS 0x9000
|
|
#define SCP03_SW_FAIL 0x6F00
|
|
|
|
/* ============================================================================
|
|
* Session Management
|
|
* ============================================================================ */
|
|
|
|
se050_status_t se050_session_create(se050_session_ctx_t **ctx, se050_i2c_hal_t *hal)
|
|
{
|
|
se050_session_ctx_t *session;
|
|
static uint32_t session_counter = 0;
|
|
|
|
if (!ctx || !hal) {
|
|
return SE050_ERR_INVALID_ARG;
|
|
}
|
|
|
|
/* Allocate session context */
|
|
session = (se050_session_ctx_t *)calloc(1, sizeof(*session));
|
|
if (!session) {
|
|
return SE050_ERR_FAIL;
|
|
}
|
|
|
|
/* Initialize session */
|
|
session->hal = hal;
|
|
session->state = SESSION_STATE_CREATED;
|
|
session->session_id = ++session_counter;
|
|
session->session_key_len = 0;
|
|
session->scp03 = NULL;
|
|
|
|
/* Zeroize session key on allocation */
|
|
memzero_explicit(session->session_key, sizeof(session->session_key));
|
|
|
|
*ctx = session;
|
|
return SE050_OK;
|
|
}
|
|
|
|
se050_status_t se050_session_open(se050_session_ctx_t *ctx)
|
|
{
|
|
uint8_t cmd[64];
|
|
uint8_t rsp[64];
|
|
int ret;
|
|
size_t cmd_len, rsp_len;
|
|
|
|
if (!ctx) {
|
|
return SE050_ERR_INVALID_ARG;
|
|
}
|
|
|
|
if (ctx->state != SESSION_STATE_CREATED) {
|
|
return SE050_ERR_SESSION;
|
|
}
|
|
|
|
/* Build OPEN_SESSION APDU */
|
|
/* CLA INS P1 P2 LC DATA LE */
|
|
cmd[0] = 0x80; /* CLA */
|
|
cmd[1] = 0x70; /* INS - OPEN_SESSION */
|
|
cmd[2] = 0x00; /* P1 */
|
|
cmd[3] = 0x00; /* P2 */
|
|
cmd[4] = 0x00; /* LC */
|
|
cmd[5] = 0x00; /* LE */
|
|
|
|
cmd_len = 6;
|
|
|
|
/* Send command */
|
|
ret = se050_i2c_write(ctx->hal, cmd, (int)cmd_len);
|
|
if (ret < 0) {
|
|
return SE050_ERR_I2C;
|
|
}
|
|
|
|
/* Receive response */
|
|
rsp_len = sizeof(rsp);
|
|
ret = se050_i2c_read(ctx->hal, rsp, (int)rsp_len);
|
|
if (ret < 0) {
|
|
return SE050_ERR_I2C;
|
|
}
|
|
rsp_len = (size_t)ret;
|
|
|
|
/* Check response status */
|
|
if (rsp_len < 2) {
|
|
return SE050_ERR_SESSION;
|
|
}
|
|
|
|
uint16_t sw = (uint16_t)((rsp[rsp_len - 2] << 8) | rsp[rsp_len - 1]);
|
|
if (sw != 0x9000) {
|
|
return SE050_ERR_SESSION;
|
|
}
|
|
|
|
ctx->state = SESSION_STATE_OPENED;
|
|
return SE050_OK;
|
|
}
|
|
|
|
void se050_session_close(se050_session_ctx_t *ctx)
|
|
{
|
|
uint8_t cmd[64];
|
|
uint8_t rsp[64];
|
|
int ret;
|
|
|
|
if (!ctx) {
|
|
return;
|
|
}
|
|
|
|
if (ctx->state != SESSION_STATE_OPENED) {
|
|
return;
|
|
}
|
|
|
|
/* Build CLOSE_SESSION APDU */
|
|
cmd[0] = 0x80; /* CLA */
|
|
cmd[1] = 0x71; /* INS - CLOSE_SESSION */
|
|
cmd[2] = 0x00; /* P1 */
|
|
cmd[3] = 0x00; /* P2 */
|
|
cmd[4] = 0x00; /* LC */
|
|
cmd[5] = 0x00; /* LE */
|
|
|
|
ret = se050_i2c_write(ctx->hal, cmd, 6);
|
|
if (ret >= 0) {
|
|
se050_i2c_read(ctx->hal, rsp, sizeof(rsp));
|
|
}
|
|
|
|
ctx->state = SESSION_STATE_CLOSED;
|
|
}
|
|
|
|
void se050_session_delete(se050_session_ctx_t *ctx)
|
|
{
|
|
if (!ctx) {
|
|
return;
|
|
}
|
|
|
|
/* Close SCP03 secure channel if initialized */
|
|
if (ctx->scp03) {
|
|
se050_scp03_free(ctx->scp03);
|
|
ctx->scp03 = NULL;
|
|
}
|
|
|
|
/* Securely zeroize session key */
|
|
if (ctx->session_key_len > 0) {
|
|
memzero_explicit(ctx->session_key, ctx->session_key_len);
|
|
ctx->session_key_len = 0;
|
|
}
|
|
|
|
/* Free session context */
|
|
free(ctx);
|
|
}
|
|
|
|
/* ============================================================================
|
|
* SCP03 Secure Channel Integration
|
|
* ============================================================================ */
|
|
|
|
/**
|
|
* @brief Initialize SCP03 secure channel for this session
|
|
* @param ctx Session context
|
|
* @return SE050_OK on success
|
|
*/
|
|
se050_status_t se050_session_scp03_init(se050_session_ctx_t *ctx)
|
|
{
|
|
if (!ctx) {
|
|
return SE050_ERR_INVALID_ARG;
|
|
}
|
|
|
|
if (ctx->state != SESSION_STATE_CREATED && ctx->state != SESSION_STATE_OPENED) {
|
|
return SE050_ERR_SESSION;
|
|
}
|
|
|
|
/* Create SCP03 context */
|
|
return se050_scp03_init(&ctx->scp03, ctx);
|
|
}
|
|
|
|
/**
|
|
* @brief Set SCP03 keys for PlatformSCP03 authentication
|
|
* @param ctx Session context
|
|
* @param enc_key Encryption key (16 bytes)
|
|
* @param mac_key MAC key (16 bytes)
|
|
* @param dek_key Data Encryption Key (16 bytes)
|
|
* @return SE050_OK on success
|
|
*/
|
|
se050_status_t se050_session_scp03_set_keys(se050_session_ctx_t *ctx,
|
|
const uint8_t *enc_key,
|
|
const uint8_t *mac_key,
|
|
const uint8_t *dek_key)
|
|
{
|
|
if (!ctx || !ctx->scp03) {
|
|
return SE050_ERR_SESSION;
|
|
}
|
|
|
|
return se050_scp03_set_keys(ctx->scp03, enc_key, mac_key, dek_key);
|
|
}
|
|
|
|
/**
|
|
* @brief Encrypt command using SCP03
|
|
* @param ctx Session context
|
|
* @param cmd Command buffer
|
|
* @param cmd_len Command length
|
|
* @return SE050_OK on success
|
|
*/
|
|
se050_status_t se050_session_scp03_encrypt(se050_session_ctx_t *ctx,
|
|
uint8_t *cmd,
|
|
size_t *cmd_len)
|
|
{
|
|
if (!ctx || !ctx->scp03) {
|
|
return SE050_ERR_SESSION;
|
|
}
|
|
|
|
return se050_scp03_encrypt_command(ctx->scp03, cmd, cmd_len);
|
|
}
|
|
|
|
/**
|
|
* @brief Decrypt response using SCP03
|
|
* @param ctx Session context
|
|
* @param cmd_len Original command length
|
|
* @param rsp Response buffer
|
|
* @param rsp_len Response length
|
|
* @return Status word (0x9000 on success)
|
|
*/
|
|
uint16_t se050_session_scp03_decrypt(se050_session_ctx_t *ctx,
|
|
size_t cmd_len,
|
|
uint8_t *rsp,
|
|
size_t *rsp_len)
|
|
{
|
|
if (!ctx || !ctx->scp03) {
|
|
return SCP03_SW_FAIL;
|
|
}
|
|
|
|
return se050_scp03_decrypt_response(ctx->scp03, cmd_len, rsp, rsp_len);
|
|
}
|