
OpenSSL 中的 MAX 系列宏EVP_MAX_MD_SIZE、EVP_MAX_IV_LENGTH 等上限定义的现状与演进方案【免费下载链接】opensslGeneral purpose TLS and crypto library项目地址: https://gitcode.com/GitHub_Trending/ope/opensslOpenSSL 的公开头文件中散布着若干形如EVP_MAX_*的#define宏它们为摘要输出、密钥、IV、分组长度和 AEAD 认证标签等设定了硬性字节上限。这些宏既被库内部大量固定长度数组所依赖又被无数第三方应用拿来分配缓冲区任何改动都必须极其谨慎。本文基于 OpenSSL 仓库中的设计文档 handling-some-max-defines.md逐个剖析HMAC_MAX_MD_CBLOCK、EVP_MAX_MD_SIZE、EVP_MAX_KEY_LENGTH、EVP_MAX_IV_LENGTH、EVP_MAX_BLOCK_LENGTH、EVP_MAX_AEAD_TAG_LENGTH六个最具争议的宏它们当前的取值、被哪些 API 调用链隐性绑定、以及项目为未来版本4.0规划的去耦方案。读完后你将理解这些上限为什么难以修改、哪些宏该保留、哪些该弃用以及开发新 API 时应如何避免继续依赖这些常量。问题背景公开头文件中的硬编码上限这些宏集中定义在 include/openssl/evp.h 中当前取值与设计文档逐一吻合#define EVP_MAX_MD_SIZE 64 /* longest known is SHA512 */ #define EVP_MAX_KEY_LENGTH 64 #define EVP_MAX_IV_LENGTH 16 #define EVP_MAX_BLOCK_LENGTH 32 #define EVP_MAX_AEAD_TAG_LENGTH 16另外 include/openssl/hmac.h 中还有一处历史遗留#define HMAC_MAX_MD_CBLOCK 200 /* Deprecated */设计文档的核心立场是公开头文件中存在多类此类#define宏其中许多上限并无争议、无需处理本文只讨论特别有问题的几个值并给出未来版本的修改或规避路径。难点在于这些常量一方面被库自身代码以微妙的方式广泛依赖例如unsigned char buf[EVP_MAX_IV_LENGTH]这类固定大小数组遍布各处另一方面又被第三方应用默认用于固定缓冲区分配因此既不能贸然改值也不能随意新增依赖它们的 API。以下按文档顺序逐个展开。HMAC_MAX_MD_CBLOCK已弃用的死宏应在 4.0 移除当前值200现状这是一个已弃用/* Deprecated */注释标注且无实际用途的定义在整个代码库中没有被使用。从源码看它仅以宏形式残留在 include/openssl/hmac.h且被OPENSSL_NO_DEPRECATED_3_0条件编译包裹#ifndef OPENSSL_NO_DEPRECATED_3_0 #define HMAC_MAX_MD_CBLOCK 200 /* Deprecated */ #endif文档提出的方案直接删除。在 4.0 版本中将其移除即可无需任何替代物。这是六个宏中最没有争议的一项——它已经与 3.0 中基于 EVP_MAC 的 HMAC 接口HMAC_Init_ex/HMAC_Update/HMAC_Final等同样被OSSL_DEPRECATEDIN_3_0标记的函数见 include/openssl/hmac.h脱钩属于纯粹的历史包袱。EVP_MAX_MD_SIZE保留原值警惕 XOF 场景当前值64分析短时间内不太可能出现超过 512 位的哈希函数当前最长的就是 SHA-512宏注释longest known is SHA512也说明了这一点。需要特别区分的是 XOF可扩展输出函数如 SHAKE 系列XOF 的输出长度不受此值限制也不应该被它限制。但该宏在整个代码库和大量第三方应用中被广泛使用是摘要输出缓冲区的事实标准大小。依赖该值的 API 调用文档列出了五处无法指定输出缓冲区长度的调用点HMAC()——无法指定输出缓冲区长度见 include/openssl/hmac.h 的函数签名输出参数为unsigned char *md, unsigned int *md_lenX509_pubkey_digest()——同样无法指定输出缓冲区长度EVP_Q_digest()——无法指定输出缓冲区长度EVP_Digest()——无法指定输出缓冲区长度EVP_DigestFinal_ex()——文档指出该函数实际上允许通过应用侧显式设置输出尺寸从而接受更大的输出是这组 API 中唯一留有余地的。文档提出的方案保留现值不作弃用——64 字节足以覆盖所有现实中的摘要算法审查代码库确认该宏没有被用在XOF 可能以任意输出长度工作的位置避免用固定 64 字节缓冲去接 XOF 输出考虑引入替代上述调用的新 API增加一个表示输出缓冲区大小的入参从根本上摆脱对宏的隐式依赖。EVP_MAX_KEY_LENGTH保留原值冻结新增依赖当前值64分析该宏在整个代码中被广泛使用且依赖方式是微妙的——可以合理假设第三方应用正拿它来分配固定大小的密钥缓冲区。短期内不太可能出现密钥超过 512 位的对称密码因此 64 是安全的下限。依赖该值的 API 调用EVP_KDF_CTX_get_kdf_size()——在设置具体密码之前对 KRB5KDF 会返回EVP_MAX_KEY_LENGTH即该宏参与了 KDF 输出尺寸的默认推断EVP_CIPHER_CTX_rand_key()——无法指定输出缓冲区长度。文档提出的方案保留现值、不作弃用可以审查代码库以减少对该值的依赖但承认此类依赖点数量众多短期内不现实关键是避免再添加依赖该值的新 API。EVP_MAX_IV_LENGTH问题最大的一个需弃用宏并重构 API当前值16分析文档明确将其定性为最 problematic 的一个。理由一旦出现分组长度超过 128 位的密码IV 有可能就需要超过 16 字节而代码库中存在大量EVP_MAX_IV_LENGTH大小的固定数组。更棘手的是它被直接写进了公开回调函数的函数签名中SSL_CTX_set_tlsext_ticket_key_evp_cb()——在回调函数签名中显式使用了EVP_MAX_IV_LENGTH。从源码看该声明位于 include/openssl/tls1.hint SSL_CTX_set_tlsext_ticket_key_evp_cb(SSL_CTX *ctx, int (*fp)(SSL *, unsigned char *, unsigned char *, EVP_CIPHER_CTX *, EVP_MAC_CTX *, int));其中第二个unsigned char *参数IV的缓冲区大小约定正是EVP_MAX_IV_LENGTH调用者必须按该宏分配SSL_CTX_set_tlsext_ticket_key_cb()——同一回调的弃用旧版本存在同样的问题。从源码结构看它在 include/openssl/tls1.h 中已被包在OPENSSL_NO_DEPRECATED_3_0条件内通过SSL_CTX_callback_ctrl桥接到SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB。文档提出的方案三个动作弃用上述 API新增替代接口显式传入_iv_参数的长度让调用者按实际密码的 IV 大小分配缓冲审查并修改代码库使其不再依赖EVP_MAX_IV_LENGTH弃用EVP_MAX_IV_LENGTH宏本身并避免再添加依赖该值的新 API。这是六个宏中唯一被明确建议弃用宏且需要替换公开 API 签名的一项体现了文档保留安全的值、只动真正有风险的值的克制策略。EVP_MAX_BLOCK_LENGTH保留原值冻结新增依赖当前值32分析该宏在代码中的使用点较少但可能已被第三方应用用于分配一个或多个分组的固定缓冲区。短期内不太可能出现分组长度超过 256 位的对称密码32 字节的取值是安全的。依赖该值的 API 调用无。文档提出的方案保留现值、不作弃用可以审查代码库以减少依赖但同样承认此类用例数量较多不再添加依赖该值的新 API。EVP_MAX_AEAD_TAG_LENGTH需弃用文档描述也要同步修改当前值16分析该宏在库内仅被 hpke 模块用于分配一个固定缓冲区——这一点可以从源码直接印证crypto/hpke/hpke.c 中写着unsigned char tag[EVP_MAX_AEAD_TAG_LENGTH];。此外EVP_EncryptInit(3)手册页在描述EVP_CIPHER_CTX_ctrl(EVP_CTRL_AEAD_SET_TAG)时提到 tag 大小至多 16 字节文档也依赖了此宏。 该值之所以有问题对于基于 HMAC/KMAC 的 AEAD 密码标签长度可以大于分组长度即便将来出现 256 位分组的块密码16 字节的标签上限也偏紧。依赖该值的 API 调用无除EVP_CIPHER_CTX_ctrl(EVP_CTRL_AEAD_SET/GET_TAG)的手册页文档描述外。文档提出的方案审查并修改代码库使其不再依赖EVP_MAX_AEAD_TAG_LENGTH如 crypto/hpke/hpke.c 处按密码实际标签长度分配弃用该宏并避免再添加依赖该值的新 API。决策汇总保留、弃用与新增依赖的冻结线将文档对六个宏的处理结论汇总如下便于快速检索与对照宏当前值定义位置处理结论关键理由HMAC_MAX_MD_CBLOCK200include/openssl/hmac.h4.0 直接删除已弃用代码库中无任何使用EVP_MAX_MD_SIZE64include/openssl/evp.h保留不弃用最长现实哈希为 512 位需审查 XOF 使用点可引入带输出长度参数的新 APIEVP_MAX_KEY_LENGTH64include/openssl/evp.h保留不弃用第三方广泛依赖避免新增依赖EVP_MAX_IV_LENGTH16include/openssl/evp.h弃用宏重构 API长分组密码可能需要更长 IV回调签名 tls1.h 显式依赖EVP_MAX_BLOCK_LENGTH32include/openssl/evp.h保留不弃用短期内无超过 256 位分组的对称密码EVP_MAX_AEAD_TAG_LENGTH16include/openssl/evp.h弃用宏HMAC/KMAC 类 AEAD 的 tag 可超过块大小这套方案背后有一条清晰的设计原则贯穿始终对现实约束内足够大的上限保持不动以保护 ABI 与生态稳定对存在理论突破可能且已渗入公开 API 签名的上限则弃用宏、替换 API、并冻结新增依赖。对库自身开发者而言最直接可执行的约束是今后设计新的公开接口时凡涉及摘要、密钥、IV、分组或 AEAD 标签的缓冲区都应通过参数显式传递长度而不是引用这些EVP_MAX_*常量。适用前提与限制说明本文所有取值、宏定义与 API 依赖关系均以当前仓库实际代码为准宏定义见 include/openssl/evp.h 与 include/openssl/hmac.h回调声明见 include/openssl/tls1.hhpke 中的固定缓冲用法见 crypto/hpke/hpke.c文档中4.0 移除等表述属于面向未来版本的设计规划该文档位于 doc/designs/ 目录是设计讨论文档当前仓库代码仍保留全部宏定义不应据此假设现有版本已移除任何宏涉及EVP_KDF_CTX_get_kdf_size()、EVP_CIPHER_CTX_rand_key()等 API 的依赖描述来自设计文档原文未在本次核对中逐一打开对应实现文件验证具体返回路径引用时请以文档表述为准。【免费下载链接】opensslGeneral purpose TLS and crypto library项目地址: https://gitcode.com/GitHub_Trending/ope/openssl创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考