Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

6.6 AUTOSAR集成实战:UDS服务的实现

一个场景:客户要求你的产品支持UDS诊断协议,特别是安全访问服务(Service 0x27)。按照汽车行业标准,诊断仪需要先通过种子-密钥挑战才能解锁安全等级,然后才能执行敏感操作。密钥计算需要用到HSM中存储的秘密数据。

一个问题浮出水面:AUTOSAR的UDS服务是异步回调模式,而HSM的API调用也需要时间。如何将它们结合起来?状态机设计需要注意什么?

一个隐喻:这像接力赛跑——UDS模块接到诊断仪的请求,把接力棒(seed请求)传给HSM模块,HSM跑完一圈(获取随机数、计算密钥),再把接力棒传回UDS,最终交给诊断仪。每个环节都不能掉棒。

UDS安全访问服务概述

什么是UDS Service 0x27?

UDS(Unified Diagnostic Services)是汽车诊断标准协议。Service 0x27(SecurityAccess)用于实现诊断仪对ECU的安全访问。

UDS 27服务流程

诊断仪                        ECU
   │                           │
   │──── 27 01(请求种子)────│
   │                           │
   │←─── 67 01 + seed ────────│
   │                           │
   │  计算key                  │
   │                           │
   │──── 27 02 + key ─────────│
   │                           │
   │←─── 67 02(验证成功)───│
   │        或                 │
    │←─── 7F 27 35(验证失败,密钥无效)──│

服务流程:

  1. 诊断仪发送27 01(子功能0x01),请求种子(seed)
  2. ECU生成随机数作为种子,返回67 01 + seed
  3. 诊断仪用预定义算法计算key
  4. 诊断仪发送27 02 + key,提交密钥
  5. ECU验证key,返回成功或失败响应

安全等级

不同的安全等级对应不同的操作权限:

安全等级子功能权限
Level 10x01/0x02扩展诊断模式
Level 20x11/0x12编程模式
Level 30x21/0x22工厂配置

每个等级使用不同的种子-密钥算法和秘密数据。

HSM在UDS 27中的角色

HSM在UDS 27服务中承担两个关键任务:

  1. 提供安全的随机数(种子):调用hsm_get_random生成不可预测的seed
  2. 存储密钥计算的秘密数据(mask):HSM中存储的mask用于key计算算法
HSM参与UDS 27流程

诊断仪          ECU/UDS         HSM
   │              │              │
   │─ 27 01 ──────│              │
   │              │─ hsm_get_random ─│
   │              │              │
   │              │←─ 随机数 ────│
   │              │              │
   │←─ 67 01 + seed ─│            │
   │              │              │
   │  计算key     │              │
   │              │              │
   │─ 27 02 + key ─│              │
   │              │─ hsm_read_file ─│
   │              │              │←─ mask
   │              │              │
   │              │  计算key      │
   │              │  比对验证     │
   │              │              │
   │←─ 67 02 或 7F 27 ─│          │

AUTOSAR异步回调模式

AUTOSAR DCM的回调机制

AUTOSAR的DCM(Diagnostic Communication Manager)模块采用异步回调模式处理UDS服务。当收到诊断请求时,DCM会调用用户注册的回调函数,回调函数返回DCM_E_PENDING表示处理未完成,DCM会持续调用直到返回最终结果。

// DCM回调函数原型
Std_ReturnType SecurityAccess_Callback(
    uint8_t* Key, 
    uint8_t* seed, 
    Dcm_NegativeResponseCodeType* ErrorCode
);

返回值:

返回值含义
E_OK / RTE_E_OK处理成功
E_NOT_OK处理失败,返回否定响应
DCM_E_PENDING处理进行中,DCM会再次调用

为什么需要异步模式?

HSM操作不是即时完成的:

  1. I2C/SPI通信需要时间
  2. HSM内部处理需要时间
  3. 多步骤操作(PIN验证→选择文件→读取)需要多次调用

同步模式会阻塞整个系统,而异步模式允许其他任务继续运行。

状态机设计

状态机结构

将UDS 27的HSM操作设计为状态机:

状态机流程

STEP_INITIAL(初始状态)
    ↓ hsm_verify_pin
STEP_PIN_VERIFIED(PIN已验证)
    ↓ hsm_select_device_file
STEP_FILE_SELECTED(文件已选择)
    ↓ hsm_read_file
STEP_KEY_PROCESSED(密钥已处理)
    ↓ 计算key、比对验证
返回结果

状态机代码实现

typedef enum {
    STEP_INITIAL,
    STEP_PIN_VERIFIED,
    STEP_FILE_SELECTED,
    STEP_KEY_PROCESSED
} SecurityAccess_StepType;

Std_ReturnType SecurityAccess_AuthenticationProcess(
    uint8_t* Key,           // 上位机发送的key
    uint8_t* seed,          // 随机数seed
    Dcm_NegativeResponseCodeType* ErrorCode,
    uint32_t hsm_file_id    // HSM文件ID(存储mask)
) {
    static SecurityAccess_StepType step = STEP_INITIAL;
    static uint8_t long_key[16] = {0};  // 从HSM读取的mask
    static uint32_t long_key_len = 0;
    
    se_error_t result;
    
    switch (step) {
        case STEP_INITIAL:
        {
            // 步骤1:验证PIN
            pin_t pin;
            uint8_t admin_pin_key[16] = HSM_PIN_KEY;
            
            memcpy(pin.pin_value, admin_pin_key, 16);
            pin.owner = ADMIN_PIN;
            pin.pin_len = 16;
            
            result = hsm_verify_pin(&pin);
            
            if (result == HSM_OK) {
                step = STEP_PIN_VERIFIED;
                return DCM_E_PENDING;  // 继续处理
            } 
            else if (result == HSM_ERR_PENDING) {
                return DCM_E_PENDING;  // HSM仍在处理
            } 
            else {
                step = STEP_INITIAL;  // 失败,重置状态
                *ErrorCode = DCM_E_REQUESTSEQUENCEERROR;
                return E_NOT_OK;
            }
        }
        break;
        
        case STEP_PIN_VERIFIED:
        {
            // 步骤2:选择文件
            result = hsm_select_device_file(hsm_file_id);
            
            if (result == HSM_OK) {
                step = STEP_FILE_SELECTED;
                return DCM_E_PENDING;
            } 
            else if (result == HSM_ERR_PENDING) {
                return DCM_E_PENDING;
            } 
            else {
                step = STEP_INITIAL;
                *ErrorCode = DCM_E_REQUESTSEQUENCEERROR;
                return E_NOT_OK;
            }
        }
        break;
        
        case STEP_FILE_SELECTED:
        {
            // 步骤3:读取mask
            result = hsm_read_file(0, 16, long_key, &long_key_len);
            
            if (result == HSM_OK) {
                step = STEP_KEY_PROCESSED;
                return DCM_E_PENDING;
            } 
            else if (result == HSM_ERR_PENDING) {
                return DCM_E_PENDING;
            } 
            else {
                step = STEP_INITIAL;
                *ErrorCode = DCM_E_REQUESTSEQUENCEERROR;
                return E_NOT_OK;
            }
        }
        break;
        
        case STEP_KEY_PROCESSED:
        {
            // 步骤4:计算并验证key
            uint8_t key_result[4] = {0};
            seed_to_key(seed, long_key, key_result);  // 客户特定的算法
            
            step = STEP_INITIAL;  // 重置状态
            
            if (compare_arrays(key_result, Key, 4)) {
                *ErrorCode = 0;
                return RTE_E_OK;  // 验证成功
            } 
            else {
                *ErrorCode = DCM_E_INVALIDKEY;
                return E_NOT_OK;  // 验证失败
            }
        }
        break;
        
        default:
            step = STEP_INITIAL;
            *ErrorCode = DCM_E_REQUESTSEQUENCEERROR;
            return E_NOT_OK;
    }
    
    *ErrorCode = DCM_E_REQUESTSEQUENCEERROR;
    return E_NOT_OK;
}

状态机的关键点

  1. 静态变量保存状态static SecurityAccess_StepType step保存当前状态,跨多次调用保持
  2. 静态变量保存数据static uint8_t long_key[16]保存从HSM读取的mask
  3. 返回DCM_E_PENDING:处理未完成时返回pending,DCM会再次调用
  4. 失败时重置状态:任何步骤失败,将状态重置为STEP_INITIAL
  5. 成功时重置状态:最终步骤完成后,重置状态准备下次请求

为什么使用static变量?

AUTOSAR回调函数会被DCM模块反复调用,每次调用都是独立的函数执行。非静态变量会在每次调用时重新初始化,无法保存进度。静态变量在函数多次调用之间保持值,适合状态机场景。

密钥计算函数

seed_to_key函数根据客户需求实现特定的密钥计算算法:

uint8_t* seed_to_key(
    const uint8_t* in_seed,    // 随机数seed
    uint8_t* in_long_key,      // HSM中的mask
    uint8_t* verify_key        // 计算结果
) {
    // 客户定义的算法
    // 例如:将seed和mask按特定规则组合运算
    
    for (int i = 0; i < 4; i++) {
        verify_key[i] = in_seed[i] ^ in_long_key[i];
        verify_key[i] = (verify_key[i] + in_long_key[i+4]) & 0xFF;
    }
    
    return verify_key;
}

不同客户有不同的算法,具体实现需要根据客户需求文档。

集成测试

测试流程

使用诊断仪工具测试UDS 27服务:

测试步骤

1. 切换到扩展模式
   发送:10 03
   响应:50 03

2. 请求种子
   发送:27 01
   响应:67 01 XX XX XX XX(4字节seed)

3. 计算key(本地计算)
   使用seed和预知的mask,按算法计算key

4. 提交key
   发送:27 02 YY YY YY YY(4字节key)
   响应:67 02(成功)或 7F 27(失败)

5. 切换到编程模式
   发送:10 02
   响应:50 02

6. 请求Level 2种子
   发送:27 11
   响应:67 11 XX XX XX XX

7. 提交Level 2 key
   发送:27 12 YY YY YY YY
   响应:67 12(成功)或 7F 27(失败)

逻辑分析仪验证

用逻辑分析仪抓取SPI通信数据,验证HSM交互:

SPI波形分析

27 01请求时的SPI通信:
帧1:获取随机数请求 → 20 00 05 00 84 00 00 08 CRC
帧2:随机数响应 → 20 00 0A [8字节随机数] 90 00 CRC

27 02请求时的SPI通信:
帧1:PIN验证请求 → ...
帧2:选择文件请求 → ...
帧3:读取mask请求 → ...

验证每个步骤的数据是否符合预期。

设计注意事项

状态重置时机

状态必须在以下时机重置:

  1. 处理失败时:重置状态,准备接受新请求
  2. 处理成功时:重置状态,准备接受新请求
  3. 超时时:AUTOSAR可能有超时机制,状态需要重置

不要在处理中途重置状态,会导致数据丢失。

错误码选择

AUTOSAR定义了多种否定响应码:

错误码含义适用场景
0x24requestSequenceError请求序列错误
0x35invalidKey密钥无效
0x26conditionsNotCorrect条件不满足
0x36securityAccessDenied安全访问被拒绝

选择合适的错误码,便于诊断仪理解失败原因。

多安全等级处理

不同安全等级使用不同的HSM文件ID:

// 配置映射
typedef struct {
    uint8_t level;       // 安全等级(0x01, 0x11, 0x21...)
    uint32_t file_id;    // HSM文件ID
} SecurityLevelConfig;

SecurityLevelConfig config[] = {
    {0x01, 0x0006},  // Level 1使用文件6的mask
    {0x11, 0x0007},  // Level 2使用文件7的mask
    {0x21, 0x0008},  // Level 3使用文件8的mask
};

根据请求的子功能选择对应的配置。

小结

AUTOSAR集成像搭建桥梁——一边是异步回调模式的UDS服务,一边是耗时操作的HSM API。状态机设计就是桥梁的结构,保证两边的数据流动顺畅。

关键设计点:

  • 状态机管理多步骤流程
  • 静态变量保存跨调用数据
  • 返回DCM_E_PENDING让DCM持续调用
  • 失败和成功都要重置状态

下一节,我们将介绍TCP命令接口——看开发调试的便捷方案。

【下集预告】

开发阶段怎么快速操作HSM?

TCP命令怎么设计?状态机怎么触发?

上位机怎么写入数据?

下一节,TCP命令接口。