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

MacOS下C语言调用OpenAI API时SSL握手失败问题求助

解决C语言调用OpenAI API的SSL握手失败问题

问题概述

调用OpenAI API时,try_connect()函数触发SSL握手失败,报错:

SSL connect error
SSL: error:0A000410:SSL routines::ssl/tls alert handshake failure

相关代码如下:

void printSSLErrors()
{
    char errstr[256] = {};

    unsigned long err = ERR_get_error();

    while (err != 0)
    {
        ERR_error_string_n(err, &errstr[0], sizeof(errstr));

        printf("SSL: %s", &errstr);

        err = ERR_get_error();
    }
}

union ipaddr
{
    uint8_t octect[4];  // e.g. address 192.168.4.5 has octect[0]=192 and octect[3]=5
    uint32_t octet_networkOrder;
} openai;

// fill the fields with the correct IP address
//openai.octet[0]=xx
//openai.octet[0]=xx
//openai.octet[0]=xx
//openai.octet[0]=xx

bool try_connect()
{
    //TCP socket creation
    int fd = ::socket(AF_INET, SOCK_STREAM, 0);

    if (fd == -1)
        return false;

    //SSL init

    ERR_clear_error();

    SSL_CTX* sslCtx = SSL_CTX_new(TLS_method());

    if (sslCtx == NULL)
    {
        //SSL context creation failed
        printSSLErrors();
        return false;
    }

    // CA file setup

    if (SSL_CTX_load_verify_file(sslCtx, "/etc/ssl/cert.pem") == 0)
    {
        //SSL load CA file failure
        printSSLErrors();
        return false;
    }

    // Certificate setup

    if (SSL_CTX_use_certificate_chain_file(sslCtx, "mycert.pem") != 1)
    {
        //SSL certificate file setup failed
        printSSLErrors();
        return false;
    }

    if (SSL_CTX_use_PrivateKey_file(sslCtx, "mykey.pem", SSL_FILETYPE_PEM) != 1)
    {
        //SSL private key file setup failed
        printSSLErrors();
        return false;
    }

    if (SSL_CTX_check_private_key(sslCtx) != 1)
    {
        //SSL private key check failed
        printSSLErrors();
        return false;
    }

    SSL_CTX_clear_mode(sslCtx, SSL_MODE_AUTO_RETRY);

    SSL* m_ssl = SSL_new(m_sslCtx);

    if (m_ssl == NULL)
    {
        printSSLErrors();
        return false;
    }

    if (SSL_set_fd(m_ssl, m_fd) != 1)
    {
        printSSLErrors();
        return false;
    }

    //connecting

    sockaddr_in addr{};
    addr.sin_family = AF_INET;
    addr.sin_port   = htons(443);

    addr.sin_addr.s_addr = openai.octet_networkOrder;

    int ret = ::connect(m_fd, (sockaddr *)&addr, sizeof(sockaddr_in));

    if (ret == -1)
        return false;


    if (SSL_connect(m_ssl) != 1)  // start SSL client handshaking
    {
        printf("SSL connect error");
        printSSLErrors();
        return false;
    }    

    return true;

}

同一系统中,官方curl示例可正常调用API:

curl https://api.openai.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
   "model": "gpt-3.5-turbo",
   "messages": [
     {
       "role": "system",
       "content": "You are a helpful assistant."
     },
     {
       "role": "user",
       "content": "Hello!"
     }
   ]
 }'

使用openssl命令测试证书与密钥,连接成功,验证结果为OK,说明证书和密钥本身无问题:

openssl s_client -connect api.openai.com:443 -servername api.openai.com -cert mycert.pem -key mykey.pem -CAfile /etc/ssl/cert.pem

问题根源

代码存在两处关键错误:

  1. 变量名错误:创建SSL对象时使用了未定义的m_sslCtx,应为sslCtx;后续调用SSL_set_fd和connect时使用了未定义的m_fd,应为之前创建的socket文件描述符fd。
  2. 缺少SNI设置:OpenAI API服务器依赖SNI(Server Name Indication)返回对应证书,代码未设置SNI导致握手失败。

修复方案

1. 修正变量名错误

将以下代码:

SSL* m_ssl = SSL_new(m_sslCtx);

改为:

SSL* m_ssl = SSL_new(sslCtx);

将:

if (SSL_set_fd(m_ssl, m_fd) != 1)

改为:

if (SSL_set_fd(m_ssl, fd) != 1)

将:

int ret = ::connect(m_fd, (sockaddr *)&addr, sizeof(sockaddr_in));

改为:

int ret = ::connect(fd, (sockaddr *)&addr, sizeof(sockaddr_in));

2. 添加SNI设置

在SSL_set_fd之后、connect之前,添加SNI配置:

if (SSL_set_tlsext_host_name(m_ssl, "api.openai.com") != 1) {
    printSSLErrors();
    return false;
}

3. 可选:指定最小TLS版本

为确保兼容性,在创建SSL上下文后添加:

SSL_CTX_set_min_proto_version(sslCtx, TLS1_2_VERSION);

修正后的关键代码片段

// ... 省略其他代码 ...

SSL_CTX_clear_mode(sslCtx, SSL_MODE_AUTO_RETRY);

SSL* m_ssl = SSL_new(sslCtx);

if (m_ssl == NULL)
{
    printSSLErrors();
    return false;
}

if (SSL_set_fd(m_ssl, fd) != 1)
{
    printSSLErrors();
    return false;
}

// 添加SNI设置
if (SSL_set_tlsext_host_name(m_ssl, "api.openai.com") != 1) {
    printSSLErrors();
    return false;
}

//connecting

sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_port   = htons(443);

addr.sin_addr.s_addr = openai.octet_networkOrder;

int ret = ::connect(fd, (sockaddr *)&addr, sizeof(sockaddr_in));

// ... 省略其他代码 ...

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 14:47:17