在指定端口上与 OpenSSL 建立 SSL 连接
我必须使用 SSL 连接到 URL host/getdata?reqtype=generate&login=xxx&pass=xxx&dest=yyy 的某个服务器。
我正在使用下面显示的代码片段,但无法从服务器获取任何数据。
CRYPTO_malloc_init();
SSL_library_init();
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
SSL_CTX* ctx = SSL_CTX_new(SSLv23_client_method());
SSL* ssl;
BIO* bio = BIO_new_ssl_connect(ctx);
char *host = "host:8888";
char *con_protocol = "";
const char *REQUEST_PROTO = "GET /getdata?reqtype=generate&login=xxx&pass=xxx&dest=yyy HTTP/1.1\nHost: %s\nAccept: */*\nConnection: keep-alive\n\n";
char *con_string = (char*)calloc((strlen(host)+strlen(con_protocol))+1, sizeof(char));
strcat(con_string, host);
strcat(con_string, con_protocol);
// Failure?
if (bio == NULL) {
printf("Error creating BIO!\n");
ERR_print_errors_fp(stderr);
// We need to free up the SSL_CTX before we leave.
SSL_CTX_free(ctx);
return;
}
// Makes ssl point to bio's SSL object.
BIO_get_ssl(bio, &ssl);
// Set the SSL to automatically retry on failure.
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
printf("connection string : %s\n", con_string);
BIO_set_conn_hostname(bio, con_string);
// Same as before, try to connect.
int y = BIO_do_connect(bio);
if (y <= 0) {
printf("Failed to connect!\nError code : %d\n", y);
BIO_free_all(bio);
SSL_CTX_free(ctx);
return;
}
// Now we need to do the SSL handshake, so we can communicate.
if (BIO_do_handshake(bio) <= 0) {
printf("Failed to do SSL handshake!\n");
BIO_free_all(bio);
SSL_CTX_free(ctx);
return;
}
// Create a buffer for grabbing information from the page.
char buf[1024];
memset(buf, 0, sizeof(buf));
// Create a buffer for the reqest we'll send to the server
char send[1024];
memset(send, 0, sizeof(send));
size_t total_size = strlen(REQUEST_PROTO)+strlen(host);
int t_size = (int)total_size+1;
char *my_buf = malloc(t_size*sizeof(char));
snprintf(my_buf, t_size, REQUEST_PROTO, host);
printf("my_buf : %s\n", my_buf);
BIO_puts(bio, my_buf);
int temp = 0;
int begin = 0;
char *key_buff = (char *)calloc(32, sizeof(char));
while (1) {
int bytes_read = BIO_read(bio, buf, sizeof(buf) - 1);
printf("bytes_read == %d\n", bytes_read);
if (bytes_read == 0) {
break;
}
else if (bytes_read < 0) {
if (!BIO_should_retry(bio)) {
printf("\nRead Failed!\n");
BIO_free_all(bio);
SSL_CTX_free(ctx);
return;
}
}
// We actually got some data, without errors!
else {
// Null-terminate our buffer, just in case
buf[bytes_read] = 0;
if ((bytes_read != 0) && (temp)) {
for (begin; begin<(bytes_read+begin); begin++) {
key_buff[begin] = buf[begin];
}
}
if (!temp) {
temp = bytes_read;
}
}
}
BIO_free_all(bio);
SSL_CTX_free(ctx);
printf("key : %s\n\n", buf);
我已经检查了与 CURL 的连接。 使用命令时 curl --insecure 'https://localhost:8888/getdata?reqtype=generate&login=xxx&pass=xxx&dest=yyy'
一切正常,但是当我从命令中删除“http”时,我得到了与应用程序中一样的空响应。不幸的是,我无法在 BIO_set_conn_hostname() 函数中添加“http”。 有些想法有什么问题?
I have to connect to some server with URL host/getdata?reqtype=generate&login=xxx&pass=xxx&dest=yyy using SSL.
I'm using code snippet shown below but I can't get any data from server.
CRYPTO_malloc_init();
SSL_library_init();
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
SSL_CTX* ctx = SSL_CTX_new(SSLv23_client_method());
SSL* ssl;
BIO* bio = BIO_new_ssl_connect(ctx);
char *host = "host:8888";
char *con_protocol = "";
const char *REQUEST_PROTO = "GET /getdata?reqtype=generate&login=xxx&pass=xxx&dest=yyy HTTP/1.1\nHost: %s\nAccept: */*\nConnection: keep-alive\n\n";
char *con_string = (char*)calloc((strlen(host)+strlen(con_protocol))+1, sizeof(char));
strcat(con_string, host);
strcat(con_string, con_protocol);
// Failure?
if (bio == NULL) {
printf("Error creating BIO!\n");
ERR_print_errors_fp(stderr);
// We need to free up the SSL_CTX before we leave.
SSL_CTX_free(ctx);
return;
}
// Makes ssl point to bio's SSL object.
BIO_get_ssl(bio, &ssl);
// Set the SSL to automatically retry on failure.
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
printf("connection string : %s\n", con_string);
BIO_set_conn_hostname(bio, con_string);
// Same as before, try to connect.
int y = BIO_do_connect(bio);
if (y <= 0) {
printf("Failed to connect!\nError code : %d\n", y);
BIO_free_all(bio);
SSL_CTX_free(ctx);
return;
}
// Now we need to do the SSL handshake, so we can communicate.
if (BIO_do_handshake(bio) <= 0) {
printf("Failed to do SSL handshake!\n");
BIO_free_all(bio);
SSL_CTX_free(ctx);
return;
}
// Create a buffer for grabbing information from the page.
char buf[1024];
memset(buf, 0, sizeof(buf));
// Create a buffer for the reqest we'll send to the server
char send[1024];
memset(send, 0, sizeof(send));
size_t total_size = strlen(REQUEST_PROTO)+strlen(host);
int t_size = (int)total_size+1;
char *my_buf = malloc(t_size*sizeof(char));
snprintf(my_buf, t_size, REQUEST_PROTO, host);
printf("my_buf : %s\n", my_buf);
BIO_puts(bio, my_buf);
int temp = 0;
int begin = 0;
char *key_buff = (char *)calloc(32, sizeof(char));
while (1) {
int bytes_read = BIO_read(bio, buf, sizeof(buf) - 1);
printf("bytes_read == %d\n", bytes_read);
if (bytes_read == 0) {
break;
}
else if (bytes_read < 0) {
if (!BIO_should_retry(bio)) {
printf("\nRead Failed!\n");
BIO_free_all(bio);
SSL_CTX_free(ctx);
return;
}
}
// We actually got some data, without errors!
else {
// Null-terminate our buffer, just in case
buf[bytes_read] = 0;
if ((bytes_read != 0) && (temp)) {
for (begin; begin<(bytes_read+begin); begin++) {
key_buff[begin] = buf[begin];
}
}
if (!temp) {
temp = bytes_read;
}
}
}
BIO_free_all(bio);
SSL_CTX_free(ctx);
printf("key : %s\n\n", buf);
I've checked connection with CURL.
When using commandcurl --insecure 'https://localhost:8888/getdata?reqtype=generate&login=xxx&pass=xxx&dest=yyy'
everything works, but when I remove 'http' from command, I get empty response as in the application. Unfortunately I can't add 'http' in BIO_set_conn_hostname() function.
Some ideas what is wrong?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
Duskwuff 是对的,因为您显然是通过 https 连接,所以使用更高级别的 cURL 会更容易(您可以使用 libcurl 以编程方式使用它)。否则,您将必须自己处理协议的 HTTP 部分。
如果这对你来说可以接受,那么我认为问题在于你的 BIO 没有缓冲,这就是为什么你没有使用 BIO_puts 从服务器获取任何数据。另请参阅这个精彩的教程:
使用两个 BIO(一个用于 SSL,一个用于缓冲)应该可以解决您的问题。
Duskwuff is right, since you are apparently connecting via https, it would be much easier for you to use something higher level as cURL (you can use it programmatically using libcurl). Otherwise you'll have to handle the HTTP part of the protocol all by yourself.
If that's acceptable for you, then I think the problem is that your BIO is not buffered, and that's why you don't get any data from the server using BIO_puts. See also this excellent turorial:
Using two BIOs (one for SSL, one for buffering) should solve your problem.