目次
はじめに
OpenSSLライブラリは、SSL/TLS通信のサーバー認証で利用する「信頼する認証局の証明書」情報を通常ファイルから取得しています。
「信頼する認証局の証明書」ファイル(以降、CA証明書ファイル)の場所は、2段階で決定します。
OpenSSLライブラリのビルド時にデフォルトパスを設定し、OpenSSLライブラリを利用するプログラムでデフォルトパスを使うか、デフォルト以外のパスを指定します。
検証環境
- macOS Sierra 10.12.6
- OpenSSLライブラリソースファイル (2018/8/29最新) 1.1.1-pre10-dev
github – openssl
OpenSSLライブラリ側
デフォルトパス
CA証明書ファイルのデフォルト位置は、OpenSSLライブラリのビルド時にオプションで設定します。openssl
コマンドのversion
サブコマンドによりビルド済みのOpenSSLライブラリの設定を確認できます。
$ openssl version -d
OPENSSLDIR: "/usr/local/etc/openssl"
ビルド時に設定できるのはCA証明書ファイルが配置されるディレクトリだけで、ファイル名はハードコーディングされていて、“cert.pem”になります。
実際に試すには、Githubからopensslのソースファイルを取得してMakefileを作成するためのconfig
スクリプトに--openssldir
オプションを指定します。
$ git clone https://github.com/openssl/openssl
$ cd openssl
$ ./config --openssldir=/foo/bar
macOS上でconfigスクリプトを実行すると、共有ライブラリの依存関係の埋め込みを行うためのオプションがデフォルトで指定されます。しかし、linux上でconfigスクリプトを実行すると、このオプションがデフォルトで指定されないため明示的に指定します。
「./config –openssldir=/foo/bar ‘-Wl,-rpath,$(LIBRPATH)’」
環境変数LD_LIBRARYやldconfigを利用する方法では、既存の環境に影響を与えてしまうので避けた方がよさそうです。
環境変数(SSL_CERT_FILE)により実行時に設定
環境変数SSL_CERT_FILE
に、CA証明書ファイルのパスを設定すれば実行時にデフォルト位置を上書きして変更できます。この環境変数にはディレクトリではなくファイルのパスを設定するので任意のファイル名を設定できます。 OpenSSLライブラリでは、こちらもデフォルトパスとして扱われています。
OpenSSLライブラリを利用するプログラム側
デフォルトパスを利用する場合
デフォルトパスを利用して、CA証明書情報を読み込むためのAPIとしてSSL_CTX_set_default_verify_file
または、SSL_CTX_set_default_verify_paths
があります。
#include <openssl/ssl.h>
int SSL_CTX_set_default_verify_file(SSL_CTX *ctx);
int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx);
SSL_CTX_set_default_verify_file
はデフォルトパスにあるCA証明書ファイルから情報を読み込みます。
ビルド時の設定より、環境変数SSL_CERT_FILE
の設定が優先されます。しかし、環境変数に設定されたファイルでエラーが発生しても、ビルド時の設定に切り替わることはありません。
環境変数が設定されているか否かで切り替わる処理となっています。./crypto/x509/by_file.c
のby_file_ctrl
関数が該当の処理になります。
static int by_file_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp,
long argl, char **ret)
{
int ok = 0;
const char *file;
switch (cmd) {
case X509_L_FILE_LOAD:
if (argl == X509_FILETYPE_DEFAULT) {
file = getenv(X509_get_default_cert_file_env());
if (file)
ok = (X509_load_cert_crl_file(ctx, file,
X509_FILETYPE_PEM) != 0);
else
ok = (X509_load_cert_crl_file
(ctx, X509_get_default_cert_file(),
X509_FILETYPE_PEM) != 0);
if (!ok) {
X509err(X509_F_BY_FILE_CTRL, X509_R_LOADING_DEFAULTS);
}
... 省略
デフォルト以外のパスを指定して利用する場合
CA証明書ファイルのパスを指定して、CA証明書情報を読み込むためのAPIとしてSSL_CTX_load_verify_locations
があります。
#include <openssl/ssl.h>
int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, const char *CApath);
詳細はman
コマンドで確認できます。第二引数CAfile
にCA証明書ファイルのパスを指定した場合、そのファイルからCA証明書情報を読み込みます。第三引数のCApath
については対応する使い方が少々特殊(利点が分からない)なので今回は無視します。
第二引数CAfile
、第三引数CApath
の両方ともにNULLを指定した場合はエラーとなります。自動的にデフォルトパスの利用とはなりません。
デフォルトパスと、指定したパスの違い
デフォルトパスにファイルが無い場合や、読み込みに失敗したしてもエラーとなりません。内部的にはエラーになっていますが、SSL_CTX_set_default_verify_file
やSSL_CTX_set_default_verify_paths
でCA証明書ファイルに対するエラーを揉み消しています。これはman
コマンドのドキュメントや、ソースコードのコメントに記載されています。
- openssl公式 – ver 1.1.0 – SSL_CTX_load_verify_locations
- github – openssl – ssl_lib.c, SSL_CTX_set_default_verify_file
SSL_CTX_set_default_verify_file
が記載されているドキュメントでないと、情報が古いためGithub上のソースファイルを参照する必要があります。
まとめ
OpenSSLライブラリを利用しているCurlやGitなどのコマンドで、SSL/TLSに関連する設定や環境変数が、どこに影響するのかが不明で障害時の対応に手間取ったためソースファイルから該当の処理を探りました。
今回の調査で環境変数SSL_CERT_FILE
(およびSSL_CERT_DIR
)がOpenSSLライブラリの機能で利用されるものだと分かりました。なので、OpenSSLライブラリを利用したプログラムは全て、この機能の影響を受けるとになります。
異なるパスに配置されたOpenSSLライブラリを参照していても、環境変数は全てに影響してしまうので使う範囲に注意が必要な機能です。
ここからOpenSSLライブラリを利用しているCurl
の実装を追っていきます。