openssl3.2 - exp - buf to bio

文章目录

openssl3.2 - exp - buf to bio

概述

不想让程序调用openssl API时, 有文件落地的动作.

如果程序有配置文件要用, 也是自己读文件到buffer, 然后转成BIO给openssl的相关有BIO入参的API用.

如果在程序中用数组定义了一些PEM内容的数组, 也可以将数组转成BIO来用.

从openssl测试代码中, 找到了BIO_new_mem_buf(), 可以做这个事情.

那么程序需要的文件输入, 都可以读入buffer, 转成BIO, 后续都用BIO来处理.

笔记

c 复制代码
/*!
* \file main.cpp
* \note buffer to bio
*/

#include "my_openSSL_lib.h"

#include <stdlib.h>
#include <stdio.h>
#include <cstdint>
#include <assert.h>

#include <openssl/bio.h>

int test_bio_new_mem_buf(void);

int main(int argc, char** argv)
{
    test_bio_new_mem_buf();
	return 0;
}

int test_bio_new_mem_buf(void)
{
    int ok = 0;
    BIO* bio = NULL;
    BUF_MEM* bufmem = NULL;
    char data[16];
    int i_rc = 0;

    do {
        // BIO_free(bio); // openssl做了处理, 即使入参为NULL, 也不会报错

        // BIO_new_mem_buf是直接将入参的buffer指到内部指针上, 所以入参指针如果是自己new出来的, 就需要自己释放

        // 如果是文件输入, 可以自己读文件到buffer中, 然后就用BIO来操作.
        bio = BIO_new_mem_buf("Hello World\n", 12);
        if (NULL == bio)
        {
            break; 
        }
        
		i_rc = BIO_get_mem_ptr(bio, &bufmem);
        if (i_rc <= 0)
        {
            break;
        }

        memset(data, 0, sizeof(data));
        if (5 != BIO_read(bio, data, 5)) 
        { 
            break; 
        }

        if (0 != strncmp(data, "Hello", 5))
        {
            break;
        }

        // b->flags & BIO_FLAGS_MEM_RDONLY
        // bio默认是只读的, 是写不进去的.
        i_rc = BIO_write(bio, "test", 4);
        assert(i_rc <= 0);

        memset(data, 0, sizeof(data));
        i_rc = BIO_read(bio, data, 16); // 连续调用BIO_read时, 是继续往后读, 读一点, 内容就少一点
        assert(7 == i_rc); // 返回值是读了多少个字节

        if (0 != strncmp(data, " World\n", 7))
        {
            break;
        }

        i_rc = BIO_reset(bio); // 只读的bio可以恢复到刚创建时的状态, 可以从头开始读.
        assert(i_rc > 0);

        i_rc = BIO_read(bio, data, 16);
        assert(12 == i_rc);

        if (0 != strncmp(data, "Hello World\n", 12))
        {
            break;
        }

        ok = 1;
    } while (false);

    if (NULL != bio)
    {
        BIO_free_all(bio);
        bio = NULL;
    }
    
    return ok;
}

bio_get_length

openssl 并不提供如何得到BIO对象内容的size.

因为很多BIO是不知道有多长的(e.g. bio for ssl)

但是对于由buffer转成BIO之后, 其实BIO内的数据长度是确定的.

查了资料, 可以用 BIO_ctrl_pending()来取长度, 但是之前要先调用一下BIO_rest().

封装了一个函数bio_get_length(), 好使.

调用端代码

c 复制代码
        // 如果是文件输入, 可以自己读文件到buffer中, 然后就用BIO来操作.
        bio = BIO_new_mem_buf("Hello World\n", 12);
        if (NULL == bio)
        {
            break; 
        }

        bio_length = bio_get_length(bio);
        assert(bio_length == 12);

函数实现

c 复制代码
size_t bio_get_length(BIO* bio)
{
	size_t bio_length = 0;

	do {
		if (NULL == bio)
		{
			break;
		}

		BIO_reset(bio);
		bio_length = BIO_ctrl_pending(bio);
	} while (false);

	return bio_length;
}

bio_to_buffer

如果想对一个已经包含了内容的BIO中的内容, 转为buffer. 以下代码好使.

c 复制代码
int test_bio_to_buffer(void)
{
    int ok = 0;
    BIO* bio = NULL;

    char data[16];
    int i_rc = 0;

    long bio_length = 0;
    uint8_t* pBufToLoadBIO = NULL;

    do {
        bio = BIO_new_mem_buf("Hello World\n", 12);
        if (NULL == bio)
        {
            break;
        }

        // 得到BIO的数据长度, 才好去开buffer
        bio_length = bio_get_length(bio);
        assert(bio_length == 12);

        // 多开一个字节, 留一个'\0'的位置, 如果内容是可见字符, 看字符串方便
        pBufToLoadBIO = new uint8_t[bio_length + 1];
        if (NULL == pBufToLoadBIO)
        {
            break;
        }

        pBufToLoadBIO[bio_length] = '\0';

        i_rc = BIO_read(bio, pBufToLoadBIO, bio_length);
        // 如果 bio_length 太大(> imax), 再分段读来处理, 现在先这样, 就当一次就读完了
        assert(i_rc == bio_length);
        // 现在可以拿pBufToLoadBIO去干活了(自己存文件, 或作其他处理)

        ok = 1;
    } while (false);

    if (NULL != bio)
    {
        BIO_free_all(bio);
        bio = NULL;
    }

    if (NULL != pBufToLoadBIO)
    {
        delete []pBufToLoadBIO;
        pBufToLoadBIO = NULL;
    }

    return ok;
}

向一个mem BIO中任意写

c 复制代码
/*!
* \file main.cpp
*/

#include "my_openSSL_lib.h"
#include <openssl/crypto.h>
#include <openssl/bio.h>

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

#include "CMemHookRec.h"

void my_openssl_app();
size_t bio_get_length(BIO* bio);

int main(int argc, char** argv)
{
	setvbuf(stdout, NULL, _IONBF, 0); // 清掉stdout缓存, 防止调用printf时阻塞
	mem_hook();

	my_openssl_app();

	mem_unhook();

	return 0;
}

void my_openssl_app()
{
	BIO* bio = NULL;
	int i_rc = 0;
	char szBuf[1024];
	size_t szWrited = 0;
	size_t sz_tmp = 0;
	int i = 0;

	do {
		bio = BIO_new(BIO_s_mem());
		if (NULL == bio)
		{
			break;
		}

		i_rc = BIO_test_flags(bio, BIO_FLAGS_MEM_RDONLY);
		assert(i_rc != BIO_FLAGS_MEM_RDONLY);

		for (i = 0; i < 10240; i++)
		{
			szBuf[0] = 't';
			i_rc = BIO_write_ex(bio, szBuf, sizeof(szBuf), &szWrited);
			assert((i_rc > 0) && (szWrited == sizeof(szBuf)));
			sz_tmp = bio_get_length(bio);
		}
	} while (false);

	if (NULL != bio)
	{
		BIO_free(bio);
		bio = NULL;
	}
}

size_t bio_get_length(BIO* bio)
{
	size_t bio_length = 0;

	// 只适合与已经全部装载了mem buffer内容的BIO
	// 因为 BIO_BUF_MEM 没有对外, 所以只能通过试读来确定BIO内容的长度
	do {
		if (NULL == bio)
		{
			break;
		}

		BIO_reset(bio);
		bio_length = BIO_ctrl_pending(bio);
	} while (false);

	return bio_length;
}

END

相关推荐
pzs02212 天前
openssl的使用
openssl
小亦小亦_空中接力4 天前
openssl+keepalived安装部署
openssl·keepalived
摸鱼手会滑6 天前
源码编译安装python3.12没有ssl模块,python3.12 ModuleNotFoundError: No module named ‘_ssl‘
ssl·openssl·python3
老朱自强不息18 天前
Windows 平台编译openssl3.3
windows·openssl
promise5241 个月前
openssl 详解
linux·运维·服务器·网络协议·安全·https·openssl
俱会一处1 个月前
用openssl 创建自签名证书用于内网HTTPS
https·openssl·内网·局域网
xiaogengtongxu1 个月前
CA证书和openssl介绍
网络·安全·openssl
蚯蚓也自由1 个月前
openssl版本不同引发的崩溃
linux·服务器·调试·openssl·崩溃
husterlichf2 个月前
openssl req 详解
openssl·ca证书
我想学LINUX2 个月前
【常见开源库的二次开发】基于openssl的加密与解密——SHA算法源码解析(六)
算法·开源·openssl·比特币·sha-1·sha-2·比特币挖矿