ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

libcurl 的 CURLOPT_SSL_CIPHER_LIST 详解:TLS 密码套件配置与各后端实现差异

libcurl 的 CURLOPT_SSL_CIPHER_LIST 详解:TLS 密码套件配置与各后端实现差异 libcurl 的 CURLOPT_SSL_CIPHER_LIST 详解TLS 密码套件配置与各后端实现差异【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curlCURLOPT_SSL_CIPHER_LIST 是 libcurl 中用于控制 TLS 1.2含 1.1、1.0连接密码套件cipher suite的核心选项。本文以该选项为主线完整讲解其用法、语法格式、默认行为并结合 curl 源码剖析 OpenSSL、GnuTLS、Schannel、wolfSSL、mbedTLS、Rustls 等不同 TLS 后端的实现差异同时补充 TLS 1.3 密码套件CURLOPT_TLS13_CIPHERS与命令行--ciphers的配套使用方案帮助读者在实际项目中精确控制 TLS 协商的密码套件范围。CURLOPT_SSL_CIPHER_LIST 是什么CURLOPT_SSL_CIPHER_LIST是 libcurl 提供的一个curl_easy_setopt选项用于指定 TLS 连接TLS 1.0 / 1.1 / 1.2所要使用的密码套件列表。该选项自 curl 7.9 起引入Added-in: 7.9是历史最悠久的 TLS 配置选项之一。它的作用范围仅限 TLS 1.2 及更早版本。若需要设置TLS 1.3的密码套件应使用独立的 CURLOPT_TLS13_CIPHERS 选项。两个选项分别对应 libcurl 内部不同的配置字段STRING_SSL_CIPHER_LIST与STRING_SSL_CIPHER13_LIST。在命令行工具 curl 中该选项对应--ciphers参数代理连接HTTPS 代理则对应--proxy-ciphers即 CURLOPT_PROXY_SSL_CIPHER_LIST。函数原型与基本用法原型#include curl/curl.h CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_CIPHER_LIST, char *list);list是一个指向以 NUL 结尾字符串的char *指针内容为一个或多个密码套件字符串以冒号:分隔。列表必须是语法上正确的否则后端可能拒绝设置并报错。最小可运行示例int main(void) { CURL *curl curl_easy_init(); if(curl) { CURLcode result; curl_easy_setopt(curl, CURLOPT_URL, https://example.com/); curl_easy_setopt(curl, CURLOPT_SSL_CIPHER_LIST, ECDHE-ECDSA-CHACHA20-POLY1305: ECDHE-RSA-CHACHA20-POLY1305); result curl_easy_perform(curl); curl_easy_cleanup(curl); } }以上示例将 TLS 1.2 的密码套件限制为两个 ChaCha20-Poly1305 套件。原文档给出的另一个 OpenSSL 风格合法示例为ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256: ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305生命周期与覆盖规则字符串复制libcurl 在设置选项时会拷贝该字符串应用无需在设置后继续保存它。重复设置多次调用该选项时最后一次设置的字符串会覆盖之前的设置。置空恢复将其设置为NULL即可禁用该选项恢复使用内置默认密码套件列表。默认值NULL即使用 libcurl 后端内置的默认列表DEFAULT: NULL, use built-in list。密码套件Cipher Suite基础在 TLS 握手中客户端与服务端需要在版本、密钥交换、批量加密、消息认证码MAC等参数上达成一致而“密码套件”正是这些算法组合的统一定义。TLS 1.3 之前套件通常由四部分组成密钥交换如 ECDHE、DHE、RSA、批量加密如 AES-GCM、CHACHA20、消息认证码如 SHA256、SHA384以及证书认证算法如 ECDSA、RSATLS 1.3 则引入了AEAD认证加密套件体系详见 docs/CIPHERS.md。命名体系OpenSSL 名与 IANA 名TLS 1.2 密码套件存在两套常用命名OpenSSL 名如ECDHE-RSA-AES128-GCM-SHA256IANA 名如TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256。IANA 的 TLS 1.2 名与 TLS 1.3 名外观相似可通过一个特征区分TLS 1.2 名中包含_WITH_而 TLS 1.3 名不含。curl 官方建议设置 TLS 1.2 套件时使用OpenSSL 名因为这是各 SSL 后端OpenSSL、LibreSSL、BoringSSL、wolfSSL、mbedTLS 等识别度最高的写法。推荐的 TLS 1.2 密码套件列表curl 在 docs/CIPHERS.md 中基于 Mozilla 的推荐整理了一份被大部分SSL 后端支持的精简列表可直接用于--ciphers/CURLOPT_SSL_CIPHER_LISTECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-ECDSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384 DHE-RSA-CHACHA20-POLY1305 ECDHE-ECDSA-AES128-SHA256 ECDHE-RSA-AES128-SHA256 ECDHE-ECDSA-AES128-SHA ECDHE-RSA-AES128-SHA ECDHE-ECDSA-AES256-SHA384 ECDHE-RSA-AES256-SHA384 ECDHE-ECDSA-AES256-SHA ECDHE-RSA-AES256-SHA DHE-RSA-AES128-SHA256 DHE-RSA-AES256-SHA256 AES128-GCM-SHA256 AES256-GCM-SHA384 AES128-SHA256 AES256-SHA256 AES128-SHA AES256-SHA DES-CBC3-SHA需要注意的是全部可用的 TLS 1.2 密码套件超过 300 个但如今大部分已被各 SSL 后端移除或不再推荐使用完整的 TLS 1.2 套件清单见 docs/CIPHERS-TLS12.md。列表解析与优先级语义机会式解析列表按冒号分隔后被“机会式”解析无法识别或后端未实现的套件会被静默忽略只要列表中至少有一个可识别的套件列表即被视为有效。顺序即优先级套件在列表中的书写顺序决定了客户端偏好顺序。协商时服务端从“服务端支持的套件 ∩ curl 发送的套件”中挑选若服务端配置为遵循客户端偏好则选中 curl 列表中第一个共同套件。TLS 1.3 与 1.2 的并集默认情况下 curl 可能同时协商 TLS 1.3 与 TLS 1.2因此握手考虑的套件是两组套件的并集。若只想考虑 TLS 1.3 套件需同时通过 CURLOPT_SSLVERSION或--tlsv1.3将最低 TLS 版本限制为 1.3。各 TLS 后端的实现差异CURLOPT_SSL_CIPHER_LIST的语义因编译时选用的 TLS 后端而异需要逐一区分。OpenSSL 及衍生后端OpenSSL、LibreSSL、BoringSSL、AWS-LC在 OpenSSL 后端中该字符串被直接透传给SSL_CTX_set_cipher_list()。从 lib/vtls/openssl.c 可以看到实际调用逻辑ciphers conn_config-cipher_list; if(ciphers (ssl_version_min CURL_SSLVERSION_TLSv1_3)) { if(!SSL_CTX_set_cipher_list(octx-ssl_ctx, ciphers)) { failf(data, failed setting cipher list: %s, ciphers); return CURLE_SSL_CIPHER; } infof(data, Cipher selection: %s, ciphers); }值得注意的两点仅当协商的最低 TLS 版本低于 1.3 时才调用SSL_CTX_set_cipher_list设置失败如字符串语法错误、所有套件均不可用时返回CURLE_SSL_CIPHER错误。除具体套件名外OpenSSL 还支持密码字符串cipher string格式如TLSv1.2、AESGCM、CHACHA20等类别关键字以及!排除、-移除并后移优先级、移除并置顶运算符例如HIGH:!aNULL:!MD5。这类写法仅在 OpenSSL 系后端可用。GnuTLS优先级字符串Priority StringGnuTLS 不使用套件列表而使用priority string语法。CURLOPT_SSL_CIPHER_LIST设置的字符串会直接影响 GnuTLS 的优先级设置具体规则见 lib/vtls/gtls.c当字符串以、-或!开头时它会被追加到 libcurl 自行生成的优先级字符串之后以:分隔。这个初始优先级受其他设置如 CURLOPT_SSLVERSION、是否协商 HTTP/3/QUIC影响否则设置的字符串会完全替换libcurl 生成的优先级字符串应用需要自行保证该优先级能满足传输所需的全部协商项——例如若优先级只允许 TLSv1.2那么所有 HTTP/3 尝试都会失败。GnuTLS 的 priority string 可以指定的内容远超密码套件包括密钥交换、MAC、压缩、TLS 版本、签名算法、群组、椭圆曲线、证书类型等。由于优先级字符串中条目顺序有意义curl 不会再把其他 SSL 选项拼接进去--ciphers是改变优先级的唯一途径。GnuTLS 常用示例命令行形式# 仅使用 aes128-gcm 与 chacha20 curl --ciphers -CIPHER_ALL:AES-128-GCM:CHACHA20-POLY1305 https://example.com/ # 仅 TLS 1.3 且排除 aes256-gcm curl --ciphers NORMAL:-VERS-ALL:TLS1.3:-AES-256-GCM https://example.com/ # 仅 TLS 1.2 且只允许 CAMELLIA-128-GCM curl --ciphers NORMAL:-VERS-ALL:TLS1.2:-CIPHER_ALL:CAMELLIA-128-GCM https://example.com/SchannelWindowsSchannel不支持直接设置具体密码套件但可以用CURLOPT_SSL_CIPHER_LIST指定加密算法CALG_xxx形式的算法标识例如仅启用或禁用某些对称算法。此外自 curl 7.77.0 起还可以传入SCH_USE_STRONG_CRYPTO以向 Schannel 传递该标志。当未指定--ciphers与--tls13-ciphers时curl 默认就会传递SCH_USE_STRONG_CRYPTO标志。wolfSSL 与 mbedTLSwolfSSL自 curl 7.53.0 起支持CURLOPT_SSL_CIPHER_LISTmbedTLS自 curl 8.8.0 起支持。curl 8.10.0 之前mbedTLS / wolfSSL 的 TLS 1.3 套件也通过本选项设置8.10.0 起改由 CURLOPT_TLS13_CIPHERS 统一处理。mbedTLS 与 Rustls 后端本身不提供“按名称设置套件”的 APIcurl 为此在 lib/vtls/cipher_suite.c 中内置了一张密码套件名称 ↔ IANA 编号的映射表Curl_cipher_suite_lookup_id()负责把 OpenSSL 名或 IANA 名解析为 16 位 IANA 编号Curl_cipher_suite_get_str()负责反向转换支持prefer_rfc选择输出 IANA 名。为压缩二进制体积该表用 C 预处理器把每个套件名拆成算法片段并压缩为 6 字节CS_ZIP_IDX由Curl_cipher_suite_walk_str()按:、,、;、空格等分隔符遍历用户提供的列表。该表的正确性由 tests/unit/unit3205.c 单元测试覆盖。RustlsRustls 自 curl 8.10.0 起支持本选项同样借助上述cipher_suite.c的映射表把名称解析为 IANA 编号后交给 Rustls。TLS 1.3 密码套件配套的 CURLOPT_TLS13_CIPHERS由于 TLS 1.3 的密码套件命名与 1.2 完全不同如TLS_AES_128_GCM_SHA256libcurl 自 7.61.0 起提供独立的 CURLOPT_TLS13_CIPHERS 选项命令行--tls13-cipherscurl_easy_setopt(curl, CURLOPT_TLS13_CIPHERS, TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256);可用于 TLS 1.3 的套件有TLS_AES_128_GCM_SHA256 TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 TLS_AES_128_CCM_SHA256 TLS_AES_128_CCM_8_SHA256wolfSSL 还额外支持TLS_SM4_GCM_SM3、TLS_SM4_CCM_SM3、TLS_SHA256_SHA256、TLS_SHA384_SHA384其中后两个是不提供任何加密的 NULL 套件不建议使用详见 docs/CIPHERS.md。在 OpenSSL 后端中CURLOPT_TLS13_CIPHERS会通过SSL_CTX_set_ciphersuites()生效见 lib/vtls/openssl.c。各后端支持时间线OpenSSL 1.1.1curl 7.61.0、LibreSSL 3.4.1curl 8.3.0、wolfSSLcurl 8.10.0、mbedTLS 3.6.0curl 8.10.0、Rustlscurl 8.10.0。GnuTLS 后端则忽略CURLOPT_TLS13_CIPHERS其 TLS 1.3 套件仍需通过 priority string 配置。命令行等价用法--cipherslibcurl 选项在 curl 命令行中对应--ciphers。命令行参数的解析入口在 src/tool_getparam.c选项注册表与 src/tool_getparam.cC_CIPHERS分支把字符串存入config-cipher_list。典型命令行用法# 仅 TLS 1.2限制为 aes128-gcm 与 chacha20OpenSSL 系后端 curl \ --ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:\ ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305 \ https://example.com/ # TLS 1.3 与 1.2 分别限制OpenSSL、LibreSSL、mbedTLS、wolfSSL 可用 curl \ --tls13-ciphers TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256 \ --ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:\ ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305 \ https://example.com/ # 只允许 TLS 1.3 且限制其套件 curl \ --tlsv1.3 \ --tls-max 1.3 \ --tls13-ciphers TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256 \ https://example.com/代理场景使用--proxy-ciphersCURLOPT_PROXY_SSL_CIPHER_LIST与--proxy-tls13-ciphersCURLOPT_PROXY_TLS13_CIPHERS。返回值与错误处理curl_easy_setopt(3)返回CURLcodeCURLE_OK (0)设置成功非零发生错误具体错误码参见 libcurl-errors。结合源码 lib/setopt.c 的实现可以看到两个关键行为case CURLOPT_SSL_CIPHER_LIST: if(Curl_ssl_supports(data, SSLSUPP_CIPHER_LIST)) /* set a list of cipher we want to use in the SSL connection */ return Curl_setstropt(data, STRING_SSL_CIPHER_LIST, ptr); else return CURLE_NOT_BUILT_IN;若当前编译的 TLS 后端不支持套件列表能力SSLSUPP_CIPHER_LIST未声明则自curl 8.10.0起返回CURLE_NOT_BUILT_IN字符串经由Curl_setstropt拷贝保存因此调用方无需在curl_easy_setopt之后保留该字符串。注意本选项的语法校验如 OpenSSL 的SSL_CTX_set_cipher_list失败发生在握手建立阶段而非setopt阶段因此语法错误通常表现为传输时返回CURLE_SSL_CIPHER而非设置选项时报错。历史版本与支持时间线后端引入版本备注OpenSSL7.9本选项首次引入wolfSSL7.53.0—Schannel7.61.0仅支持算法级CALG_xxx不支持具体套件mbedTLS8.8.0借助cipher_suite.c名称映射表Rustls8.10.0借助cipher_suite.c名称映射表不支持时的返回码8.10.0返回CURLE_NOT_BUILT_IN对于 TLS 1.3 套件CURLOPT_TLS13_CIPHERSOpenSSL 1.1.17.61.0、LibreSSL 3.4.18.3.0、wolfSSL8.10.0、mbedTLS 3.6.08.10.0、Rustls8.10.0在 8.10.0 之前mbedTLS 与 wolfSSL 的 TLS 1.3 套件是通过CURLOPT_SSL_CIPHER_LIST设置的。实践建议优先使用 ECDHE 系套件ECDHE-*-AES*-GCM-SHA*与ECDHE-*-CHACHA20-POLY1305兼具前向保密与良好兼容性是 Mozilla 推荐列表的主力区分 TLS 版本TLS 1.2 用CURLOPT_SSL_CIPHER_LIST/--ciphersTLS 1.3 用CURLOPT_TLS13_CIPHERS/--tls13-ciphers两者默认行为是并集后端差异先行确认同一份字符串在 OpenSSL 与 GnuTLS 下语法完全不同OpenSSL 套件名 vs GnuTLS priority string在 Schannel 下只能指定算法跨平台部署时应针对各后端分别设计配置利用--tlsv1.3 --tls-max 1.3收紧版本需要仅 TLS 1.3 时配合 CURLOPT_SSLVERSION 将最低/最高版本锁定避免 1.2 与 1.3 套件并集带来的意外协商结果。完整的密码套件背景说明可继续阅读 docs/CIPHERS.md 与 docs/CIPHERS-TLS12.md。【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表