# ECDSA签名算法 ***Copyright © Quectel Wireless Solutions Co., Ltd. 2026. All rights reserved.*** --- ## 功能概述 ECDSA是一种基于椭圆曲线的数字签名算法,用于验证数据来源是否可信、内容是否被篡改。当前系统基于Mbed TLS/PSA Crypto提供ECDSA能力,可支持签名生成、签名合法性校验,以及与ECC密钥、SHA摘要算法配合完成安全认证流程。 在实际使用中,ECDSA通常不作为独立业务功能提供,而是作为TLS、证书校验、设备认证、eSIM认证等安全链路中的底层密码能力使用。 ## 常见应用场景 1. TLS安全连接认证:在HTTPS、MQTT over TLS、WebSocket over TLS等安全通信场景中,ECDSA可用于服务器证书或客户端证书的身份认证。设备在建立TLS连接时,会校验证书链中的ECDSA签名,确认通信对端证书是否可信,从而防止连接到伪造服务器或非法设备。 2. X.509证书链校验:ECDSA可用于验证X.509证书中的签名是否合法。例如CA证书对下级证书的签名、业务证书公钥算法的匹配性检查、证书链完整性验证等环节,都可能涉及ECDSA校验。若证书使用的公钥算法、曲线或签名格式不符合要求,系统会判定为证书校验异常。 3. eSIM远程认证流程:在eSIM相关业务中,ECDSA可用于校验远程服务端或认证实体的证书与签名,例如*CERT.DPAuth.ECDSA*相关认证流程。通过ECDSA校验,可以确认SM-DP+等远程实体的身份可信,保障profile下载、安装、认证过程的安全性。 4. 数据完整性和来源校验:对于固件包、配置文件、授权数据、业务令牌等关键数据,也可以使用ECDSA进行签名校验。设备侧通过公钥验证签名,确认数据未被篡改且来源可信,适用于安全升级、授权校验、关键配置下发等场景。 ## 常见问题 1. 使用ECDSA时,需要确保签名格式、公钥、曲线参数和摘要算法与签名生成端保持一致。常见问题包括签名格式RAW/DER不匹配、公钥或证书算法不支持、曲线参数不符合系统配置、原始数据或摘要被修改等。 2. ECDSA验签依赖正确的证书链和可信根证书配置。 3. 在多线程场景下,不建议多个线程同时复用同一个ECDSA上下文。 4. 实际业务中建议优先使用系统已配置支持的曲线和摘要算法,避免引入未验证的自定义曲线或非标准签名格式。 ## ECDSA签名流程 ECDSA的典型流程分为密钥准备、签名生成、签名验证三个阶段。 ### 密钥准备流程 首先选择一条椭圆曲线,如 *secp256r1*、*secp384r1*。 然后生成一对ECC密钥: - 私钥:由签名方保存,用来生成签名,不得泄露。 - 公钥:分发给验证方,用于校验签名是否合法。 即:私钥负责签名,公钥负责验签。 ### 签名生成流程 签名方获取原始数据后,通常不直接对完整数据签名,而是先计算摘要。 流程如下: 1. 对原始数据计算Hash,如SHA-256、SHA-384。 2. 使用ECC私钥对Hash结果进行ECDSA签名。 3. 输出签名结果,通常包含两个值:r、s。 4. 根据协议要求,将签名编码成RAW或DER格式。 5. 将原始数据或摘要、签名值、证书或公钥一起发送给验证方。 ### 签名验证流程 验证方收到数据和签名后,会使用签名方的公钥进行校验。 流程如下: 1. 获取原始数据、签名值和签名方公钥。 2. 对原始数据使用相同Hash算法计算摘要。 3. 检查签名格式是否合法,包括RAW/DER编码、长度以及r、s值是否有效。 4. 检查公钥和曲线参数是否符合要求。 5. 使用ECDSA验签算法校验签名是否匹配。 6. 验签通过,表明数据未被篡改且来源可信;验签失败,表明数据、签名、公钥或算法参数不匹配。 # ECDSA签名算法API ## 头文件 *psa/crypto.h* ## 函数概览 | **函数** | **说明** | | --- | --- | | `psa_crypto_init()` | 初始化PSA Crypto组件 | | `psa_set_key_type()` | 设置密钥类型及椭圆曲线族 | | `psa_set_key_bits()` | 设置密钥位数 | | `psa_set_key_usage_flags()` | 设置密钥允许的用途 | | `psa_set_key_algorithm()` | 设置密钥允许使用的算法 | | `psa_generate_key()` | 生成ECDSA密钥对 | | `psa_import_key()` | 导入已有私钥或公钥 | | `psa_export_public_key()` | 导出密钥对中的公钥 | | `psa_hash_compute()` | 计算消息哈希 | | `psa_sign_message()` | 对原始消息进行签名 | | `psa_verify_message()` | 验证原始消息签名 | | `psa_sign_hash()` | 对已计算的哈希值签名 | | `psa_verify_hash()` | 验证哈希值签名 | | `psa_destroy_key()` | 销毁密钥 | | `psa_reset_key_attributes()` | 重置密钥属性结构体 | ## 函数详解 ### psa_crypto_init() - **功能描述** 初始化PSA Crypto模块。调用其他PSA Crypto接口前,必须先调用本函数。 - **函数原型** ```c psa_status_t psa_crypto_init(void); ``` - **参数说明** 无 - **返回值说明** *PSA_SUCCESS*:函数执行成功 其他值(详见 [*psa_status_t*](#psastatust)):函数执行失败 ### psa_set_key_type() - **功能描述** 设置密钥属性中的密钥类型。 - **函数原型** ```c void psa_set_key_type(psa_key_attributes_t *attributes, psa_key_type_t type); ``` - **参数说明** | **参数名** | **输入/输出** | **类型** | **说明** | | --- | --- | --- | --- | | *attributes* | 输入/输出 | *psa_key_attributes_t** | 密钥属性对象;详见 [*psa_key_attributes_t*](#psakeyattributes_t) | | *type* | 输入 | *psa_key_type_t* | 密钥类型;ECDSA常用 *PSA_KEY_TYPE_ECC_KEY_PAIR()* 或 *PSA_KEY_TYPE_ECC_PUBLIC_KEY()*;详见 [*psa_key_type_t*](#psakeytype_t) | - **返回值说明** 无 ### psa_set_key_bits() - **功能描述** 设置密钥属性中的密钥位宽。 - **函数原型** ```c void psa_set_key_bits(psa_key_attributes_t *attributes, size_t bits); ``` - **参数说明** | **参数名** | **输入/输出** | **类型** | **说明** | | --- | --- | --- | --- | | *attributes* | 输入/输出 | *psa_key_attributes_t** | 密钥属性对象;详见 [*psa_key_attributes_t*](#psakeyattributes_t) | | *bits* | 输入 | size_t | 密钥位宽;常用取值:256、384、521;单位:位 | - **返回值说明** 无 ### psa_set_key_usage_flags() - **功能描述** 设置密钥允许执行的用途。 - **函数原型** ```c void psa_set_key_usage_flags(psa_key_attributes_t *attributes, psa_key_usage_t usage_flags); ``` - **参数说明** | **参数名** | **输入/输出** | **类型** | **说明** | | --- | --- | --- | --- | | *attributes* | 输入/输出 | *psa_key_attributes_t** | 密钥属性对象;详见 [*psa_key_attributes_t*](#psakeyattributes_t) | | *usage_flags* | 输入 | *psa_key_usage_t* | 密钥用途;常用 *PSA_KEY_USAGE_SIGN_HASH*、*PSA_KEY_USAGE_VERIFY_HASH*;详见 [*psa_key_usage_t*](#psakeyusage_t) | - **返回值说明** 无 ### psa_set_key_algorithm() - **功能描述** 设置密钥允许使用的算法。 - **函数原型** ```c void psa_set_key_algorithm(psa_key_attributes_t *attributes, psa_algorithm_t alg); ``` - **参数说明** | **参数名** | **输入/输出** | **类型** | **说明** | | --- | --- | --- | --- | | *attributes* | 输入/输出 | *psa_key_attributes_t** | 密钥属性对象;详见 [*psa_key_attributes_t*](#psakeyattributes_t) | | *alg* | 输入 | *psa_algorithm_t* | 密钥允许使用的算法;常用 *PSA_ALG_ECDSA(PSA_ALG_SHA_256)*;详见 [*psa_algorithm_t*](#psaalgorithmt) | - **返回值说明** 无 ### psa_generate_key() - **功能描述** 根据密钥属性生成密钥。 - **函数原型** ```c psa_status_t psa_generate_key(const psa_key_attributes_t *attributes, mbedtls_svc_key_id_t *key); ``` - **参数说明** | **参数名** | **输入/输出** | **类型** | **说明** | | --- | --- | --- | --- | | *attributes* | 输入 | *const psa_key_attributes_t** | 密钥属性对象;详见 [*psa_key_attributes_t*](#psakeyattributes_t) | | *key* | 输出 | mbedtls_svc_key_id_t * | 生成后的密钥标识 | - **返回值说明** *PSA_SUCCESS*:函数执行成功 其他值(详见 [*psa_status_t*](#psastatust)):函数执行失败 ### psa_import_key() - **功能描述** 根据密钥属性导入外部密钥。 - **函数原型** ```c psa_status_t psa_import_key(const psa_key_attributes_t *attributes, const uint8_t *data, size_t data_length, mbedtls_svc_key_id_t *key); ``` - **参数说明** | **参数名** | **输入/输出** | **类型** | **说明** | | --- | --- | --- | --- | | *attributes* | 输入 | *const psa_key_attributes_t** | 密钥属性对象;详见 [*psa_key_attributes_t*](#psakeyattributes_t) | | *data* | 输入 | const uint8_t * | 待导入的密钥数据 | | *data_length* | 输入 | size_t | 密钥数据长度;单位:字节 | | *key* | 输出 | mbedtls_svc_key_id_t * | 导入后的密钥标识 | - **返回值说明** *PSA_SUCCESS*:函数执行成功 其他值(详见 [*psa_status_t*](#psastatust)):函数执行失败 ### psa_hash_compute() - **功能描述** 计算输入数据的Hash摘要。 - **函数原型** ```c psa_status_t psa_hash_compute(psa_algorithm_t alg, const uint8_t *input, size_t input_length, uint8_t *hash, size_t hash_size, size_t *hash_length); ``` - **参数说明** | **参数名** | **输入/输出** | **类型** | **说明** | | --- | --- | --- | --- | | *alg* | 输入 | *psa_algorithm_t* | Hash算法;常用 *PSA_ALG_SHA_256*;详见 [*psa_algorithm_t*](#psaalgorithmt) | | *input* | 输入 | const uint8_t * | 待计算摘要的原始数据 | | *input_length* | 输入 | size_t | 原始数据长度;单位:字节 | | *hash* | 输出 | uint8_t * | 摘要输出缓冲区 | | *hash_size* | 输入 | size_t | 摘要输出缓冲区大小;单位:字节 | | *hash_length* | 输出 | size_t * | 实际输出的摘要长度;单位:字节 | - **返回值说明** *PSA_SUCCESS*:函数执行成功 其他值(详见 [*psa_status_t*](#psastatust)):函数执行失败 ### psa_sign_hash() - **功能描述** 对已计算完成的摘要数据生成ECDSA签名。 - **函数原型** ```c psa_status_t psa_sign_hash(mbedtls_svc_key_id_t key, psa_algorithm_t alg, const uint8_t *hash, size_t hash_length, uint8_t *signature, size_t signature_size, size_t *signature_length); ``` - **参数说明** | **参数名** | **输入/输出** | **类型** | **说明** | | --- | --- | --- | --- | | *key* | 输入 | mbedtls_svc_key_id_t | 签名使用的ECC私钥标识 | | *alg* | 输入 | *psa_algorithm_t* | 签名算法;常用 *PSA_ALG_ECDSA(PSA_ALG_SHA_256)*;详见 [*psa_algorithm_t*](#psaalgorithmt) | | *hash* | 输入 | const uint8_t * | 待签名的摘要数据 | | *hash_length* | 输入 | size_t | 摘要数据长度;单位:字节 | | *signature* | 输出 | uint8_t * | 签名结果输出缓冲区 | | *signature_size* | 输入 | size_t | 签名结果缓冲区大小;单位:字节 | | *signature_length* | 输出 | size_t * | 实际生成的签名长度;单位:字节 | - **返回值说明** *PSA_SUCCESS*:函数执行成功 其他值(详见 [*psa_status_t*](#psastatust)):函数执行失败 ### psa_verify_hash() - **功能描述** 校验已计算完成的摘要数据与ECDSA签名是否匹配。 - **函数原型** ```c psa_status_t psa_verify_hash(mbedtls_svc_key_id_t key, psa_algorithm_t alg, const uint8_t *hash, size_t hash_length, const uint8_t *signature, size_t signature_length); ``` - **参数说明** | **参数名** | **输入/输出** | **类型** | **说明** | | --- | --- | --- | --- | | *key* | 输入 | mbedtls_svc_key_id_t | 验签使用的ECC公钥或密钥对标识 | | *alg* | 输入 | *psa_algorithm_t* | 验签算法;常用 *PSA_ALG_ECDSA(PSA_ALG_SHA_256)*;详见 [*psa_algorithm_t*](#psaalgorithmt) | | *hash* | 输入 | const uint8_t * | 待验签的摘要数据 | | *hash_length* | 输入 | size_t | 摘要数据长度;单位:字节 | | *signature* | 输入 | const uint8_t * | 待校验的ECDSA签名数据 | | *signature_length* | 输入 | size_t | 签名数据长度;单位:字节 | - **返回值说明** *PSA_SUCCESS*:函数执行成功 其他值(详见 [*psa_status_t*](#psastatust)):函数执行失败 ### psa_sign_message() - **功能描述** 对原始消息数据生成ECDSA签名。 - **函数原型** ```c psa_status_t psa_sign_message(mbedtls_svc_key_id_t key, psa_algorithm_t alg, const uint8_t *input, size_t input_length, uint8_t *signature, size_t signature_size, size_t *signature_length); ``` - **参数说明** | **参数名** | **输入/输出** | **类型** | **说明** | | --- | --- | --- | --- | | *key* | 输入 | mbedtls_svc_key_id_t | 签名使用的ECC私钥标识 | | *alg* | 输入 | *psa_algorithm_t* | 签名算法;常用 *PSA_ALG_ECDSA(PSA_ALG_SHA_256)*;详见 [*psa_algorithm_t*](#psaalgorithmt) | | *input* | 输入 | const uint8_t * | 待签名的原始消息数据 | | *input_length* | 输入 | size_t | 原始消息数据长度;单位:字节 | | *signature* | 输出 | uint8_t * | 签名结果输出缓冲区 | | *signature_size* | 输入 | size_t | 签名结果缓冲区大小;单位:字节 | | *signature_length* | 输出 | size_t * | 实际生成的签名长度;单位:字节 | - **返回值说明** *PSA_SUCCESS*:函数执行成功 其他值(详见 [*psa_status_t*](#psastatust)):函数执行失败 ### psa_verify_message() - **功能描述** 校验原始消息数据与ECDSA签名是否匹配。 - **函数原型** ```c psa_status_t psa_verify_message(mbedtls_svc_key_id_t key, psa_algorithm_t alg, const uint8_t *input, size_t input_length, const uint8_t *signature, size_t signature_length); ``` - **参数说明** | **参数名** | **输入/输出** | **类型** | **说明** | | --- | --- | --- | --- | | *key* | 输入 | mbedtls_svc_key_id_t | 验签使用的ECC公钥或密钥对标识 | | *alg* | 输入 | *psa_algorithm_t* | 验签算法;常用 *PSA_ALG_ECDSA(PSA_ALG_SHA_256)*;详见 [*psa_algorithm_t*](#psaalgorithmt) | | *input* | 输入 | const uint8_t * | 待验签的原始消息数据 | | *input_length* | 输入 | size_t | 原始消息数据长度;单位:字节 | | *signature* | 输入 | const uint8_t * | 待校验的ECDSA签名数据 | | *signature_length* | 输入 | size_t | 签名数据长度;单位:字节 | - **返回值说明** *PSA_SUCCESS*:函数执行成功 其他值(详见 [*psa_status_t*](#psastatust)):函数执行失败 ### psa_destroy_key() - **功能描述** 销毁指定密钥并释放相关资源。 - **函数原型** ```c psa_status_t psa_destroy_key(mbedtls_svc_key_id_t key); ``` - **参数说明** | **参数名** | **输入/输出** | **类型** | **说明** | | --- | --- | --- | --- | | *key* | 输入 | mbedtls_svc_key_id_t | 需要销毁的密钥标识 | - **返回值说明** *PSA_SUCCESS*:函数执行成功 其他值(详见 [*psa_status_t*](#psastatust)):函数执行失败 ### psa_reset_key_attributes() - **功能描述** 重置密钥属性对象。 - **函数原型** ```c void psa_reset_key_attributes(psa_key_attributes_t *attributes); ``` - **参数说明** | **参数名** | **输入/输出** | **类型** | **说明** | | --- | --- | --- | --- | | *attributes* | 输出 | *psa_key_attributes_t** | 密钥属性对象;详见 [*psa_key_attributes_t*](#psakeyattributes_t) | - **返回值说明** 无 ## 结构体定义 ### psa_key_attributes_t PSA密钥属性结构体定义如下: ```c struct psa_key_attributes_s { psa_key_type_t type; psa_key_bits_t bits; psa_key_lifetime_t lifetime; psa_key_policy_t policy; psa_key_id_t id; }; ``` | **成员** | **类型** | **说明** | | --- | --- | --- | | *type* | *psa_key_type_t* | 密钥类型,例如AES密钥、RSA公钥、RSA密钥对、ECC公钥或ECC密钥对。通过 *psa_set_key_type()* 设置 | | *bits* | *psa_key_bits_t* | 密钥长度,单位为位。例如AES-128填写128、RSA-2048填写2048、P-256填写256。通过 *psa_set_key_bits()* 设置 | | *lifetime* | *psa_key_lifetime_t* | 密钥生命周期及存储位置。用于区分临时密钥、持久化密钥,以及密钥由本地软件还是安全硬件管理。通过 *psa_set_key_lifetime()* 设置 | | *policy* | *psa_key_policy_t* | 密钥使用策略,包括允许的操作和算法,例如允许加密、解密、签名、验签,以及允许使用AES-GCM、RSA-OAEP或ECDSA等算法 | | *id* | *psa_key_id_t* | 持久化密钥标识符。临时密钥通常不需要设置;持久化密钥通过 *psa_set_key_id()* 指定 | ```{note} 该结构体通常不直接访问内部成员,而是通过 *psa_set_key_type()*、*psa_set_key_bits()*、*psa_set_key_usage_flags()*、*psa_set_key_algorithm()* 等接口设置。 ``` ## 枚举定义 ### psa_status_t 操作状态码枚举定义如下: ```c typedef int32_t psa_status_t; ``` | **成员** | **说明** | | --- | --- | | *PSA_SUCCESS* | 函数执行成功 | | *PSA_ERROR_INVALID_HANDLE* | 密钥标识无效 | | *PSA_ERROR_NOT_PERMITTED* | 密钥权限或算法策略不允许执行当前操作 | | *PSA_ERROR_INVALID_SIGNATURE* | 签名校验失败 | | *PSA_ERROR_BUFFER_TOO_SMALL* | 输出缓冲区空间不足 | | *PSA_ERROR_NOT_SUPPORTED* | 当前算法、曲线或密钥类型不支持 | | *PSA_ERROR_INVALID_ARGUMENT* | 输入参数无效 | | *PSA_ERROR_INSUFFICIENT_ENTROPY* | 随机数资源不足 | | *PSA_ERROR_INSUFFICIENT_MEMORY* | 内存不足 | | *PSA_ERROR_BAD_STATE* | PSA Crypto未初始化或当前状态异常 | ### psa_key_type_t 密钥类型枚举定义如下: ```c typedef uint16_t psa_key_type_t; ``` | **成员** | **说明** | | --- | --- | | *PSA_KEY_TYPE_ECC_KEY_PAIR(curve)* | ECC密钥对类型;用于ECDSA签名 | | *PSA_KEY_TYPE_ECC_PUBLIC_KEY(curve)* | ECC公钥类型;用于ECDSA验签 | | *PSA_ECC_FAMILY_SECP_R1* | SECP R1曲线族;作为 *curve* 参数取值;如secp256r1、secp384r1、secp521r1 | | *PSA_ECC_FAMILY_SECP_K1* | SECP K1曲线族;作为 *curve* 参数取值;如secp256k1 | | *PSA_ECC_FAMILY_BRAINPOOL_P_R1* | Brainpool P-R1曲线族;作为 *curve* 参数取值 | ### psa_key_usage_t 密钥用途类型枚举定义如下: ```c typedef uint32_t psa_key_usage_t; ``` | **成员** | **说明** | | --- | --- | | *PSA_KEY_USAGE_SIGN_HASH* | 允许使用密钥对摘要数据进行签名 | | *PSA_KEY_USAGE_VERIFY_HASH* | 允许使用密钥验证摘要数据的签名 | | *PSA_KEY_USAGE_SIGN_MESSAGE* | 允许使用密钥对原始消息进行签名 | | *PSA_KEY_USAGE_VERIFY_MESSAGE* | 允许使用密钥验证原始消息的签名 | | *PSA_KEY_USAGE_EXPORT* | 允许导出密钥 | | *PSA_KEY_USAGE_COPY* | 允许复制密钥 | ### psa_algorithm_t 算法类型枚举定义如下: ```c typedef uint32_t psa_algorithm_t; ``` | **成员** | **说明** | | --- | --- | | *PSA_ALG_ECDSA(hash_alg)* | 随机化ECDSA签名算法 | | *PSA_ALG_DETERMINISTIC_ECDSA(hash_alg)* | 确定性ECDSA签名算法;符合RFC 6979 | | *PSA_ALG_ECDSA_ANY* | 不指定摘要算法的ECDSA算法;通常用于已计算摘要场景 | | *PSA_ALG_SHA_256* | SHA-256摘要算法 | | *PSA_ALG_SHA_384* | SHA-384摘要算法 | | *PSA_ALG_SHA_512* | SHA-512摘要算法 | # 应用逻辑流程图 ```{image} images/image_PmztbM5uxomkYrxVuQRcDXxknWf.webp :width: 1040px :height: 736px :align: center ``` # 示例代码 完整示例代码请查看https://github.com/UniRTOS/UniRTOS-Doc-Examples/blob/main/network/crypto/ecdsa_demo.c