c - C 使用 openssl 执行 HTTPS 请求
问题描述
我是 C 语言的新手,我正在尝试在 Linux Ubuntu 18.04 中使用 OpenSSL 执行简单的 SSL GET 请求。我在Simple C example of doing an HTTP POST and consumption the response 中找到了这个
#include <stdio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#define HOST "www.google.com"
#define PORT "443"
int main() {
//
// Initialize the variables
//
BIO* bio;
SSL* ssl;
SSL_CTX* ctx;
//
// Registers the SSL/TLS ciphers and digests.
//
// Basically start the security layer.
//
SSL_library_init();
//
// Creates a new SSL_CTX object as a framework to establish TLS/SSL
// or DTLS enabled connections
//
ctx = SSL_CTX_new(SSLv23_client_method());
//
// -> Error check
//
if (ctx == NULL)
{
printf("Ctx is null\n");
}
//
// Creates a new BIO chain consisting of an SSL BIO
//
bio = BIO_new_ssl_connect(ctx);
//
// Use the variable from the beginning of the file to create a
// string that contains the URL to the site that you want to connect
// to while also specifying the port.
//
BIO_set_conn_hostname(bio, HOST ":" PORT);
//
// Attempts to connect the supplied BIO
//
if(BIO_do_connect(bio) <= 0)
{
printf("Failed connection\n");
return 1;
}
else
{
printf("Connected\n");
}
//
// The bare minimum to make a HTTP request.
//
char* write_buf = "GET / HTTP/1.1\r\n"
"Host: " HOST "\r\n"
"Connection: close\r\n"
"\r\n";
//
// Attempts to write len bytes from buf to BIO
//
if(BIO_write(bio, write_buf, strlen(write_buf)) <= 0)
{
//
// Handle failed writes here
//
if(!BIO_should_retry(bio))
{
// Not worth implementing, but worth knowing.
}
//
// -> Let us know about the failed writes
//
printf("Failed write\n");
}
//
// Variables used to read the response from the server
//
int size;
char buf[1024];
//
// Read the response message
//
for(;;)
{
//
// Get chunks of the response 1023 at the time.
//
size = BIO_read(bio, buf, 1023);
//
// If no more data, then exit the loop
//
if(size <= 0)
{
break;
}
//
// Terminate the string with a 0, to let know C when the string
// ends.
//
buf[size] = 0;
//
// -> Print out the response
//
printf("%s", buf);
}
//
// Clean after ourselves
//
BIO_free_all(bio);
SSL_CTX_free(ctx);
return 0;
}
此代码运行良好,但对于某些网站,例如ghostbin.co,连接失败......是什么原因造成的?我使用gcc test.c -o test -lssl -lcrypto
. 我正在使用 OpenSSL 1.1.1 2018 年 9 月 11 日
解决方案
几乎总是当 OpenSSL 例程返回错误指示时,您可以并且应该从错误堆栈中获取附加信息;请参阅https://www.openssl.org/docs/faq.html#PROG8和手册页,例如
https://www.openssl.org/docs/manmaster/man3/ERR_print_errors.html
https://www.openssl。 org/docs/manmaster/man3/ERR_get_error.html
https://www.openssl.org/docs/manmaster/man3/ERR_error_string.html
https://www.openssl.org/docs/manmaster/man3/ERR_load_crypto_strings.html
但是在这种情况下,它只会告诉您服务器通过发送警报 40 中止了握手,这是 SSL/TLS 中信息量较少的警报代码之一。需要一点知识才能在 CloudFlare 上找到 ghostbin.co,它要求连接使用服务器名称指示(也称为 SNI)——本世纪许多 SSL/TLS 服务器都是如此(因为顶级 IPv4 耗尽),尤其是那些像 CDN 服务或共享主机一样共享。OpenSSL API 确实允许客户端发送 SNI,但仅使用每个连接的 SSL 对象而不是 SSL_CTX,并且使用(相当陈旧且相当老旧的)BIO_ssl,SSL 对象被隐藏,因此您需要BIO_get_ssl(bio,&sslptr)
然后SSL_set_tlsext_host_name(sslptr,name)
(尽管我注意到手册页的 const 错误;这确实是一个使用宏SSL_ctrl
它需要一个绝对非常量的指针)。
推荐阅读
- angular - Angular Material 6:无法读取 MatHeaderRowDef 表中未定义的属性“查找”
- r - 每年按月计算因子水平
- python - 在 Python 中安装包 mapclassify 时出错
- react-native - 在 react-native 中导航时检测键盘模式
- c# - RSA加密:参数不正确
- wordpress - Wordpress 从用户那里获取帖子[关系]
- java - 在本地计算机上使用 DynamoDB 进行非常慢的保存操作
- docker - 在 Docker 中运行 Keycloak 时出错
- windows - 使用 PowerShell 的 SOAP Web 服务的正确参数数量
- python - 为什么 Psycopg 提供 `cursor` 的方法(`copy_to()`、`copy_from()`),而不是调用 `cursor.execute()` 来发送 `COPY` 命令?