"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));
我正在用 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));