OpenSSL客户端认证和macOS

我正在尝试用C语言编程连接到OpenAI API以进行一些查询,但在调用try_connect()时失败,错误信息如下:

SSL connect errorSSL: 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];  // 例如,地址192.168.4.5有octect[0]=192和octect[3]=5    uint32_t octet_networkOrder;} openai;// 用正确的IP地址填充字段//openai.octet[0]=xx//openai.octet[0]=xx//openai.octet[0]=xx//openai.octet[0]=xxbool try_connect(){    //创建TCP套接字    int fd = ::socket(AF_INET, SOCK_STREAM, 0);    if (fd == -1)        return false;    //SSL初始化    ERR_clear_error();    SSL_CTX* sslCtx = SSL_CTX_new(TLS_method());    if (sslCtx == NULL)    {        //SSL上下文创建失败        printSSLErrors();        return false;    }    //设置CA文件    if (SSL_CTX_load_verify_file(sslCtx, "/etc/ssl/cert.pem") == 0)    {        //SSL加载CA文件失败        printSSLErrors();        return false;    }    //设置证书    if (SSL_CTX_use_certificate_chain_file(sslCtx, "mycert.pem") != 1)    {        //SSL证书文件设置失败        printSSLErrors();        return false;    }    if (SSL_CTX_use_PrivateKey_file(sslCtx, "mykey.pem", SSL_FILETYPE_PEM) != 1)    {        //SSL私钥文件设置失败        printSSLErrors();        return false;    }    if (SSL_CTX_check_private_key(sslCtx) != 1)    {        //SSL私钥检查失败        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;    }    //连接    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)  // 开始SSL客户端握手    {        printf("SSL connect error");        printSSLErrors();        return false;    }        return true;}

这段代码已经在其他不需要客户端认证的服务器上测试过,运行正常。 api.openai.com 需要客户端认证,因此在try_connect()中失败。mykey.pemmycert.pem是从Keychain Access应用程序中导出的文件,起始于com.apple.systemdefault证书和私钥。我无法在其他系统上进行测试..

有趣的是,在同一系统上使用提供的curl示例,curl运行正常:

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 s_client -connect api.openai.com:443 -servername api.openai.com -cert mycert.pem -key mykey.pem -CAfile /etc/ssl/cert.pem

它能够连接

Connecting to 104.18.7.192CONNECTED(00000006)depth=2 C=US, O=Google Trust Services LLC, CN=GTS Root R1verify return:1depth=1 C=US, O=Google Trust Services LLC, CN=GTS CA 1P5verify return:1depth=0 CN=api.openai.comverify return:1---Certificate chain 0 s:CN=api.openai.com   i:C=US, O=Google Trust Services LLC, CN=GTS CA 1P5   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256   v:NotBefore: Feb 25 00:03:27 2024 GMT; NotAfter: May 25 00:03:26 2024 GMT 1 s:C=US, O=Google Trust Services LLC, CN=GTS CA 1P5   i:C=US, O=Google Trust Services LLC, CN=GTS Root R1   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256   v:NotBefore: Aug 13 00:00:42 2020 GMT; NotAfter: Sep 30 00:00:42 2027 GMT 2 s:C=US, O=Google Trust Services LLC, CN=GTS Root R1   i:C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA   a:PKEY: rsaEncryption, 4096 (bit); sigalg: RSA-SHA256   v:NotBefore: Jun 19 00:00:42 2020 GMT; NotAfter: Jan 28 00:00:42 2028 GMT---Server certificate-----BEGIN CERTIFICATE-----BLA BLA BLA-----END CERTIFICATE-----subject=CN=api.openai.comissuer=C=US, O=Google Trust Services LLC, CN=GTS CA 1P5---No client certificate CA names sentPeer signing digest: SHA256Peer signature type: RSA-PSSServer Temp Key: X25519, 253 bits---SSL handshake has read 4691 bytes and written 402 bytesVerification: OK---New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384Server public key is 2048 bitThis TLS version forbids renegotiation.Compression: NONEExpansion: NONENo ALPN negotiatedEarly data was not sentVerify return code: 0 (ok)

所以我认为我拥有的证书和密钥是正确的,并且被服务器接受


回答:

我找到了原因。

SSL_set_tlsext_host_name()应该在SSL_connect()调用之前调用,以便SSL知道服务器的主机名并完成验证。

我添加了这样的调用,现在它工作了。

希望这个答案对某人有用

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注