From 0b5ae0f22b57f8232fbeb4751766abe99b222c6c Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Fri, 24 May 2019 21:32:37 -0700 Subject: [PATCH 1/7] Skip one assertion for OpenSSL::PKey::EC::Point#mul on LibreSSL [ Original commit is 4e9801dff855 in 2.2.0. This is a backport to the 2.1 branch. ] LibreSSL 2.8.0+ does not support multiple elements in the first argument. --- test/test_pkey_ec.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/test_pkey_ec.rb b/test/test_pkey_ec.rb index dc5a14e6b..95b5a6426 100644 --- a/test/test_pkey_ec.rb +++ b/test/test_pkey_ec.rb @@ -309,8 +309,14 @@ def test_ec_point_mul result_b1 = point_a.mul([3], []) assert_equal B(%w{ 04 10 0D }), result_b1.to_octet_string(:uncompressed) # 3 * point_a + 2 * point_a = 3 * (6, 3) + 2 * (6, 3) = (7, 11) - result_b1 = point_a.mul([3, 2], [point_a]) - assert_equal B(%w{ 04 07 0B }), result_b1.to_octet_string(:uncompressed) + begin + result_b1 = point_a.mul([3, 2], [point_a]) + rescue OpenSSL::PKey::EC::Point::Error + # LibreSSL doesn't support multiple entries in first argument + raise if $!.message !~ /called a function you should not call/ + else + assert_equal B(%w{ 04 07 0B }), result_b1.to_octet_string(:uncompressed) + end # 3 * point_a + 5 * point_a.group.generator = 3 * (6, 3) + 5 * (5, 1) = (13, 10) result_b1 = point_a.mul([3], [], 5) assert_equal B(%w{ 04 0D 0A }), result_b1.to_octet_string(:uncompressed) From 9b46c6a603b07ba4f930b4afb58a7ae76c86eadd Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Wed, 12 Aug 2020 18:25:16 +0900 Subject: [PATCH 2/7] .github/workflows/test.yml: use GitHub Actions .github/workflows/test.yml is copied from current master's (last update by commit 0a2e8c67f252), and then the LibreSSL versions to run test with are adjusted for Ruby/OpenSSL 2.1. --- .github/workflows/test.yml | 120 +++++++++++++++++++++++++++++++++++++ .travis.yml | 39 ------------ appveyor.yml | 26 -------- 3 files changed, 120 insertions(+), 65 deletions(-) create mode 100644 .github/workflows/test.yml delete mode 100644 .travis.yml delete mode 100644 appveyor.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 000000000..a4a41cbdb --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,120 @@ +name: CI + +on: [push, pull_request] + +jobs: + test: + name: >- + ${{ matrix.os }} ${{ matrix.ruby }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest, macos-latest ] + ruby: [ head, 2.7, 2.6, 2.5, 2.4, 2.3 ] + steps: + - name: repo checkout + uses: actions/checkout@v2 + + - name: load ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + + - name: depends + run: rake install_dependencies + + - name: compile + run: rake compile -- --enable-debug + + - name: test + run: rake test TESTOPTS="-v --no-show-detail-immediately" OSSL_MDEBUG=1 + + test-windows: + name: >- + ${{ matrix.os }} ${{ matrix.ruby }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ windows-latest ] + ruby: [ mswin, mingw, 2.7, 2.6, 2.5, 2.4, 2.3 ] + steps: + - name: repo checkout + uses: actions/checkout@v2 + + - name: load ruby, install/update gcc, install openssl + uses: MSP-Greg/setup-ruby-pkgs@v1 + with: + ruby-version: ${{ matrix.ruby }} + mingw: _upgrade_ openssl + + - name: depends + run: rake install_dependencies + + # SSL_DIR is set as needed by MSP-Greg/setup-ruby-pkgs + # only used with mswin + - name: compile + run: rake compile -- --enable-debug $env:SSL_DIR + + - name: test + run: rake test TESTOPTS="-v --no-show-detail-immediately" OSSL_MDEBUG=1 + + test-openssls: + name: >- + ${{ matrix.openssl }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest ] + ruby: [ 2.7 ] + openssl: + - openssl-1.0.1u # EOL + - openssl-1.0.2u # EOL + - openssl-1.1.0l # EOL + - openssl-1.1.1g + - libressl-2.5.5 # EOL + - libressl-3.1.3 + - libressl-3.2.0 + steps: + - name: repo checkout + uses: actions/checkout@v2 + + - name: prepare openssl + run: | + mkdir -p tmp/build-openssl && cd tmp/build-openssl + case ${{ matrix.openssl }} in + openssl-*) + curl -OL https://ftp.openssl.org/source/${{ matrix.openssl }}.tar.gz + tar xf ${{ matrix.openssl }}.tar.gz && cd ${{ matrix.openssl }} + # shared is required for 1.0.x. + ./Configure --prefix=$HOME/.openssl/${{ matrix.openssl }} \ + shared linux-x86_64 + make depend + ;; + libressl-*) + curl -OL https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/${{ matrix.openssl }}.tar.gz + tar xf ${{ matrix.openssl }}.tar.gz && cd ${{ matrix.openssl }} + ./configure --prefix=$HOME/.openssl/${{ matrix.openssl }} + ;; + *) + false + ;; + esac + make -j4 + make install_sw + + - name: load ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + + - name: depends + run: rake install_dependencies + + - name: compile + run: rake compile -- --enable-debug --with-openssl-dir=$HOME/.openssl/${{ matrix.openssl }} + + - name: test + run: rake test TESTOPTS="-v --no-show-detail-immediately" OSSL_MDEBUG=1 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index d00e2bdb7..000000000 --- a/.travis.yml +++ /dev/null @@ -1,39 +0,0 @@ -language: c -sudo: required -group: edge -dist: trusty -services: - - docker -before_install: - - sudo apt-get -qq update -install: - - sudo sh -c "curl -L https://github.com/docker/compose/releases/download/1.8.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose" - - sudo chmod +x /usr/local/bin/docker-compose -script: - - docker -v - - docker-compose -v - - docker-compose build --no-cache - - docker-compose run test -matrix: - fast_finish: true - include: - - env: RUBY_VERSION=ruby-2.3 OPENSSL_VERSION=openssl-1.0.2 - - env: RUBY_VERSION=ruby-2.4 OPENSSL_VERSION=openssl-1.0.2 - - env: RUBY_VERSION=ruby-2.5 OPENSSL_VERSION=openssl-1.0.1 - - env: RUBY_VERSION=ruby-2.5 OPENSSL_VERSION=openssl-1.0.2 - - env: RUBY_VERSION=ruby-2.5 OPENSSL_VERSION=openssl-1.1.0 - - env: RUBY_VERSION=ruby-2.5 OPENSSL_VERSION=openssl-1.1.1 - - env: RUBY_VERSION=ruby-2.5 OPENSSL_VERSION=libressl-2.5 - - env: RUBY_VERSION=ruby-2.5 OPENSSL_VERSION=libressl-2.6 - - env: RUBY_VERSION=ruby-2.5 OPENSSL_VERSION=libressl-2.7 - - language: ruby - rvm: ruby-head - before_install: - - "rake install_dependencies" - script: - - "rake compile -- --enable-debug" - - "rake test" - allow_failures: - - language: ruby - rvm: ruby-head - - env: RUBY_VERSION=ruby-2.5 OPENSSL_VERSION=openssl-1.1.1 diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 18484fb95..000000000 --- a/appveyor.yml +++ /dev/null @@ -1,26 +0,0 @@ ---- -clone_depth: 10 -install: - - ps: | - $Env:PATH = "C:\Ruby${Env:ruby_version}\bin;${Env:PATH}" - if ($Env:ruby_version -match "^23" ) { - # RubyInstaller; download OpenSSL headers from OpenKnapsack Project - $Env:openssl_dir = "C:\Ruby${Env:ruby_version}" - appveyor DownloadFile http://dl.bintray.com/oneclick/OpenKnapsack/x64/openssl-1.0.2j-x64-windows.tar.lzma - 7z e openssl-1.0.2j-x64-windows.tar.lzma - 7z x -y -oC:\Ruby${Env:ruby_version} openssl-1.0.2j-x64-windows.tar - } else { - # RubyInstaller2; openssl package seems to be installed already - $Env:openssl_dir = "C:\msys64\mingw64" - } - - ruby -v - - rake install_dependencies -build_script: - - rake -rdevkit compile -- --with-openssl-dir=%openssl_dir% --enable-debug -test_script: - - rake test OSSL_MDEBUG=1 -deploy: off -environment: - matrix: - - ruby_version: "23-x64" # RI - - ruby_version: "24-x64" # RI2 From 9561199b9f8d95dced791ab83158b11cf1e4ba61 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Sun, 9 Aug 2020 00:22:08 +0900 Subject: [PATCH 3/7] x509store: fix memory leak in X509::StoreContext.new The certificate passed as the second argument was not properly free'd in the error paths. --- ext/openssl/ossl_x509store.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/ext/openssl/ossl_x509store.c b/ext/openssl/ossl_x509store.c index 61543d44f..6c5f1c794 100644 --- a/ext/openssl/ossl_x509store.c +++ b/ext/openssl/ossl_x509store.c @@ -517,7 +517,9 @@ static VALUE ossl_x509stctx_set_time(VALUE, VALUE); /* * call-seq: - * StoreContext.new(store, cert = nil, chain = nil) + * StoreContext.new(store, cert = nil, untrusted = nil) + * + * Sets up a StoreContext for a verification of the X.509 certificate _cert_. */ static VALUE ossl_x509stctx_initialize(int argc, VALUE *argv, VALUE self) @@ -527,15 +529,24 @@ ossl_x509stctx_initialize(int argc, VALUE *argv, VALUE self) X509_STORE *x509st; X509 *x509 = NULL; STACK_OF(X509) *x509s = NULL; + int state; rb_scan_args(argc, argv, "12", &store, &cert, &chain); GetX509StCtx(self, ctx); GetX509Store(store, x509st); - if(!NIL_P(cert)) x509 = DupX509CertPtr(cert); /* NEED TO DUP */ - if(!NIL_P(chain)) x509s = ossl_x509_ary2sk(chain); - if(X509_STORE_CTX_init(ctx, x509st, x509, x509s) != 1){ + if (!NIL_P(cert)) + x509 = DupX509CertPtr(cert); /* NEED TO DUP */ + if (!NIL_P(chain)) { + x509s = ossl_protect_x509_ary2sk(chain, &state); + if (state) { + X509_free(x509); + rb_jump_tag(state); + } + } + if (X509_STORE_CTX_init(ctx, x509st, x509, x509s) != 1){ + X509_free(x509); sk_X509_pop_free(x509s, X509_free); - ossl_raise(eX509StoreError, NULL); + ossl_raise(eX509StoreError, "X509_STORE_CTX_init"); } if (!NIL_P(t = rb_iv_get(store, "@time"))) ossl_x509stctx_set_time(self, t); From 2e700c80bfab1b2668174a207588301cbfbdcd3d Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Mon, 22 Oct 2018 10:26:33 +0900 Subject: [PATCH 4/7] ssl: retry write on EPROTOTYPE on macOS Errno::EPROTOTYPE is not supposed to be raised by SSLSocket#write. However, on macOS, send(2) which is called via SSL_write() can occasionally return EPROTOTYPE. Retry SSL_write() so that we get a proper error, just as ext/socket does. Reference: https://bugs.ruby-lang.org/issues/14713 Reference: https://github.com/ruby/openssl/issues/227 --- ext/openssl/ossl_ssl.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index 3e38bd134..29e7b1d6a 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -1685,6 +1685,11 @@ ossl_start_ssl(VALUE self, int (*func)(), const char *funcname, VALUE opts) rb_io_wait_readable(fptr->fd); continue; case SSL_ERROR_SYSCALL: +#ifdef __APPLE__ + /* See ossl_ssl_write_internal() */ + if (errno == EPROTOTYPE) + continue; +#endif if (errno) rb_sys_fail(funcname); ossl_raise(eSSLError, "%s SYSCALL returned=%d errno=%d state=%s", funcname, ret2, errno, SSL_state_string_long(ssl)); #if defined(SSL_R_CERTIFICATE_VERIFY_FAILED) @@ -1975,6 +1980,16 @@ ossl_ssl_write_internal(VALUE self, VALUE str, VALUE opts) rb_io_wait_readable(fptr->fd); continue; case SSL_ERROR_SYSCALL: +#ifdef __APPLE__ + /* + * It appears that send syscall can return EPROTOTYPE if the + * socket is being torn down. Retry to get a proper errno to + * make the error handling in line with the socket library. + * [Bug #14713] https://bugs.ruby-lang.org/issues/14713 + */ + if (errno == EPROTOTYPE) + continue; +#endif if (errno) rb_sys_fail(0); default: ossl_raise(eSSLError, "SSL_write"); From b3972a7d597e182e67cd6d1bcf6237cfe2275dc1 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Thu, 18 Feb 2021 16:33:10 +0900 Subject: [PATCH 5/7] .github/workflows: disable pkg-config on Windows tests Let ext/openssl/extconf.rb find the correct OpenSSL installation from the default include/library paths. Since some time ago, the test environment contains another OpenSSL installation and pkg-config from Mingw-w64. However, as pkg-config is not available in RubyInstaller (Ruby 2.3), simply invoking pkg-config command from our ext/openssl/extconf.rb ends up with picking up Mingw-w64's OpenSSL, which is incompatible with RI. --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a4a41cbdb..20fbd00d1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -52,10 +52,11 @@ jobs: - name: depends run: rake install_dependencies + # pkg-config is disabled because it can pick up the different OpenSSL installation # SSL_DIR is set as needed by MSP-Greg/setup-ruby-pkgs # only used with mswin - name: compile - run: rake compile -- --enable-debug $env:SSL_DIR + run: rake compile -- --enable-debug --without-pkg-config $env:SSL_DIR - name: test run: rake test TESTOPTS="-v --no-show-detail-immediately" OSSL_MDEBUG=1 From 9b59f34345a7b04b7e60c8457ae0cd6c18dbd388 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Wed, 17 Feb 2021 22:58:40 +0900 Subject: [PATCH 6/7] bn: check -1 return from BIGNUM functions Although the manpage says that BIGNUM functions return 0 on error, OpenSSL versions before 1.0.2n and current LibreSSL versions may return -1 instead. Note that the implementation of OpenSSL::BN#mod_inverse is extracted from BIGNUM_2c() macro as it didn't really share the same function signature with others. --- ext/openssl/ossl_bn.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/ext/openssl/ossl_bn.c b/ext/openssl/ossl_bn.c index 4666ce6c2..ba5f38b2e 100644 --- a/ext/openssl/ossl_bn.c +++ b/ext/openssl/ossl_bn.c @@ -397,7 +397,7 @@ ossl_bn_is_negative(VALUE self) if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ - if (!BN_##func(result, bn, ossl_bn_ctx)) { \ + if (BN_##func(result, bn, ossl_bn_ctx) <= 0) { \ BN_free(result); \ ossl_raise(eBNError, NULL); \ } \ @@ -423,7 +423,7 @@ BIGNUM_1c(sqr) if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ - if (!BN_##func(result, bn1, bn2)) { \ + if (BN_##func(result, bn1, bn2) <= 0) { \ BN_free(result); \ ossl_raise(eBNError, NULL); \ } \ @@ -456,7 +456,7 @@ BIGNUM_2(sub) if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ - if (!BN_##func(result, bn1, bn2, ossl_bn_ctx)) { \ + if (BN_##func(result, bn1, bn2, ossl_bn_ctx) <= 0) { \ BN_free(result); \ ossl_raise(eBNError, NULL); \ } \ @@ -500,11 +500,21 @@ BIGNUM_2c(gcd) BIGNUM_2c(mod_sqr) /* - * Document-method: OpenSSL::BN#mod_inverse * call-seq: - * bn.mod_inverse(bn2) => aBN + * bn.mod_inverse(bn2) => aBN */ -BIGNUM_2c(mod_inverse) +static VALUE +ossl_bn_mod_inverse(VALUE self, VALUE other) +{ + BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; + VALUE obj; + GetBN(self, bn1); + obj = NewBN(rb_obj_class(self)); + if (!(result = BN_mod_inverse(NULL, bn1, bn2, ossl_bn_ctx))) + ossl_raise(eBNError, "BN_mod_inverse"); + SetBN(obj, result); + return obj; +} /* * call-seq: @@ -553,7 +563,7 @@ ossl_bn_div(VALUE self, VALUE other) if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ - if (!BN_##func(result, bn1, bn2, bn3, ossl_bn_ctx)) { \ + if (BN_##func(result, bn1, bn2, bn3, ossl_bn_ctx) <= 0) { \ BN_free(result); \ ossl_raise(eBNError, NULL); \ } \ @@ -595,7 +605,7 @@ BIGNUM_3c(mod_exp) { \ BIGNUM *bn; \ GetBN(self, bn); \ - if (!BN_##func(bn, NUM2INT(bit))) { \ + if (BN_##func(bn, NUM2INT(bit)) <= 0) { \ ossl_raise(eBNError, NULL); \ } \ return self; \ @@ -655,7 +665,7 @@ ossl_bn_is_bit_set(VALUE self, VALUE bit) if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ - if (!BN_##func(result, bn, b)) { \ + if (BN_##func(result, bn, b) <= 0) { \ BN_free(result); \ ossl_raise(eBNError, NULL); \ } \ @@ -685,7 +695,7 @@ BIGNUM_SHIFT(rshift) int b; \ b = NUM2INT(bits); \ GetBN(self, bn); \ - if (!BN_##func(bn, bn, b)) \ + if (BN_##func(bn, bn, b) <= 0) \ ossl_raise(eBNError, NULL); \ return self; \ } @@ -724,7 +734,7 @@ BIGNUM_SELF_SHIFT(rshift) if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ - if (!BN_##func(result, b, top, bottom)) { \ + if (BN_##func(result, b, top, bottom) <= 0) { \ BN_free(result); \ ossl_raise(eBNError, NULL); \ } \ @@ -753,7 +763,7 @@ BIGNUM_RAND(pseudo_rand) if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ - if (!BN_##func##_range(result, bn)) { \ + if (BN_##func##_range(result, bn) <= 0) { \ BN_free(result); \ ossl_raise(eBNError, NULL); \ } \ From fef83a1015fc8d1714acf1276178dbd80d1ad55e Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Thu, 25 Feb 2021 17:16:29 +0900 Subject: [PATCH 7/7] .github/workflows: update Ruby and OpenSSL/LibreSSL versions --- .github/workflows/test.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 20fbd00d1..48f59c5f0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,7 +11,7 @@ jobs: fail-fast: false matrix: os: [ ubuntu-latest, macos-latest ] - ruby: [ head, 2.7, 2.6, 2.5, 2.4, 2.3 ] + ruby: [ head, "3.0", "2.7", "2.6", "2.5", "2.4", "2.3" ] steps: - name: repo checkout uses: actions/checkout@v2 @@ -38,7 +38,7 @@ jobs: fail-fast: false matrix: os: [ windows-latest ] - ruby: [ mswin, mingw, 2.7, 2.6, 2.5, 2.4, 2.3 ] + ruby: [ mswin, mingw, "3.0", "2.7", "2.6", "2.5", "2.4", "2.3" ] steps: - name: repo checkout uses: actions/checkout@v2 @@ -69,14 +69,14 @@ jobs: fail-fast: false matrix: os: [ ubuntu-latest ] - ruby: [ 2.7 ] + ruby: [ "3.0" ] openssl: - openssl-1.0.1u # EOL - openssl-1.0.2u # EOL - openssl-1.1.0l # EOL - - openssl-1.1.1g + - openssl-1.1.1j - libressl-2.5.5 # EOL - - libressl-3.1.3 + - libressl-3.1.5 - libressl-3.2.0 steps: - name: repo checkout