"tlsv1 alert unknown ca" 使用 OpenSSL 创建服务器时 API

"tlsv1 alert unknown ca" when creating server with OpenSSL API

我正在用 C 中的 OpenSSL API 创建一个 Web 服务器,一切正常,我可以通过浏览器访问我的网站,但是当我在 Discord 上共享 link 时,我得到了这个错误信息 : 1568:error:14094418:SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca:ssl\record\rec_layer_s3.c:1544:SSL alert number 48

我想要的是 Discord 集成显示 link 的预览,如下所示:Discord integration example

这就是我所做的:

#define CA_CERT_FILE     "cacert.pem"
#define SERVER_CERT_FILE "cert.pem"
#define SERVER_KEY_FILE  "key.pem"

SSL_CTX *create_context() {
    SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
    if(!ctx) {
        wprintf(L"Unable to create SSL context");
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }

    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); //Tested with a callback function that return 1, still not work
    SSL_CTX_set_verify_depth(ctx, 4);
    SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION);
    SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(CA_CERT_FILE));

    if(!SSL_CTX_load_verify_locations(ctx, CA_CERT_FILE, NULL)) {
        printf("SSL_CTX_load_verify_locations error!\n");
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }

    if(SSL_CTX_use_certificate_file(ctx, SERVER_CERT_FILE, SSL_FILETYPE_PEM) <= 0) {
        printf("SSL_CTX_use_certificate_file error!\n");
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }

    if(SSL_CTX_use_PrivateKey_file(ctx, SERVER_KEY_FILE, SSL_FILETYPE_PEM) <= 0) {
        printf("SSL_CTX_use_PrivateKey_file error!\n");
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }

    if(!SSL_CTX_check_private_key(ctx)) {
        printf("SSL_CTX_check_private_key error!\n");
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }

    return ctx;
}
if(SSL_CTX_use_certificate_file(ctx, SERVER_CERT_FILE, SSL_FILETYPE_PEM) <= 0) {
  ...

这只设置服务器证书,不设置任何中间证书。我认为可以假设您使用的是公开颁发的证书(例如来自 Let's Encrypt),在这种情况下,很可能有一个(或多个)中间证书需要与服务器证书一起发送,以便 TLS client can build the trust chain to the locally trusted root certificate .

如果证书验证由于无法建立信任链而失败,客户端可能会生成一个 TLS 警报,如 unknown ca 并关闭连接。此收到的 TLS 警报是您当前在服务器端看到的。

如果缺少这些中间证书,一些 TLS 客户端将解决此错误配置并自行填写缺少的中间证书。但这通常只由浏览器完成,而不是由 Python、Java、C 等编程语言中的 TLS 堆栈完成,...。因此,可能是您的服务器在浏览器中工作,但在被不同的 TLS 客户端访问时无法工作,即使两者都使用同一组受信任的根证书。

解决方法是发送中间证书。这可以通过将服务器证书和中间件(按该顺序)放在同一个文件中并使用 SSL_CTX_use_certificate_chain_file 而不是 SSL_CTX_use_certificate_file.

来完成

除此之外,尚不清楚您的代码为何要求提供客户端证书。 Discord 很可能无法向您发送一个或不发送您期望的一个,这可能会导致其他问题。可能是你只是简单地从某个地方复制了代码并且不明白它在做什么,但就是这些行:

SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); //Tested with a callback function that return 1, still not work
SSL_CTX_set_verify_depth(ctx, 4);
...
SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(CA_CERT_FILE));