CCFC3008PCSN JTAG 加解密流程详解

适用芯片:CCFC3008PCSN(CCFC30XX 系列)

参考文档:CCFC3008PCS Reference Manual Rev 1.3.0

参考代码:CCFC30XX_MCAL_V3.0.8_P3

最后更新:2025年8月

目录

  1. 前言(#1-前言)

  2. 安全架构概述(#2-安全架构概述)

  3. JTAG 密钥管理方式(#3-jtag-密钥管理方式)

  4. UTEST 区关键地址(#4-utest-区关键地址)

  5. 生命周期(Life Cycle)(#5-生命周期life-cycle)

  6. JTAG 密钥设置完整流程(#6-jtag-密钥设置完整流程)

  7. 软件函数调用流程(#7-软件函数调用流程)

  • 7.5 建议调用位置(#75-建议调用位置)
  1. JTAG 调试连接流程(#8-jtag-调试连接流程)

  2. JTAG 永久禁用流程(#9-jtag-永久禁用流程)

  3. JTAGM 模块寄存器(#10-jtagm-模块寄存器)

  4. 注意事项(#11-注意事项)

  5. 与 NXP/Infineon 芯片的对比(#12-与-nxpinfineon-芯片的对比)

  6. 总结(#13-总结)

1. 前言

CCFC3008PCSN 是一款国产高性能车规级 MCU,其调试接口(JTAG)采用密钥认证机制 进行安全管控。芯片在出厂时 JTAG 处于开放状态,开发者可以自由连接调试器。一旦设置了 JTAG 密钥并将芯片生命周期推进到 OEM_PRODUCTION 或之后阶段,JTAG 接口将被锁定,调试器连接时必须提供正确的 32 字节密钥才能解锁。

本文基于官方 Reference Manual、MCAL 代码包以及实际工程经验,详细介绍 CCFC3008PCSN 的 JTAG 加解密流程,包括密钥生成、设置、验证以及永久禁用等完整操作。

2. 安全架构概述

CCFC3008PCSN 的安全体系由以下核心组件协同构成:

2.1 硬件安全模块(HSM)

HSM(Hardware Security Module)是芯片内部独立的安全处理器(基于 C2002 内核),包含:

  • 128KB HSM Code Flash --- 存放 HSM 固件
  • HSM Data Flash --- 存放密钥等敏感数据
  • 硬件加密引擎 --- 支持 AES/3DES/SM1/SM4 对称算法、RSA/ECC/SM2 非对称算法、SHA/HMAC 哈希算法
  • 真随机数发生器(TRNG)

HSM 负责密钥的生成、存储、衍生和认证,是 JTAG 安全机制的核心执行者。

2.2 PASS 模块(Password and Security Module)

PASS 模块管理芯片的密码保护组(Password Groups),控制 Flash 的读写保护、调试接口锁定、生命周期状态等。

2.3 生命周期(Life Cycle)

芯片通过生命周期状态机来控制不同阶段的安全策略。详见第 5 节(#5-生命周期life-cycle)。

2.4 UTEST Flash 区域

UTEST(User Test)Flash 是芯片内部的一块特殊 Flash 区域,用于存储:

  • JTAG 密码(0x00400120 ~ 0x0040013F)
  • PASS 密码组(0x00400140 ~ 0x004001BF)
  • 生命周期槽位(0x00400200 ~ 0x0040024F)
  • DCF 记录(Device Configuration Format)

重要:一旦生命周期进入 OEM_PRODUCTION 或更后阶段,UTEST 中的 JTAG 密码和 PASS 密码区域将变为不可读(hidden)。

2.5 SSCM 模块(System Status and Configuration Module)

SSCM 在芯片上电启动过程中负责读取 DCF 记录、检查生命周期状态,并判断是否允许 JTAG 连接。

3. JTAG 密钥管理方式

CCFC30XX 系列支持两种 JTAG 密钥管理方式:

方式一:用户自行管理密钥(外部导入)

用户通过 HSM 接口直接导入一个 32 字节的 JTAG 密钥。用户需要自行保管密钥,一旦丢失将无法恢复 JTAG 访问。
// 用户自定义 32 字节密钥示例
static uint8 App_JtagPassWd32 = {
0x5A, 0x5A, 0x5A, 0x5A, 0x4B, 0x4B, 0x4B, 0x4B,
0x3C, 0x3C, 0x3C, 0x3C, 0x2D, 0x2D, 0x2D, 0x2D,
0x5A, 0x5A, 0x5A, 0x5A, 0x4B, 0x4B, 0x4B, 0x4B,
0x3C, 0x3C, 0x3C, 0x3C, 0x2D, 0x2D, 0x2D, 0x2D
};

方式二:HSM 内部管理密钥(推荐)

用户通过 HSM API 接口传入密钥分散因子(Derivative) ,HSM 使用该分散因子进行密钥衍生,生成的密钥存储在 HSM 内部密钥区中。这种方式实现了一机一密,安全性更高。
// 使用分散因子衍生密钥
uint8 derive32;
cc_memset(derive, 0x5A, sizeof(derive)); // 分散因子
status = HSM_LLD_GenerateJtagPasswd(App_hJtagKey, derive, 32, passwd);
HSM 内部管理方式的优势:密钥存储在 HSM 受保护区域,外部无法直接读取;可通过分散因子实现不同设备使用不同密钥。

4. UTEST 区关键地址

以下为 UTEST Flash 中与 JTAG 安全相关的关键地址(来自 Reference Manual):

|------------------------------|----------|---------------------------------------|
| 地址范围 | 大小 | 描述 |
| `0x00400120 ~ 0x0040013F` | 32 Bytes | **JTAG Password** --- 由用户编程 |
| `0x00400140 ~ 0x0040015F` | 32 Bytes | PASS Password Group 0 |
| `0x00400160 ~ 0x0040017F` | 32 Bytes | PASS Password Group 1 |
| `0x00400180 ~ 0x0040019F` | 32 Bytes | PASS Password Group 2 |
| `0x004001A0 ~ 0x004001BF` | 32 Bytes | PASS Password Group 3 |
| `0x00400200 ~ 0x0040020F` | 16 Bytes | Lifecycle Slot 0 --- JDP_PROD |
| `0x00400210 ~ 0x0040021F` | 16 Bytes | Lifecycle Slot 1 --- CUST_DEL |
| `0x00400220 ~ 0x0040022F` | 16 Bytes | Lifecycle Slot 2 --- OEM_PROD |
| `0x00400230 ~ 0x0040023F` | 16 Bytes | Lifecycle Slot 3 --- IN_FIELD |
| `0x00400240 ~ 0x0040024F` | 16 Bytes | Lifecycle Slot 4 --- FAILURE_ANALYSIS |

当生命周期达到 CUST_DEL(Customer Delivery)或之后阶段时,JTAG Password 和 PASS Password 区域变为不可读(hidden)。

5. 生命周期(Life Cycle)

CCFC3008PCSN 定义了以下生命周期状态:

|---------------------------|---------|--------|----------------------|
| 生命周期状态 | 枚举值 | 含义 | 说明 |
| **FAILURE_ANALYSIS** | `0x0` | 失效分析 | 芯片返回工厂进行分析,JTAG 完全开放 |
| **OEM_PRODUCTION** | `0x2` | OEM 生产 | JTAG 密钥已设置,需密码才能连接 |
| **CUSTOMER_DELIVERY** | `0x3` | 客户交付 | 安全级别进一步提升 |
| **JDP_PRODUCTION** | `0x6` | JDP 生产 | 芯片出厂初始状态 |
| **IN_FIELD** | `0x7` | 现场运行 | 最终部署状态,JTAG 可被永久禁用 |

代码中对应的枚举定义:
typedef enum
{
MCU_LIFE_CYCLE_FAILURE_ANALYSIS = 0x0u,
MCU_LIFE_CYCLE_OEM_PRODUCTION = 0x2u,
MCU_LIFE_CYCLE_CUSTOMER_DELIVERY = 0x3u,
MCU_LIFE_CYCLE_JDP_PRODUCTION = 0x6u,
MCU_LIFE_CYCLE_IN_FIELD = 0x7u
} MCU_LifeCycle_t;

生命周期推进规则 :生命周期只能向前推进,不可回退。一旦设定为 OEM_PRODUCTION,就无法回到 JDP_PRODUCTION。

6. JTAG 密钥设置完整流程

JTAG 密钥设置的完整流程如下:
┌─────────────────────────────────────────────────────────────┐
│ JTAG 密钥设置流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ① 设备认证(Device Authentication) │
│ └─ App_OpenDevAuth_New() 打开 HSM 设备认证 │
│ ↓ │
│ ② 检查 JTAG 密钥是否已存在 │
│ └─ HSM_LLD_GetKeyInfo() 查询密钥状态 │
│ ↓ │
│ ③ 生成 JTAG 密钥(32 字节) │
│ └─ HSM_LLD_GenerateJtagPasswd() 使用分散因子衍生密钥 │
│ ↓ │
│ ④ 获取生成的 JTAG 密钥 │
│ └─ HSM_LLD_GetJtagPasswd() 读取密钥用于验证 │
│ ↓ │
│ ⑤ 解锁 UTEST Flash │
│ └─ UTest_PassUnlockFlash() 解锁 UTEST 区 │
│ ↓ │
│ ⑥ 写入 JTAG 密钥到 UTEST │
│ └─ UTest_SetJtagPasswd() 写入 0x00400120~0x0040013F │
│ ↓ │
│ ⑦ 设置生命周期为 OEM_PRODUCTION │
│ └─ UTest_SetLifeCycle(MCU_LIFE_CYCLE_OEM_PRODUCTION) │
│ ↓ │
│ ⑧ 重新上电,JTAG 密钥生效 │
│ │
└─────────────────────────────────────────────────────────────┘

6.1 完整代码实现

以下代码来自 MCAL 测试工程 test_crypto_Jtag.c,展示了 HSM 模式下 JTAG 密钥设置的完整流程:

复制代码
AppStatus_t App_SetJtagPasswd(void)
{
    Std_ReturnType retVal;
    AppStatus_t AppStatus = APP_STATUS_SUCCESS;
    status_t status;
    hsmKeyInfo_t keyInfo;

    uint8_t passwd[32] = {0x0u};
    uint8_t derive[32] = {0x0u};
    uint8_t readPasswd[32] = {0x0u};
    uint16_t readPasswdLen;

    if (TRUE == HSM_ENABLED) {
        /* ===== 步骤 1:设备认证 ===== */
        retVal = (Std_ReturnType)App_OpenDevAuth_New(
            App_DevAuthKey,
            sizeof(App_DevAuthKey),
            HSM_DEV_AUTH_ALL
        );
        if (E_OK != retVal) {
            PSPRINTF("ERROR: Func_OpenDevAuth!\r\n");
            return APP_STATUS_RESULTVERIFYFAIL;
        }
        PSPRINTF("Func_OpenDevAuth SUCCESS!\r\n");

        /* ===== 步骤 2:检查 JTAG 密钥是否已设置 ===== */
        status = HSM_LLD_GetKeyInfo(App_hJtagKey, &keyInfo);
        if (STATUS_HSM_KEY_EMPTY != status) {
            PSPRINTF("Jtag passwd has already set!\r\n");
            return APP_STATUS_JTAG_KEY_EXIST;
        }

        /* ===== 步骤 3:生成 JTAG 密钥 ===== */
        cc_memset(derive, 0x5A, sizeof(derive));  // 分散因子
        status = HSM_LLD_GenerateJtagPasswd(
            App_hJtagKey,   // 密钥句柄
            derive,         // 分散因子
            32,             // 分散因子长度
            passwd          // 输出:32字节密钥
        );
        if (STATUS_SUCCESS != status) {
            PSPRINTF("HSM_LLD_GenerateJtagPasswd fail!\r\n");
            return APP_STATUS_JTAG_KEY_GENERATE_FAIL;
        }
        PSPRINTF("HSM_LLD_GenerateJtagPasswd success!\r\n");

        /* ===== 步骤 4:获取并验证 JTAG 密钥 ===== */
        status = HSM_LLD_GetJtagPasswd(
            App_hJtagKey,
            readPasswd,
            &readPasswdLen
        );
        if (STATUS_SUCCESS != status) {
            PSPRINTF("HSM_LLD_GetJtagPasswd fail!\r\n");
            return APP_STATUS_JTAG_KEY_GET_FAIL;
        }
        if (0u != cc_memcmp(readPasswd, passwd, 32u)) {
            PSPRINTF("jtag passwd compare fail!\r\n");
            return APP_STATUS_JTAG_KEY_ERROR;
        }
    } else {
        /* 非 HSM 模式:使用用户自定义密钥 */
        cc_memcpy(passwd, App_JtagPassWd, 32);
    }

    /* ===== 步骤 5:解锁 UTEST Flash ===== */
    status = UTest_PassUnlockFlash();
    if (STATUS_SUCCESS != status) {
        PSPRINTF("UTest_PassUnlockFlash fail!\r\n");
        return APP_STATUS_JTAG_UNLOCK_FLASH_FAIL;
    }
    PSPRINTF("UTest_PassUnlockFlash success!\r\n");

    /* ===== 步骤 6:写入 JTAG 密钥到 UTEST ===== */
    status = UTest_SetJtagPasswd(passwd);
    if (STATUS_SUCCESS != status) {
        PSPRINTF("UTest_SetJtagPasswd fail!\r\n");
        return APP_STATUS_JTAG_KEY_SET_FAIL;
    }
    PSPRINTF("UTest_SetJtagPasswd success!\r\n");

    /* ===== 步骤 7:设置生命周期为 OEM_PRODUCTION ===== */
    status = UTest_SetLifeCycle(MCU_LIFE_CYCLE_OEM_PRODUCTION);
    if (STATUS_SUCCESS != status) {
        PSPRINTF("UTest_SetLifeCycle fail!\r\n");
        return APP_STATUS_JTAG_SET_LIFE_CYCLE_FAIL;
    }
    PSPRINTF("UTest_SetLifeCycle success!\r\n");

    return AppStatus;
}

7. 软件函数调用流程

7.1 核心 API 接口

以下为 JTAG 密钥管理相关的核心 API:

|----------------------------------|-------------|--------------------------------|
| 函数 | 所属模块 | 功能 |
| `App_OpenDevAuth_New()` | Application | 打开 HSM 设备认证,获取 HSM 操作权限 |
| `HSM_LLD_GetKeyInfo()` | Crypto LLD | 查询指定密钥句柄的状态(空/已存在) |
| `HSM_LLD_GenerateJtagPasswd()` | Crypto LLD | 使用分散因子生成 32 字节 JTAG 密钥 |
| `HSM_LLD_GetJtagPasswd()` | Crypto LLD | 从 HSM 密钥区读取 JTAG 密钥 |
| `UTest_PassUnlockFlash()` | JTAG LLD(库) | 解锁 UTEST Flash 区域 |
| `UTest_SetJtagPasswd()` | JTAG LLD(库) | 将密钥写入 UTEST 的 JTAG Password 区域 |
| `UTest_SetLifeCycle()` | JTAG LLD(库) | 设置芯片生命周期状态 |
| `UTest_DisableJtag()` | JTAG LLD(库) | 永久禁用 JTAG 接口 |

7.2 JTAG LLD 库接口

jtag_lld.h 中声明的库函数接口:

复制代码
// 设置 JTAG 密码(写入 UTEST)
FUNC(status_t, CRYPTO_CODE) UTest_SetJtagPasswd(
    P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_DATA) passwd
);

// 解锁 UTEST Flash
FUNC(status_t, CRYPTO_CODE) UTest_PassUnlockFlash(void);

// 设置生命周期
FUNC(status_t, CRYPTO_CODE) UTest_SetLifeCycle(
    VAR(MCU_LifeCycle_t, AUTOMATIC) lifeCycle
);

// 永久禁用 JTAG
FUNC(status_t, CRYPTO_CODE) UTest_DisableJtag(void);

// 获取库版本
const char *UTest_Get_LibJTAG_Version();

7.3 HSM 密钥生成接口

Crypto_LLDriver.h 中定义的 JTAG 密钥生成接口:
// HSM 密钥标志:解锁 JTAG
#define HSM_KEY_FLAG_USAGE_UNLOCK_JTAG (hsmKeyFlags_t)(1U << 10)

// 密钥生成方案:JTAG Password
#define HSM_KEY_GEN_JTAG_PASSWD ((hsmKeyGenScheme_t)5U)

复制代码
// JTAG Password 生成方案结构体
typedef struct {
    uint32_t    derivativeLen;   // 分散因子长度
    HOST_ADDR   pDerivative;     // 分散因子指针
    HOST_ADDR   pPasswd;         // 输出:32 字节密钥
} hsmKeyGenJtagPasswdScheme_t;

// 生成 JTAG 密钥
FUNC(status_t, CRYPTO_CODE) HSM_LLD_GenerateJtagPasswd(
    VAR(hsmKeyHandle_t, AUTOMATIC) keyHandle,
    P2CONST(uint8, AUTOMATIC, CRYPTO_APPL_DATA) pDerivative,
    VAR(uint32, AUTOMATIC) derivativeLen,
    P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) pJtagPasswd
);

// 获取 JTAG 密钥
FUNC(status_t, CRYPTO_CODE) HSM_LLD_GetJtagPasswd(
    VAR(hsmKeyHandle_t, AUTOMATIC) keyHandle,
    P2VAR(uint8, AUTOMATIC, CRYPTO_APPL_DATA) pJtagPasswd,
    P2VAR(uint16, AUTOMATIC, CRYPTO_APPL_DATA) pJtagPasswdLen
);

7.4 调用时序图

复制代码
应用程序(Z4 核)                    HSM 子系统                  UTEST Flash
     │                                  │                          │
     │  App_OpenDevAuth_New()           │                          │
     │─────────────────────────────────>│                          │
     │<─────────────────────────────────│                          │
     │   设备认证通过                    │                          │
     │                                  │                          │
     │  HSM_LLD_GetKeyInfo()            │                          │
     │─────────────────────────────────>│                          │
     │<─────────────────────────────────│                          │
     │   密钥槽为空,可以生成            │                          │
     │                                  │                          │
     │  HSM_LLD_GenerateJtagPasswd()    │                          │
     │─────────────────────────────────>│                          │
     │                                  │ 使用分散因子衍生密钥      │
     │                                  │ 存储到 HSM 密钥区        │
     │<─────────────────────────────────│                          │
     │   返回 32 字节密钥               │                          │
     │                                  │                          │
     │  HSM_LLD_GetJtagPasswd()         │                          │
     │─────────────────────────────────>│                          │
     │<─────────────────────────────────│                          │
     │   读取密钥并验证一致性            │                          │
     │                                  │                          │
     │  UTest_PassUnlockFlash()         │                          │
     │─────────────────────────────────────────────────────────────>│
     │<─────────────────────────────────────────────────────────────│
     │   UTEST 解锁成功                                            │
     │                                  │                          │
     │  UTest_SetJtagPasswd(passwd)     │                          │
     │─────────────────────────────────────────────────────────────>│
     │<─────────────────────────────────────────────────────────────│
     │   密钥写入 0x00400120~0x0040013F                             │
     │                                  │                          │
     │  UTest_SetLifeCycle(OEM_PROD)    │                          │
     │─────────────────────────────────────────────────────────────>│
     │<─────────────────────────────────────────────────────────────│
     │   生命周期设置为 OEM_PRODUCTION                             │
     │                                  │                          │
     │  重新上电,JTAG 密钥生效          │                          │

7.5 建议调用位置

JTAG 密钥设置是一个一次性操作,在生产线上或设备初次部署时执行。以下基于 MCAL 工程代码结构给出建议的调用位置。

7.5.1 核心启动流程回顾

MCAL 工程中 main.c 的启动流程如下(以 Core0 为例):
main()
└─ Core0Main()
├─ Jtag_Swap() // 仅 CCFC3012PT JTAG 映射交换
├─ cmpu_init() // MPU 初始化
├─ Intc_Init() // 中断控制器初始化
├─ 等待 HSM 就绪 // HSM 握手
├─ Mcu_Init() // MCU 时钟初始化
├─ Port_Init() // 端口初始化
├─ Console_Init() // 调试串口初始化
├─ shell_init() // Shell 命令行初始化
├─ initLINFlexD_2() // HSM 模式 与 HSM 通信的 UART 初始化
└─ test_startup_core0() // 测试用例入口
└─ tester_crypto.c → App_SetJtagPasswd() // JTAG 密钥设置

7.5.2 推荐调用策略

|---------------------|----------------------------------|--------------------------|------------------------------------|
| 场景 | 调用位置 | 调用方式 | 说明 |
| **开发调试阶段** | 不调用 | --- | 保持 JTAG 开放,生命周期 `JDP_PRODUCTION` |
| **产线量产**(一次性设置) | `test_startup_core0()` 或独立量产脚本 | 通过 Shell 命令触发,或编译为独立量产固件 | 调用 `App_SetJtagPasswd()` 后立即重新上电 |
| **产线量产**(永久禁用) | `test_startup_core0()` 或独立量产脚本 | 调用 `App_DisableJtag()` | 建议在设置密钥之后、出货前执行 |
| **应用固件正常启动** | 不调用 | --- | 应用固件中不应包含 JTAG 密钥设置代码 |

7.5.3 典型集成示例

方式一:Shell 命令触发(推荐)

在 MCAL 工程中,可通过 Shell 命令系统注册 JTAG 操作命令,方便产线人员通过串口终端执行:
// 在 shell 命令注册表中添加 JTAG 相关命令
// 参考 tester_crypto.c 中调用方式,在 shell 命令回调中执行:

复制代码
ShellCommand jtagCmds[] = {
    {
        .name = "jtag_set_passwd",
        .handler = cmd_jtag_set_passwd,
        .help = "Set JTAG password and advance Life Cycle to OEM_PRODUCTION"
    },
    {
        .name = "jtag_disable",
        .handler = cmd_jtag_disable,
        .help = "Permanently disable JTAG and set Life Cycle to IN_FIELD"
    },
};

// 命令回调实现
static int cmd_jtag_set_passwd(int argc, char *argv[])
{
    AppStatus_t status = App_SetJtagPasswd();
    if (status == APP_STATUS_SUCCESS) {
        printf("JTAG password set successfully. Please power-cycle the device.\r\n");
    } else {
        printf("JTAG password set failed. Error code: 0x%02X\r\n", status);
    }
    return 0;
}

static int cmd_jtag_disable(int argc, char *argv[])
{
    printf("WARNING: This will permanently disable JTAG. Continue? (y/n): ");
    // ... 确认逻辑 ...
    AppStatus_t status = App_DisableJtag();
    if (status == APP_STATUS_SUCCESS) {
        printf("JTAG permanently disabled.\r\n");
    }
    return 0;
}

方式二:测试代码中直接调用

在 test_startup_core0() 中直接调用(仅用于量产固件,不用于日常开发):

复制代码
void test_startup_core0(void)
{
    AppStatus_t status;

    /* ===== 量产步骤:设置 JTAG 密钥 ===== */
    status = App_SetJtagPasswd();
    if (status == APP_STATUS_SUCCESS) {
        PSPRINTF("JTAG password set OK. Please power-cycle.\r\n");
    } else {
        PSPRINTF("JTAG password set FAIL. Error: 0x%02X\r\n", status);
        /* 根据错误码处理:密钥已存在则跳过,其他错误则停机等待 */
        if (status == APP_STATUS_JTAG_KEY_EXIST) {
            PSPRINTF("JTAG key already exists, skipping.\r\n");
        } else {
            for (;;) { /* 停机等待人工处理 */ }
        }
    }

    /* 注意:设置完成后必须重新上电才生效 */
}

7.5.4 关键注意事项

  1. 只在 Core0 上调用 :App_SetJtagPasswd() 和 App_DisableJtag() 必须在 MCU_INIT_CORE_ID(即 Core0)上执行,因为 HSM 设备认证和 UTEST Flash 操作需要主核权限。

  2. HSM 就绪后才能调用 :代码中 Core0Main() 已经包含等待 HSM 就绪的逻辑(while(HSM.HSM_STATUS!=0)),因此在此之后调用是安全的。

  3. 不要在应用固件中保留:JTAG 密钥设置代码仅存在于量产固件中,应用固件中不应包含 ------ 避免误操作导致密钥被重复设置(虽然代码有防重复机制,但保留这些代码增加了安全风险)。

  4. 量产固件与应用固件分离:建议采用两套固件:

  • 量产固件:包含 JTAG 密钥设置 + 应用功能,在产线烧录执行后,密钥生效

  • 应用固件:仅包含应用功能,不含 JTAG 密钥设置代码

  1. 设置后必须重新上电 :App_SetJtagPasswd() 执行成功后,UTEST 中已写入密钥、生命周期已推进,但需重新上电后 SSCM 才会读取新的生命周期状态并启用 JTAG 密钥保护。

8. JTAG 调试连接流程

8.1 密钥未设置时

芯片出厂或生命周期为 JDP_PRODUCTION 时,JTAG 接口完全开放,调试器可直接连接,无需任何认证。

8.2 密钥已设置后

当生命周期为 OEM_PRODUCTION 或之后阶段时:

  1. 调试器连接时:芯片检测到 JTAG 请求,发现密钥已设置,拒绝直接连接

  2. 调试器提示输入密钥:用户在调试器界面输入 32 字节 JTAG 密钥

  3. HSM 认证:芯片将输入的密钥提交给 HSM 进行认证

  4. 认证通过:HSM 认证通过后,开放 JTAG 调试权限

  5. 正常调试:此时可以正常进行代码下载、调试等操作
    Reference Manual 原文:

"In the case of a secured device, it is possible to submit the debug password to access device and/or HSM debug through the JTAG module. The HSM responds by performing certification of the provided password and eventually may enable debug access to the different cores."

8.3 上电启动时的 JTAG 检测

根据 Reference Manual,芯片上电启动流程中(SSCM 接管后),第一步就是检查是否有 JTAG 请求(state A):
"The SSCM now controls the boot-up sequence and begins by determining if a JTAG request is pending."

9. JTAG 永久禁用流程

在产品最终部署阶段,可以将 JTAG 接口永久禁用,防止任何调试访问。代码实现如下:

复制代码
AppStatus_t App_DisableJtag(void)
{
    AppStatus_t AppStatus = APP_STATUS_SUCCESS;
    status_t status;

    /* 步骤 1:解锁 UTEST Flash */
    status = UTest_PassUnlockFlash();
    if (STATUS_SUCCESS != status) {
        PSPRINTF("UTest_PassUnlockFlash fail!\r\n");
        return APP_STATUS_PROCJOBFAIL;
    }
    PSPRINTF("UTest_PassUnlockFlash success!\r\n");

    /* 步骤 2:永久禁用 JTAG */
    status = UTest_DisableJtag();
    if (STATUS_SUCCESS != status) {
        PSPRINTF("UTest_DisableJtag fail!\r\n");
        return APP_STATUS_PROCJOBFAIL;
    }
    PSPRINTF("UTest_DisableJtag success!\r\n");

    /* 步骤 3:设置生命周期为 IN_FIELD */
    status = UTest_SetLifeCycle(MCU_LIFE_CYCLE_IN_FIELD);
    if (STATUS_SUCCESS != status) {
        PSPRINTF("UTest_SetLifeCycle fail!\r\n");
        return APP_STATUS_PROCJOBFAIL;
    }
    PSPRINTF("UTest_SetLifeCycle success!\r\n");

    return AppStatus;
}

警告:JTAG 永久禁用后不可逆,芯片将无法再通过 JTAG 进行调试或代码下载。

10. JTAGM 模块寄存器

CCFC3008PCSN 的 JTAG Master(JTAGM)模块负责 JTAG 通信控制,主要寄存器如下:

|---------------|--------|--------------------------------|
| 寄存器 | 偏移 | 描述 |
| **MCR** | 0x00 | 模块配置寄存器(TCK 选择、中断使能、JCOMP 等) |
| **SR** | 0x04 | 状态寄存器(JTAGEN、JTAGSAFE、CRC 校验等) |
| **DOR0** | 0x08 | 数据输出寄存器 0(TMS 高 32 位) |
| **DOR1** | 0x0C | 数据输出寄存器 1(TMS 低 28 位) |
| **DOR2** | 0x10 | 数据输出寄存器 2(TDI 高 32 位) |
| **DOR3** | 0x14 | 数据输出寄存器 3(TDI 低 28 位 + Send 位) |
| **RxCRC** | 0x18 | 接收 CRC 寄存器 |
| **DIR0** | 0x1C | 数据输入寄存器 0(TDO 低 32 位) |
| **DIR1** | 0x20 | 数据输入寄存器 1(TDO 高 28 位) |

关键状态位:
// SR 寄存器关键位
JTAGM_SR_tag.B.JTAGEN // JTAG 使能状态
JTAGM_SR_tag.B.JTAGSAFE // JTAG 安全状态
JTAGM_SR_tag.B.TOOL // 调试工具连接状态
JTAGM_SR_tag.B.Idle // 模块空闲状态

11. 注意事项

11.1 密钥只可设置一次

JTAG 密钥只可以设置一次,不支持重复生成 JTAG 密钥。

代码中通过 HSM_LLD_GetKeyInfo() 检查密钥槽是否为空来防止重复设置。如果密钥槽不为空(STATUS_HSM_KEY_EMPTY != status),则返回 APP_STATUS_JTAG_KEY_EXIST 错误。

11.2 密钥不可恢复

设置密钥后,如果擦除 HSM 密钥区,将无法通过 HSM 接口获取到 JTAG 密钥。

因此,在使用 HSM 内部管理方式时,务必在密钥生成后立即通过 HSM_LLD_GetJtagPasswd() 读取并妥善保管密钥副本。

11.3 生命周期不可逆

生命周期只能向前推进,不能回退。一旦进入 OEM_PRODUCTION 或更后阶段,JTAG 密码区域变为不可读。

11.4 调试器兼容性

设置 JTAG 密钥后,需要使用支持 JTAG 密码认证的调试器(如 GreenHills MULTI、HighTec、S32DS 等)。不同调试器的密钥输入界面和流程可能有所不同。

11.5 量产建议

  • 开发阶段:保持生命周期为 JDP_PRODUCTION,JTAG 完全开放
  • 测试阶段:设置 JTAG 密钥,生命周期推进到 OEM_PRODUCTION
  • 量产阶段:
  • 如需保留调试能力:保持 OEM_PRODUCTION 并妥善保管密钥
  • 如需完全禁用调试:调用 App_DisableJtag() 并设置生命周期为 IN_FIELD

11.6 错误码参考

|------------------------------------------------|--------------------|
| 错误码 | 含义 |
| `APP_STATUS_JTAG_KEY_EXIST (0x20)` | JTAG 密钥已存在,不可重复设置 |
| `APP_STATUS_JTAG_KEY_GENERATE_FAIL (0x21)` | JTAG 密钥生成失败 |
| `APP_STATUS_JTAG_KEY_GET_FAIL (0x22)` | JTAG 密钥获取失败 |
| `APP_STATUS_JTAG_KEY_ERROR (0x23)` | JTAG 密钥校验错误 |
| `APP_STATUS_JTAG_UNLOCK_FLASH_FAIL (0x24)` | UTEST Flash 解锁失败 |
| `APP_STATUS_JTAG_KEY_SET_FAIL (0x25)` | JTAG 密钥写入 UTEST 失败 |
| `APP_STATUS_JTAG_SET_LIFE_CYCLE_FAIL (0x26)` | 生命周期设置失败 |

12. 与 NXP/Infineon 芯片的对比

CCFC3008PCSN 在 JTAG 安全机制上与 NXP 和 Infineon 同类芯片有许多相似之处,也有其独特特点:

12.1 对比总览

|---------------------|------------------------------|------------------------------|-------------------------------|
| 特性 | CCFC3008PCSN | NXP S32K3xx | Infineon AURIX TC3xx |
| **安全核心** | HSM(C2002 内核) | HSE(Cortex-M0+) | HSM(Tricore 内核) |
| **JTAG 认证方式** | 32 字节密码 | 128 位密码 + Challenge-Response | 128 位密码 + Challenge-Response |
| **密钥管理** | 用户管理 / HSM 内部管理 | HSE 密钥槽管理 | HSM 密钥槽管理 |
| **生命周期** | 5 级(JDP→CUST→OEM→FIELD→FA) | 7 级(CUST→OEM→IN FIELD→FA 等) | 5 级(CUST→OEM→IN FIELD→FA 等) |
| **密码存储** | UTEST Flash(0x00400120) | UTEST Flash | UCB(User Configuration Block) |
| **Secure Boot** | 支持(RSA 2048/4096 + AES-CMAC) | 支持(RSA + ECC) | 支持(RSA + ECC + SM2) |
| **一机一密** | 支持(分散因子衍生) | 支持 | 支持 |
| **JTAG 永久禁用** | 支持 | 支持 | 支持 |
| **国密算法** | 支持(SM2/SM3/SM4) | 不支持 | 部分支持 |

12.2 与 NXP 的主要差异

  1. 认证机制 :NXP S32K3xx 除了支持密码认证,还支持 Challenge-Response 协议(调试器发送随机挑战码,芯片返回响应),CCFC3008PCSN 当前主要使用密码认证方式。

  2. 生命周期:NXP 的生命周期状态更细化(7 级),包括 CUST_DEL、OEM_PROD、IN_FIELD、FA 等,但核心逻辑与 CCFC3008PCSN 类似。

  3. HSE vs HSM:NXP 使用 HSE(Hardware Security Engine)作为安全子系统,而 CCFC3008PCSN 使用 HSM。两者功能类似,但固件架构和 API 不同。

  4. 密码存储:两者都使用 UTEST Flash 存储密码,但 NXP 的实现中密码区域在生命周期推进后也变为不可读。

12.3 与 Infineon 的主要差异

  1. UCB 机制:Infineon AURIX TC3xx 使用 UCB(User Configuration Block)存储安全配置和密码,而 CCFC3008PCSN 使用 UTEST Flash + DCF 记录。

  2. Challenge-Response:Infineon 支持更完善的 Challenge-Response 认证协议,主要用于调试和固件更新场景。

  3. HSM 内核:Infineon 的 HSM 基于 Tricore 架构,与主 CPU 同构;CCFC3008PCSN 的 HSM 基于 C2002 内核,与主 CPU(Z4/Z7)异构。

  4. 国密支持:CCFC3008PCSN 原生支持 SM2/SM3/SM4 国密算法,这是对国产化需求的重要适配,Infineon 和 NXP 芯片在这方面的支持较弱。

12.4 CCFC3008PCSN 的独特优势

  1. 原生国密算法支持:SM2/SM3/SM4 全覆盖,符合国产化密码合规要求

  2. 双密钥管理方式:既支持用户自行管理密钥,也支持 HSM 内部衍生管理,灵活性更高

  3. 32 字节密码长度:相比 NXP 和 Infineon 的 128 位(16 字节),密码空间更大,安全性更高

  4. 完整的代码示例:MCAL 包中提供了完整的 JTAG 密钥设置、禁用等示例代码,降低开发门槛

13. 总结

CCFC3008PCSN 的 JTAG 安全机制是一套成熟、完善的调试安全方案,核心流程总结如下:

  1. 密钥生成 :通过 HSM 的 HSM_LLD_GenerateJtagPasswd() 接口,使用分散因子衍生 32 字节密钥

  2. 密钥存储 :解锁 UTEST Flash 后,调用 UTest_SetJtagPasswd() 将密钥写入 0x00400120~0x0040013F

  3. 生命周期管理 :调用 UTest_SetLifeCycle() 将芯片推进到 OEM_PRODUCTION 或更后阶段

  4. 调试认证:重新上电后,调试器连接时需要输入正确的 32 字节密钥,HSM 认证通过后开放调试权限

  5. 永久禁用 :量产部署后,可调用 UTest_DisableJtag() 永久关闭 JTAG 接口

该方案结合了硬件安全模块(HSM)、密码保护模块(PASS)和生命周期管理,提供了从开发到量产全生命周期的安全保护。与 NXP 和 Infineon 同类产品相比,CCFC3008PCSN 在国密算法支持、密码长度和密钥管理灵活性方面具有独特优势,是国产车规 MCU 在安全领域的重要实践。
版权声明:本文基于 CCFC3008PCS Reference Manual Rev 1.3.0 和 CCFC30XX_MCAL_V3.0.8_P3 代码包编写,仅供学习交流使用。

免责声明:文中涉及的代码示例来自官方 MCAL 测试工程,实际使用时请根据具体项目需求进行调整。

相关推荐
咖啡八杯1 个月前
GoF设计模式——访问者模式
设计模式·访问者模式
risc1234561 个月前
通过树来理解访问者模式 访问者模式的灵魂在于数据结构的遍历 访问者访问的是数据结构的某一个元素他要觉得要不要访问这个元素或者访问哪些元素
lucene·访问者模式
我登哥MVP1 个月前
走进 Gang of Four 设计模式:访问者模式
java·设计模式·访问者模式·原型模式
java_cj2 个月前
从kubectl学Visitor模式:如何优雅处理多态数据结构的遍历
云原生·golang·k8s·访问者模式
qq_297574672 个月前
设计模式系列文章(基础篇第22篇):访问者模式——分离数据结构与操作,实现灵活扩展
数据结构·设计模式·访问者模式
2601_961194023 个月前
考研模拟卷谁的比较好|27李林合工大肖四肖八数学英语408PDF
考研·elasticsearch·全文检索·代理模式·lucene·桥接模式·访问者模式
雪度娃娃3 个月前
行为型设计模式——访问者模式
设计模式·访问者模式
多加点辣也没关系3 个月前
设计模式-访问者模式
设计模式·访问者模式
承渊政道3 个月前
极空间NAS部署Photopea:私有在线修图工作站,手机平板随时编辑
安全·docker·容器·ip·访问者模式·photoshop·持续部署