ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

curl/libcurl 使用 CURLOPT_SSH_PRIVATE_KEYFILE 配置 SSH 私钥进行 SFTP/SCP 认证

curl/libcurl 使用 CURLOPT_SSH_PRIVATE_KEYFILE 配置 SSH 私钥进行 SFTP/SCP 认证 curl/libcurl 使用 CURLOPT_SSH_PRIVATE_KEYFILE 配置 SSH 私钥进行 SFTP/SCP 认证【免费下载链接】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本文基于 curl 官方 libcurl 选项文档讲解CURLOPT_SSH_PRIVATE_KEYFILE的完整用法它用于为 SFTP 与 SCP 协议指定 SSH 私钥文件路径配合CURLOPT_KEYPASSWD处理加密私钥、配合CURLOPT_SSH_PUBLIC_KEYFILE处理公钥派生失败场景。读完本文你将掌握在 libcurl 程序中配置密钥认证的关键调用方式、默认密钥查找规则、认证失败的常见原因以及 libcurl 内部如何借助 libssh2/libssh 后端完成公钥认证。选项概览CURLOPT_SSH_PRIVATE_KEYFILE用于设置 SSH 认证使用的私钥文件路径。它在 libcurl 选项表include/curl/curl.h中定义从 curl 7.16.1 版本起可用仅适用于 SFTP 与 SCP 两种协议。函数原型如下#include curl/curl.h CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSH_PRIVATE_KEYFILE, char *filename);其中filename是私钥文件的路径字符串可以是绝对路径或相对路径。该选项属于字符串类选项通过curl_easy_setopt传入后libcurl 会拷贝该字符串见下文源码分析因此应用程序在调用之后无需继续保持该字符串有效。默认行为未设置时使用哪些私钥如果不使用本选项指定私钥libcurl 会按照以下顺序自动查找默认私钥文件若设置了HOME环境变量依次尝试$HOME/.ssh/id_rsa和$HOME/.ssh/id_dsa若HOME未设置或上述路径均不存在则在当前工作目录下依次尝试id_rsa和id_dsa。上述默认查找逻辑可以在源码 lib/vssh/vssh.c 的Curl_ssh_setup_pkey()函数中看到完整实现约第 365448 行它先读取HOME环境变量拼出~/.ssh/id_rsa不存在则尝试~/.ssh/id_dsa再退而求其次在当前目录查找全部失败后置为空字符串以避免产生误导性日志。基础用法示例下面是一个最小可运行的示例它使用sftp://协议连接服务器显式指定私钥文件并用CURLOPT_KEYPASSWD提供私钥口令若私钥有口令保护int main(void) { CURL *curl curl_easy_init(); if(curl) { CURLcode result; curl_easy_setopt(curl, CURLOPT_URL, sftp://example.com/file); curl_easy_setopt(curl, CURLOPT_SSH_PRIVATE_KEYFILE, /home/clarkkent/.ssh/id_rsa); curl_easy_setopt(curl, CURLOPT_KEYPASSWD, password); result curl_easy_perform(curl); curl_easy_cleanup(curl); } }同样的选项也适用于scp://协议例如将 URL 换成scp://example.com/path/to/file即可。关于口令参数的补充私钥文件若设置了口令保护必须通过CURLOPT_KEYPASSWD传入口令否则认证会失败。相关细节参见 docs/libcurl/opts/CURLOPT_KEYPASSWD.md。在 lib/vssh/vssh.c 第 430432 行可以看到未设置口令时 libcurl 会将其置为空字符串传给 SSH 后端因此无口令私钥也能正常工作。公钥的派生规则SSH 公钥认证需要同时具备公钥与私钥。libcurl 的处理规则是优先从私钥派生公钥SSH 库在可能的情况下会直接从私钥文件中派生对应的公钥此时无需单独指定公钥文件派生失败时必须显式提供公钥如果 SSH 库无法从私钥推导出公钥且应用程序也没有通过CURLOPT_SSH_PUBLIC_KEYFILE指定公钥文件则本次传输会失败。在 libssh2 后端lib/vssh/libssh2.c 的ssh_state_auth_pkey()约第 14931524 行中认证调用为libssh2_userauth_publickey_fromfile_ex(sshc-ssh_session, user, strlen(user), sshc-pub_key, sshc-priv_key, sshc-passphrase);可以看到公钥pub_key与私钥priv_key同时被传入认证函数。当用户未显式指定公钥时lib/vssh/vssh.c 第 418428 行的注释明确指出libcurl 会保持pub_key为 NULL交由 SSH 库从私钥中提取公钥。在 libssh 后端lib/vssh/libssh.c 的myssh_in_AUTH_PKEY_INIT()约第 856899 行中流程类似有私钥时调用ssh_pki_import_privkey_file()导入私钥无显式私钥时则调用ssh_userauth_publickey_auto()使用默认密钥自动认证。因此实际使用中常见两种配置方式场景配置方式私钥可派生公钥大多数 RSA/Ed25519 私钥仅设置CURLOPT_SSH_PRIVATE_KEYFILE即可私钥无法派生公钥同时设置CURLOPT_SSH_PRIVATE_KEYFILE与CURLOPT_SSH_PUBLIC_KEYFILE公钥选项的详细说明见 docs/libcurl/opts/CURLOPT_SSH_PUBLIC_KEYFILE.md。选项生效时机与连接复用文档明确说明CURLOPT_SSH_PRIVATE_KEYFILE仅在新建 SSH 连接时生效。私钥用于 libcurl 建立新 SSH 连接的时刻一旦连接成功建立并通过验证该连接即被视为已审查vetted之后 libcurl可能复用这条连接——即使在此期间修改了本选项的值也不会影响已复用连接上的认证身份。这一点对长连接、连接池复用场景有实际意义如果你需要在同一程序中切换不同身份访问不同服务器应确保不同身份使用独立的 easy handle或通过连接相关选项如 URL 中的主机端口差异避免复用旧连接。底层实现选项如何存储与传递CURLOPT_SSH_PRIVATE_KEYFILE的处理入口位于 lib/setopt.c 的setopt_cptr_ssh()约第 21482162 行case CURLOPT_SSH_PRIVATE_KEYFILE: /* * Use this file instead of the $HOME/.ssh/id_dsa file */ return Curl_setstropt(data, STRING_SSH_PRIVATE_KEY, ptr);它通过Curl_setstropt()将字符串拷贝并存入data-set结构中的字符串槽位STRING_SSH_PRIVATE_KEY该枚举定义于 lib/urldata.h 第 761 行注释为path to the private key file for auth。这正解释了文档中应用程序无需在设置后继续保留该字符串的约定——libcurl 内部已经完成了拷贝。随后在建立 SSH 连接时lib/vssh/vssh.c 的Curl_ssh_setup_pkey()会读取该字符串第 373378 行有则直接使用无则走默认查找逻辑。认证阶段再由具体 SSH 后端libssh2 或 libssh读取并执行密钥认证。从代码结构看curl 对 SSH 协议族采用了可插拔后端设计lib/vssh/目录下同时存在 libssh2.clibssh2 后端与 libssh.clibssh 后端两者都实现了私钥导入与公钥认证的状态机逻辑。具体使用哪个后端取决于编译时的配置。返回值与错误处理curl_easy_setopt()总是返回CURLcode类型CURLE_OK值为 0表示设置成功非零值表示出错具体错误码参见 docs/libcurl/libcurl-errors.md。需要注意的是CURLE_OK只代表选项被正确接收并存储并不代表私钥文件真实存在、格式合法或认证能够通过。私钥加载失败、口令错误等认证阶段的问题会在curl_easy_perform()阶段以CURLE_LOGIN_DENIED等错误码返回。例如在 lib/vssh/libssh.c 第 882886 行私钥文件加载失败时会打印Could not load private key file %s并返回CURLE_LOGIN_DENIED。相关选项与测试验证与 SSH 认证相关的配套选项包括CURLOPT_SSH_PUBLIC_KEYFILE指定公钥文件路径CURLOPT_KEYPASSWD私钥口令CURLOPT_SSH_AUTH_TYPES指定允许的 SSH 认证方式如仅启用CURLSSH_AUTH_PUBLICKEYCURLOPT_SSH_HOST_PUBLIC_KEY_MD5/CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256校验服务器主机公钥指纹。在测试套件中tests/libtest/lib582.c 与 tests/libtest/lib583.c 是直接引用该选项的 libtest 用例可用于验证选项的编译与使用方式docs/libcurl/symbols-in-versions中则记录了CURLOPT_SSH_PRIVATE_KEYFILE自 7.16.1 起进入公共 API 的版本信息。常见问题排查要点结合文档与源码遇到 SSH 密钥认证失败时可依次检查私钥路径是否正确路径可以是绝对的或相对的但必须是 libcurl 运行进程可读的文件口令是否匹配私钥有口令时必须设置CURLOPT_KEYPASSWD且 libcurl 会直接将其透传给 SSH 后端公钥是否缺失若 SSH 库无法从私钥派生公钥必须同时设置CURLOPT_SSH_PUBLIC_KEYFILE否则传输失败认证方式是否被启用确认CURLOPT_SSH_AUTH_TYPES中包含了CURLSSH_AUTH_PUBLICKEY否则私钥配置不会被使用连接是否被复用修改本选项只影响新建连接排查问题时可通过curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1L)强制建立新连接来验证。【免费下载链接】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),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进