gpt4 book ai didi

c - C 中的 SSL/HTTPS 客户端

转载 作者:太空宇宙 更新时间:2023-11-04 08:32:21 25 4
gpt4 key购买 nike

我使用我发现的一些示例代码用 C 语言编写了一个简单的 SSL/HTTPS 客户端,当我使用它向 https 服务器发送 GET 请求时,我收到了一个不寻常的响应,这是来自 stackoverflow.com 的响应:

HTTP/1.1 200 OK Cache-Control: public, no-cache="Set-Cookie", max-age=36 Content-Type: text/html; charset=utf-8 Expires: Sat, 03 Jan 2015 16:54:57 GMT Last-Modified: Sat, 03 Jan 2015 16:53:57 GMT Vary: * X-Frame-Options: SAMEORIGIN Set-Cookie: prov=407726d8-1493-4ebd-8657-8958be5b2683; domain=.stackoverflow.com; expires=Fri, 01-Jan-2055 00:00:00 GMT; path=/; HttpOnly Date: Sat, 03 Jan 2015 16:54:20 GMT Content-Length: 239129

<title>Stack Overflow</title>
<link rel="shortcut icon" href="//cdn.sstatic.net/stackoverflow/img/favicon.ico?v=038622610830">
<link rel="apple-touch-icon image_src" href="//cdn.sstatic.net/stackoverflow/img/apple-touch-icon.png?v=fd7230a85918">
<link rel="search" type="application/opensearchdescription+xml" title="Stack Overflow" href="/opensearch.xml">
<meta name="twitter:card" content="summary">
<meta name="twitter:domain" content="stackoverflow.com"/>
<meta property="og:type" content="website" />
<meta property="og:image" itemprop="image primaryImageOfPage" content="http://cdn.sstatic.net/stackoverflow/img/apple-touch-icon@2.png?v=fde65a5a78c6"

/>

当我使用 openssl 命令行工具执行相同的操作时,我得到一个包含索引页的正常响应。我试过更改一些代码并遵循不同的教程,但似乎没有任何效果。如何让程序返回索引页面而不是我当前得到的响应?,这里是程序的源代码:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

/**
* Simple log function
*/
void slog(char* message) {
fprintf(stdout, message);
}

/**
* Print SSL error details
*/
void print_ssl_error(char* message, FILE* out) {

fprintf(out, message);
fprintf(out, "Error: %s\n", ERR_reason_error_string(ERR_get_error()));
fprintf(out, "%s\n", ERR_error_string(ERR_get_error(), NULL));
ERR_print_errors_fp(out);
}

/**
* Print SSL error details with inserted content
*/
void print_ssl_error_2(char* message, char* content, FILE* out) {

fprintf(out, message, content);
fprintf(out, "Error: %s\n", ERR_reason_error_string(ERR_get_error()));
fprintf(out, "%s\n", ERR_error_string(ERR_get_error(), NULL));
ERR_print_errors_fp(out);
}

/**
* Initialise OpenSSL
*/
void init_openssl() {

/* call the standard SSL init functions */
SSL_load_error_strings();
SSL_library_init();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();

/* seed the random number system - only really nessecary for systems without '/dev/random' */
/* RAND_add(?,?,?); need to work out a cryptographically significant way of generating the seed */
}


/**
* Connect to a host using an encrypted stream
*/
BIO* connect_encrypted(char* host_and_port, char* store_path, SSL_CTX** ctx, SSL** ssl) {

BIO* bio = NULL;
int r = 0;

/* Set up the SSL pointers */
*ctx = SSL_CTX_new(TLSv1_client_method());
*ssl = NULL;
r = SSL_CTX_load_verify_locations(*ctx, store_path, NULL);

if (r == 0) {

print_ssl_error_2("Unable to load the trust store from %s.\n", store_path, stdout);
return NULL;
}

/* Setting up the BIO SSL object */
bio = BIO_new_ssl_connect(*ctx);
BIO_get_ssl(bio, ssl);
if (!(*ssl)) {

print_ssl_error("Unable to allocate SSL pointer.\n", stdout);
return NULL;
}
SSL_set_mode(*ssl, SSL_MODE_AUTO_RETRY);

/* Attempt to connect */
BIO_set_conn_hostname(bio, host_and_port);

/* Verify the connection opened and perform the handshake */
if (BIO_do_connect(bio) < 1) {

print_ssl_error_2("Unable to connect BIO.%s\n", host_and_port, stdout);
return NULL;
}

if (SSL_get_verify_result(*ssl) != X509_V_OK) {

print_ssl_error("Unable to verify connection result.\n", stdout);
}

return bio;
}

/**
* Read a from a stream and handle restarts if nessecary
*/
ssize_t read_from_stream(BIO* bio, char* buffer, ssize_t length) {

ssize_t r = -1;

while (r < 0) {

r = BIO_read(bio, buffer, length);
if (r == 0) {

print_ssl_error("Reached the end of the data stream.\n", stdout);
continue;

} else if (r < 0) {

if (!BIO_should_retry(bio)) {

print_ssl_error("BIO_read should retry test failed.\n", stdout);
continue;
}

/* It would be prudent to check the reason for the retry and handle
* it appropriately here */
}

};

return r;
}

/**
* Write to a stream and handle restarts if nessecary
*/
int write_to_stream(BIO* bio, char* buffer, ssize_t length) {

ssize_t r = -1;

while (r < 0) {

r = BIO_write(bio, buffer, length);
if (r <= 0) {

if (!BIO_should_retry(bio)) {

print_ssl_error("BIO_read should retry test failed.\n", stdout);
continue;
}

/* It would be prudent to check the reason for the retry and handle
* it appropriately here */
}

}

return r;
}

/**
* Main SSL demonstration code entry point
*/
int main() {

char* host_and_port = "stackoverflow.com:443";
char* server_request = "GET / HTTP/1.1\r\nHost: stackoverflow.com\r\n\r\n";
char* store_path = "mycert.pem";
char buffer[4096];
buffer[0] = 0;

BIO* bio;
SSL_CTX* ctx = NULL;
SSL* ssl = NULL;

/* initilise the OpenSSL library */
init_openssl();

if ((bio = connect_encrypted(host_and_port, store_path, &ctx, &ssl)) == NULL)
return (EXIT_FAILURE);


write_to_stream(bio, server_request, strlen(server_request));
read_from_stream(bio, buffer, 4096);
printf("%s\r\n", buffer);

/* clean up the SSL context resources for the encrypted link */
SSL_CTX_free(ctx);

return (EXIT_SUCCESS);
}

最佳答案

您调用 read_from_stream 最多读取 4096 个字节,但答案可能比这长得多。您必须重试读取直到调用返回 0。您还必须在每次读取之前清理缓冲区。像这样:

int l;
bzero(buffer,4096); // clean the buffer
while (l=read_from_stream(bio,buffer,4096)) { // try to read 4096 bytes from stream to buffer
printf("%s",buffer); // write exactly what was read...
bzero(buffer,4096); // clean the buffer
}

注意服务器可以向您发送 ASCII nul 字节(在 HTML 页面中很少见,但可能用于其他类型的数据)...此代码没有考虑到这一点。

通常你必须解码标题,并解码 Content-Length: 一个。它旨在为您提供要在 HTTP header 之后读取的数据字节数(在您的示例中为 239129)。

关于c - C 中的 SSL/HTTPS 客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27757515/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com