"uninitialized constant OpenSSL::PKey::EC" 来自 Ruby 在 CentOS 6.6 上

"uninitialized constant OpenSSL::PKey::EC" from Ruby on CentOS 6.6

我有一个使用 openid_connect gem 的 Rails 服务器应用程序。当我尝试在 CentOS 6.6 上 运行 它时,我得到:

uninitialized constant OpenSSL::PKey::EC

这是完整的堆栈跟踪:

$ rails server
/home/foo/.rvm/gems/ruby-2.1.3/gems/json-jwt-1.5.1/lib/json/jwk/jwkizable.rb:69:in `<top (required)>': uninitialized constant OpenSSL::PKey::EC (NameError)
    from /home/foo/.rvm/gems/ruby-2.1.3/gems/json-jwt-1.5.1/lib/json/jwt.rb:102:in `<top (required)>'
    from /home/foo/.rvm/gems/ruby-2.1.3/gems/openid_connect-0.9.2/lib/openid_connect/response_object/id_token.rb:1:in `<top (required)>'
    from /home/foo/.rvm/gems/ruby-2.1.3/gems/openid_connect-0.9.2/lib/openid_connect/response_object.rb:7:in `block in <top (required)>'
    from /home/foo/.rvm/gems/ruby-2.1.3/gems/openid_connect-0.9.2/lib/openid_connect/response_object.rb:6:in `each'
    from /home/foo/.rvm/gems/ruby-2.1.3/gems/openid_connect-0.9.2/lib/openid_connect/response_object.rb:6:in `<top (required)>'
    from /home/foo/.rvm/gems/ruby-2.1.3/gems/openid_connect-0.9.2/lib/openid_connect/connect_object.rb:52:in `<top (required)>'
    from /home/foo/.rvm/gems/ruby-2.1.3/gems/openid_connect-0.9.2/lib/openid_connect.rb:85:in `<top (required)>'
    from /home/foo/.rvm/gems/ruby-2.1.3/gems/bundler-1.10.6/lib/bundler/runtime.rb:76:in `require'
    from /home/foo/.rvm/gems/ruby-2.1.3/gems/bundler-1.10.6/lib/bundler/runtime.rb:76:in `block (2 levels) in require'
    from /home/foo/.rvm/gems/ruby-2.1.3/gems/bundler-1.10.6/lib/bundler/runtime.rb:72:in `each'
    from /home/foo/.rvm/gems/ruby-2.1.3/gems/bundler-1.10.6/lib/bundler/runtime.rb:72:in `block in require'
    from /home/foo/.rvm/gems/ruby-2.1.3/gems/bundler-1.10.6/lib/bundler/runtime.rb:61:in `each'
    from /home/foo/.rvm/gems/ruby-2.1.3/gems/bundler-1.10.6/lib/bundler/runtime.rb:61:in `require'
    from /home/foo/.rvm/gems/ruby-2.1.3/gems/bundler-1.10.6/lib/bundler.rb:134:in `require'
    from /home/foo/tmp/openid_connect_sample/config/application.rb:7:in `<top (required)>'
    from /home/foo/.rvm/gems/ruby-2.1.3/gems/railties-3.2.22/lib/rails/commands.rb:53:in `require'
    from /home/foo/.rvm/gems/ruby-2.1.3/gems/railties-3.2.22/lib/rails/commands.rb:53:in `block in <top (required)>'
    from /home/foo/.rvm/gems/ruby-2.1.3/gems/railties-3.2.22/lib/rails/commands.rb:50:in `tap'
    from /home/foo/.rvm/gems/ruby-2.1.3/gems/railties-3.2.22/lib/rails/commands.rb:50:in `<top (required)>'
    from script/rails:6:in `require'
    from script/rails:6:in `<main>'

这是什么意思,我该如何克服它?

此问题源于 Red Hat 拒绝在 CentOS 的默认 OpenSSL 构建中包含某些椭圆曲线 (EC) 算法(出于对专利诉讼的恐惧)。

注意:根据,CentOS 6.7没有这个问题。

openid_connect gem 依赖于 json-jwt gem,后者使用其中一种未包含的算法。

因此,您需要重建包含所需算法的新版本 OpenSSL。

这些是我在我的机器上构建新 OpenSSL 所遵循的步骤(改编自 here):

  1. cd /usr/src
  2. wget https://www.openssl.org/source/openssl-1.0.1l.tar.gz
  3. yum install autoconf automake(您可能已经安装了这些)
  4. tar zxvf openssl-1.0.1l.tar.gz
  5. cd openssl-1.0.1l
  6. export CFLAGS="-fPIC"
  7. ./config --prefix=/opt/openssl shared enable-ec enable-ecdh enable-ecdsa
  8. make all
  9. make install

现在,您的 Ruby 可能仍然 link 针对旧的 OpenSSL 库,因此您需要将其重建为 link 新的。

你在用rvm吗?太好了!您安装的任何新 Rubies 都将针对新的 OpenSSL 进行构建。 rvm remove 你的 Ruby 并重新安装它(或者简单地安装一个不同的 ruby 版本)。

不使用 rvm? 那么我想您需要以传统方式重建 Ruby。但是您可能已经知道该怎么做,对吗?如果没有,您需要查看其他教程,因为我们无法在此处介绍。

现在重新安装 bunder 并执行 bundle install,您的 rails server 现在应该 运行 成功。

(如果有人要提供更正或说明,请发表评论,我会根据需要进行编辑。)

我 运行 在 CentOS 6.6 上遇到了同样的问题。但我不想重新编译自定义 openssl 和 ruby 来解决这个问题。我没有做很好的笔记,因为我尝试了很多东西,但似乎将所有最新和最伟大的软件包更新到 CentOS 6.7 解决了这个问题。

以下是我拥有的一些相关软件包版本:

openssl098e-0.9.8e-18.el6_5.2.x86_64                                                            
openssl-1.0.1e-42.el6.x86_64                                                                
openssl-1.0.1e-42.el6.i686
openssl-devel-1.0.1e-42.el6.x86_64
glibc-2.12-1.166.el6_7.3.x86_64
kernel-2.6.32-573.7.1.el6.x86_64

在更新这些软件包、重新启动并重新安装我的包后,json-jwt gem 完美运行。

这是我们的生产机器,我相信 ruby 标准库是从源代码编译的,然后创建为自定义 RPM。

我们的构建服务器使用 RVM,这最终变得更加痛苦。 RVM 安装程序一直为 centos 拉二进制文件,同样的故障又回来了。

Found remote file https://rvm.io/binaries/centos/6/x86_64/ruby-1.9.3-p484.tar.bz2

我强制源代码像这样重新编译:

rvm reinstall --disable-binary ruby-1.9.3-p484

我注意到一条看起来非常棒的消息:

 #applying patch .rvm/patches/ruby/ssl_no_ec2m.patch.

那个补丁文件有一些 C 宏条件似乎排除了一些 EC 相关代码。

成功了!我还注意到 ruby 的 openssl.so 里面有很多 EC 相关的符号。之前打包的centosruby没有有这些:

$ cd ~/.rvm/rubies/ruby-1.9.3-p484/lib/ruby/1.9.1/x86_64-linux
$ strings openssl.so |grep _EC
PEM_write_bio_ECPKParameters
i2d_ECPKParameters
PEM_read_bio_ECPKParameters
d2i_ECPKParameters
PEM_write_bio_ECPrivateKey
i2d_ECPrivateKey_bio
i2d_EC_PUBKEY_bio
PEM_write_bio_EC_PUBKEY
PEM_read_bio_ECPrivateKey
PEM_read_bio_EC_PUBKEY
d2i_ECPrivateKey_bio
d2i_EC_PUBKEY_bio
OPENSSL_1.0.1_EC
EVP_PKEY_assign_EC_KEY
OP_SINGLE_ECDH_USE

如果非要我猜的话,对我的新 openssl 1.0.1 包的重新编译一定触发了一些 C 宏,这些宏打开了某种不受法律保护的替代算法。

如果您检查 openssl.so 的符号,但它没有所有这些 _EC 相关的东西,那可能是个问题。