C++
openssl
boost
libressl
Boost.ASIO.SSL

LibreSSL と Boost.ASIO.SSL を組み合わせて使う事になった場合に ::SSL_CTX_get_default_passwd_cb_userdata 等複数箇所で翻訳時エラーが生じてしまう場合の応急対処法

More than 1 year has passed since last update.


問題

LibreSSL と Boost.ASIO.SSL を組み合わせて使う事になった場合に ::SSL_CTX_get_default_passwd_cb_userdata 等複数箇所で翻訳時エラーが生じてしまう。


発生条件

以下の組み合わせにより発生する。



  1. LibreSSL を使用したい


    • 執筆時点の最新版は 2.5.0, 2.4.4 、あるいはそれ以降も対応されない可能性あり。




  2. Boost.ASIO.SSL を使用したい。


    • Boost-1.61以降執筆現在最新1.63まで、あるいはそれ以降も対応されない可能性あり。




現象

翻訳時エラーが発生する。Boost.ASIO.SSL

...include/boost/asio/ssl/impl/context.ipp: In destructor 'boost::asio::ssl::context::~context()':

.../include/boost/asio/ssl/impl/context.ipp:232:25: error: '::SSL_CTX_get_default_passwd_cb_userdata' has not been declared
void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_);
^~

類似のエラーが大量に発生する。


原因

Boost.ASIO.SSL の以下のコミットから asio/ssl/impl/context.hpp などのソースコード複数について OPENSSL_VERSION_NUMBER によるプリプロセッサーレベルの分岐処理が導入され、 OpenSSL-1.1 系の API への対応が追加された。

#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)

void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_);
#else // (OPENSSL_VERSION_NUMBER >= 0x10100000L)
void* cb_userdata = handle_->default_passwd_callback_userdata;
#endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L)

#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) \

&& (OPENSSL_VERSION_NUMBER < 0x10100000L)
::SSL_COMP_free_compression_methods();
#endif // (OPENSSL_VERSION_NUMBER >= 0x10002000L)

OpenSSL では OPENSSL_VERSION_NUMBER0x10100000L 未満か否かによって OpenSSL-1.1 系の API を使用可能か判別できる。

# define OPENSSL_VERSION_NUMBER  0x10100040L

# ifdef OPENSSL_FIPS
# define OPENSSL_VERSION_TEXT "OpenSSL 1.1.0d-fips-dev xx XXX xxxx"
# else
# define OPENSSL_VERSION_TEXT "OpenSSL 1.1.0d-dev xx XXX xxxx"
# endif

一方、 LibreSSL-2.4/2.5 系では openssl/opensslv.hOPENSSL_VERSION_NUMBER0x20000000L と LibreSSL または互換の OpenSSL の API とは連動せず固定値で定義している。

/* These will never change */

#define OPENSSL_VERSION_NUMBER 0x20000000L
#define OPENSSL_VERSION_TEXT LIBRESSL_VERSION_TEXT
#define OPENSSL_VERSION_PTEXT " part of " OPENSSL_VERSION_TEXT

また、 LibreSSL-2.4/2.5 は OpenSSL-1.1 系の API に対応していない。

よって、 LibreSSL-2.4/2.5 と Boost-1.61/1.62/1.63.ASIO.SSL を組み合わせると、 Boost.ASIO.SSL のソースコード中から OpenSSL-1.1 系の API を使用するコードがプリプロセッサーレベルで有効となり、 OpenSSL-1.1 系の API に未対応の LibreSSL-2.4/2.5 ではその API が未定義で使用できないため、翻訳時エラーとなる。


余談: LibreSSL のバージョン情報

原因と直接は関係しないが、 LibreSSL のバージョン情報をプリプロセッサーで取得したい場合は、 openssl/opensslv.h に次の LibreSSL 独自の定義が追加されているのでこちらを使用できる。

#define LIBRESSL_VERSION_NUMBER       0x2030200fL

#define LIBRESSL_VERSION_TEXT "LibreSSL 2.3.2"


応急対処法

Boost.ASIO.SSL のヘッダーインクルード前後で OPENSSL_VERSION_NUMBER を偽装する事で比較的簡単に応急対処できる。

/// @brief LibreSSL と Boost.ASIO.SSL の OpenSSL-1.1 API 対応判定の偽装処理

/// @ref http://qiita.com/usagi/items/acee410849ca8f4f9c11
/// @{
#if LIBRESSL_VERSION_NUMBER <= 0x2050100fL
#include <openssl/opensslv.h>
#undef OPENSSL_VERSION_NUMBER
#define OPENSSL_VERSION_NUMBER 0x10001fffL
#endif
/// @}

#include <boost/asio/ssl.hpp>


注意


  • この記事で紹介する対処方法は「応急」である事を理解して施し、適切な保守を行う必要がある。