编译测试程序
这一步我们需要编写一个测试程序,从模糊测试器获取输入数据,调用OpenSSL库进行检测。这部分程序我们称之为测试驱动。
1. 创建测试驱动文件
创建一个文件fuzzer.cpp,使用以下的内容:
// Licensed under the Apache License, Version 2.0 (the "License");
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <assert.h>
#include <stdint.h>
#include <stddef.h>
#include <wfuzz.h>
SSL_CTX *sctx;
void ssl_heartbleed_init() {
SSL_library_init();
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
assert (sctx = SSL_CTX_new(TLSv1_method()));
/* These two file were created with this command:
openssl req -x509 -newkey rsa:512 -keyout runtime/server.key \
-out runtime/server.pem -days 9999 -nodes -subj /CN=a/
*/
assert(SSL_CTX_use_certificate_file(sctx, "runtime/server.pem",
SSL_FILETYPE_PEM));
assert(SSL_CTX_use_PrivateKey_file(sctx, "runtime/server.key",
SSL_FILETYPE_PEM));
}
void ssl_heartbleed(std::string content) {
SSL *server = SSL_new(sctx);
BIO *sinbio = BIO_new(BIO_s_mem());
BIO *soutbio = BIO_new(BIO_s_mem());
SSL_set_bio(server, sinbio, soutbio);
SSL_set_accept_state(server);
BIO_write(sinbio, content.data(), content.size());
SSL_do_handshake(server);
SSL_free(server);
}
WFUZZ_TEST_ENTRYPOINT_WITH_INIT(ssl_heartbleed, ssl_heartbleed_init);
其中 ssl_heartbleed_init
函数用于初始化测试环境。由于这些初始化本身只需要执行一次,如果把它重复执行,会拖慢测试的速度。因此我们使用一个独立的函数来定义它。这个函数的名称本身是不重要的,只需要在下面的注册部分引用即可。
ssl_heartbleed
函数是实际执行测试的部分,它有一个参数content,这说明在测试过程中,每次引擎需要随机生成一个std::string类型的content来调用这个函数。
最后WFUZZ_TEST_ENTRYPOINT_WITH_INIT是一个宏,用来注册测试入口和初始化入口。
2. 编译测试驱动
使用以下命令可以编译这个文件:
wfuzz-c++ -o openssl-fuzz fuzz.cpp -I./install/include \
./install/lib/libssl.a \
./install/lib/libcrypto.a
编译完成后,请在当前目录下查看 openssl-fuzz
文件,如果存在,说明已经成功编译了测试驱动。
3. 创建证书文件
您可能注意到,在初始化函数中,会读取两个文件 runtime/server.pem
和 runtime/server.key
。这两个文件是用于SSL连接的公钥和私钥。可以通过 openssl
命令来生成:
mkdir -p runtime
openssl req -x509 -newkey rsa:512 -keyout runtime/server.key \
-out runtime/server.pem -days 9999 -nodes -subj /CN=a/
执行完该命令后,请确认当前目录下的runtime子目录中创建了 server.pem
和 server.key
两个文件。