c语言利用openssl实现简单客户端和服务端(观察记录层最大长度)


前言

本文是使用openssl111w实现的简单客户端和服务端,主要用于观察openssl一个记录层数据包的大小。


一、客户端实现

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h>  
#include <sys/types.h>   
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <openssl/ssl.h>  
#include <openssl/err.h>  
#define PORT 8000
#define SERVER_IP "127.0.0.1"
#define SERVER_KEY "./rsa_cert/serverkey.pem"
#define SERVER_CERT "./rsa_cert/servercert.pem"
#define CA_CERT "./rsa_cert/cacert.pem"
// 初始化OpenSSL库 
void init_openssl() {  
    SSL_load_error_strings();  
    OpenSSL_add_all_algorithms();  
    SSL_library_init();  
}  
//创建原始套接字
int create_connect_fd()
{
    struct sockaddr_in serv_addr;
    int client_fd;
    
    // 创建socket
    if ((client_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("\n Socket creation error \n");
        return -1;
    }
    
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    
    // 使用inet_pton转换IP字符串为网络字节序
    if(inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr)<=0)
    {
        printf("\nInvalid address/ Address not supported \n");
        return -1;
    }
    
    // 连接服务器
    if (connect(client_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
    {
        printf("\nConnection Failed \n");
        return -1;
    }
    return client_fd;
}
//创建ssl上下文
SSL_CTX* create_ssl_ctx() {  
    const SSL_METHOD *method;  
    SSL_CTX *ctx;  
  
    method = TLSv1_2_client_method();  
    ctx = SSL_CTX_new(method);  
    if (!ctx) {  
        printf("Unable to create SSL context");  
        ERR_print_errors_fp(stderr);  
        return NULL;
    } 
        // 加载服务器证书和私钥  
    if (SSL_CTX_use_certificate_file(ctx, SERVER_CERT, SSL_FILETYPE_PEM) <= 0) {  
        ERR_print_errors_fp(stderr); 
        printf("load server cert failed\n"); 
        return NULL;  
    }  
  
    if (SSL_CTX_use_PrivateKey_file(ctx, SERVER_KEY, SSL_FILETYPE_PEM) <= 0) {  
        ERR_print_errors_fp(stderr);  
        printf("load server key failed\n");
        return NULL;
    }  
  
    // 检查私钥和证书是否匹配  
    if (!SSL_CTX_check_private_key(ctx)) {  
        printf("cert and key mismatch\n");
        return NULL;
    }   
	//加载CA证书
    if (!SSL_CTX_load_verify_locations(ctx, CA_CERT, NULL)) {  
        printf("load ca cert failed\n");
        return NULL; 
    }  
      //必须验证服务端证书,不设置则不验证
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);  
    return ctx;  
}  


int main()
{
    SSL_CTX *ctx;
    SSL *ssl;
    int client_fd,send_len;
    char buf[102400] = {0};

    /* 初始化SSL库 */
    init_openssl();

    /* 创建SSL_CTX结构体 */
    ctx = create_ssl_ctx();  
    if(ctx == NULL)
    {
        printf("create ssl ctx failed\n");
        return -1;
    }
    /* TCP协议连接到服务器 */
    client_fd = create_connect_fd(); 
    if(client_fd < 0)
    {
        printf("create client fd failed\n");
        return -1;
    }
    //创建ssl对象
    ssl = SSL_new(ctx);
    SSL_set_fd(ssl, client_fd);
	//ssl握手
    if (SSL_connect(ssl) == -1) {
        ERR_print_errors_fp(stderr);
        return -1;
    }

    printf("Connected with %s encryption\n", SSL_get_cipher(ssl));

    /* 发送数据 */
    send_len = SSL_write(ssl, buf, sizeof(buf));
    if(send_len < 0)
    {
        printf("SSL_write failed\n");
    }
    else
    {
        printf("write len:%d\n", send_len);
    }
    SSL_shutdown(ssl);
    SSL_free(ssl);
    close(client_fd);
    SSL_CTX_free(ctx);
    return 0;
}

二、服务端实现

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h>  
#include <sys/types.h>   
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <openssl/ssl.h>  
#include <openssl/err.h>  
#define PORT 8000
#define SERVER_KEY "./rsa_cert/serverkey.pem"
#define SERVER_CERT "./rsa_cert/servercert.pem"
#define CA_CERT "./rsa_cert/cacert.pem"
// 初始化OpenSSL库  
void init_openssl() {  
    SSL_load_error_strings();  
    OpenSSL_add_all_algorithms();  
    SSL_library_init();  
}  
   
// 创建ssl上下文 
SSL_CTX* create_ssl_ctx() {  
    const SSL_METHOD *method;  
    SSL_CTX *ctx;  
  
    OpenSSL_add_ssl_algorithms();  
    method = TLSv1_2_server_method();  
    ctx = SSL_CTX_new(method);  
    if (!ctx) {  
        printf("Unable to create SSL context");  
        ERR_print_errors_fp(stderr);  
        return NULL;
    }  
    // 加载服务器证书和私钥  
    if (SSL_CTX_use_certificate_file(ctx, SERVER_CERT, SSL_FILETYPE_PEM) <= 0) {  
        ERR_print_errors_fp(stderr); 
        printf("load server cert failed\n"); 
        return NULL;  
    }  
  
    if (SSL_CTX_use_PrivateKey_file(ctx, SERVER_KEY, SSL_FILETYPE_PEM) <= 0) {  
        ERR_print_errors_fp(stderr);  
        printf("load server key failed\n");
        return NULL;
    }  
  
    // 检查私钥和证书是否匹配  
    if (!SSL_CTX_check_private_key(ctx)) {  
        printf("cert and key mismatch\n");
        return NULL;
    }  

    if (!SSL_CTX_load_verify_locations(ctx, CA_CERT, NULL)) {  
        printf("load ca cert failed\n");
        return NULL; 
    }  
    //必须验证服务端证书,不设置则不验证
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);  
  
    return ctx;  
}  
//创建监听套接字
int create_listenfd()
{
    int listen_fd;
    struct sockaddr_in server_addr;
    int opt = 1;
    if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
    {
        printf("socket failed\n");
        return -1;
    }
    
    // 设置socket选项,允许重复使用地址
    if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR,&opt, sizeof(opt)))
    {
        printf("setsockopt failed\n");
        return -1;
    }
    
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(PORT);
    
    // 绑定socket到指定地址和端口
    if (bind(listen_fd, (struct sockaddr *)&server_addr, 
                                sizeof(server_addr))<0)
    {
        printf("bind failed\n");
        return -1;
    }
    // 开始监听,最大等待队列长度为5
    if (listen(listen_fd, 5) < 0)
    {
        printf("listen failed\n");
        return -1;
    }
    return listen_fd;
}
  

int main() {  
    int listen_fd,con_fd,recv_len;
    char buf[20480] = {0};
    init_openssl();  
    //创建ssl上下文
    SSL_CTX *ctx = create_ssl_ctx();  
    if(ctx == NULL)
    {
        printf("create ssl ctx failed\n");
        return -1;
    }
    //创建监听套接字
    listen_fd = create_listenfd();
    if(listen_fd < 0)
    {
        printf("create listen fd failed\n");
        return -1;
    }

    while(1) {
        struct sockaddr_in client_addr;
        socklen_t len = sizeof(client_addr);
        SSL *ssl;
        //等待客户端发起tcp链接
        con_fd = accept(listen_fd, (struct sockaddr*)&client_addr, &len);
        if(con_fd < 0)
        {
            printf("create connetct fd failed\n");
            return -1;
        }
        printf("create connect fd success\n");

        ssl = SSL_new(ctx);
        SSL_set_fd(ssl, con_fd);
        //等待ssl握手
        if (SSL_accept(ssl) == -1) {
            ERR_print_errors_fp(stderr);
            return -1;
        } 
        printf("SSL Connection established\n");
        for (;;) {
          //读取ssl数据
            recv_len = SSL_read(ssl, buf, sizeof(buf));
            if (recv_len > 0)
                printf("Received_len:%d \n", recv_len);
            else {
                ERR_print_errors_fp(stderr);
                break;
            }
        }
        SSL_shutdown(ssl);
        SSL_free(ssl);
        close(con_fd);
    }

    SSL_CTX_free(ctx);
    close(listen_fd);
    return 0;  
}

总结

服务端ssl_read能够接受的最大数据包是16384(2^14)字节,也就是一个记录层的最大数据。
在这里插入图片描述

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值