You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++/Windows下使用libcurl携带客户端证书调用API报CURLE_SSL_CERTPROBLEM问题

libcurl Schannel后端加载PEM客户端证书返回CURLE_SSL_CERTPROBLEM错误

我已在此处搜索,但未找到匹配的相关内容。我使用curl.exe测试是完全正常的,随后我尝试编写了一个小型测试程序:在VS2017中创建了一个Win32命令行项目,将simplessl.c中的代码复制进去。但问题在于,无论我尝试使用什么证书,始终会返回CURLE_SSL_CERTPROBLEM错误,该错误指向客户端证书异常。我甚至尝试了公开的2048位RSA证书和密钥,依旧报错,不清楚该如何排查问题。

测试程序代码

#include "pch.h"
#include <iostream>
#include <curl/curl.h>

int main()
{
    std::cout << "Hello World!\n"; 
    CURL *curl;
    CURLcode res;
    FILE *headerfile;
    const char *pPassphrase = NULL;

    static const char *pCertFile = "C:\\Prog\\TestCurl\\2048b-rsa-example-cert.pem";
    static const char *pCACertFile = "cacert.pem";
    static const char *pHeaderFile = "C:\\Prog\\TestCurl\\requestWith.txt";

    const char *pKeyName;
    const char *pKeyType;

    const char *pEngine;

#ifdef USE_ENGINE
    pKeyName = "rsa_test";
    pKeyType = "ENG";
    pEngine = "chil";            /* for nChiper HSM... */
#else
    pKeyName = "C:\\Prog\\TestCurl\\2048b-rsa-example-keypair.pem";
    pKeyType = "PEM";
    pEngine = NULL;
#endif

    headerfile = fopen(pHeaderFile, "wb");

    curl_global_init(CURL_GLOBAL_DEFAULT);

    curl = curl_easy_init();
    if (curl) {
        /* what call to write: */
        //curl_easy_setopt(curl, CURLOPT_URL, "https://pintatesti.vero.fi/FIS/Return/IIT/Test/GetWithholdingPercentage/v1");
        curl_easy_setopt(curl, CURLOPT_URL, "https://www.pedago.fi");
        curl_easy_setopt(curl, CURLOPT_HEADERDATA, headerfile);

        do { /* dummy loop, just to break out from */
            if (pEngine) {
                /* use crypto engine */
                if (curl_easy_setopt(curl, CURLOPT_SSLENGINE, pEngine) != CURLE_OK) {
                    /* load the crypto engine */
                    fprintf(stderr, "can't set crypto engine\n");
                    break;
                }
                if (curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1L) != CURLE_OK) {
                    /* set the crypto engine as default */
                    /* only needed for the first time you load
                       a engine in a curl object... */
                    fprintf(stderr, "can't set crypto engine as default\n");
                    break;
                }
            }
            /* cert is stored PEM coded in file... */
            /* since PEM is default, we needn't set it for PEM */
            curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");

            /* set the cert for client authentication */
            curl_easy_setopt(curl, CURLOPT_SSLCERT, pCertFile);

            /* sorry, for engine we must set the passphrase
               (if the key has one...) */
            if (pPassphrase)
                curl_easy_setopt(curl, CURLOPT_KEYPASSWD, pPassphrase);

            /* if we use a key stored in a crypto engine,
               we must set the key type to "ENG" */
            curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, pKeyType);

            /* set the private key (file or ID in engine) */
            curl_easy_setopt(curl, CURLOPT_SSLKEY, pKeyName);

            /* set the file with the certs vaildating the server */
            //curl_easy_setopt(curl, CURLOPT_CAINFO, pCACertFile);

            /* disconnect if we can't validate server's cert */
            curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);

            /* Perform the request, res will get the return code */
            res = curl_easy_perform(curl);
            /* Check for errors */
            if (res != CURLE_OK)
                fprintf(stderr, "curl_easy_perform() failed: %s\n",
                    curl_easy_strerror(res));

            /* we are done... */
        } while (0);
        /* always cleanup */
        curl_easy_cleanup(curl);
    }

    curl_global_cleanup();

    return 0;
}

补充说明

  • 我获取到的底层错误是*"schannel: certificate format compatibility error"*,我能找到的唯一相关记录是schannel.c中对P12类型的判断,但我的证书是PEM格式?
  • 如果我将证书导入本地存储,程序确实可以运行,但我非常不希望采用这种方案。另外我发现调用curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);开启日志是非常好的排查手段,目前我已经有了进一步进展。
  • 问题已经解决,和2019年Stack Overflow上的同类型客户端证书调用问题逻辑一致,不过我还是更希望直接使用证书文件的方案。
  • 我使用的libcurl版本为*"libcurl/7.79.1 Schannel WinIDN"*

内容的提问来源于stack exchange,提问作者AndersG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 12:57:02