编译测试程序

这一步我们需要编写一个测试程序,从模糊测试器获取输入数据,调用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.pemruntime/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.pemserver.key 两个文件。