openSSL编程

目录

1、ssl服务初始化

2、服务端初始化

3、客户端初始化

4、封装ssl握手函数

5、封装SSL_read函数

6、封装SSL_write函数

7、demo示例

8、总结与说明


1、ssl服务初始化

void ssl_service_init(void)
{
	//ssl库初始化
    SSL_library_init(); 
    //载入ssl算法
    OpenSSL_add_all_algorithms();
    //载入ssl错误消息
    SSL_load_error_strings();
}

2、服务端初始化

SSL_CTX *ssl_server_init(int verify_type, const char *ca, const char *user_cert, const char *user_key)
{
	//创建SSL_CTX Content Text),兼容 ssl v2 和 v3 版本
    //SSLv2_server_method() v2, SSLv3_server_method() v3
    SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
    if (ctx == NULL) 
    {
        ERR_print_errors_fp(stderr);
        return NULL;
    }

    if (verify_type == SSL_VERIFY_NONE)
    {
    	//单向认证:SSL_VERIFY_NONE 不认证对方
	 	SSL_CTX_set_verify(ctx,SSL_VERIFY_NONE,NULL);   
    }
    else if (verify_type == SSL_VERIFY_PEER)
    {
    	//双向验证
	    //SSL_VERIFY_PEER:要求对证书进行认证,没有证书也会放行
	    //SSL_VERIFY_FAIL_IF_NO_PEER_CERT:要求客户端需要提供证书,但验证发现单独使用没有证书也会放行
    	SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
    	//设置信任根证书
	    if (SSL_CTX_load_verify_locations(ctx, ca, NULL) <= 0)
	    {
	        ERR_print_errors_fp(stderr);
	        SSL_CTX_free(ctx);
	        return NULL;
	    }
    }
    else
    {
    	SSL_CTX_free(ctx);
    	return NULL;
    }	

     //载入用户的数字证书,此证书用来发送给客户端,证书里包含有公钥
    if (SSL_CTX_use_certificate_file(ctx, user_cert, SSL_FILETYPE_PEM) <= 0) 
    {
        ERR_print_errors_fp(stderr);
        SSL_CTX_free(ctx);
        return NULL;
    }
    //载入用户私钥
    if (SSL_CTX_use_PrivateKey_file(ctx, user_key, SSL_FILETYPE_PEM) <= 0) 
    {
        ERR_print_errors_fp(stderr);
        SSL_CTX_free(ctx);
        return NULL;
    }
    //检查用户私钥是否正确
    if (!SSL_CTX_check_private_key(ctx)) 
    {
        ERR_print_errors_fp(stderr);
        SSL_CTX_free(ctx);
        return NULL;
    }

    return ctx;
}

3、客户端初始化

SSL_CTX *ssl_client_init(int verify_type, const char *ca, const char *user_cert, const char *user_key)
{
	SSL_CTX *ctx = SSL_CTX_new(SSLv23_client_method());
    if (ctx == NULL) {
        ERR_print_errors_fp(stderr);
        return NULL;
    }

    if (verify_type == SSL_VERIFY_NONE)
    {
		SSL_CTX_set_verify(ctx,SSL_VERIFY_NONE,NULL);
    }
    else if (verify_type == SSL_VERIFY_PEER)
    {
    	SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
	    if (SSL_CTX_load_verify_locations(ctx, ca,NULL) <= 0)
	    {
	        ERR_print_errors_fp(stderr);
	        SSL_CTX_free(ctx);
	        return NULL;
	    }

	    if (SSL_CTX_use_certificate_file(ctx, user_cert, SSL_FILETYPE_PEM) <= 0) 
	    {
	        ERR_print_errors_fp(stderr);
	        SSL_CTX_free(ctx);
	        return NULL;
	    }
	    
	    if (SSL_CTX_use_PrivateKey_file(ctx, user_key, SSL_FILETYPE_PEM) <= 0) 
	    {
	        ERR_print_errors_fp(stderr);
	        SSL_CTX_free(ctx);
	        return NULL;
	    }
	    
	    if (!SSL_CTX_check_private_key(ctx)) 
	    {
	        ERR_print_errors_fp(stderr);
	        SSL_CTX_free(ctx);
	        return NULL;
	    }
    }
    else
    {
    	SSL_CTX_free(ctx);
    	return NULL;
    }	

    return ctx;
}

4、封装ssl握手函数

/*
	handshake_type:	1 connect 状态 
					2 accept 状态
 */
SSL *sslDoHandshake(int handshake_type, SSL_CTX *ctx, int fd, int *err_code)
{
    if (ctx == NULL)
	{
		return NULL;
	}
    //基于 ctx 创建一个新的 SSL 句柄
    SSL *ssl = SSL_new(ctx);
	if (!ssl)
	{
		ssl = NULL;
		return NULL;
	}
    //将 socket 加入到 SSL
    if (!SSL_set_fd(ssl, fd))
    {
        SSL_free(ssl);
		ssl = NULL;
		return NULL;
	}

	if (handshake_type == 1)
	{
		//设置 SSL 为 connect 状态 
		SSL_set_connect_state(ssl);
	}
	else if (handshake_type == 2)
	{
		//设置 SSL 为 accept 状态 
    	SSL_set_accept_state(ssl);
	}
	else
	{
		SSL_free(ssl);
		ssl = NULL;
		return NULL;
	}

	int ret, err, cnt = 0;
	
	while ((ret = SSL_do_handshake(ssl)) != 1)
	{
		err = SSL_get_error(ssl, ret);
		if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ)
		{	
			usleep(100*1000);
			cnt++;
			if (cnt == 10)  //防止 SSL_do_handshake 一直失败,无法跳出循环
			{
        		SSL_free(ssl);
				ssl = NULL;
				break;	
			}
			continue;
		}
		else
		{
			*err_code = err;
			//err == 5 SSL_ERROR_SYSCALL 关闭相关资源,重新连接
			
			printf("SSL_do_handshake failed, err_code : %d\n", err);
			ERR_print_errors_fp(stderr);
            SSL_shutdown(ssl);
        	SSL_free(ssl);
			ssl = NULL;
			break;
		}
	}
	
	printf("SSL_do_handshake, ret : %d\n", ret);
    return ssl;	
}

5、封装SSL_read函数

/*
 	SSL_read(SSL *ssl,char *buf,int num)
	正常:返回1到num个字节数
	错误:返回0或负数
*/
int sslRead(SSL *ssl, int fd, char *buf, int len, int timeout)
{
	if (ssl == NULL)
	{
		return -1;
	}
	
	int err, res, ret, bytes = 0, cnt = 0;
    fd_set rfds;  
    struct timeval tv;  
    
    if (timeout > 0)
	{
	    FD_ZERO(&rfds);  
    	FD_SET(fd, &rfds); 
	}

	do
	{	
        if (timeout > 0)
		{
			tv.tv_sec = timeout/1000;  
	    	tv.tv_usec = timeout%1000;  
			ret = select(fd + 1, &rfds, NULL, NULL, &tv); 
			if (ret == 0)
			{
				printf("time out\n");
				return -2;
			}
			else if (ret < 0)
			{
				return -1;
			}

			if(!FD_ISSET(fd,&rfds))
			{
				return -1;
			}
		}	
	
		res = SSL_read(ssl, buf + bytes, len);
		if (res >= 1)
		{
			cnt = 0;
			bytes += res;
            len -= res;
		}
		else
		{
			err = SSL_get_error(ssl, res);
			if (err == SSL_ERROR_WANT_READ)
			{
				usleep(100*1000);
				cnt++;
				if (cnt == 5)
				{
					return -2;
				}	
				continue;
			}
			else
			{
				printf("ssl read failed...\n");
            	ERR_print_errors_fp(stderr); 

				if (err == SSL_ERROR_SYSCALL)  //可能是对方已经关闭连接,因此要关闭相关资源,重新连接
				{
					return -5;
				}
				
            	return -1;
			}	
		}	
	}
	while(len > 0 && SSL_pending(ssl));   //SSL_pending(ssl)返回可读的ssl数据字节数
	
	return bytes;
}
注:当返回0时,可能是SSL_pending的问题导致未进入循环,应再次调用sslRead

6、封装SSL_write函数

/*
 	SSL_write(SSL *ssl,const char *buf,int num)
	正常:返回1到num个字节数
	错误:返回0或负数
*/
int sslWrite(SSL *ssl, char *buf, int len)
{
	if (ssl == NULL)
	{
		return -1;
	}
	
	int err, res, bytes = 0, cnt = 0;

	while(len > 0)
	{
        res = SSL_write(ssl, buf + bytes, len);	
        if (res >= 1)
		{
			cnt = 0;
			bytes += res;
            len -= res;
		}
		else
		{
			err = SSL_get_error(ssl, res);
			if (err == SSL_ERROR_WANT_WRITE)
			{
				usleep(100*1000);
				cnt++;
				if (cnt == 5)
				{
					return -2;
				}	
				continue;
			}
			else
			{
				printf("ssl write failed...\n");
            	ERR_print_errors_fp(stderr); 

				if (err == SSL_ERROR_SYSCALL) //可能是对方已经关闭连接,因此要关闭相关资源,重新连接
				{
					return -5;
				}

            	return -1;
			}	
		}
	}

	printf("ssl write, bytes:%d\n", bytes);
	return bytes;
}

7、demo示例

int main(int argc, char const *argv[])
{
	//客户端demo流程
	/*
	ssl_service_init
	ssl_client_init
	创建socket
	sslDoHandshake
	sslRead或sslWrite
	*/

	//服务端demo流程
	/*
	ssl_service_init
	ssl_server_init
	创建socket
	sslDoHandshake
	sslRead或sslWrite
	*/
	return 0;
}

8、总结与说明

8.1、openssl官方函数:https://www.ibm.com/docs/en/ztpf/2021?topic=services-ztpf-cc-apis
8.2、如果移植到设备上运行时出现未知错误,可能是编译openssl时存在问题
8.3、如果出现 SSL_ERROR_SYSCALL,没有重新初始化ssl,将会出现以下问题,导致CPU异常偏高
[ 1954.054545] [drm:rot_client_get_device] *ERROR* wait2start timeout. timeout=5jif, ret=0
[ 1954.074862] [drm:rot_client_exec_fb_sync] *ERROR* wait4finish timeout: 5jif --> 0

——————————————

仅供学习与参考

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第一章 基础知识 81.1 对称算法 81.2摘要算法 81.3 公钥算法 91.4 回调函数 11第二章 openssl简介 132.1 openssl简介 132.2 openssl安装 132.2.1 linux下的安装 132.2.2 windows编译与安装 132.3 openssl源代码 142.4 openssl学习方法 16第三章openssl堆栈 173.1 openssl堆栈 173.2 数据结构 173.3 源码 173.4 定义用户自己的堆栈函数 183.5 编程示例 19第四章 openssl哈希表 214.1 哈希表 214.2 哈希表数据结构 214.3 函数说明 224.4 编程示例 24第五章 openssl内存分配 275.1 openssl内存分配 275.2 内存数据结构 275.3 主要函数 285.4 编程示例 28第六章 Openssl动态模块加载 316.1 动态库加载 316.2 DSO概述 316.3 数据结构 316.4 编程示例 32第七章 openssl抽象IO 357.1 openssl抽象IO 357.2 数据结构 357.3 BIO 函数 367.4 编程示例 377.4.1 mem bio 377.4.2 file bio 377.4.3 socket bio 387.4.4 md BIO 407.4.5 cipher BIO 407.4.6 ssl BIO 417.4.7 其他示例 43第八章 Openssl配置文件 448.1 概述 448.2 openssl配置文件读取 448.3 主要函数 448.4 编程示例 45第九章 Openssl随机数 479.1 随机数 479.2 openssl随机数数据结构与源码 479.3 主要函数 489.4 编程示例 49第十章 Openssl文本数据库 5110.1 概述 5110.2 数据结构 5110.3 函数说明 5210.4 编程示例 52第十一章 Openssl大数 5511.1 介绍 5511.2 openssl大数表示 5511.3 大数函数 5511.4 使用示例 58第十二章 Openssl base64编解码 6512.1 BASE64编码介绍 6512.2 BASE64编解码原理 6512.3 主要函数 6612.4 编程示例 66第十三章 Openssl ASN1库 6913.1 ASN1简介 6913.2 DER编码 7013.3 ASN1基本类型示例 7113.4 openssl 的ASN.1库 7313.5 用openssl的ASN.1库DER编码 7413.6 Openssl的ASN.1宏 7513.7 ASN1常用函数 7613.8 属性证书编码 90第十四章 Openssl错误处理 9414.1 概述 9414.2 数据结构 9414.3 主要函数 9614.4 编程示例 98第十五章 Openssl摘要与HMAC 10115.1 概述 10115.2 openssl摘要实现 10115.3 函数说明 10115.4 编程示例 10215.5 HMAC 103第十六章 Openssl数据压缩 10516.1 简介 10516.2 数据结构 10516.3 函数说明 10616.4 openssl中压缩算法协商 10616.5 编程示例 107第十七章 Openssl RSA 10817.1 RSA介绍 10817.2 openssl的RSA实现 10817.3 RSA签名与验证过程 10917.4 数据结构 10917.4.1 RSA_METHOD 10917.4.2 RSA 11017.5 主要函数 11117.6编程示例 11217.6.1密钥生成

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值