これは ドリコム Advent Calendar 2017 の17日目です。
16日目は miyachik さんによる、『Golangでどこでもtwitterできるbinaryをつくる』です

こんにちは。サーバサイドエンジニアのhayabusa333 (橘田)です。
この記事では個人で作成しているElixir-Phoenixアプリで発生した暗号化周りでのエラー現象とどのように解決したかについて共有したいと思います。

今回のエラーが発生した環境

  • Mac
  • Erlang/OTP 20
  • Elixir 1.5.1

事の始まり

皆さまはElixirの開発環境はどのようにして用意されているでしょうか?
brew install elixir でしょうか? それとも kerl や exenv などを使用してバージョン管理をしていらっしゃるのでしょうか?
私はElixir自体のコードを読んだり、試してみたりをしますので、 make にて Erlang も Elixirも入れておりました。
しかしそれが今回の問題の原因でもありました。

エラー発生

今回の問題に関してですが、上記の環境とは別の環境にて開発を行なった機能を確認のため自分自身のMacにて実行し、確認を行なっていたところ下記のようなエラーが発生いたしました。

** (exit) an exception was raised:
** (ErlangError) Erlang error: :notsup
(crypto) :crypto.aes_gcm_encrypt

Erlang側の crypto.aes_gcm_encryptにてエラーが発生しているようでしたので、cryptoにて使用できるencryptの一覧を表示して見たところ下記のような内容が表示されました。

iex(1)> :crypto.supports()
[hashs: [:sha, :sha224, :sha256, :sha384, :sha512, :md4, :md5, :ripemd160],
ciphers: [:des3_cbc, :des_ede3, :des3_cbf, :des3_cfb, :aes_cbc, :aes_cbc128,
:aes_cfb8, :aes_cfb128, :aes_cbc256, :aes_ctr, :aes_ecb, :aes_ige256,
:des_cbc, :des_cfb, :des_ecb, :blowfish_cbc, :blowfish_cfb64, :blowfish_ofb64,
:blowfish_ecb, :rc2_cbc, :rc4],
public_keys: [:rsa, :dss, :dh, :ec_gf2m, :ecdsa, :ecdh, :srp]]

見事にaes_gcmが対応していない事が発覚しましたが、他のMac環境では問題なく aes_gcmは対応しており、Linux環境でも同様にaes_gcmは対応しているため私自身の環境でのみ発生しているようです。

なぜ発生したか

理由としましては、MacのOpenSSLは標準的に入っているのが、0.9.8であり、Mac環境下のErlangがオプションにて使用するOpenSSLを指定しない場合にはMacのデフォルトのOpenSSLを見に行っていることが原因のようでした。

これは環境変数にてOpenSSLの参照先を変更しても同様にデフォルトのOpenSSLを見るため、brew install でOpenSSLを更新・参照先変更を行なってから、makeを実施しても同様の問題が発生いたします。

aes_gcm はOpenSSLの1.0.1から入っているようなので、Erlangのビルド時に使用するOpenSSLのバージョンを指定する必要がありました。

上記の問題ですが brew install elixir などで入れた場合には起こりません。
なぜ起こらないかと言いますと、brew install 時に新しいOpenSSLを内部で持ってきており、そちらを使用してインストールを行なっていたからです。

そこでErlangをインストールする際にbrewなどで入れた新しいOpenSSLを指定することによって今回の問題は解決します。

$ make clean
$ ./configure --disable-dynamic-ssl-lib --with-ssl=/usr/local/opt/openssl
$ make
$ make install

今回の問題としましてはErlang側にて参照するOpenSSLが古く、aes_gcmは使用できないために問題が発生していたので、Elixir側は新規に何かする必要はありません。
Elixir自体は新しくインストールされたErlangを使用して、正常に動作します。

まとめ

いかがだったでしょうか?
今回の問題は、Macを開発環境として brew install しているだけでは問題が発生しない内容となります。
しかし 本番環境、ステージング環境などでMacを使用している、 環境自体のOpenSSLのバージョンが古い、asdf にてビルド時のOpenSSLのビルド設定にOpenSSLのバージョン指定をしていなかったなどで問題が発生する可能性があります。
Erlangのビルドオプションに関しましては、Building and Installing Erlang/OTPに他にも記載されておりますので確認しておくと幸せになれるかと思います。
リンク先のオプションではインストールする先だけではなく、キャッシュラインサイズの指定であったり、アトミックメモリアクセスに使用するライブラリを変えられたりなどの情報が記載されております。
また記載されているもの以外も確認されたい方は実際のconfigureが生成される内容を確認されると良いかと思います。

それでは皆さま良いAlchemistライフを

次の日は、大原さんの記事です。お楽しみに!