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

相关推荐
coder4_6 天前
OpenSSL 加密算法与证书管理全解析:从基础到私有 CA 实战
https·openssl·ssl/tls·加密算法·ca证书
王小义笔记13 天前
windows电脑如何执行openssl rand命令
windows·openssl
Humbunklung16 天前
VC++ 使用OpenSSL创建RSA密钥PEM文件
开发语言·c++·openssl
深耕AI1 个月前
Win64OpenSSL-3_5_2.exe【安装步骤】
openssl
看那山瞧那水1 个月前
DELPHI 利用OpenSSL实现加解密,证书(X.509)等功能
delphi·openssl
洋哥网络科技2 个月前
openssl升级
openssl
Lazy Dave2 个月前
gmssl私钥文件格式
网络安全·ssl·openssl
沉在嵌入式的鱼3 个月前
RK3588移植Openssl库
linux·rk3588·openssl
黑屋里的马3 个月前
ssl相关命令生成证书
服务器·网络·ssl·openssl·gmssl
fangeqin3 个月前
ubuntu源码安装python3.13遇到Could not build the ssl module!解决方法
linux·python·ubuntu·openssl