文章目录
-
- [openssl3.2 - exp - buf to bio](#openssl3.2 - exp - buf to bio)
- 概述
- 笔记
- bio_get_length
- [向一个mem BIO中任意写](#向一个mem BIO中任意写)
- END
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;
}