OpenSSL 客户端身份验证和 macos

问题描述 投票:0回答:1

我正在尝试以编程方式连接到 Openai API 以在 c 中进行一些查询,但是 当我打电话给

try_connect()
时,它失败了:

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;

}

该代码已在其他不要求客户端身份验证的服务器上进行了测试,并且运行良好。

api.openai.com
要求客户端身份验证,因此此代码在 try_connect() 中失败。
mykey.pem
mycert.pem
是从钥匙串访问应用程序导出的文件,从
com.apple.systemdefault
证书和私钥开始。 我无法尝试其他不同的系统..

有趣的是,curl 在同一系统中运行良好,使用 providedcurl 示例:

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.192
CONNECTED(00000006)
depth=2 C=US, O=Google Trust Services LLC, CN=GTS Root R1
verify return:1
depth=1 C=US, O=Google Trust Services LLC, CN=GTS CA 1P5
verify return:1
depth=0 CN=api.openai.com
verify 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.com
issuer=C=US, O=Google Trust Services LLC, CN=GTS CA 1P5
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 4691 bytes and written 402 bytes
Verification: OK
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 2048 bit
This TLS version forbids renegotiation.
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)

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

c openssl openai-api client-certificates
1个回答
0
投票

我找到原因了。

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

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

我希望这个答案对某人有用

© www.soinside.com 2019 - 2024. All rights reserved.