ssl socket bio整理
目前准备自己使用基于udp的ssl流传输数据。研究了一下ssl;测试了一下demo。
ssl_ctx = SSL_CTX_new(SSLv23_client_method()); // #define SSLv23_client_method TLS_client_method
//////ssl_ctx = SSL_CTX_new(SSLv23_method());
ssl = SSL_new(ssl_ctx); SSL_set_fd(ssl, sockfd);
SSL_set_connect_state(ssl);// s->handshake_func = s->method->ssl_connect;
if (SSL_connect(ssl) == -1)
SSL 创建:
TLS_method是怎么实现的,是通过定义了一个宏:
在methods.c文件中有如下的定义,
IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, 0, 0, TLS_client_method, ssl_undefined_function, ossl_statem_connect, TLSv1_2_enc_data)
IMPLEMENT_tls_meth_func 在ssl_locl.h中
/* Used to hold SSL/TLS functions */ struct ssl_method_st { int version; unsigned flags; unsigned long mask; int (*ssl_new) (SSL *s); int (*ssl_clear) (SSL *s); void (*ssl_free) (SSL *s); int (*ssl_accept) (SSL *s); int (*ssl_connect) (SSL *s); int (*ssl_read) (SSL *s, void *buf, size_t len, size_t *readbytes); int (*ssl_peek) (SSL *s, void *buf, size_t len, size_t *readbytes); int (*ssl_write) (SSL *s, const void *buf, size_t len, size_t *written); int (*ssl_shutdown) (SSL *s); int (*ssl_renegotiate) (SSL *s); int (*ssl_renegotiate_check) (SSL *s, int); int (*ssl_read_bytes) (SSL *s, int type, int *recvd_type, unsigned char *buf, size_t len, int peek, size_t *readbytes); int (*ssl_write_bytes) (SSL *s, int type, const void *buf_, size_t len, size_t *written); int (*ssl_dispatch_alert) (SSL *s); long (*ssl_ctrl) (SSL *s, int cmd, long larg, void *parg); long (*ssl_ctx_ctrl) (SSL_CTX *ctx, int cmd, long larg, void *parg); const SSL_CIPHER *(*get_cipher_by_char) (const unsigned char *ptr); int (*put_cipher_by_char) (const SSL_CIPHER *cipher, WPACKET *pkt, size_t *len); size_t (*ssl_pending) (const SSL *s); int (*num_ciphers) (void); const SSL_CIPHER *(*get_cipher) (unsigned ncipher); long (*get_timeout) (void); const struct ssl3_enc_method *ssl3_enc; /* Extra SSLv3/TLS stuff */ int (*ssl_version) (void); long (*ssl_callback_ctrl) (SSL *s, int cb_id, void (*fp) (void)); long (*ssl_ctx_callback_ctrl) (SSL_CTX *s, int cb_id, void (*fp) (void)); };
# define IMPLEMENT_tls_meth_func(version, flags, mask, func_name, s_accept, \ s_connect, enc_data) \ const SSL_METHOD *func_name(void) \ { \ static const SSL_METHOD func_name##_data= { \ version, \ flags, \ mask, \ tls1_new, \ tls1_clear, \ tls1_free, \ s_accept, \ s_connect, \ ssl3_read, \ ssl3_peek, \ ssl3_write, \ ssl3_shutdown, \ ssl3_renegotiate, \ ssl3_renegotiate_check, \ ssl3_read_bytes, \ ssl3_write_bytes, \ ssl3_dispatch_alert, \ ssl3_ctrl, \ ssl3_ctx_ctrl, \ ssl3_get_cipher_by_char, \ ssl3_put_cipher_by_char, \ ssl3_pending, \ ssl3_num_ciphers, \ ssl3_get_cipher, \ tls1_default_timeout, \ &enc_data, \ ssl_undefined_void_function, \ ssl3_callback_ctrl, \ ssl3_ctx_callback_ctrl, \ }; \ return &func_name##_data; \ }
宏定义替换为:
static const SSL_METHOD TLS_client_method_data= { \ TLS_ANY_VERSION, \ 0, \ 0, \ tls1_new, \ tls1_clear, \ tls1_free, \ ssl_undefined_function, \ ossl_statem_connect, \ ssl3_read, \ ssl3_peek, \ ssl3_write, \ ssl3_shutdown, \ ssl3_renegotiate, \ ssl3_renegotiate_check, \ ssl3_read_bytes, \ ssl3_write_bytes, \ ssl3_dispatch_alert, \ ssl3_ctrl, \ ssl3_ctx_ctrl, \ ssl3_get_cipher_by_char, \ ssl3_put_cipher_by_char, \ ssl3_pending, \ ssl3_num_ciphers, \ ssl3_get_cipher, \ tls1_default_timeout, \ &TLSv1_2_enc_data, \ ssl_undefined_void_function, \ ssl3_callback_ctrl, \ ssl3_ctx_callback_ctrl, \ };
ssl 代码分析:
1:建立一个BIO,BIO是OpenSSL提供的用来进行算法封装的处理结构,还可以将多个算法串联起来,这样可以很方便地实现数据的封装;/
2、把套接字和BIO联系
3、 把SSL和BIO联系起来,包括读写操作
// 设置SSL读写BIO s->rbio=rbio; s->wbio=wbio;
int SSL_set_fd(SSL *s, int fd) { int ret = 0; BIO *bio = NULL; bio = BIO_new(BIO_s_socket()); if (bio == NULL) { SSLerr(SSL_F_SSL_SET_FD, ERR_R_BUF_LIB); goto err; } BIO_set_fd(bio, fd, BIO_NOCLOSE); SSL_set_bio(s, bio, bio); ret = 1; err: return ret; } static const BIO_METHOD methods_sockp = { BIO_TYPE_SOCKET, "socket", /* TODO: Convert to new style write function */ bwrite_conv, sock_write, /* TODO: Convert to new style read function */ bread_conv, sock_read, sock_puts, NULL, /* sock_gets, */ sock_ctrl, sock_new, sock_free, NULL, /* sock_callback_ctrl */ }; const BIO_METHOD *BIO_s_socket(void) { return &methods_sockp; } BIO *BIO_new(const BIO_METHOD *method) { BIO *bio = OPENSSL_zalloc(sizeof(*bio)); if (bio == NULL) { BIOerr(BIO_F_BIO_NEW, ERR_R_MALLOC_FAILURE); return NULL; } bio->method = method; bio->shutdown = 1; bio->references = 1; if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data)) goto err; bio->lock = CRYPTO_THREAD_lock_new(); if (bio->lock == NULL) { BIOerr(BIO_F_BIO_NEW, ERR_R_MALLOC_FAILURE); CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data); goto err; } if (method->create != NULL && !method->create(bio)) { BIOerr(BIO_F_BIO_NEW, ERR_R_INIT_FAIL); CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data); CRYPTO_THREAD_lock_free(bio->lock); goto err; } if (method->create == NULL) bio->init = 1; return bio; err: OPENSSL_free(bio); return NULL; }
void SSL_set_accept_state(SSL *s) { s->server = 1; s->shutdown = 0; ossl_statem_clear(s); s->handshake_func = s->method->ssl_accept; clear_ciphers(s); } int SSL_do_handshake(SSL *s) { int ret = 1; if (s->handshake_func == NULL) { SSLerr(SSL_F_SSL_DO_HANDSHAKE, SSL_R_CONNECTION_TYPE_NOT_SET); return -1; } ossl_statem_check_finish_init(s, -1); s->method->ssl_renegotiate_check(s, 0); if (SSL_in_init(s) || SSL_in_before(s)) { if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) { struct ssl_async_args args; args.s = s; ret = ssl_start_async_job(s, &args, ssl_do_handshake_intern); } else { ret = s->handshake_func(s); // 在IMPLEMENT_tls_meth_func初始化中定义的,是ossl_statem_accept函数。 } } return ret; }
ssl 握手为: 在IMPLEMENT_tls_meth_func初始化中定义的,是ossl_statem_accept函数。
#include <stdio.h> #include <openssl/ssl.h> #include <openssl/err.h> #include <unistd.h> #include <arpa/inet.h> #include <string.h> #include <stdlib.h> // gcc -o sslbio sslbio.c -O0 -ggdb -I/usr/local/ssl/include -L/usr/local/ssl/lib -lssl -lcrypto struct connection { SSL_CTX *ssl_ctx; SSL *ssl; BIO *ssl_in; BIO *ssl_out; int sockfd; int failed; int write_alerts; } *conn; void init_conn() { SSL_CTX *ctx; SSL *ssl; long options; SSL_library_init(); OpenSSL_add_all_algorithms(); SSL_load_error_strings(); ctx = SSL_CTX_new(SSLv23_client_method()); if (!ctx) { ERR_print_errors_fp(stderr); exit(EXIT_FAILURE); } ssl = SSL_new(ctx); if (!ssl) { ERR_print_errors_fp(stderr); SSL_CTX_free(ctx); exit(EXIT_FAILURE); } conn->ssl_ctx = ctx; conn->ssl = ssl; SSL_set_app_data(conn->ssl, conn); SSL_set_msg_callback_arg(conn->ssl, conn); options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_SINGLE_DH_USE; SSL_set_options(conn->ssl, options); conn->ssl_in = BIO_new(BIO_s_mem()); conn->ssl_out = BIO_new(BIO_s_mem()); SSL_set_bio(conn->ssl, conn->ssl_in, conn->ssl_out); } void send_msg(uint8_t *buf, int len) { send(conn->sockfd, buf, len, 0); } int recvbuf_msg(uint8_t *buf, int bufsize) { int ret = 0; ret = recv(conn->sockfd, buf, bufsize, 0); return ret; } int connection_handshake() { char tmpbuf[10240]; char bufin[10240]; int res = 0; SSL_set_connect_state(conn->ssl); while (1) { res = SSL_connect(conn->ssl); if (res != 1) { int err = SSL_get_error(conn->ssl, res); if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { res = BIO_ctrl_pending(conn->ssl_out); if (res > 0) { res = BIO_read(conn->ssl_out, tmpbuf, sizeof(tmpbuf)); send_msg((uint8_t *)tmpbuf, res); } res = recvbuf_msg((uint8_t *)bufin, sizeof(bufin)); if (res > 0) { BIO_write(conn->ssl_in, bufin, res); } } else { conn->failed++; fprintf(stderr, "OpenSSL: Could not generate ClientHello\n"); conn->write_alerts++; return -1; } } if (SSL_is_init_finished(conn->ssl)) { printf("SSL handshake finished\n"); return 1; } } return 0; } void send_https_get_request() { const char *request = "GET / HTTP/1.1\r\nHost: www.baidu.com\r\nConnection: close\r\n\r\n"; int request_len = strlen(request); char tmpbuf[10240]; char bufin[10240]; int res; // Send the HTTP GET request SSL_write(conn->ssl, request, request_len); // Read the SSL data from the ssl_out BIO and send it to the socket res = BIO_ctrl_pending(conn->ssl_out); if (res > 0) { res = BIO_read(conn->ssl_out, tmpbuf, sizeof(tmpbuf)); send_msg((uint8_t *)tmpbuf, res); } // Receive the server response and feed it to ssl_in BIO while ((res = recvbuf_msg((uint8_t *)bufin, sizeof(bufin))) > 0) { BIO_write(conn->ssl_in, bufin, res); // Read decrypted data from SSL object while ((res = SSL_read(conn->ssl, tmpbuf, sizeof(tmpbuf) - 1)) > 0) { tmpbuf[res] = '\0'; printf("%s", tmpbuf); } if (res < 0) { int err = SSL_get_error(conn->ssl, res); if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { continue; } else { break; } } } } int main() { struct sockaddr_in server_addr; conn = (struct connection *)malloc(sizeof(struct connection)); init_conn(); conn->sockfd = socket(AF_INET, SOCK_STREAM, 0); if (conn->sockfd < 0) { perror("Socket creation failed"); exit(EXIT_FAILURE); } server_addr.sin_family = AF_INET; server_addr.sin_port = htons(443); inet_pton(AF_INET, "183.2.172.42", &server_addr.sin_addr); // www.baidu.com if (connect(conn->sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { perror("Connection failed"); close(conn->sockfd); exit(EXIT_FAILURE); } if (connection_handshake() == 1) { printf("Handshake successful\n"); send_https_get_request(); } else { printf("Handshake failed\n"); } close(conn->sockfd); SSL_free(conn->ssl); SSL_CTX_free(conn->ssl_ctx); free(conn); return 0; }
http代理服务器(3-4-7层代理)-网络事件库公共组件、内核kernel驱动 摄像头驱动 tcpip网络协议栈、netfilter、bridge 好像看过!!!!
但行好事 莫问前程
--身高体重180的胖子
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
2021-06-14 tcp ip 三次握手时数据结构-